dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / rcm_daemon / common / ip_rcm.c
blobb471a09d2844f99e59c1d8f4e6149a055bea670f
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 (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
26 * This RCM module adds support to the RCM framework for IP managed
27 * interfaces.
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <assert.h>
34 #include <string.h>
35 #include <synch.h>
36 #include <libintl.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <sys/types.h>
40 #include <sys/wait.h>
41 #include <sys/stat.h>
42 #include <sys/socket.h>
43 #include <sys/sockio.h>
44 #include <net/if.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <stropts.h>
48 #include <strings.h>
49 #include <sys/sysmacros.h>
50 #include <inet/ip.h>
51 #include <libinetutil.h>
52 #include <libdllink.h>
53 #include <libgen.h>
54 #include <ipmp_admin.h>
55 #include <libipadm.h>
57 #include "rcm_module.h"
60 * Definitions
62 #define _(x) gettext(x)
64 /* Some generic well-knowns and defaults used in this module */
65 #define ARP_MOD_NAME "arp" /* arp module */
66 #define IP_MAX_MODS 9 /* max modules pushed on intr */
67 #define MAX_RECONFIG_SIZE 1024 /* Max. reconfig string size */
69 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
70 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
72 #define RCM_STR_SUNW_IP "SUNW_ip/" /* IP address export prefix */
74 #define SBIN_IFCONFIG "/sbin/ifconfig" /* ifconfig command */
75 #define SBIN_IFPARSE "/sbin/ifparse" /* ifparse command */
76 #define DHCPFILE_FMT "/etc/dhcp.%s" /* DHCP config file */
77 #define CFGFILE_FMT_IPV4 "/etc/hostname.%s" /* IPV4 config file */
78 #define CFGFILE_FMT_IPV6 "/etc/hostname6.%s" /* IPV6 config file */
79 #define CFG_CMDS_STD " netmask + broadcast + up" /* Normal config string */
80 #define CFG_DHCP_CMD "dhcp wait 0" /* command to start DHCP */
82 /* Some useful macros */
83 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
84 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
85 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
87 /* Interface Cache state flags */
88 #define CACHE_IF_STALE 0x1 /* stale cached data */
89 #define CACHE_IF_NEW 0x2 /* new cached interface */
90 #define CACHE_IF_OFFLINED 0x4 /* interface offlined */
91 #define CACHE_IF_IGNORE 0x8 /* state held elsewhere */
93 /* Network Cache lookup options */
94 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
95 #define CACHE_REFRESH 0x2 /* refresh cache */
97 /* RCM IPMP Module specific property definitions */
98 #define RCM_IPMP_MIN_REDUNDANCY 1 /* default min. redundancy */
100 /* Stream module operations */
101 #define MOD_INSERT 0 /* Insert a mid-stream module */
102 #define MOD_REMOVE 1 /* Remove a mid-stream module */
103 #define MOD_CHECK 2 /* Check mid-stream module safety */
106 * IP module data types
109 /* Physical interface representation */
110 typedef struct ip_pif {
111 char pi_ifname[LIFNAMSIZ]; /* interface name */
112 char pi_grname[LIFGRNAMSIZ]; /* IPMP group name */
113 struct ip_lif *pi_lifs; /* ptr to logical interfaces */
114 } ip_pif_t;
116 /* Logical interface representation */
117 typedef struct ip_lif
119 struct ip_lif *li_next; /* ptr to next lif */
120 struct ip_lif *li_prev; /* previous next ptr */
121 ip_pif_t *li_pif; /* back ptr to phy int */
122 ushort_t li_ifnum; /* interface number */
123 union {
124 sa_family_t family;
125 struct sockaddr_storage storage;
126 struct sockaddr_in ip4; /* IPv4 */
127 struct sockaddr_in6 ip6; /* IPv6 */
128 } li_addr;
129 uint64_t li_ifflags; /* current IFF_* flags */
130 int li_modcnt; /* # of modules */
131 char *li_modules[IP_MAX_MODS]; /* module list pushed */
132 char *li_reconfig; /* Reconfiguration string */
133 int32_t li_cachestate; /* cache state flags */
134 } ip_lif_t;
136 /* Cache element */
137 typedef struct ip_cache
139 struct ip_cache *ip_next; /* next cached resource */
140 struct ip_cache *ip_prev; /* prev cached resource */
141 char *ip_resource; /* resource name */
142 ip_pif_t *ip_pif; /* ptr to phy int */
143 int32_t ip_ifred; /* min. redundancy */
144 int ip_cachestate; /* cache state flags */
145 } ip_cache_t;
148 * Global cache for network interfaces
150 static ip_cache_t cache_head;
151 static ip_cache_t cache_tail;
152 static mutex_t cache_lock;
153 static int events_registered = 0;
155 static dladm_handle_t dld_handle = NULL;
156 static ipadm_handle_t ip_handle = NULL;
159 * RCM module interface prototypes
161 static int ip_register(rcm_handle_t *);
162 static int ip_unregister(rcm_handle_t *);
163 static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t,
164 char **, char **, nvlist_t *, rcm_info_t **);
165 static int ip_suspend(rcm_handle_t *, char *, id_t,
166 timespec_t *, uint_t, char **, rcm_info_t **);
167 static int ip_resume(rcm_handle_t *, char *, id_t, uint_t,
168 char **, rcm_info_t **);
169 static int ip_offline(rcm_handle_t *, char *, id_t, uint_t,
170 char **, rcm_info_t **);
171 static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
172 char **, rcm_info_t **);
173 static int ip_remove(rcm_handle_t *, char *, id_t, uint_t,
174 char **, rcm_info_t **);
175 static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t,
176 char **, nvlist_t *, rcm_info_t **);
178 /* Module private routines */
179 static void free_cache();
180 static int update_cache(rcm_handle_t *);
181 static void cache_remove(ip_cache_t *);
182 static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char);
183 static void free_node(ip_cache_t *);
184 static void cache_insert(ip_cache_t *);
185 static char *ip_usage(ip_cache_t *);
186 static int update_pif(rcm_handle_t *, int, int, struct ifaddrs *);
187 static int ip_ipmp_offline(ip_cache_t *);
188 static int ip_ipmp_undo_offline(ip_cache_t *);
189 static int if_cfginfo(ip_cache_t *, uint_t);
190 static int if_unplumb(ip_cache_t *);
191 static int if_replumb(ip_cache_t *);
192 static void ip_log_err(ip_cache_t *, char **, char *);
193 static char *get_link_resource(const char *);
194 static void clr_cfg_state(ip_pif_t *);
195 static int modop(char *, char *, int, char);
196 static int get_modlist(char *, ip_lif_t *);
197 static int ip_domux2fd(int *, int *, int *, struct lifreq *);
198 static int ip_plink(int, int, int, struct lifreq *);
199 static int ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
200 rcm_info_t **);
201 static int ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
202 rcm_info_t **);
203 static char **ip_get_addrlist(ip_cache_t *);
204 static void ip_free_addrlist(char **);
205 static void ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **,
206 uint_t, rcm_info_t **);
207 static boolean_t ip_addrstr(ip_lif_t *, char *, size_t);
209 static int if_configure_hostname(datalink_id_t);
210 static int if_configure_ipadm(datalink_id_t);
211 static boolean_t if_hostname_exists(char *, sa_family_t);
212 static boolean_t isgrouped(const char *);
213 static int if_config_inst(const char *, FILE *, int, boolean_t);
214 static uint_t ntok(const char *cp);
215 static boolean_t ifconfig(const char *, const char *, const char *, boolean_t);
217 /* Module-Private data */
218 static struct rcm_mod_ops ip_ops =
220 RCM_MOD_OPS_VERSION,
221 ip_register,
222 ip_unregister,
223 ip_get_info,
224 ip_suspend,
225 ip_resume,
226 ip_offline,
227 ip_undo_offline,
228 ip_remove,
229 NULL,
230 NULL,
231 ip_notify_event
235 * rcm_mod_init() - Update registrations, and return the ops structure.
237 struct rcm_mod_ops *
238 rcm_mod_init(void)
240 char errmsg[DLADM_STRSIZE];
241 dladm_status_t status;
242 ipadm_status_t iph_status;
244 rcm_log_message(RCM_TRACE1, "IP: mod_init\n");
246 cache_head.ip_next = &cache_tail;
247 cache_head.ip_prev = NULL;
248 cache_tail.ip_prev = &cache_head;
249 cache_tail.ip_next = NULL;
250 (void) mutex_init(&cache_lock, 0, NULL);
252 if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
253 rcm_log_message(RCM_WARNING,
254 "IP: mod_init failed: cannot get datalink handle: %s\n",
255 dladm_status2str(status, errmsg));
256 return (NULL);
259 if ((iph_status = ipadm_open(&ip_handle, 0)) != IPADM_SUCCESS) {
260 rcm_log_message(RCM_ERROR,
261 "IP: mod_init failed: cannot get IP handle: %s\n",
262 ipadm_status2str(iph_status));
263 dladm_close(dld_handle);
264 dld_handle = NULL;
265 return (NULL);
268 /* Return the ops vectors */
269 return (&ip_ops);
273 * rcm_mod_info() - Return a string describing this module.
275 const char *
276 rcm_mod_info(void)
278 rcm_log_message(RCM_TRACE1, "IP: mod_info\n");
280 return ("IP Multipathing module version 1.23");
284 * rcm_mod_fini() - Destroy the network interfaces cache.
287 rcm_mod_fini(void)
289 rcm_log_message(RCM_TRACE1, "IP: mod_fini\n");
291 free_cache();
292 (void) mutex_destroy(&cache_lock);
294 dladm_close(dld_handle);
295 ipadm_close(ip_handle);
296 return (RCM_SUCCESS);
300 * ip_register() - Make sure the cache is properly sync'ed, and its
301 * registrations are in order.
303 static int
304 ip_register(rcm_handle_t *hd)
306 rcm_log_message(RCM_TRACE1, "IP: register\n");
308 /* Guard against bad arguments */
309 assert(hd != NULL);
311 if (update_cache(hd) < 0)
312 return (RCM_FAILURE);
315 * Need to register interest in all new resources
316 * getting attached, so we get attach event notifications
318 if (!events_registered) {
319 if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
320 != RCM_SUCCESS) {
321 rcm_log_message(RCM_ERROR,
322 _("IP: failed to register %s\n"),
323 RCM_RESOURCE_LINK_NEW);
324 return (RCM_FAILURE);
325 } else {
326 rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
327 RCM_RESOURCE_LINK_NEW);
328 events_registered++;
332 return (RCM_SUCCESS);
336 * ip_unregister() - Walk the cache, unregistering all the networks.
338 static int
339 ip_unregister(rcm_handle_t *hd)
341 ip_cache_t *probe;
343 rcm_log_message(RCM_TRACE1, "IP: unregister\n");
345 /* Guard against bad arguments */
346 assert(hd != NULL);
348 /* Walk the cache, unregistering everything */
349 (void) mutex_lock(&cache_lock);
350 probe = cache_head.ip_next;
351 while (probe != &cache_tail) {
352 if (rcm_unregister_interest(hd, probe->ip_resource, 0)
353 != RCM_SUCCESS) {
354 /* unregister failed for whatever reason */
355 (void) mutex_unlock(&cache_lock);
356 return (RCM_FAILURE);
358 cache_remove(probe);
359 free_node(probe);
360 probe = cache_head.ip_next;
362 (void) mutex_unlock(&cache_lock);
365 * Need to unregister interest in all new resources
367 if (events_registered) {
368 if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
369 != RCM_SUCCESS) {
370 rcm_log_message(RCM_ERROR,
371 _("IP: failed to unregister %s\n"),
372 RCM_RESOURCE_LINK_NEW);
373 return (RCM_FAILURE);
374 } else {
375 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
376 RCM_RESOURCE_LINK_NEW);
377 events_registered--;
381 return (RCM_SUCCESS);
385 * ip_offline() - Offline an interface.
387 static int
388 ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
389 char **errorp, rcm_info_t **depend_info)
391 ip_cache_t *node;
392 ip_pif_t *pif;
393 boolean_t detachable = B_FALSE;
394 boolean_t ipmp;
395 int retval;
397 rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc);
399 /* Guard against bad arguments */
400 assert(hd != NULL);
401 assert(rsrc != NULL);
402 assert(id == (id_t)0);
403 assert(errorp != NULL);
404 assert(depend_info != NULL);
406 /* Lock the cache and lookup the resource */
407 (void) mutex_lock(&cache_lock);
408 node = cache_lookup(hd, rsrc, CACHE_REFRESH);
409 if (node == NULL) {
410 ip_log_err(node, errorp, "Unrecognized resource");
411 errno = ENOENT;
412 (void) mutex_unlock(&cache_lock);
413 return (RCM_SUCCESS);
416 pif = node->ip_pif;
418 /* Establish default detachability criteria */
419 if (flags & RCM_FORCE)
420 detachable = B_TRUE;
422 /* Check if the interface is under IPMP */
423 ipmp = (pif->pi_grname[0] != '\0');
426 * Even if the interface is not under IPMP, it's possible that it's
427 * still okay to offline it as long as there are higher-level failover
428 * mechanisms for the addresses it owns (e.g., clustering). In this
429 * case, ip_offlinelist() will return RCM_SUCCESS, and we charge on.
431 if (!ipmp && !detachable) {
432 /* Inform consumers of IP addresses being offlined */
433 if (ip_offlinelist(hd, node, errorp, flags, depend_info) ==
434 RCM_SUCCESS) {
435 rcm_log_message(RCM_DEBUG,
436 "IP: consumers agree on detach");
437 } else {
438 ip_log_err(node, errorp,
439 "Device consumers prohibit offline");
440 (void) mutex_unlock(&cache_lock);
441 return (RCM_FAILURE);
445 /* Check if it's a query */
446 if (flags & RCM_QUERY) {
447 rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n",
448 rsrc);
449 (void) mutex_unlock(&cache_lock);
450 return (RCM_SUCCESS);
453 /* Check detachability, save configuration if detachable */
454 if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) {
455 node->ip_cachestate |= CACHE_IF_IGNORE;
456 rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc);
457 (void) mutex_unlock(&cache_lock);
458 return (RCM_SUCCESS);
461 /* standalone detachable device */
462 if (!ipmp) {
463 if (if_unplumb(node) < 0) {
464 ip_log_err(node, errorp,
465 "Failed to unplumb the device");
467 errno = EIO;
468 (void) mutex_unlock(&cache_lock);
469 return (RCM_FAILURE);
472 node->ip_cachestate |= CACHE_IF_OFFLINED;
473 rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc);
474 (void) mutex_unlock(&cache_lock);
475 return (RCM_SUCCESS);
479 * This is an IPMP interface that can be offlined.
480 * Request in.mpathd(1M) to offline the physical interface.
482 if ((retval = ip_ipmp_offline(node)) != IPMP_SUCCESS)
483 ip_log_err(node, errorp, "in.mpathd offline failed");
485 if (retval == IPMP_EMINRED && !detachable) {
487 * in.mpathd(1M) could not offline the device because it was
488 * the last interface in the group. However, it's possible
489 * that it's still okay to offline it as long as there are
490 * higher-level failover mechanisms for the addresses it owns
491 * (e.g., clustering). In this case, ip_offlinelist() will
492 * return RCM_SUCCESS, and we charge on.
494 /* Inform consumers of IP addresses being offlined */
495 if (ip_offlinelist(hd, node, errorp, flags,
496 depend_info) == RCM_SUCCESS) {
497 rcm_log_message(RCM_DEBUG,
498 "IP: consumers agree on detach");
499 } else {
500 ip_log_err(node, errorp,
501 "Device consumers prohibit offline");
502 (void) mutex_unlock(&cache_lock);
503 errno = EBUSY;
504 return (RCM_FAILURE);
508 if (if_unplumb(node) < 0) {
509 rcm_log_message(RCM_ERROR,
510 _("IP: Unplumb failed (%s)\n"),
511 pif->pi_ifname);
513 /* Request in.mpathd to undo the offline */
514 if (ip_ipmp_undo_offline(node) != IPMP_SUCCESS) {
515 ip_log_err(node, errorp, "Undo offline failed");
516 (void) mutex_unlock(&cache_lock);
517 return (RCM_FAILURE);
519 (void) mutex_unlock(&cache_lock);
520 return (RCM_FAILURE);
523 node->ip_cachestate |= CACHE_IF_OFFLINED;
524 rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc);
525 (void) mutex_unlock(&cache_lock);
526 return (RCM_SUCCESS);
530 * ip_undo_offline() - Undo offline of a previously offlined device.
532 /*ARGSUSED*/
533 static int
534 ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
535 char **errorp, rcm_info_t **depend_info)
537 ip_cache_t *node;
539 rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc);
541 /* Guard against bad arguments */
542 assert(hd != NULL);
543 assert(rsrc != NULL);
544 assert(id == (id_t)0);
545 assert(errorp != NULL);
546 assert(depend_info != NULL);
548 (void) mutex_lock(&cache_lock);
549 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
551 if (node == NULL) {
552 ip_log_err(node, errorp, "No such device");
553 (void) mutex_unlock(&cache_lock);
554 errno = ENOENT;
555 return (RCM_FAILURE);
558 /* Check if no attempt should be made to online the device here */
559 if (node->ip_cachestate & CACHE_IF_IGNORE) {
560 node->ip_cachestate &= ~(CACHE_IF_IGNORE);
561 (void) mutex_unlock(&cache_lock);
562 return (RCM_SUCCESS);
565 /* Check if the interface was previously offlined */
566 if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) {
567 ip_log_err(node, errorp, "Device not offlined");
568 (void) mutex_unlock(&cache_lock);
569 errno = ENOTSUP;
570 return (RCM_FAILURE);
573 if (if_replumb(node) == -1) {
574 /* re-plumb failed */
575 ip_log_err(node, errorp, "Replumb failed");
576 (void) mutex_unlock(&cache_lock);
577 errno = EIO;
578 return (RCM_FAILURE);
582 /* Inform consumers about IP addresses being un-offlined */
583 (void) ip_onlinelist(hd, node, errorp, flags, depend_info);
585 node->ip_cachestate &= ~(CACHE_IF_OFFLINED);
586 rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc);
587 (void) mutex_unlock(&cache_lock);
588 return (RCM_SUCCESS);
592 * ip_get_info() - Gather usage information for this resource.
594 /*ARGSUSED*/
596 ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
597 char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info)
599 ip_cache_t *node;
600 char *infostr;
602 /* Guard against bad arguments */
603 assert(hd != NULL);
604 assert(rsrc != NULL);
605 assert(id == (id_t)0);
606 assert(usagep != NULL);
607 assert(errorp != NULL);
608 assert(depend_info != NULL);
610 rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc);
612 (void) mutex_lock(&cache_lock);
613 node = cache_lookup(hd, rsrc, CACHE_REFRESH);
614 if (!node) {
615 rcm_log_message(RCM_INFO,
616 _("IP: get_info(%s) unrecognized resource\n"), rsrc);
617 (void) mutex_unlock(&cache_lock);
618 errno = ENOENT;
619 return (RCM_FAILURE);
622 infostr = ip_usage(node);
624 if (infostr == NULL) {
625 /* most likely malloc failure */
626 rcm_log_message(RCM_ERROR,
627 _("IP: get_info(%s) malloc failure\n"), rsrc);
628 (void) mutex_unlock(&cache_lock);
629 errno = ENOMEM;
630 *errorp = NULL;
631 return (RCM_FAILURE);
634 /* Set client/role properties */
635 (void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP");
637 /* Set usage property, infostr will be freed by caller */
638 *usagep = infostr;
640 rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n",
641 rsrc, infostr);
643 (void) mutex_unlock(&cache_lock);
644 return (RCM_SUCCESS);
648 * ip_suspend() - Nothing to do, always okay
650 /*ARGSUSED*/
651 static int
652 ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
653 uint_t flags, char **errorp, rcm_info_t **depend_info)
655 /* Guard against bad arguments */
656 assert(hd != NULL);
657 assert(rsrc != NULL);
658 assert(id == (id_t)0);
659 assert(interval != NULL);
660 assert(errorp != NULL);
661 assert(depend_info != NULL);
663 rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc);
664 return (RCM_SUCCESS);
668 * ip_resume() - Nothing to do, always okay
670 /*ARGSUSED*/
671 static int
672 ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
673 char **errorp, rcm_info_t ** depend_info)
675 /* Guard against bad arguments */
676 assert(hd != NULL);
677 assert(rsrc != NULL);
678 assert(id == (id_t)0);
679 assert(errorp != NULL);
680 assert(depend_info != NULL);
682 rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc);
684 return (RCM_SUCCESS);
688 * ip_remove() - remove a resource from cache
690 /*ARGSUSED*/
691 static int
692 ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
693 char **errorp, rcm_info_t **depend_info)
695 ip_cache_t *node;
697 /* Guard against bad arguments */
698 assert(hd != NULL);
699 assert(rsrc != NULL);
700 assert(id == (id_t)0);
701 assert(errorp != NULL);
702 assert(depend_info != NULL);
704 rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc);
706 (void) mutex_lock(&cache_lock);
707 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
708 if (!node) {
709 rcm_log_message(RCM_INFO,
710 _("IP: remove(%s) unrecognized resource\n"), rsrc);
711 (void) mutex_unlock(&cache_lock);
712 errno = ENOENT;
713 return (RCM_FAILURE);
716 /* remove the cached entry for the resource */
717 cache_remove(node);
718 free_node(node);
720 (void) mutex_unlock(&cache_lock);
721 return (RCM_SUCCESS);
725 * ip_notify_event - Project private implementation to receive new resource
726 * events. It intercepts all new resource events. If the
727 * new resource is a network resource, pass up a notify
728 * for it too. The new resource need not be cached, since
729 * it is done at register again.
731 /*ARGSUSED*/
732 static int
733 ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
734 char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
736 datalink_id_t linkid;
737 nvpair_t *nvp = NULL;
738 uint64_t id64;
740 assert(hd != NULL);
741 assert(rsrc != NULL);
742 assert(id == (id_t)0);
743 assert(nvl != NULL);
745 rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc);
747 if (!STREQ(rsrc, RCM_RESOURCE_LINK_NEW)) {
748 rcm_log_message(RCM_INFO,
749 _("IP: unrecognized event for %s\n"), rsrc);
750 ip_log_err(NULL, errorp, "unrecognized event");
751 errno = EINVAL;
752 return (RCM_FAILURE);
755 /* Update cache to reflect latest interfaces */
756 if (update_cache(hd) < 0) {
757 rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n"));
758 ip_log_err(NULL, errorp, "Private Cache update failed");
759 return (RCM_FAILURE);
762 rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n");
763 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
764 if (STREQ(nvpair_name(nvp), RCM_NV_LINKID)) {
765 if (nvpair_value_uint64(nvp, &id64) != 0) {
766 rcm_log_message(RCM_WARNING,
767 _("IP: cannot get linkid\n"));
768 return (RCM_FAILURE);
770 linkid = (datalink_id_t)id64;
772 * Grovel through /etc/hostname* files and configure
773 * interface in the same way that they would be handled
774 * by network/physical.
776 if (if_configure_hostname(linkid) != 0) {
777 rcm_log_message(RCM_ERROR,
778 _("IP: Configuration failed (%u)\n"),
779 linkid);
780 ip_log_err(NULL, errorp,
781 "Failed configuring one or more IP "
782 "addresses");
786 * Query libipadm for persistent configuration info
787 * and resurrect that persistent configuration.
789 if (if_configure_ipadm(linkid) != 0) {
790 rcm_log_message(RCM_ERROR,
791 _("IP: Configuration failed (%u)\n"),
792 linkid);
793 ip_log_err(NULL, errorp,
794 "Failed configuring one or more IP "
795 "addresses");
798 /* Notify all IP address consumers */
799 ip_consumer_notify(hd, linkid, errorp, flags,
800 depend_info);
804 rcm_log_message(RCM_TRACE1,
805 "IP: notify_event: device configuration complete\n");
807 return (RCM_SUCCESS);
811 * ip_usage - Determine the usage of a device. Call with cache_lock held.
812 * The returned buffer is owned by caller, and the caller
813 * must free it up when done.
815 static char *
816 ip_usage(ip_cache_t *node)
818 ip_lif_t *lif;
819 uint_t numup;
820 char *sep, *buf, *linkidstr;
821 datalink_id_t linkid;
822 const char *msg;
823 char link[MAXLINKNAMELEN];
824 char addrstr[INET6_ADDRSTRLEN];
825 char errmsg[DLADM_STRSIZE];
826 dladm_status_t status;
827 boolean_t offline, ipmp;
828 size_t bufsz = 0;
830 rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource);
833 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid>
835 linkidstr = strchr(node->ip_resource, '/');
836 assert(linkidstr != NULL);
837 linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource;
839 errno = 0;
840 linkid = strtol(linkidstr, &buf, 10);
841 if (errno != 0 || *buf != '\0') {
842 rcm_log_message(RCM_ERROR,
843 _("IP: usage(%s) parse linkid failure (%s)\n"),
844 node->ip_resource, strerror(errno));
845 return (NULL);
848 if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL, NULL,
849 NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
850 rcm_log_message(RCM_ERROR,
851 _("IP: usage(%s) get link name failure(%s)\n"),
852 node->ip_resource, dladm_status2str(status, errmsg));
853 return (NULL);
856 /* TRANSLATION_NOTE: separator used between IP addresses */
857 sep = _(", ");
859 numup = 0;
860 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next)
861 if (lif->li_ifflags & IFF_UP)
862 numup++;
864 ipmp = (node->ip_pif->pi_grname[0] != '\0');
865 offline = ((node->ip_cachestate & CACHE_IF_OFFLINED) != 0);
867 if (offline) {
868 msg = _("offlined");
869 } else if (numup == 0) {
870 msg = _("plumbed but down");
871 } else {
872 if (ipmp) {
873 msg = _("providing connectivity for IPMP group ");
874 bufsz += LIFGRNAMSIZ;
875 } else {
876 msg = _("hosts IP addresses: ");
877 bufsz += (numup * (INET6_ADDRSTRLEN + strlen(sep)));
881 bufsz += strlen(link) + strlen(msg) + 1;
882 if ((buf = malloc(bufsz)) == NULL) {
883 rcm_log_message(RCM_ERROR,
884 _("IP: usage(%s) malloc failure(%s)\n"),
885 node->ip_resource, strerror(errno));
886 return (NULL);
888 (void) snprintf(buf, bufsz, "%s: %s", link, msg);
890 if (!offline && numup > 0) {
891 if (ipmp) {
892 (void) strlcat(buf, node->ip_pif->pi_grname, bufsz);
893 } else {
894 lif = node->ip_pif->pi_lifs;
895 for (; lif != NULL; lif = lif->li_next) {
896 if (!(lif->li_ifflags & IFF_UP))
897 continue;
899 if (!ip_addrstr(lif, addrstr, sizeof (addrstr)))
900 continue;
902 (void) strlcat(buf, addrstr, bufsz);
903 if (--numup > 0)
904 (void) strlcat(buf, sep, bufsz);
909 rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
910 node->ip_resource, buf);
912 return (buf);
915 static boolean_t
916 ip_addrstr(ip_lif_t *lif, char *addrstr, size_t addrsize)
918 int af = lif->li_addr.family;
919 void *addr;
921 if (af == AF_INET6) {
922 addr = &lif->li_addr.ip6.sin6_addr;
923 } else if (af == AF_INET) {
924 addr = &lif->li_addr.ip4.sin_addr;
925 } else {
926 rcm_log_message(RCM_DEBUG,
927 "IP: unknown addr family %d, assuming AF_INET\n", af);
928 af = AF_INET;
929 addr = &lif->li_addr.ip4.sin_addr;
931 if (inet_ntop(af, addr, addrstr, addrsize) == NULL) {
932 rcm_log_message(RCM_ERROR,
933 _("IP: inet_ntop: %s\n"), strerror(errno));
934 return (B_FALSE);
937 rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr);
938 return (B_TRUE);
942 * Cache management routines, all cache management functions should be
943 * be called with cache_lock held.
947 * cache_lookup() - Get a cache node for a resource.
948 * Call with cache lock held.
950 * This ensures that the cache is consistent with the system state and
951 * returns a pointer to the cache element corresponding to the resource.
953 static ip_cache_t *
954 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
956 ip_cache_t *probe;
958 rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc);
960 if ((options & CACHE_REFRESH) && (hd != NULL)) {
961 /* drop lock since update locks cache again */
962 (void) mutex_unlock(&cache_lock);
963 (void) update_cache(hd);
964 (void) mutex_lock(&cache_lock);
967 probe = cache_head.ip_next;
968 while (probe != &cache_tail) {
969 if (probe->ip_resource &&
970 STREQ(rsrc, probe->ip_resource)) {
971 rcm_log_message(RCM_TRACE2,
972 "IP: cache lookup success(%s)\n", rsrc);
973 return (probe);
975 probe = probe->ip_next;
977 return (NULL);
981 * free_node - Free a node from the cache
982 * Call with cache_lock held.
984 static void
985 free_node(ip_cache_t *node)
987 ip_pif_t *pif;
988 ip_lif_t *lif, *tmplif;
990 if (node) {
991 if (node->ip_resource) {
992 free(node->ip_resource);
995 /* free the pif */
996 pif = node->ip_pif;
997 if (pif) {
998 /* free logical interfaces */
999 lif = pif->pi_lifs;
1000 while (lif) {
1001 tmplif = lif->li_next;
1002 free(lif);
1003 lif = tmplif;
1005 free(pif);
1007 free(node);
1012 * cache_insert - Insert a resource node in cache
1013 * Call with the cache_lock held.
1015 static void
1016 cache_insert(ip_cache_t *node)
1018 rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n",
1019 node->ip_resource);
1021 /* insert at the head for best performance */
1022 node->ip_next = cache_head.ip_next;
1023 node->ip_prev = &cache_head;
1025 node->ip_next->ip_prev = node;
1026 node->ip_prev->ip_next = node;
1030 * cache_remove() - Remove a resource node from cache.
1031 * Call with the cache_lock held.
1033 static void
1034 cache_remove(ip_cache_t *node)
1036 rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n",
1037 node->ip_resource);
1039 node->ip_next->ip_prev = node->ip_prev;
1040 node->ip_prev->ip_next = node->ip_next;
1041 node->ip_next = NULL;
1042 node->ip_prev = NULL;
1046 * update_pif() - Update physical interface properties
1047 * Call with cache_lock held
1050 update_pif(rcm_handle_t *hd, int af, int sock, struct ifaddrs *ifa)
1052 char *rsrc;
1053 ifspec_t ifspec;
1054 ushort_t ifnumber = 0;
1055 ip_cache_t *probe;
1056 ip_pif_t pif;
1057 ip_pif_t *probepif;
1058 ip_lif_t *probelif;
1059 struct lifreq lifreq;
1060 struct sockaddr_storage ifaddr;
1061 uint64_t ifflags;
1062 int lif_listed = 0;
1064 rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", ifa->ifa_name);
1066 if (!ifparse_ifspec(ifa->ifa_name, &ifspec)) {
1067 rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"),
1068 ifa->ifa_name);
1069 return (-1);
1072 (void) snprintf(pif.pi_ifname, sizeof (pif.pi_ifname), "%s%d",
1073 ifspec.ifsp_devnm, ifspec.ifsp_ppa);
1074 if (ifspec.ifsp_lunvalid)
1075 ifnumber = ifspec.ifsp_lun;
1077 /* Get the interface flags */
1078 ifflags = ifa->ifa_flags;
1081 * Ignore interfaces that are always incapable of DR:
1082 * - IFF_VIRTUAL: e.g., loopback and vni
1083 * - IFF_POINTOPOINT: e.g., sppp and ip.tun
1084 * - !IFF_MULTICAST: e.g., ip.6to4tun
1085 * - IFF_IPMP: IPMP meta-interfaces
1087 * Note: The !IFF_MULTICAST check can be removed once iptun is
1088 * implemented as a datalink.
1090 if (!(ifflags & IFF_MULTICAST) ||
1091 (ifflags & (IFF_POINTOPOINT | IFF_VIRTUAL | IFF_IPMP))) {
1092 rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n",
1093 pif.pi_ifname);
1094 return (0);
1097 /* Get the interface group name for this interface */
1098 bzero(&lifreq, sizeof (lifreq));
1099 (void) strncpy(lifreq.lifr_name, ifa->ifa_name, LIFNAMSIZ);
1101 if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) {
1102 if (errno != ENXIO) {
1103 rcm_log_message(RCM_ERROR,
1104 _("IP: SIOCGLIFGROUPNAME(%s): %s\n"),
1105 lifreq.lifr_name, strerror(errno));
1107 return (-1);
1110 /* copy the group name */
1111 (void) strlcpy(pif.pi_grname, lifreq.lifr_groupname,
1112 sizeof (pif.pi_grname));
1114 /* Get the interface address for this interface */
1115 (void) memcpy(&ifaddr, ifa->ifa_addr, sizeof (ifaddr));
1117 rsrc = get_link_resource(pif.pi_ifname);
1118 if (rsrc == NULL) {
1119 rcm_log_message(RCM_ERROR,
1120 _("IP: get_link_resource(%s) failed\n"),
1121 lifreq.lifr_name);
1122 return (-1);
1125 probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
1126 if (probe != NULL) {
1127 free(rsrc);
1128 probe->ip_cachestate &= ~(CACHE_IF_STALE);
1129 } else {
1130 if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) {
1131 /* malloc errors are bad */
1132 free(rsrc);
1133 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1134 strerror(errno));
1135 return (-1);
1138 probe->ip_resource = rsrc;
1139 probe->ip_pif = NULL;
1140 probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY;
1141 probe->ip_cachestate |= CACHE_IF_NEW;
1143 cache_insert(probe);
1146 probepif = probe->ip_pif;
1147 if (probepif != NULL) {
1148 /* Check if lifs need to be updated */
1149 probelif = probepif->pi_lifs;
1150 while (probelif != NULL) {
1151 if ((probelif->li_ifnum == ifnumber) &&
1152 (probelif->li_addr.family == ifaddr.ss_family)) {
1154 rcm_log_message(RCM_TRACE2,
1155 "IP: refreshing lifs for %s, ifnum=%d\n",
1156 pif.pi_ifname, probelif->li_ifnum);
1158 /* refresh lif properties */
1159 (void) memcpy(&probelif->li_addr, &ifaddr,
1160 sizeof (probelif->li_addr));
1162 probelif->li_ifflags = ifflags;
1164 lif_listed++;
1165 probelif->li_cachestate &= ~(CACHE_IF_STALE);
1166 break;
1168 probelif = probelif->li_next;
1172 if (probepif == NULL) {
1173 if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) {
1174 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1175 strerror(errno));
1176 if (probe->ip_pif == NULL) {
1177 /* we created it, so clean it up */
1178 free(probe);
1180 return (-1);
1183 probe->ip_pif = probepif;
1185 /* Save interface name */
1186 (void) memcpy(&probepif->pi_ifname, &pif.pi_ifname,
1187 sizeof (pif.pi_ifname));
1190 /* save the group name */
1191 (void) strlcpy(probepif->pi_grname, pif.pi_grname,
1192 sizeof (pif.pi_grname));
1194 /* add lif, if this is a lif and it is not in cache */
1195 if (!lif_listed) {
1196 rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n",
1197 pif.pi_ifname);
1199 if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) {
1200 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1201 strerror(errno));
1202 return (-1);
1205 /* save lif properties */
1206 (void) memcpy(&probelif->li_addr, &ifaddr,
1207 sizeof (probelif->li_addr));
1209 probelif->li_ifnum = ifnumber;
1210 probelif->li_ifflags = ifflags;
1212 /* insert us at the head of the lif list */
1213 probelif->li_next = probepif->pi_lifs;
1214 if (probelif->li_next != NULL) {
1215 probelif->li_next->li_prev = probelif;
1217 probelif->li_prev = NULL;
1218 probelif->li_pif = probepif;
1220 probepif->pi_lifs = probelif;
1223 rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n",
1224 probe->ip_resource);
1226 return (0);
1230 * update_ipifs() - Determine all network interfaces in the system
1231 * Call with cache_lock held
1233 static int
1234 update_ipifs(rcm_handle_t *hd, int af)
1237 struct ifaddrs *ifa;
1238 ipadm_addr_info_t *ainfo;
1239 ipadm_addr_info_t *ptr;
1240 ipadm_status_t status;
1241 int sock;
1243 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
1244 rcm_log_message(RCM_ERROR,
1245 _("IP: failure opening %s socket: %s\n"),
1246 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
1247 return (-1);
1250 status = ipadm_addr_info(ip_handle, NULL, &ainfo, IPADM_OPT_ZEROADDR,
1251 LIFC_UNDER_IPMP);
1252 if (status != IPADM_SUCCESS) {
1253 (void) close(sock);
1254 return (-1);
1256 for (ptr = ainfo; ptr; ptr = IA_NEXT(ptr)) {
1257 ifa = &ptr->ia_ifa;
1258 if (ptr->ia_state != IFA_DISABLED &&
1259 af == ifa->ifa_addr->sa_family)
1260 (void) update_pif(hd, af, sock, ifa);
1262 (void) close(sock);
1263 ipadm_free_addr_info(ainfo);
1264 return (0);
1268 * update_cache() - Update cache with latest interface info
1270 static int
1271 update_cache(rcm_handle_t *hd)
1273 ip_cache_t *probe;
1274 struct ip_lif *lif;
1275 struct ip_lif *nextlif;
1276 int rv;
1277 int i;
1279 rcm_log_message(RCM_TRACE2, "IP: update_cache\n");
1281 (void) mutex_lock(&cache_lock);
1283 /* first we walk the entire cache, marking each entry stale */
1284 probe = cache_head.ip_next;
1285 while (probe != &cache_tail) {
1286 probe->ip_cachestate |= CACHE_IF_STALE;
1287 if ((probe->ip_pif != NULL) &&
1288 ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1289 while (lif != NULL) {
1290 lif->li_cachestate |= CACHE_IF_STALE;
1291 lif = lif->li_next;
1294 probe = probe->ip_next;
1297 rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n");
1298 if (update_ipifs(hd, AF_INET) < 0) {
1299 (void) mutex_unlock(&cache_lock);
1300 return (-1);
1303 rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n");
1304 if (update_ipifs(hd, AF_INET6) < 0) {
1305 (void) mutex_unlock(&cache_lock);
1306 return (-1);
1309 probe = cache_head.ip_next;
1310 /* unregister devices that are not offlined and still in cache */
1311 while (probe != &cache_tail) {
1312 ip_cache_t *freeit;
1313 if ((probe->ip_pif != NULL) &&
1314 ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1315 /* clear stale lifs */
1316 while (lif != NULL) {
1317 if (lif->li_cachestate & CACHE_IF_STALE) {
1318 nextlif = lif->li_next;
1319 if (lif->li_prev != NULL)
1320 lif->li_prev->li_next = nextlif;
1321 if (nextlif != NULL)
1322 nextlif->li_prev = lif->li_prev;
1323 if (probe->ip_pif->pi_lifs == lif)
1324 probe->ip_pif->pi_lifs =
1325 nextlif;
1326 for (i = 0; i < IP_MAX_MODS; i++) {
1327 free(lif->li_modules[i]);
1329 free(lif->li_reconfig);
1330 free(lif);
1331 lif = nextlif;
1332 } else {
1333 lif = lif->li_next;
1337 if ((probe->ip_cachestate & CACHE_IF_STALE) &&
1338 !(probe->ip_cachestate & CACHE_IF_OFFLINED)) {
1339 (void) rcm_unregister_interest(hd, probe->ip_resource,
1341 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
1342 probe->ip_resource);
1343 freeit = probe;
1344 probe = probe->ip_next;
1345 cache_remove(freeit);
1346 free_node(freeit);
1347 continue;
1350 if (!(probe->ip_cachestate & CACHE_IF_NEW)) {
1351 probe = probe->ip_next;
1352 continue;
1355 rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL);
1356 if (rv != RCM_SUCCESS) {
1357 rcm_log_message(RCM_ERROR,
1358 _("IP: failed to register %s\n"),
1359 probe->ip_resource);
1360 (void) mutex_unlock(&cache_lock);
1361 return (-1);
1362 } else {
1363 rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
1364 probe->ip_resource);
1365 probe->ip_cachestate &= ~(CACHE_IF_NEW);
1367 probe = probe->ip_next;
1370 (void) mutex_unlock(&cache_lock);
1371 return (0);
1375 * free_cache() - Empty the cache
1377 static void
1378 free_cache()
1380 ip_cache_t *probe;
1382 rcm_log_message(RCM_TRACE2, "IP: free_cache\n");
1384 (void) mutex_lock(&cache_lock);
1385 probe = cache_head.ip_next;
1386 while (probe != &cache_tail) {
1387 cache_remove(probe);
1388 free_node(probe);
1389 probe = cache_head.ip_next;
1391 (void) mutex_unlock(&cache_lock);
1395 * ip_log_err() - RCM error log wrapper
1397 static void
1398 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
1400 char *ifname = NULL;
1401 int size;
1402 const char *errfmt;
1403 char *error = NULL;
1405 if ((node != NULL) && (node->ip_pif != NULL) &&
1406 (node->ip_pif->pi_ifname != NULL)) {
1407 ifname = node->ip_pif->pi_ifname;
1410 if (ifname == NULL) {
1411 rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg);
1412 errfmt = _("IP: %s");
1413 size = strlen(errfmt) + strlen(errmsg) + 1;
1414 if (errorp != NULL && (error = malloc(size)) != NULL)
1415 (void) snprintf(error, size, errfmt, errmsg);
1416 } else {
1417 rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname);
1418 errfmt = _("IP: %s(%s)");
1419 size = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1;
1420 if (errorp != NULL && (error = malloc(size)) != NULL)
1421 (void) snprintf(error, size, errfmt, errmsg, ifname);
1424 if (errorp != NULL)
1425 *errorp = error;
1429 * if_cfginfo() - Save off the config info for all interfaces
1431 static int
1432 if_cfginfo(ip_cache_t *node, uint_t force)
1434 ip_lif_t *lif;
1435 ip_pif_t *pif;
1436 int i;
1437 FILE *fp;
1438 char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
1439 char buf[MAX_RECONFIG_SIZE];
1441 rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource);
1443 pif = node->ip_pif;
1444 lif = pif->pi_lifs;
1446 while (lif != NULL) {
1447 /* Make a list of modules pushed and save */
1448 if (lif->li_ifnum == 0) { /* physical instance */
1449 if (get_modlist(pif->pi_ifname, lif) == -1) {
1450 rcm_log_message(RCM_ERROR,
1451 _("IP: get modlist error (%s) %s\n"),
1452 pif->pi_ifname, strerror(errno));
1453 clr_cfg_state(pif);
1454 return (-1);
1457 if (!force) {
1458 /* Look if unknown modules have been inserted */
1459 for (i = (lif->li_modcnt - 2); i > 0; i--) {
1460 if (modop(pif->pi_ifname,
1461 lif->li_modules[i],
1462 i, MOD_CHECK) == -1) {
1463 rcm_log_message(RCM_ERROR,
1464 _("IP: module %s@%d\n"),
1465 lif->li_modules[i], i);
1466 clr_cfg_state(pif);
1467 return (-1);
1472 /* Last module is the device driver, so ignore that */
1473 for (i = (lif->li_modcnt - 2); i > 0; i--) {
1474 rcm_log_message(RCM_TRACE2,
1475 "IP: modremove Pos = %d, Module = %s \n",
1476 i, lif->li_modules[i]);
1477 if (modop(pif->pi_ifname, lif->li_modules[i],
1478 i, MOD_REMOVE) == -1) {
1479 while (i != (lif->li_modcnt - 2)) {
1480 if (modop(pif->pi_ifname,
1481 lif->li_modules[i],
1482 i, MOD_INSERT) == -1) {
1483 /* Gross error */
1484 rcm_log_message(
1485 RCM_ERROR,
1486 _("IP: if_cfginfo"
1487 "(%s) %s\n"),
1488 pif->pi_ifname,
1489 strerror(errno));
1490 clr_cfg_state(pif);
1491 return (-1);
1493 i++;
1495 rcm_log_message(
1496 RCM_ERROR,
1497 _("IP: if_cfginfo(%s): modremove "
1498 "%s failed: %s\n"), pif->pi_ifname,
1499 lif->li_modules[i],
1500 strerror(errno));
1501 clr_cfg_state(pif);
1502 return (-1);
1507 /* Save reconfiguration information */
1508 if (lif->li_ifflags & IFF_IPV4) {
1509 (void) snprintf(syscmd, sizeof (syscmd),
1510 "%s %s:%d configinfo\n", SBIN_IFCONFIG,
1511 pif->pi_ifname, lif->li_ifnum);
1512 } else if (lif->li_ifflags & IFF_IPV6) {
1513 (void) snprintf(syscmd, sizeof (syscmd),
1514 "%s %s:%d inet6 configinfo\n", SBIN_IFCONFIG,
1515 pif->pi_ifname, lif->li_ifnum);
1517 rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd);
1519 /* open a pipe to retrieve reconfiguration info */
1520 if ((fp = popen(syscmd, "r")) == NULL) {
1521 rcm_log_message(RCM_ERROR,
1522 _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1523 pif->pi_ifname, lif->li_ifnum, strerror(errno));
1524 clr_cfg_state(pif);
1525 return (-1);
1527 bzero(buf, MAX_RECONFIG_SIZE);
1529 if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) {
1530 rcm_log_message(RCM_ERROR,
1531 _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1532 pif->pi_ifname, lif->li_ifnum, strerror(errno));
1533 (void) pclose(fp);
1534 clr_cfg_state(pif);
1535 return (-1);
1537 (void) pclose(fp);
1539 if ((lif->li_reconfig = strdup(buf)) == NULL) {
1540 rcm_log_message(RCM_ERROR,
1541 _("IP: malloc error (%s) %s\n"),
1542 pif->pi_ifname, strerror(errno));
1543 clr_cfg_state(pif);
1544 return (-1);
1546 rcm_log_message(RCM_DEBUG,
1547 "IP: if_cfginfo: reconfig string(%s:%d) = %s\n",
1548 pif->pi_ifname, lif->li_ifnum, lif->li_reconfig);
1550 lif = lif->li_next;
1553 return (0);
1557 * if_unplumb() - Unplumb the interface
1558 * Save off the modlist, ifconfig options and unplumb.
1559 * Fail, if an unknown module lives between IP and driver and
1560 * force is not set
1561 * Call with cache_lock held
1563 static int
1564 if_unplumb(ip_cache_t *node)
1566 ip_lif_t *lif;
1567 ip_pif_t *pif = node->ip_pif;
1568 boolean_t ipv4 = B_FALSE;
1569 boolean_t ipv6 = B_FALSE;
1571 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource);
1573 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1574 if (lif->li_ifflags & IFF_IPV4) {
1575 ipv4 = B_TRUE;
1576 } else if (lif->li_ifflags & IFF_IPV6) {
1577 ipv6 = B_TRUE;
1578 } else {
1579 /* Unlikely case */
1580 rcm_log_message(RCM_DEBUG,
1581 "IP: Unplumb ignored (%s:%d)\n",
1582 pif->pi_ifname, lif->li_ifnum);
1586 if (ipv4 && !ifconfig(pif->pi_ifname, "inet", "unplumb", B_FALSE)) {
1587 rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
1588 pif->pi_ifname, strerror(errno));
1589 return (-1);
1592 if (ipv6 && !ifconfig(pif->pi_ifname, "inet6", "unplumb", B_FALSE)) {
1593 rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
1594 pif->pi_ifname, strerror(errno));
1595 return (-1);
1598 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n",
1599 node->ip_resource);
1601 return (0);
1605 * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface
1606 * instances and the logical interfaces in order, restoring
1607 * all ifconfig options
1608 * Call with cache_lock held
1610 static int
1611 if_replumb(ip_cache_t *node)
1613 ip_lif_t *lif;
1614 ip_pif_t *pif;
1615 int i;
1616 boolean_t success, ipmp;
1617 const char *fstr;
1618 char lifname[LIFNAMSIZ];
1619 char buf[MAX_RECONFIG_SIZE];
1620 int max_lifnum = 0;
1622 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource);
1625 * Be extra careful about bringing up the interfaces in the
1626 * correct order:
1627 * - First plumb in the physical interface instances
1628 * - modinsert the necessary modules@pos
1629 * - Next, add the logical interfaces being careful about
1630 * the order, (follow the cached interface number li_ifnum order)
1633 pif = node->ip_pif;
1634 ipmp = (node->ip_pif->pi_grname[0] != '\0');
1637 * Make a first pass to plumb in physical interfaces and get a count
1638 * of the max logical interfaces
1640 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1641 max_lifnum = MAX(lif->li_ifnum, max_lifnum);
1642 if (lif->li_ifflags & IFF_IPV4) {
1643 fstr = "inet";
1644 } else if (lif->li_ifflags & IFF_IPV6) {
1645 fstr = "inet6";
1646 } else {
1647 /* Unlikely case */
1648 rcm_log_message(RCM_DEBUG,
1649 "IP: Re-plumb ignored (%s:%d)\n",
1650 pif->pi_ifname, lif->li_ifnum);
1651 continue;
1654 /* ignore logical interface instances */
1655 if (lif->li_ifnum != 0)
1656 continue;
1658 if ((lif->li_ifflags & IFF_NOFAILOVER) || !ipmp) {
1659 success = ifconfig("", "", lif->li_reconfig, B_FALSE);
1660 } else {
1661 (void) snprintf(buf, sizeof (buf), "plumb group %s",
1662 pif->pi_grname);
1663 success = ifconfig(pif->pi_ifname, fstr, buf, B_FALSE);
1666 if (!success) {
1667 rcm_log_message(RCM_ERROR,
1668 _("IP: Cannot plumb (%s) %s\n"), pif->pi_ifname,
1669 strerror(errno));
1670 return (-1);
1674 * Restart DHCP if necessary.
1676 if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1677 !ifconfig(pif->pi_ifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1678 rcm_log_message(RCM_ERROR, _("IP: Cannot start DHCP "
1679 "(%s) %s\n"), pif->pi_ifname, strerror(errno));
1680 return (-1);
1683 rcm_log_message(RCM_TRACE2,
1684 "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt);
1685 /* modinsert modules in order, ignore driver(last) */
1686 for (i = 0; i < (lif->li_modcnt - 1); i++) {
1687 rcm_log_message(RCM_TRACE2,
1688 "IP: modinsert: Pos = %d Mod = %s\n",
1689 i, lif->li_modules[i]);
1690 if (modop(pif->pi_ifname, lif->li_modules[i], i,
1691 MOD_INSERT) == -1) {
1692 rcm_log_message(RCM_ERROR,
1693 _("IP: modinsert error(%s)\n"),
1694 pif->pi_ifname);
1695 return (-1);
1700 /* Now, add all the logical interfaces in the correct order */
1701 for (i = 1; i <= max_lifnum; i++) {
1702 (void) snprintf(lifname, LIFNAMSIZ, "%s:%d", pif->pi_ifname, i);
1704 /* reset lif through every iteration */
1705 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1707 * Process entries in order. If the interface is
1708 * using IPMP, only process test addresses.
1710 if (lif->li_ifnum != i ||
1711 (ipmp && !(lif->li_ifflags & IFF_NOFAILOVER)))
1712 continue;
1714 if (!ifconfig("", "", lif->li_reconfig, B_FALSE)) {
1715 rcm_log_message(RCM_ERROR,
1716 _("IP: Cannot addif (%s) %s\n"), lifname,
1717 strerror(errno));
1718 return (-1);
1722 * Restart DHCP if necessary.
1724 if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1725 !ifconfig(lifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1726 rcm_log_message(RCM_ERROR,
1727 _("IP: Cannot start DHCP (%s) %s\n"),
1728 lifname, strerror(errno));
1729 return (-1);
1734 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n",
1735 node->ip_resource);
1737 return (0);
1741 * clr_cfg_state() - Cleanup after errors in unplumb
1743 static void
1744 clr_cfg_state(ip_pif_t *pif)
1746 ip_lif_t *lif;
1747 int i;
1749 lif = pif->pi_lifs;
1751 while (lif != NULL) {
1752 lif->li_modcnt = 0;
1753 free(lif->li_reconfig);
1754 lif->li_reconfig = NULL;
1755 for (i = 0; i < IP_MAX_MODS; i++) {
1756 free(lif->li_modules[i]);
1757 lif->li_modules[i] = NULL;
1759 lif = lif->li_next;
1764 * Attempt to offline ip_cache_t `node'; returns an IPMP error code.
1766 static int
1767 ip_ipmp_offline(ip_cache_t *node)
1769 int retval;
1770 ipmp_handle_t handle;
1772 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n");
1774 if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
1775 rcm_log_message(RCM_ERROR,
1776 _("IP: cannot create ipmp handle: %s\n"),
1777 ipmp_errmsg(retval));
1778 return (retval);
1781 retval = ipmp_offline(handle, node->ip_pif->pi_ifname, node->ip_ifred);
1782 if (retval != IPMP_SUCCESS) {
1783 rcm_log_message(RCM_ERROR, _("IP: ipmp_offline error: %s\n"),
1784 ipmp_errmsg(retval));
1785 } else {
1786 rcm_log_message(RCM_TRACE1, "IP: ipmp_offline success\n");
1789 ipmp_close(handle);
1790 return (retval);
1794 * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code.
1796 static int
1797 ip_ipmp_undo_offline(ip_cache_t *node)
1799 int retval;
1800 ipmp_handle_t handle;
1802 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_undo_offline\n");
1804 if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
1805 rcm_log_message(RCM_ERROR,
1806 _("IP: cannot create ipmp handle: %s\n"),
1807 ipmp_errmsg(retval));
1808 return (retval);
1811 retval = ipmp_undo_offline(handle, node->ip_pif->pi_ifname);
1812 if (retval != IPMP_SUCCESS) {
1813 rcm_log_message(RCM_ERROR,
1814 _("IP: ipmp_undo_offline error: %s\n"),
1815 ipmp_errmsg(retval));
1816 } else {
1817 rcm_log_message(RCM_TRACE1, "IP: ipmp_undo_offline success\n");
1820 ipmp_close(handle);
1821 return (retval);
1825 * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a
1826 * dynamically allocated string containing the associated link resource
1827 * name ("SUNW_datalink/<linkid>").
1829 static char *
1830 get_link_resource(const char *link)
1832 char errmsg[DLADM_STRSIZE];
1833 datalink_id_t linkid;
1834 uint32_t flags;
1835 char *resource;
1836 dladm_status_t status;
1838 status = dladm_name2info(dld_handle, link, &linkid, &flags, NULL, NULL);
1839 if (status != DLADM_STATUS_OK)
1840 goto fail;
1842 if (!(flags & DLADM_OPT_ACTIVE)) {
1843 status = DLADM_STATUS_FAILED;
1844 goto fail;
1847 resource = malloc(RCM_LINK_RESOURCE_MAX);
1848 if (resource == NULL) {
1849 rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"),
1850 strerror(errno), link);
1851 return (NULL);
1854 (void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u",
1855 RCM_LINK_PREFIX, linkid);
1857 return (resource);
1859 fail:
1860 rcm_log_message(RCM_ERROR,
1861 _("IP: get_link_resource for %s error(%s)\n"),
1862 link, dladm_status2str(status, errmsg));
1863 return (NULL);
1867 * modop() - Remove/insert a module
1869 static int
1870 modop(char *name, char *arg, int pos, char op)
1872 char syscmd[LIFNAMSIZ+MAXPATHLEN]; /* must be big enough */
1874 rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name);
1876 /* Nothing to do with "ip", "arp" */
1877 if ((arg == NULL) || (strcmp(arg, "") == 0) ||
1878 STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) {
1879 rcm_log_message(RCM_TRACE1, "IP: modop success\n");
1880 return (0);
1883 if (op == MOD_CHECK) {
1885 * No known good modules (yet) apart from ip and arp
1886 * which are handled above
1888 return (-1);
1891 if (op == MOD_REMOVE) {
1892 (void) snprintf(syscmd, sizeof (syscmd),
1893 "%s %s modremove %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
1894 } else if (op == MOD_INSERT) {
1895 (void) snprintf(syscmd, sizeof (syscmd),
1896 "%s %s modinsert %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
1897 } else {
1898 rcm_log_message(RCM_ERROR,
1899 _("IP: modop(%s): unknown operation\n"), name);
1900 return (-1);
1903 rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd);
1904 if (rcm_exec_cmd(syscmd) == -1) {
1905 rcm_log_message(RCM_ERROR,
1906 _("IP: modop(%s): %s\n"), name, strerror(errno));
1907 return (-1);
1910 rcm_log_message(RCM_TRACE1, "IP: modop success\n");
1911 return (0);
1915 * get_modlist() - return a list of pushed mid-stream modules
1916 * Required memory is malloced to construct the list,
1917 * Caller must free this memory list
1918 * Call with cache_lock held
1920 static int
1921 get_modlist(char *name, ip_lif_t *lif)
1923 int mux_fd;
1924 int muxid_fd;
1925 int fd;
1926 int i;
1927 int num_mods;
1928 struct lifreq lifr;
1929 struct str_list strlist = { 0 };
1931 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name);
1933 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1934 lifr.lifr_flags = lif->li_ifflags;
1935 if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) {
1936 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name);
1937 return (-1);
1940 if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) {
1941 rcm_log_message(RCM_ERROR,
1942 _("IP: get_modlist(%s): I_LIST(%s) \n"),
1943 name, strerror(errno));
1944 goto fail;
1947 strlist.sl_nmods = num_mods;
1948 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods);
1949 if (strlist.sl_modlist == NULL) {
1950 rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"),
1951 name, strerror(errno));
1952 goto fail;
1955 if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
1956 rcm_log_message(RCM_ERROR,
1957 _("IP: get_modlist(%s): I_LIST error: %s\n"),
1958 name, strerror(errno));
1959 goto fail;
1962 for (i = 0; i < strlist.sl_nmods; i++) {
1963 lif->li_modules[i] = strdup(strlist.sl_modlist[i].l_name);
1964 if (lif->li_modules[i] == NULL) {
1965 rcm_log_message(RCM_ERROR,
1966 _("IP: get_modlist(%s): %s\n"),
1967 name, strerror(errno));
1968 while (i > 0)
1969 free(lif->li_modules[--i]);
1970 goto fail;
1974 lif->li_modcnt = strlist.sl_nmods;
1975 free(strlist.sl_modlist);
1977 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name);
1978 return (ip_plink(mux_fd, muxid_fd, fd, &lifr));
1979 fail:
1980 free(strlist.sl_modlist);
1981 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
1982 return (-1);
1986 * ip_domux2fd() - Helper function for mod*() functions
1987 * Stolen from ifconfig.c
1989 static int
1990 ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr)
1992 int muxid_fd;
1993 char *udp_dev_name;
1995 if (lifr->lifr_flags & IFF_IPV6) {
1996 udp_dev_name = UDP6_DEV_NAME;
1997 } else {
1998 udp_dev_name = UDP_DEV_NAME;
2001 if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) {
2002 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2003 udp_dev_name, strerror(errno));
2004 return (-1);
2006 if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) {
2007 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2008 udp_dev_name, strerror(errno));
2009 (void) close(muxid_fd);
2010 return (-1);
2012 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) {
2013 rcm_log_message(RCM_ERROR,
2014 _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"),
2015 udp_dev_name, strerror(errno));
2016 (void) close(*mux_fd);
2017 (void) close(muxid_fd);
2018 return (-1);
2021 rcm_log_message(RCM_TRACE2,
2022 "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n",
2023 lifr->lifr_arp_muxid, lifr->lifr_ip_muxid);
2025 if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) {
2026 rcm_log_message(RCM_ERROR,
2027 _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"),
2028 udp_dev_name, strerror(errno));
2029 (void) close(*mux_fd);
2030 (void) close(muxid_fd);
2031 return (-1);
2033 if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) {
2034 rcm_log_message(RCM_ERROR,
2035 _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"),
2036 udp_dev_name, strerror(errno));
2037 (void) close(*mux_fd);
2038 (void) close(muxid_fd);
2039 return (-1);
2042 /* Note: mux_fd and muxid_fd are closed in ip_plink below */
2043 *muxid_fdp = muxid_fd;
2044 return (0);
2048 * ip_plink() - Helper function for mod*() functions.
2049 * Stolen from ifconfig.c
2051 static int
2052 ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr)
2054 int mux_id;
2056 if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) {
2057 rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"),
2058 UDP_DEV_NAME, strerror(errno));
2059 (void) close(mux_fd);
2060 (void) close(muxid_fd);
2061 (void) close(fd);
2062 return (-1);
2065 lifr->lifr_ip_muxid = mux_id;
2066 if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) {
2067 rcm_log_message(RCM_ERROR,
2068 _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"),
2069 UDP_DEV_NAME, strerror(errno));
2070 (void) close(mux_fd);
2071 (void) close(muxid_fd);
2072 (void) close(fd);
2073 return (-1);
2076 (void) close(mux_fd);
2077 (void) close(muxid_fd);
2078 (void) close(fd);
2079 return (0);
2083 * ip_onlinelist()
2085 * Notify online to IP address consumers.
2087 /*ARGSUSED*/
2088 static int
2089 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2090 rcm_info_t **depend_info)
2092 char **addrlist;
2093 int ret = RCM_SUCCESS;
2095 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n");
2097 addrlist = ip_get_addrlist(node);
2098 if (addrlist == NULL || addrlist[0] == NULL) {
2099 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n");
2100 ip_free_addrlist(addrlist);
2101 return (ret);
2104 ret = rcm_notify_online_list(hd, addrlist, 0, depend_info);
2106 ip_free_addrlist(addrlist);
2107 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n");
2108 return (ret);
2112 * ip_offlinelist()
2114 * Offline IP address consumers.
2116 /*ARGSUSED*/
2117 static int
2118 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2119 rcm_info_t **depend_info)
2121 char **addrlist;
2122 int ret = RCM_SUCCESS;
2124 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n");
2126 addrlist = ip_get_addrlist(node);
2127 if (addrlist == NULL || addrlist[0] == NULL) {
2128 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n");
2129 ip_free_addrlist(addrlist);
2130 return (RCM_SUCCESS);
2133 if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info))
2134 != RCM_SUCCESS) {
2135 if (ret == RCM_FAILURE)
2136 (void) rcm_notify_online_list(hd, addrlist, 0, NULL);
2138 ret = RCM_FAILURE;
2141 ip_free_addrlist(addrlist);
2142 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n");
2143 return (ret);
2147 * ip_get_addrlist() - Get the list of IP addresses on this interface (node);
2148 * This routine malloc()s required memory for the list.
2149 * Returns the list on success, NULL on failure.
2150 * Call with cache_lock held.
2152 static char **
2153 ip_get_addrlist(ip_cache_t *node)
2155 ip_lif_t *lif;
2156 char **addrlist = NULL;
2157 int i, numifs;
2158 size_t addrlistsize;
2159 char addrstr[INET6_ADDRSTRLEN];
2161 rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n",
2162 node->ip_resource);
2164 numifs = 0;
2165 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
2166 numifs++;
2170 * Allocate space for resource names list; add 1 and use calloc()
2171 * so that the list is NULL-terminated.
2173 if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) {
2174 rcm_log_message(RCM_ERROR,
2175 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2176 node->ip_resource, strerror(errno));
2177 return (NULL);
2180 for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL;
2181 lif = lif->li_next, i++) {
2183 if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) {
2184 ip_free_addrlist(addrlist);
2185 return (NULL);
2188 addrlistsize = strlen(addrstr) + sizeof (RCM_STR_SUNW_IP);
2189 if ((addrlist[i] = malloc(addrlistsize)) == NULL) {
2190 rcm_log_message(RCM_ERROR,
2191 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2192 node->ip_resource, strerror(errno));
2193 ip_free_addrlist(addrlist);
2194 return (NULL);
2196 (void) snprintf(addrlist[i], addrlistsize, "%s%s",
2197 RCM_STR_SUNW_IP, addrstr);
2199 rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]);
2202 rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n",
2203 node->ip_resource);
2205 return (addrlist);
2208 static void
2209 ip_free_addrlist(char **addrlist)
2211 int i;
2213 if (addrlist == NULL)
2214 return;
2216 for (i = 0; addrlist[i] != NULL; i++)
2217 free(addrlist[i]);
2218 free(addrlist);
2222 * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
2225 static void
2226 ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
2227 uint_t flags, rcm_info_t **depend_info)
2229 char cached_name[RCM_LINK_RESOURCE_MAX];
2230 ip_cache_t *node;
2232 assert(linkid != DATALINK_INVALID_LINKID);
2234 rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid);
2236 /* Check for the interface in the cache */
2237 (void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2238 RCM_LINK_PREFIX, linkid);
2240 (void) mutex_lock(&cache_lock);
2241 if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) {
2242 rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"),
2243 linkid);
2244 (void) mutex_unlock(&cache_lock);
2245 return;
2248 * Inform anonymous consumers about IP addresses being onlined.
2250 (void) ip_onlinelist(hd, node, errorp, flags, depend_info);
2252 (void) mutex_unlock(&cache_lock);
2254 rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n");
2258 * Gets the interface name for the given linkid. Returns -1 if there is
2259 * any error. It fills in the interface name in `ifinst' if the interface
2260 * is not already configured. Otherwise, it puts a null string in `ifinst'.
2262 static int
2263 if_configure_get_linkid(datalink_id_t linkid, char *ifinst, size_t len)
2265 char cached_name[RCM_LINK_RESOURCE_MAX];
2266 ip_cache_t *node;
2268 /* Check for the interface in the cache */
2269 (void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2270 RCM_LINK_PREFIX, linkid);
2272 /* Check if the interface is new or was not previously offlined */
2273 (void) mutex_lock(&cache_lock);
2274 if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) &&
2275 (!(node->ip_cachestate & CACHE_IF_OFFLINED))) {
2276 rcm_log_message(RCM_TRACE1,
2277 _("IP: Skipping configured interface(%u)\n"), linkid);
2278 (void) mutex_unlock(&cache_lock);
2279 *ifinst = '\0';
2280 return (0);
2282 (void) mutex_unlock(&cache_lock);
2284 if (dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, NULL, ifinst,
2285 len) != DLADM_STATUS_OK) {
2286 rcm_log_message(RCM_ERROR,
2287 _("IP: get %u link name failed\n"), linkid);
2288 return (-1);
2290 return (0);
2294 * if_configure_hostname() - Configure a physical interface after attach
2295 * based on the information in /etc/hostname.*
2297 static int
2298 if_configure_hostname(datalink_id_t linkid)
2300 FILE *hostfp, *host6fp;
2301 boolean_t ipmp = B_FALSE;
2302 char ifinst[MAXLINKNAMELEN];
2303 char cfgfile[MAXPATHLEN];
2305 assert(linkid != DATALINK_INVALID_LINKID);
2306 rcm_log_message(RCM_TRACE1, _("IP: if_configure_hostname(%u)\n"),
2307 linkid);
2309 if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
2310 return (-1);
2312 /* Check if the interface is already configured. */
2313 if (ifinst[0] == '\0')
2314 return (0);
2317 * Scan the IPv4 and IPv6 hostname files to see if (a) they exist
2318 * and (b) if either one places the interface into an IPMP group.
2320 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifinst);
2321 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2322 if ((hostfp = fopen(cfgfile, "r")) != NULL) {
2323 if (isgrouped(cfgfile))
2324 ipmp = B_TRUE;
2327 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifinst);
2328 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2329 if ((host6fp = fopen(cfgfile, "r")) != NULL) {
2330 if (!ipmp && isgrouped(cfgfile))
2331 ipmp = B_TRUE;
2335 * Configure the interface according to its hostname files.
2337 if (hostfp != NULL &&
2338 if_config_inst(ifinst, hostfp, AF_INET, ipmp) == -1) {
2339 rcm_log_message(RCM_ERROR,
2340 _("IP: IPv4 Post-attach failed (%s)\n"), ifinst);
2341 goto fail;
2344 if (host6fp != NULL &&
2345 if_config_inst(ifinst, host6fp, AF_INET6, ipmp) == -1) {
2346 rcm_log_message(RCM_ERROR,
2347 _("IP: IPv6 Post-attach failed (%s)\n"), ifinst);
2348 goto fail;
2351 (void) fclose(hostfp);
2352 (void) fclose(host6fp);
2353 rcm_log_message(RCM_TRACE1, "IP: if_configure_hostname(%s) success\n",
2354 ifinst);
2355 return (0);
2356 fail:
2357 (void) fclose(hostfp);
2358 (void) fclose(host6fp);
2359 return (-1);
2363 * if_configure_ipadm() - Configure a physical interface after attach
2364 * Queries libipadm for persistent configuration information and then
2365 * resurrects that persistent configuration.
2367 static int
2368 if_configure_ipadm(datalink_id_t linkid)
2370 char ifinst[MAXLINKNAMELEN];
2371 boolean_t found;
2372 ipadm_if_info_t *ifinfo, *ptr;
2373 ipadm_status_t status;
2375 assert(linkid != DATALINK_INVALID_LINKID);
2376 rcm_log_message(RCM_TRACE1, _("IP: if_configure_ipadm(%u)\n"),
2377 linkid);
2379 if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
2380 return (-1);
2382 /* Check if the interface is already configured. */
2383 if (ifinst[0] == '\0')
2384 return (0);
2386 status = ipadm_if_info(ip_handle, ifinst, &ifinfo, 0, LIFC_UNDER_IPMP);
2387 if (status == IPADM_ENXIO)
2388 goto done;
2389 if (status != IPADM_SUCCESS) {
2390 rcm_log_message(RCM_ERROR,
2391 _("IP: IPv4 Post-attach failed (%s) Error %s\n"),
2392 ifinst, ipadm_status2str(status));
2393 goto fail;
2395 if (ifinfo != NULL) {
2396 found = B_FALSE;
2397 for (ptr = ifinfo; ptr; ptr = ptr->ifi_next) {
2398 if (strncmp(ptr->ifi_name, ifinst,
2399 sizeof (ifinst)) == 0) {
2400 found = B_TRUE;
2401 break;
2404 free(ifinfo);
2405 if (!found) {
2406 return (0);
2408 if (if_hostname_exists(ifinst, AF_INET) ||
2409 if_hostname_exists(ifinst, AF_INET6)) {
2410 rcm_log_message(RCM_WARNING,
2411 _("IP: IPv4 Post-attach (%s) found both "
2412 "/etc/hostname and ipadm persistent configuration. "
2413 "Ignoring ipadm config\n"), ifinst);
2414 return (0);
2416 status = ipadm_enable_if(ip_handle, ifinst, IPADM_OPT_ACTIVE);
2417 if (status != IPADM_SUCCESS) {
2418 rcm_log_message(RCM_ERROR,
2419 _("IP: Post-attach failed (%s) Error %s\n"),
2420 ifinst, ipadm_status2str(status));
2421 goto fail;
2424 done:
2425 rcm_log_message(RCM_TRACE1, "IP: if_configure_ipadm(%s) success\n",
2426 ifinst);
2427 return (0);
2428 fail:
2429 return (-1);
2433 * isgrouped() - Scans the given config file to see if this interface is
2434 * using IPMP. Returns B_TRUE or B_FALSE.
2436 static boolean_t
2437 isgrouped(const char *cfgfile)
2439 FILE *fp;
2440 struct stat statb;
2441 char *nlp, *line, *token, *lasts, *buf;
2442 boolean_t grouped = B_FALSE;
2444 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile);
2446 if (stat(cfgfile, &statb) != 0) {
2447 rcm_log_message(RCM_TRACE1,
2448 _("IP: No config file(%s)\n"), cfgfile);
2449 return (B_FALSE);
2453 * We also ignore single-byte config files because the file should
2454 * always be newline-terminated, so we know there's nothing of
2455 * interest. Further, a single-byte file would cause the fgets() loop
2456 * below to spin forever.
2458 if (statb.st_size <= 1) {
2459 rcm_log_message(RCM_TRACE1,
2460 _("IP: Empty config file(%s)\n"), cfgfile);
2461 return (B_FALSE);
2464 if ((fp = fopen(cfgfile, "r")) == NULL) {
2465 rcm_log_message(RCM_ERROR,
2466 _("IP: Cannot open configuration file(%s): %s\n"), cfgfile,
2467 strerror(errno));
2468 return (B_FALSE);
2471 if ((buf = malloc(statb.st_size)) == NULL) {
2472 rcm_log_message(RCM_ERROR,
2473 _("IP: malloc failure(%s): %s\n"), cfgfile,
2474 strerror(errno));
2475 goto out;
2478 while (fgets(buf, statb.st_size, fp) != NULL) {
2479 if ((nlp = strrchr(buf, '\n')) != NULL)
2480 *nlp = '\0';
2482 line = buf;
2483 while ((token = strtok_r(line, " \t", &lasts)) != NULL) {
2484 line = NULL;
2485 if (STREQ("group", token) &&
2486 strtok_r(NULL, " \t", &lasts) != NULL) {
2487 grouped = B_TRUE;
2488 goto out;
2492 out:
2493 free(buf);
2494 (void) fclose(fp);
2496 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s): %d\n", cfgfile,
2497 grouped);
2499 return (grouped);
2503 * if_config_inst() - Configure an interface instance as specified by the
2504 * address family af and if it is grouped (ipmp).
2506 static int
2507 if_config_inst(const char *ifinst, FILE *hfp, int af, boolean_t ipmp)
2509 FILE *ifparsefp;
2510 struct stat statb;
2511 char *buf = NULL;
2512 char *ifparsebuf = NULL;
2513 uint_t ifparsebufsize;
2514 const char *fstr; /* address family string */
2515 boolean_t stdif = B_FALSE;
2517 rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) ipmp = %d\n",
2518 ifinst, ipmp);
2520 if (fstat(fileno(hfp), &statb) != 0) {
2521 rcm_log_message(RCM_ERROR,
2522 _("IP: Cannot fstat file(%s)\n"), ifinst);
2523 goto fail;
2526 switch (af) {
2527 case AF_INET:
2528 fstr = "inet";
2529 break;
2530 case AF_INET6:
2531 fstr = "inet6";
2532 break;
2533 default:
2534 assert(0);
2538 * The hostname file exists; plumb the physical interface.
2540 if (!ifconfig(ifinst, fstr, "plumb", B_FALSE))
2541 goto fail;
2543 /* Skip static configuration if the hostname file is empty */
2544 if (statb.st_size <= 1) {
2545 rcm_log_message(RCM_TRACE1,
2546 _("IP: Zero size hostname file(%s)\n"), ifinst);
2547 goto configured;
2550 if (fseek(hfp, 0, SEEK_SET) == -1) {
2551 rcm_log_message(RCM_ERROR,
2552 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2553 strerror(errno));
2554 goto fail;
2558 * Allocate the worst-case single-line buffer sizes. A bit skanky,
2559 * but since hostname files are small, this should suffice.
2561 if ((buf = calloc(1, statb.st_size)) == NULL) {
2562 rcm_log_message(RCM_ERROR,
2563 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2564 goto fail;
2567 ifparsebufsize = statb.st_size + sizeof (SBIN_IFPARSE " -s inet6 ");
2568 if ((ifparsebuf = calloc(1, ifparsebufsize)) == NULL) {
2569 rcm_log_message(RCM_ERROR,
2570 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2571 goto fail;
2575 * For IPv4, determine whether the hostname file consists of a single
2576 * line. We need to handle these specially since they should
2577 * automatically be suffixed with "netmask + broadcast + up".
2579 if (af == AF_INET &&
2580 fgets(buf, statb.st_size, hfp) != NULL &&
2581 fgets(buf, statb.st_size, hfp) == NULL) {
2582 rcm_log_message(RCM_TRACE1, "IP: one-line hostname file\n");
2583 stdif = B_TRUE;
2586 if (fseek(hfp, 0L, SEEK_SET) == -1) {
2587 rcm_log_message(RCM_ERROR,
2588 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2589 strerror(errno));
2590 goto fail;
2594 * Loop through the file one line at a time and feed it to ifconfig.
2595 * If the interface is using IPMP, then we use /sbin/ifparse -s to
2596 * weed out all of the data addresses, since those are already on the
2597 * IPMP meta-interface.
2599 while (fgets(buf, statb.st_size, hfp) != NULL) {
2600 if (ntok(buf) == 0)
2601 continue;
2603 if (!ipmp) {
2604 (void) ifconfig(ifinst, fstr, buf, stdif);
2605 continue;
2608 (void) snprintf(ifparsebuf, ifparsebufsize, SBIN_IFPARSE
2609 " -s %s %s", fstr, buf);
2610 if ((ifparsefp = popen(ifparsebuf, "r")) == NULL) {
2611 rcm_log_message(RCM_ERROR,
2612 _("IP: cannot configure %s: popen \"%s\" "
2613 "failed: %s\n"), ifinst, buf, strerror(errno));
2614 goto fail;
2617 while (fgets(buf, statb.st_size, ifparsefp) != NULL) {
2618 if (ntok(buf) > 0)
2619 (void) ifconfig(ifinst, fstr, buf, stdif);
2622 if (pclose(ifparsefp) == -1) {
2623 rcm_log_message(RCM_ERROR,
2624 _("IP: cannot configure %s: pclose \"%s\" "
2625 "failed: %s\n"), ifinst, buf, strerror(errno));
2626 goto fail;
2630 configured:
2632 * Bring up the interface (it may already be up)
2634 * Technically, since the boot scripts only unconditionally bring up
2635 * IPv6 interfaces, we should only unconditionally bring up IPv6 here.
2636 * However, if we don't bring up IPv4, and a legacy IPMP configuration
2637 * without test addresses is being used, we will never bring the
2638 * interface up even though we would've at boot. One fix is to check
2639 * if the IPv4 hostname file contains data addresses that we would've
2640 * brought up, but there's no simple way to do that. Given that it's
2641 * rare to have persistent IP configuration for an interface that
2642 * leaves it down, we cheap out and always bring it up for IPMP.
2644 if ((af == AF_INET6 || ipmp) && !ifconfig(ifinst, fstr, "up", B_FALSE))
2645 goto fail;
2648 * For IPv4, if a DHCP configuration file exists, have DHCP configure
2649 * the interface. As with the boot scripts, this is done after the
2650 * hostname files are processed so that configuration in those files
2651 * (such as IPMP group names) will be applied first.
2653 if (af == AF_INET) {
2654 char dhcpfile[MAXPATHLEN];
2655 char *dhcpbuf;
2656 off_t i, dhcpsize;
2658 (void) snprintf(dhcpfile, MAXPATHLEN, DHCPFILE_FMT, ifinst);
2659 if (stat(dhcpfile, &statb) == -1)
2660 goto out;
2662 if ((dhcpbuf = copylist(dhcpfile, &dhcpsize)) == NULL) {
2663 rcm_log_message(RCM_ERROR, _("IP: cannot read "
2664 "(%s): %s\n"), dhcpfile, strerror(errno));
2665 goto fail;
2669 * The copylist() API converts \n's to \0's, but we want them
2670 * to be spaces.
2672 if (dhcpsize > 0) {
2673 for (i = 0; i < dhcpsize; i++)
2674 if (dhcpbuf[i] == '\0')
2675 dhcpbuf[i] = ' ';
2676 dhcpbuf[dhcpsize - 1] = '\0';
2678 (void) ifconfig(ifinst, CFG_DHCP_CMD, dhcpbuf, B_FALSE);
2679 free(dhcpbuf);
2681 out:
2682 free(ifparsebuf);
2683 free(buf);
2684 rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) success\n", ifinst);
2685 return (0);
2686 fail:
2687 free(ifparsebuf);
2688 free(buf);
2689 rcm_log_message(RCM_ERROR, "IP: if_config_inst(%s) failure\n", ifinst);
2690 return (-1);
2694 * ntok() - count the number of tokens in the provided buffer.
2696 static uint_t
2697 ntok(const char *cp)
2699 uint_t ntok = 0;
2701 for (;;) {
2702 while (ISSPACE(*cp))
2703 cp++;
2705 if (ISEOL(*cp))
2706 break;
2708 do {
2709 cp++;
2710 } while (!ISSPACE(*cp) && !ISEOL(*cp));
2712 ntok++;
2714 return (ntok);
2717 static boolean_t
2718 ifconfig(const char *ifinst, const char *fstr, const char *buf, boolean_t stdif)
2720 char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
2721 int status;
2723 (void) snprintf(syscmd, sizeof (syscmd), SBIN_IFCONFIG " %s %s %s",
2724 ifinst, fstr, buf);
2726 if (stdif)
2727 (void) strlcat(syscmd, CFG_CMDS_STD, sizeof (syscmd));
2729 rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd);
2730 if ((status = rcm_exec_cmd(syscmd)) != 0) {
2731 if (WIFEXITED(status)) {
2732 rcm_log_message(RCM_ERROR, _("IP: \"%s\" failed with "
2733 "exit status %d\n"), syscmd, WEXITSTATUS(status));
2734 } else {
2735 rcm_log_message(RCM_ERROR, _("IP: Error: %s: %s\n"),
2736 syscmd, strerror(errno));
2738 return (B_FALSE);
2740 return (B_TRUE);
2744 * Return TRUE if a writeable /etc/hostname[6].ifname file exists.
2746 static boolean_t
2747 if_hostname_exists(char *ifname, sa_family_t af)
2749 char cfgfile[MAXPATHLEN];
2751 if (af == AF_INET) {
2752 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifname);
2753 if (access(cfgfile, W_OK|F_OK) == 0)
2754 return (B_TRUE);
2755 } else if (af == AF_INET6) {
2756 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifname);
2757 if (access(cfgfile, W_OK|F_OK) == 0)
2758 return (B_TRUE);
2760 return (B_FALSE);