4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * RCM module to prevent plumbed IP addresses from being removed.
42 #include <sys/param.h>
44 #include <sys/types.h>
46 #include <sys/cladm.h>
48 #include <sys/ioctl.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
55 #include <netinet/ip6.h>
58 #include <libinetutil.h>
60 #include "rcm_module.h"
62 #define SUNW_IP "SUNW_ip/"
63 #define IP_REG_SIZE (9 + INET6_ADDRSTRLEN)
64 #define IP_ANON_USAGE gettext("Plumbed IP Address")
65 #define IP_SUSPEND_ERR gettext("Plumbed IP Addresses cannot be suspended")
66 #define IP_OFFLINE_ERR gettext("Invalid operation: IP cannot be offlined")
67 #define IP_REMOVE_ERR gettext("Invalid operation: IP cannot be removed")
68 #define IP_REG_FAIL gettext("Registration Failed")
69 #define IP_NO_CLUSTER gettext("Could not read cluster network addresses")
71 #define IP_FLAG_NEW 0x00
72 #define IP_FLAG_REG 0x01
73 #define IP_FLAG_CL 0x02
74 #define IP_FLAG_IGNORE 0x04
75 #define IP_FLAG_DELETE 0x08
77 static int ip_anon_register(rcm_handle_t
*);
78 static int ip_anon_unregister(rcm_handle_t
*);
79 static int ip_anon_getinfo(rcm_handle_t
*, char *, id_t
, uint_t
,
80 char **, char **, nvlist_t
*, rcm_info_t
**);
81 static int ip_anon_suspend(rcm_handle_t
*, char *, id_t
,
82 timespec_t
*, uint_t
, char **, rcm_info_t
**);
83 static int ip_anon_resume(rcm_handle_t
*, char *, id_t
, uint_t
,
84 char **, rcm_info_t
**);
85 static int ip_anon_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
86 char **, rcm_info_t
**);
87 static int ip_anon_online(rcm_handle_t
*, char *, id_t
, uint_t
,
88 char **, rcm_info_t
**);
89 static int ip_anon_remove(rcm_handle_t
*, char *, id_t
, uint_t
,
90 char **, rcm_info_t
**);
92 static int exclude_ipv4(cladm_netaddrs_t exclude_addrs
,
94 static int exclude_ipv6(cladm_netaddrs_t exclude_addrs
,
98 typedef struct ip_status
{
100 char device
[IP_REG_SIZE
];
101 struct ip_status
*next
;
104 static ip_status_t
*findreg(char *reg
);
105 static ip_status_t
*addreg(char *reg
);
106 static int deletereg(ip_status_t
*entry
);
108 static ip_status_t
*ip_list
= NULL
;
109 static mutex_t ip_list_lock
;
111 static struct rcm_mod_ops ip_anon_ops
=
130 return (&ip_anon_ops
);
136 return ("RCM IP address module 1.4");
144 /* free the registration list */
146 (void) mutex_lock(&ip_list_lock
);
147 while (ip_list
!= NULL
) {
148 tlist
= ip_list
->next
;
152 (void) mutex_unlock(&ip_list_lock
);
154 (void) mutex_destroy(&ip_list_lock
);
155 return (RCM_SUCCESS
);
159 ip_anon_register(rcm_handle_t
*hdl
)
162 struct ifaddrlist
*al
= NULL
, *al6
= NULL
;
163 char errbuf
[ERRBUFSIZE
];
164 char treg
[IP_REG_SIZE
], tstr
[IP_REG_SIZE
];
165 cladm_netaddrs_t exclude_addrs
;
166 int num_ifs
, num_ifs6
, i
, ret
;
167 uint32_t num_exclude_addrs
= 0;
168 ip_status_t
*tlist
, *tentry
;
170 (void) mutex_lock(&ip_list_lock
);
172 rcm_log_message(RCM_DEBUG
, "ip_anon: registration refresh.\n");
174 exclude_addrs
.cladm_num_netaddrs
= 0;
176 if (_cladm(CL_INITIALIZE
, CL_GET_BOOTFLAG
, &bootflags
) != 0) {
177 rcm_log_message(RCM_ERROR
,
178 gettext("unable to check cluster status\n"));
179 (void) mutex_unlock(&ip_list_lock
);
180 return (RCM_FAILURE
);
183 rcm_log_message(RCM_DEBUG
,
184 "ip_anon: cladm bootflags=%d\n", bootflags
);
186 if (bootflags
== 3) {
188 /* build the exclusion list */
190 if ((ret
= _cladm(CL_CONFIG
, CL_GET_NUM_NETADDRS
,
191 &num_exclude_addrs
)) == 0) {
192 exclude_addrs
.cladm_num_netaddrs
= num_exclude_addrs
;
194 if (num_exclude_addrs
== 0)
195 rcm_log_message(RCM_DEBUG
,
196 "ip_anon: no addresses excluded\n");
198 if ((exclude_addrs
.cladm_netaddrs_array
=
199 malloc(sizeof (cladm_netaddr_entry_t
) *
200 (num_exclude_addrs
))) == NULL
) {
201 rcm_log_message(RCM_ERROR
,
202 gettext("out of memory\n"));
203 (void) mutex_unlock(&ip_list_lock
);
204 return (RCM_FAILURE
);
207 if ((ret
= _cladm(CL_CONFIG
,
208 CL_GET_NETADDRS
, &exclude_addrs
))
210 rcm_log_message(RCM_ERROR
,
212 (void) mutex_unlock(&ip_list_lock
);
213 return (RCM_FAILURE
);
218 if ((ret
!= 0) && (errno
== EINVAL
)) {
219 rcm_log_message(RCM_DEBUG
,
220 "no _cladm() backend to get addrs\n");
222 rcm_log_message(RCM_ERROR
, IP_NO_CLUSTER
);
223 (void) mutex_unlock(&ip_list_lock
);
224 return (RCM_FAILURE
);
227 rcm_log_message(RCM_DEBUG
,
228 "cladm returned %d errno=%d\n", ret
, errno
);
230 rcm_log_message(RCM_DEBUG
,
231 "ip_anon: num exclude addrs: %d\n",
232 exclude_addrs
.cladm_num_netaddrs
);
234 /* print the exclusion list for debugging purposes */
236 for (i
= 0; i
< exclude_addrs
.cladm_num_netaddrs
; i
++) {
237 (void) strcpy(treg
, "<UNKNOWN>");
238 (void) strcpy(tstr
, "<UNKNOWN>");
239 if (exclude_addrs
.cladm_netaddrs_array
[i
].\
240 cl_ipversion
== IPV4_VERSION
) {
241 (void) inet_ntop(AF_INET
,
242 &exclude_addrs
.cladm_netaddrs_array
[i
].
243 cl_ipv_un
.cl_ipv4
.ipv4_netaddr
,
244 treg
, INET_ADDRSTRLEN
);
246 (void) inet_ntop(AF_INET
,
247 &exclude_addrs
.cladm_netaddrs_array
[i
].
248 cl_ipv_un
.cl_ipv4
.ipv4_netmask
,
249 tstr
, INET_ADDRSTRLEN
);
252 if (exclude_addrs
.cladm_netaddrs_array
[i
].\
253 cl_ipversion
== IPV6_VERSION
) {
254 (void) inet_ntop(AF_INET6
,
255 &exclude_addrs
.cladm_netaddrs_array
[i
].
256 cl_ipv_un
.cl_ipv6
.ipv6_netaddr
,
257 treg
, INET6_ADDRSTRLEN
);
259 (void) inet_ntop(AF_INET6
,
260 &exclude_addrs
.cladm_netaddrs_array
[i
].
261 cl_ipv_un
.cl_ipv6
.ipv6_netmask
,
262 tstr
, INET6_ADDRSTRLEN
);
264 rcm_log_message(RCM_DEBUG
, "IPV%d: %s %s\n",
265 exclude_addrs
.cladm_netaddrs_array
[i
].
266 cl_ipversion
, treg
, tstr
);
271 /* obtain a list of all IPv4 and IPv6 addresses in the system */
273 rcm_log_message(RCM_DEBUG
,
274 "ip_anon: obtaining list of IPv4 addresses.\n");
275 num_ifs
= ifaddrlist(&al
, AF_INET
, LIFC_UNDER_IPMP
, errbuf
);
277 rcm_log_message(RCM_ERROR
,
278 gettext("cannot get IPv4 address list errno=%d (%s)\n"),
280 (void) mutex_unlock(&ip_list_lock
);
281 return (RCM_FAILURE
);
284 rcm_log_message(RCM_DEBUG
,
285 "ip_anon: obtaining list of IPv6 addresses.\n");
287 num_ifs6
= ifaddrlist(&al6
, AF_INET6
, LIFC_UNDER_IPMP
, errbuf
);
288 if (num_ifs6
== -1) {
289 rcm_log_message(RCM_ERROR
,
290 gettext("cannot get IPv6 address list errno=%d (%s)\n"),
293 (void) mutex_unlock(&ip_list_lock
);
294 return (RCM_FAILURE
);
297 /* check the state of outstanding registrations against the list */
299 rcm_log_message(RCM_DEBUG
,
300 "ip_anon: checking outstanding registrations.\n");
303 while (tlist
!= NULL
) {
304 tlist
->flags
|= IP_FLAG_DELETE
;
310 rcm_log_message(RCM_DEBUG
, "ip_anon: checking IPv4 addresses.\n");
312 for (i
= 0; i
< num_ifs
; i
++) {
313 (void) inet_ntop(AF_INET
, &al
[i
].addr
.addr
, tstr
,
315 (void) strcpy(treg
, SUNW_IP
);
316 (void) strcat(treg
, tstr
);
318 if ((tlist
= findreg(treg
)) == NULL
)
319 tlist
= addreg(treg
);
321 tlist
->flags
&= (~IP_FLAG_DELETE
);
324 rcm_log_message(RCM_ERROR
,
325 gettext("out of memory\n"));
328 (void) mutex_unlock(&ip_list_lock
);
329 return (RCM_FAILURE
);
332 if (exclude_ipv4(exclude_addrs
, al
[i
].addr
.addr
.s_addr
))
333 tlist
->flags
|= IP_FLAG_CL
;
338 rcm_log_message(RCM_DEBUG
, "ip_anon: checking IPv6 addresses.\n");
340 for (i
= 0; i
< num_ifs6
; i
++) {
341 (void) inet_ntop(AF_INET6
, &al6
[i
].addr
.addr
, tstr
,
343 (void) strcpy(treg
, SUNW_IP
);
344 (void) strcat(treg
, tstr
);
346 if ((tlist
= findreg(treg
)) == NULL
)
347 tlist
= addreg(treg
);
349 tlist
->flags
&= (~IP_FLAG_DELETE
);
352 rcm_log_message(RCM_ERROR
,
353 gettext("out of memory\n"));
356 (void) mutex_unlock(&ip_list_lock
);
357 return (RCM_FAILURE
);
360 if (exclude_ipv6(exclude_addrs
, al6
[i
].addr
.addr6
._S6_un
.\
362 tlist
->flags
|= IP_FLAG_CL
;
365 rcm_log_message(RCM_DEBUG
, "ip_anon: updating reg. state.\n");
367 /* examine the list of ip address registrations and their state */
370 while (tlist
!= NULL
) {
374 if (tentry
->flags
& IP_FLAG_DELETE
) {
375 if (tentry
->flags
& IP_FLAG_REG
) {
376 rcm_log_message(RCM_DEBUG
,
377 "ip_anon: unregistering interest in %s\n",
379 if (rcm_unregister_interest(hdl
,
380 tentry
->device
, 0) != 0) {
381 rcm_log_message(RCM_ERROR
,
382 gettext("failed to unregister"));
385 (void) deletereg(tentry
);
386 } else if (!(tentry
->flags
& IP_FLAG_IGNORE
)) {
388 * If the registration is not a clustered devices and
389 * not already registered, then RCM doesn't
390 * currently know about it.
392 if (!(tentry
->flags
& IP_FLAG_CL
) &&
393 !(tentry
->flags
& IP_FLAG_REG
)) {
394 tentry
->flags
|= IP_FLAG_REG
;
395 rcm_log_message(RCM_DEBUG
,
396 "ip_anon: registering interest in %s\n",
398 if (rcm_register_interest(hdl
,
399 tentry
->device
, 0, NULL
) !=
401 rcm_log_message(RCM_ERROR
,
405 (void) mutex_unlock(&ip_list_lock
);
406 return (RCM_FAILURE
);
408 rcm_log_message(RCM_DEBUG
,
409 "ip_anon: registered %s\n",
415 * If the entry is registered and clustered, then
416 * the configuration has been changed and it
417 * should be unregistered.
419 if ((tentry
->flags
& IP_FLAG_REG
) &
420 (tentry
->flags
& IP_FLAG_CL
)) {
421 rcm_log_message(RCM_DEBUG
,
422 "ip_anon: unregistering in %s\n",
424 if (rcm_unregister_interest(hdl
,
425 tentry
->device
, 0) != 0) {
426 rcm_log_message(RCM_ERROR
,
427 gettext("failed to unregister"));
429 tentry
->flags
&= (~IP_FLAG_REG
);
435 while (tlist
!= NULL
) {
436 rcm_log_message(RCM_DEBUG
, "ip_anon: %s (%Xh)\n",
437 tlist
->device
, tlist
->flags
);
440 rcm_log_message(RCM_DEBUG
, "ip_anon: registration complete.\n");
444 (void) mutex_unlock(&ip_list_lock
);
445 return (RCM_SUCCESS
);
449 ip_anon_unregister(rcm_handle_t
*hdl
)
453 (void) mutex_lock(&ip_list_lock
);
456 while (tlist
!= NULL
) {
457 if ((tlist
->flags
& IP_FLAG_REG
)) {
458 if (rcm_unregister_interest(hdl
,
459 tlist
->device
, 0) != 0) {
460 rcm_log_message(RCM_ERROR
,
461 gettext("failed to unregister"));
463 tlist
->flags
&= (~IP_FLAG_REG
);
468 (void) mutex_unlock(&ip_list_lock
);
470 return (RCM_SUCCESS
);
475 ip_anon_getinfo(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
, uint_t flags
,
476 char **infostr
, char **errstr
, nvlist_t
*props
, rcm_info_t
**dependent
)
479 assert(rsrcname
!= NULL
&& infostr
!= NULL
);
481 if ((*infostr
= strdup(IP_ANON_USAGE
)) == NULL
)
482 rcm_log_message(RCM_ERROR
, gettext("strdup failure\n"));
484 return (RCM_SUCCESS
);
489 ip_anon_suspend(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
,
490 timespec_t
*interval
, uint_t flags
, char **errstr
,
491 rcm_info_t
**dependent
)
493 if ((*errstr
= strdup(IP_SUSPEND_ERR
)) == NULL
)
494 rcm_log_message(RCM_ERROR
, gettext("strdup failure\n"));
496 return (RCM_FAILURE
);
501 ip_anon_resume(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
, uint_t flags
,
502 char **errstr
, rcm_info_t
**dependent
)
504 return (RCM_SUCCESS
);
509 ip_anon_offline(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
, uint_t flags
,
510 char **errstr
, rcm_info_t
**dependent
)
512 if ((*errstr
= strdup(IP_OFFLINE_ERR
)) == NULL
)
513 rcm_log_message(RCM_ERROR
, gettext("strdup failure\n"));
515 return (RCM_FAILURE
);
520 ip_anon_online(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
, uint_t flags
,
521 char **errstr
, rcm_info_t
**dependent
)
523 return (RCM_SUCCESS
);
528 ip_anon_remove(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
, uint_t flags
,
529 char **errstr
, rcm_info_t
**dependent
)
531 if ((*errstr
= strdup(IP_REMOVE_ERR
)) == NULL
)
532 rcm_log_message(RCM_ERROR
, gettext("strdup failure\n"));
534 return (RCM_FAILURE
);
538 * Call with ip_list_lock held.
549 while ((tlist
!= NULL
) && (!done
)) {
550 if (strcmp(tlist
->device
, reg
) == 0)
562 ip_status_t
*tlist
, *tentry
;
564 tentry
= (ip_status_t
*)malloc(sizeof (ip_status_t
));
568 tentry
->flags
= IP_FLAG_NEW
;
570 (void) strcpy(tentry
->device
, reg
);
576 while (tlist
->next
!= NULL
)
578 tlist
->next
= tentry
;
585 deletereg(ip_status_t
*entry
)
592 if (entry
== ip_list
) {
593 ip_list
= ip_list
->next
;
597 while ((tlist
->next
!= NULL
) && (tlist
->next
!= entry
))
600 if (tlist
->next
!= entry
)
602 tlist
->next
= entry
->next
;
609 exclude_ipv4(cladm_netaddrs_t exclude_addrs
, ipaddr_t address
)
612 char taddr
[IP_REG_SIZE
], tmask
[IP_REG_SIZE
], tmatch
[IP_REG_SIZE
];
613 ipaddr_t ipv4_netaddr
, ipv4_netmask
;
615 (void) inet_ntop(AF_INET
, &address
, taddr
, INET_ADDRSTRLEN
);
617 rcm_log_message(RCM_DEBUG
, "ip_anon: exclude_ipv4 (%s, %d)\n",
618 taddr
, exclude_addrs
.cladm_num_netaddrs
);
620 * If this falls in the exclusion list, the IP_FLAG_CL
621 * bit should be set for the adapter.
623 for (i
= 0; i
< exclude_addrs
.cladm_num_netaddrs
; i
++) {
624 if (exclude_addrs
.cladm_netaddrs_array
[i
].\
625 cl_ipversion
== IPV4_VERSION
) {
627 ipv4_netaddr
= exclude_addrs
.\
628 cladm_netaddrs_array
[i
].cl_ipv_un
.cl_ipv4
.\
630 ipv4_netmask
= exclude_addrs
.\
631 cladm_netaddrs_array
[i
].cl_ipv_un
.cl_ipv4
.\
634 (void) inet_ntop(AF_INET
, &ipv4_netaddr
, tmatch
,
636 (void) inet_ntop(AF_INET
, &ipv4_netmask
, tmask
,
639 if ((address
& ipv4_netmask
) == ipv4_netaddr
) {
640 rcm_log_message(RCM_DEBUG
,
641 "ip_anon: matched %s:%s => %s\n",
642 taddr
, tmask
, tmatch
);
647 rcm_log_message(RCM_DEBUG
, "ip_anon: no match for %s\n",
653 exclude_ipv6(cladm_netaddrs_t exclude_addrs
, uint32_t address
[4])
656 uint32_t addr
[4], ipv6_netaddr
[4], ipv6_netmask
[4];
657 char taddr
[IP_REG_SIZE
], tmask
[IP_REG_SIZE
], tmatch
[IP_REG_SIZE
];
659 (void) inet_ntop(AF_INET6
, address
, taddr
, INET6_ADDRSTRLEN
);
662 * If this falls in the exclusion list, the IP_FLAG_CL
663 * bit should be set for the adapter.
666 for (i
= 0; i
< exclude_addrs
.cladm_num_netaddrs
; i
++) {
667 if (exclude_addrs
.cladm_netaddrs_array
[i
].\
668 cl_ipversion
== IPV6_VERSION
) {
670 for (j
= 0; j
< 4; j
++) {
671 ipv6_netaddr
[j
] = exclude_addrs
.\
672 cladm_netaddrs_array
[i
].\
673 cl_ipv_un
.cl_ipv6
.ipv6_netaddr
[j
];
675 ipv6_netmask
[j
] = exclude_addrs
.\
676 cladm_netaddrs_array
[i
].\
677 cl_ipv_un
.cl_ipv6
.ipv6_netmask
[j
];
679 addr
[j
] = address
[j
] & ipv6_netmask
[j
];
680 if (addr
[j
] == ipv6_netaddr
[j
])
684 (void) inet_ntop(AF_INET6
, ipv6_netaddr
, tmatch
,
686 (void) inet_ntop(AF_INET6
, ipv6_netmask
, tmask
,
693 rcm_log_message(RCM_DEBUG
, "ip_anon: no match for %s\n",