8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / rcm_daemon / common / ip_anon_rcm.c
blob6e1fe1bf39363f505d607eb5c663038f32e5d54b
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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.
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include <memory.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <thread.h>
38 #include <synch.h>
39 #include <assert.h>
40 #include <errno.h>
41 #include <libintl.h>
42 #include <sys/param.h>
43 #include <sys/wait.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/cladm.h>
47 #include <sys/file.h>
48 #include <sys/ioctl.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <sys/time.h>
52 #include <net/if.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
55 #include <netinet/ip6.h>
56 #include <inet/ip.h>
57 #include <inet/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,
93 ipaddr_t address);
94 static int exclude_ipv6(cladm_netaddrs_t exclude_addrs,
95 uint32_t address[4]);
98 typedef struct ip_status {
99 int flags;
100 char device[IP_REG_SIZE];
101 struct ip_status *next;
102 } ip_status_t;
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 =
113 RCM_MOD_OPS_VERSION,
114 ip_anon_register,
115 ip_anon_unregister,
116 ip_anon_getinfo,
117 ip_anon_suspend,
118 ip_anon_resume,
119 ip_anon_offline,
120 ip_anon_online,
121 ip_anon_remove,
122 NULL,
123 NULL,
124 NULL
127 struct rcm_mod_ops *
128 rcm_mod_init()
130 return (&ip_anon_ops);
133 const char *
134 rcm_mod_info()
136 return ("RCM IP address module 1.4");
140 rcm_mod_fini()
142 ip_status_t *tlist;
144 /* free the registration list */
146 (void) mutex_lock(&ip_list_lock);
147 while (ip_list != NULL) {
148 tlist = ip_list->next;
149 free(ip_list);
150 ip_list = tlist;
152 (void) mutex_unlock(&ip_list_lock);
154 (void) mutex_destroy(&ip_list_lock);
155 return (RCM_SUCCESS);
158 static int
159 ip_anon_register(rcm_handle_t *hdl)
161 int bootflags;
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");
197 else {
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))
209 != 0) {
210 rcm_log_message(RCM_ERROR,
211 IP_NO_CLUSTER);
212 (void) mutex_unlock(&ip_list_lock);
213 return (RCM_FAILURE);
217 } else {
218 if ((ret != 0) && (errno == EINVAL)) {
219 rcm_log_message(RCM_DEBUG,
220 "no _cladm() backend to get addrs\n");
221 } else {
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);
276 if (num_ifs == -1) {
277 rcm_log_message(RCM_ERROR,
278 gettext("cannot get IPv4 address list errno=%d (%s)\n"),
279 errno, errbuf);
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"),
291 errno, errbuf);
292 free(al);
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");
302 tlist = ip_list;
303 while (tlist != NULL) {
304 tlist->flags |= IP_FLAG_DELETE;
305 tlist = tlist->next;
308 /* IPv4 */
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,
314 INET_ADDRSTRLEN);
315 (void) strcpy(treg, SUNW_IP);
316 (void) strcat(treg, tstr);
318 if ((tlist = findreg(treg)) == NULL)
319 tlist = addreg(treg);
320 else
321 tlist->flags &= (~IP_FLAG_DELETE);
323 if (tlist == NULL) {
324 rcm_log_message(RCM_ERROR,
325 gettext("out of memory\n"));
326 free(al);
327 free(al6);
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;
336 /* IPv6 */
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,
342 INET6_ADDRSTRLEN);
343 (void) strcpy(treg, SUNW_IP);
344 (void) strcat(treg, tstr);
346 if ((tlist = findreg(treg)) == NULL)
347 tlist = addreg(treg);
348 else
349 tlist->flags &= (~IP_FLAG_DELETE);
351 if (tlist == NULL) {
352 rcm_log_message(RCM_ERROR,
353 gettext("out of memory\n"));
354 free(al);
355 free(al6);
356 (void) mutex_unlock(&ip_list_lock);
357 return (RCM_FAILURE);
360 if (exclude_ipv6(exclude_addrs, al6[i].addr.addr6._S6_un.\
361 _S6_u32))
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 */
369 tlist = ip_list;
370 while (tlist != NULL) {
371 tentry = tlist;
372 tlist = tlist->next;
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",
378 tentry->device);
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",
397 tentry->device);
398 if (rcm_register_interest(hdl,
399 tentry->device, 0, NULL) !=
400 RCM_SUCCESS) {
401 rcm_log_message(RCM_ERROR,
402 IP_REG_FAIL);
403 free(al);
404 free(al6);
405 (void) mutex_unlock(&ip_list_lock);
406 return (RCM_FAILURE);
407 } else {
408 rcm_log_message(RCM_DEBUG,
409 "ip_anon: registered %s\n",
410 tentry->device);
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",
423 tentry->device);
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);
434 tlist = ip_list;
435 while (tlist != NULL) {
436 rcm_log_message(RCM_DEBUG, "ip_anon: %s (%Xh)\n",
437 tlist->device, tlist->flags);
438 tlist = tlist->next;
440 rcm_log_message(RCM_DEBUG, "ip_anon: registration complete.\n");
442 free(al);
443 free(al6);
444 (void) mutex_unlock(&ip_list_lock);
445 return (RCM_SUCCESS);
448 static int
449 ip_anon_unregister(rcm_handle_t *hdl)
451 ip_status_t *tlist;
453 (void) mutex_lock(&ip_list_lock);
455 tlist = ip_list;
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);
465 tlist = tlist->next;
468 (void) mutex_unlock(&ip_list_lock);
470 return (RCM_SUCCESS);
473 /*ARGSUSED*/
474 static int
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);
487 /*ARGSUSED*/
488 static int
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);
499 /*ARGSUSED*/
500 static int
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);
507 /*ARGSUSED*/
508 static int
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);
518 /*ARGSUSED*/
519 static int
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);
526 /*ARGSUSED*/
527 static int
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.
541 static ip_status_t *
542 findreg(char *reg)
544 ip_status_t *tlist;
545 int done;
547 tlist = ip_list;
548 done = 0;
549 while ((tlist != NULL) && (!done)) {
550 if (strcmp(tlist->device, reg) == 0)
551 done = 1;
552 else
553 tlist = tlist->next;
556 return (tlist);
559 static ip_status_t *
560 addreg(char *reg)
562 ip_status_t *tlist, *tentry;
564 tentry = (ip_status_t *)malloc(sizeof (ip_status_t));
565 if (tentry == NULL)
566 return (tentry);
568 tentry->flags = IP_FLAG_NEW;
569 tentry->next = NULL;
570 (void) strcpy(tentry->device, reg);
572 if (ip_list == NULL)
573 ip_list = tentry;
574 else {
575 tlist = ip_list;
576 while (tlist->next != NULL)
577 tlist = tlist->next;
578 tlist->next = tentry;
581 return (tentry);
584 static int
585 deletereg(ip_status_t *entry)
587 ip_status_t *tlist;
589 if (entry == NULL)
590 return (-1);
592 if (entry == ip_list) {
593 ip_list = ip_list->next;
594 free(entry);
595 } else {
596 tlist = ip_list;
597 while ((tlist->next != NULL) && (tlist->next != entry))
598 tlist = tlist->next;
600 if (tlist->next != entry)
601 return (-1);
602 tlist->next = entry->next;
603 free(entry);
605 return (0);
608 static int
609 exclude_ipv4(cladm_netaddrs_t exclude_addrs, ipaddr_t address)
611 int i;
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.\
629 ipv4_netaddr;
630 ipv4_netmask = exclude_addrs.\
631 cladm_netaddrs_array[i].cl_ipv_un.cl_ipv4.\
632 ipv4_netmask;
634 (void) inet_ntop(AF_INET, &ipv4_netaddr, tmatch,
635 INET_ADDRSTRLEN);
636 (void) inet_ntop(AF_INET, &ipv4_netmask, tmask,
637 INET_ADDRSTRLEN);
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);
643 return (1);
647 rcm_log_message(RCM_DEBUG, "ip_anon: no match for %s\n",
648 taddr);
649 return (0);
652 static int
653 exclude_ipv6(cladm_netaddrs_t exclude_addrs, uint32_t address[4])
655 int i, j, numequal;
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) {
669 numequal = 0;
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])
681 numequal++;
684 (void) inet_ntop(AF_INET6, ipv6_netaddr, tmatch,
685 INET6_ADDRSTRLEN);
686 (void) inet_ntop(AF_INET6, ipv6_netmask, tmask,
687 INET6_ADDRSTRLEN);
689 if (numequal == 4)
690 return (1);
693 rcm_log_message(RCM_DEBUG, "ip_anon: no match for %s\n",
694 taddr);
695 return (0);