4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
26 * This RCM module adds support to the RCM framework for IP managed
39 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <sys/sockio.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
49 #include <sys/sysmacros.h>
51 #include <libinetutil.h>
52 #include <libdllink.h>
54 #include <ipmp_admin.h>
57 #include "rcm_module.h"
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 */
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 */
125 struct sockaddr_storage storage
;
126 struct sockaddr_in ip4
; /* IPv4 */
127 struct sockaddr_in6 ip6
; /* IPv6 */
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 */
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 */
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
,
201 static int ip_offlinelist(rcm_handle_t
*, ip_cache_t
*, char **, uint_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
=
235 * rcm_mod_init() - Update registrations, and return the ops structure.
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
));
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
);
268 /* Return the ops vectors */
273 * rcm_mod_info() - Return a string describing this module.
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.
289 rcm_log_message(RCM_TRACE1
, "IP: mod_fini\n");
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.
304 ip_register(rcm_handle_t
*hd
)
306 rcm_log_message(RCM_TRACE1
, "IP: register\n");
308 /* Guard against bad arguments */
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
)
321 rcm_log_message(RCM_ERROR
,
322 _("IP: failed to register %s\n"),
323 RCM_RESOURCE_LINK_NEW
);
324 return (RCM_FAILURE
);
326 rcm_log_message(RCM_DEBUG
, "IP: registered %s\n",
327 RCM_RESOURCE_LINK_NEW
);
332 return (RCM_SUCCESS
);
336 * ip_unregister() - Walk the cache, unregistering all the networks.
339 ip_unregister(rcm_handle_t
*hd
)
343 rcm_log_message(RCM_TRACE1
, "IP: unregister\n");
345 /* Guard against bad arguments */
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)
354 /* unregister failed for whatever reason */
355 (void) mutex_unlock(&cache_lock
);
356 return (RCM_FAILURE
);
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)
370 rcm_log_message(RCM_ERROR
,
371 _("IP: failed to unregister %s\n"),
372 RCM_RESOURCE_LINK_NEW
);
373 return (RCM_FAILURE
);
375 rcm_log_message(RCM_DEBUG
, "IP: unregistered %s\n",
376 RCM_RESOURCE_LINK_NEW
);
381 return (RCM_SUCCESS
);
385 * ip_offline() - Offline an interface.
388 ip_offline(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
389 char **errorp
, rcm_info_t
**depend_info
)
393 boolean_t detachable
= B_FALSE
;
397 rcm_log_message(RCM_TRACE1
, "IP: offline(%s)\n", rsrc
);
399 /* Guard against bad arguments */
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
);
410 ip_log_err(node
, errorp
, "Unrecognized resource");
412 (void) mutex_unlock(&cache_lock
);
413 return (RCM_SUCCESS
);
418 /* Establish default detachability criteria */
419 if (flags
& RCM_FORCE
)
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
) ==
435 rcm_log_message(RCM_DEBUG
,
436 "IP: consumers agree on detach");
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",
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 */
463 if (if_unplumb(node
) < 0) {
464 ip_log_err(node
, errorp
,
465 "Failed to unplumb the device");
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");
500 ip_log_err(node
, errorp
,
501 "Device consumers prohibit offline");
502 (void) mutex_unlock(&cache_lock
);
504 return (RCM_FAILURE
);
508 if (if_unplumb(node
) < 0) {
509 rcm_log_message(RCM_ERROR
,
510 _("IP: Unplumb failed (%s)\n"),
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.
534 ip_undo_offline(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
535 char **errorp
, rcm_info_t
**depend_info
)
539 rcm_log_message(RCM_TRACE1
, "IP: online(%s)\n", rsrc
);
541 /* Guard against bad arguments */
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
);
552 ip_log_err(node
, errorp
, "No such device");
553 (void) mutex_unlock(&cache_lock
);
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
);
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
);
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.
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
)
602 /* Guard against bad arguments */
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
);
615 rcm_log_message(RCM_INFO
,
616 _("IP: get_info(%s) unrecognized resource\n"), rsrc
);
617 (void) mutex_unlock(&cache_lock
);
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
);
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 */
640 rcm_log_message(RCM_TRACE1
, "IP: get_info(%s) info = %s \n",
643 (void) mutex_unlock(&cache_lock
);
644 return (RCM_SUCCESS
);
648 * ip_suspend() - Nothing to do, always okay
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 */
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
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 */
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
692 ip_remove(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
693 char **errorp
, rcm_info_t
**depend_info
)
697 /* Guard against bad arguments */
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
);
709 rcm_log_message(RCM_INFO
,
710 _("IP: remove(%s) unrecognized resource\n"), rsrc
);
711 (void) mutex_unlock(&cache_lock
);
713 return (RCM_FAILURE
);
716 /* remove the cached entry for the resource */
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.
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
;
741 assert(rsrc
!= NULL
);
742 assert(id
== (id_t
)0);
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");
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"),
780 ip_log_err(NULL
, errorp
,
781 "Failed configuring one or more IP "
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"),
793 ip_log_err(NULL
, errorp
,
794 "Failed configuring one or more IP "
798 /* Notify all IP address consumers */
799 ip_consumer_notify(hd
, linkid
, errorp
, flags
,
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.
816 ip_usage(ip_cache_t
*node
)
820 char *sep
, *buf
, *linkidstr
;
821 datalink_id_t linkid
;
823 char link
[MAXLINKNAMELEN
];
824 char addrstr
[INET6_ADDRSTRLEN
];
825 char errmsg
[DLADM_STRSIZE
];
826 dladm_status_t status
;
827 boolean_t offline
, ipmp
;
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
;
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
));
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
));
856 /* TRANSLATION_NOTE: separator used between IP addresses */
860 for (lif
= node
->ip_pif
->pi_lifs
; lif
!= NULL
; lif
= lif
->li_next
)
861 if (lif
->li_ifflags
& IFF_UP
)
864 ipmp
= (node
->ip_pif
->pi_grname
[0] != '\0');
865 offline
= ((node
->ip_cachestate
& CACHE_IF_OFFLINED
) != 0);
869 } else if (numup
== 0) {
870 msg
= _("plumbed but down");
873 msg
= _("providing connectivity for IPMP group ");
874 bufsz
+= LIFGRNAMSIZ
;
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
));
888 (void) snprintf(buf
, bufsz
, "%s: %s", link
, msg
);
890 if (!offline
&& numup
> 0) {
892 (void) strlcat(buf
, node
->ip_pif
->pi_grname
, bufsz
);
894 lif
= node
->ip_pif
->pi_lifs
;
895 for (; lif
!= NULL
; lif
= lif
->li_next
) {
896 if (!(lif
->li_ifflags
& IFF_UP
))
899 if (!ip_addrstr(lif
, addrstr
, sizeof (addrstr
)))
902 (void) strlcat(buf
, addrstr
, bufsz
);
904 (void) strlcat(buf
, sep
, bufsz
);
909 rcm_log_message(RCM_TRACE2
, "IP: usage (%s) info = %s\n",
910 node
->ip_resource
, buf
);
916 ip_addrstr(ip_lif_t
*lif
, char *addrstr
, size_t addrsize
)
918 int af
= lif
->li_addr
.family
;
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
;
926 rcm_log_message(RCM_DEBUG
,
927 "IP: unknown addr family %d, assuming AF_INET\n", af
);
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
));
937 rcm_log_message(RCM_DEBUG
, "IP addr := %s\n", addrstr
);
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.
954 cache_lookup(rcm_handle_t
*hd
, char *rsrc
, char options
)
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
);
975 probe
= probe
->ip_next
;
981 * free_node - Free a node from the cache
982 * Call with cache_lock held.
985 free_node(ip_cache_t
*node
)
988 ip_lif_t
*lif
, *tmplif
;
991 if (node
->ip_resource
) {
992 free(node
->ip_resource
);
998 /* free logical interfaces */
1001 tmplif
= lif
->li_next
;
1012 * cache_insert - Insert a resource node in cache
1013 * Call with the cache_lock held.
1016 cache_insert(ip_cache_t
*node
)
1018 rcm_log_message(RCM_TRACE2
, "IP: cache insert(%s)\n",
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.
1034 cache_remove(ip_cache_t
*node
)
1036 rcm_log_message(RCM_TRACE2
, "IP: cache remove(%s)\n",
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
)
1054 ushort_t ifnumber
= 0;
1059 struct lifreq lifreq
;
1060 struct sockaddr_storage ifaddr
;
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"),
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",
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
));
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
);
1119 rcm_log_message(RCM_ERROR
,
1120 _("IP: get_link_resource(%s) failed\n"),
1125 probe
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
1126 if (probe
!= NULL
) {
1128 probe
->ip_cachestate
&= ~(CACHE_IF_STALE
);
1130 if ((probe
= calloc(1, sizeof (ip_cache_t
))) == NULL
) {
1131 /* malloc errors are bad */
1133 rcm_log_message(RCM_ERROR
, _("IP: calloc: %s\n"),
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
;
1165 probelif
->li_cachestate
&= ~(CACHE_IF_STALE
);
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"),
1176 if (probe
->ip_pif
== NULL
) {
1177 /* we created it, so clean it up */
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 */
1196 rcm_log_message(RCM_TRACE2
, "IP: adding lifs to %s\n",
1199 if ((probelif
= calloc(1, sizeof (ip_lif_t
))) == NULL
) {
1200 rcm_log_message(RCM_ERROR
, _("IP: malloc: %s\n"),
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
);
1230 * update_ipifs() - Determine all network interfaces in the system
1231 * Call with cache_lock held
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
;
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
));
1250 status
= ipadm_addr_info(ip_handle
, NULL
, &ainfo
, IPADM_OPT_ZEROADDR
,
1252 if (status
!= IPADM_SUCCESS
) {
1256 for (ptr
= ainfo
; ptr
; ptr
= IA_NEXT(ptr
)) {
1258 if (ptr
->ia_state
!= IFA_DISABLED
&&
1259 af
== ifa
->ifa_addr
->sa_family
)
1260 (void) update_pif(hd
, af
, sock
, ifa
);
1263 ipadm_free_addr_info(ainfo
);
1268 * update_cache() - Update cache with latest interface info
1271 update_cache(rcm_handle_t
*hd
)
1275 struct ip_lif
*nextlif
;
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
;
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
);
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
);
1309 probe
= cache_head
.ip_next
;
1310 /* unregister devices that are not offlined and still in cache */
1311 while (probe
!= &cache_tail
) {
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
=
1326 for (i
= 0; i
< IP_MAX_MODS
; i
++) {
1327 free(lif
->li_modules
[i
]);
1329 free(lif
->li_reconfig
);
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
);
1344 probe
= probe
->ip_next
;
1345 cache_remove(freeit
);
1350 if (!(probe
->ip_cachestate
& CACHE_IF_NEW
)) {
1351 probe
= probe
->ip_next
;
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
);
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
);
1375 * free_cache() - Empty the cache
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
);
1389 probe
= cache_head
.ip_next
;
1391 (void) mutex_unlock(&cache_lock
);
1395 * ip_log_err() - RCM error log wrapper
1398 ip_log_err(ip_cache_t
*node
, char **errorp
, char *errmsg
)
1400 char *ifname
= 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
);
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
);
1429 * if_cfginfo() - Save off the config info for all interfaces
1432 if_cfginfo(ip_cache_t
*node
, uint_t force
)
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
);
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
));
1458 /* Look if unknown modules have been inserted */
1459 for (i
= (lif
->li_modcnt
- 2); i
> 0; i
--) {
1460 if (modop(pif
->pi_ifname
,
1462 i
, MOD_CHECK
) == -1) {
1463 rcm_log_message(RCM_ERROR
,
1464 _("IP: module %s@%d\n"),
1465 lif
->li_modules
[i
], i
);
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
,
1482 i
, MOD_INSERT
) == -1) {
1497 _("IP: if_cfginfo(%s): modremove "
1498 "%s failed: %s\n"), pif
->pi_ifname
,
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
));
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
));
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
));
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
);
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
1561 * Call with cache_lock held
1564 if_unplumb(ip_cache_t
*node
)
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
) {
1576 } else if (lif
->li_ifflags
& IFF_IPV6
) {
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
));
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
));
1598 rcm_log_message(RCM_TRACE2
, "IP: if_unplumb(%s) success\n",
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
1611 if_replumb(ip_cache_t
*node
)
1616 boolean_t success
, ipmp
;
1618 char lifname
[LIFNAMSIZ
];
1619 char buf
[MAX_RECONFIG_SIZE
];
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
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)
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
) {
1644 } else if (lif
->li_ifflags
& IFF_IPV6
) {
1648 rcm_log_message(RCM_DEBUG
,
1649 "IP: Re-plumb ignored (%s:%d)\n",
1650 pif
->pi_ifname
, lif
->li_ifnum
);
1654 /* ignore logical interface instances */
1655 if (lif
->li_ifnum
!= 0)
1658 if ((lif
->li_ifflags
& IFF_NOFAILOVER
) || !ipmp
) {
1659 success
= ifconfig("", "", lif
->li_reconfig
, B_FALSE
);
1661 (void) snprintf(buf
, sizeof (buf
), "plumb group %s",
1663 success
= ifconfig(pif
->pi_ifname
, fstr
, buf
, B_FALSE
);
1667 rcm_log_message(RCM_ERROR
,
1668 _("IP: Cannot plumb (%s) %s\n"), pif
->pi_ifname
,
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
));
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"),
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
)))
1714 if (!ifconfig("", "", lif
->li_reconfig
, B_FALSE
)) {
1715 rcm_log_message(RCM_ERROR
,
1716 _("IP: Cannot addif (%s) %s\n"), lifname
,
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
));
1734 rcm_log_message(RCM_TRACE2
, "IP: if_replumb(%s) success \n",
1741 * clr_cfg_state() - Cleanup after errors in unplumb
1744 clr_cfg_state(ip_pif_t
*pif
)
1751 while (lif
!= NULL
) {
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
;
1764 * Attempt to offline ip_cache_t `node'; returns an IPMP error code.
1767 ip_ipmp_offline(ip_cache_t
*node
)
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
));
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
));
1786 rcm_log_message(RCM_TRACE1
, "IP: ipmp_offline success\n");
1794 * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code.
1797 ip_ipmp_undo_offline(ip_cache_t
*node
)
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
));
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
));
1817 rcm_log_message(RCM_TRACE1
, "IP: ipmp_undo_offline success\n");
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>").
1830 get_link_resource(const char *link
)
1832 char errmsg
[DLADM_STRSIZE
];
1833 datalink_id_t linkid
;
1836 dladm_status_t status
;
1838 status
= dladm_name2info(dld_handle
, link
, &linkid
, &flags
, NULL
, NULL
);
1839 if (status
!= DLADM_STATUS_OK
)
1842 if (!(flags
& DLADM_OPT_ACTIVE
)) {
1843 status
= DLADM_STATUS_FAILED
;
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
);
1854 (void) snprintf(resource
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
1855 RCM_LINK_PREFIX
, linkid
);
1860 rcm_log_message(RCM_ERROR
,
1861 _("IP: get_link_resource for %s error(%s)\n"),
1862 link
, dladm_status2str(status
, errmsg
));
1867 * modop() - Remove/insert a module
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");
1883 if (op
== MOD_CHECK
) {
1885 * No known good modules (yet) apart from ip and arp
1886 * which are handled above
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
);
1898 rcm_log_message(RCM_ERROR
,
1899 _("IP: modop(%s): unknown operation\n"), name
);
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
));
1910 rcm_log_message(RCM_TRACE1
, "IP: modop success\n");
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
1921 get_modlist(char *name
, ip_lif_t
*lif
)
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
);
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
));
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
));
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
));
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
));
1969 free(lif
->li_modules
[--i
]);
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
));
1980 free(strlist
.sl_modlist
);
1981 (void) ip_plink(mux_fd
, muxid_fd
, fd
, &lifr
);
1986 * ip_domux2fd() - Helper function for mod*() functions
1987 * Stolen from ifconfig.c
1990 ip_domux2fd(int *mux_fd
, int *muxid_fdp
, int *fd
, struct lifreq
*lifr
)
1995 if (lifr
->lifr_flags
& IFF_IPV6
) {
1996 udp_dev_name
= UDP6_DEV_NAME
;
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
));
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
);
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
);
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
);
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
);
2042 /* Note: mux_fd and muxid_fd are closed in ip_plink below */
2043 *muxid_fdp
= muxid_fd
;
2048 * ip_plink() - Helper function for mod*() functions.
2049 * Stolen from ifconfig.c
2052 ip_plink(int mux_fd
, int muxid_fd
, int fd
, struct lifreq
*lifr
)
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
);
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
);
2076 (void) close(mux_fd
);
2077 (void) close(muxid_fd
);
2085 * Notify online to IP address consumers.
2089 ip_onlinelist(rcm_handle_t
*hd
, ip_cache_t
*node
, char **errorp
, uint_t flags
,
2090 rcm_info_t
**depend_info
)
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
);
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");
2114 * Offline IP address consumers.
2118 ip_offlinelist(rcm_handle_t
*hd
, ip_cache_t
*node
, char **errorp
, uint_t flags
,
2119 rcm_info_t
**depend_info
)
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
))
2135 if (ret
== RCM_FAILURE
)
2136 (void) rcm_notify_online_list(hd
, addrlist
, 0, NULL
);
2141 ip_free_addrlist(addrlist
);
2142 rcm_log_message(RCM_TRACE2
, "IP: ip_offlinelist done\n");
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.
2153 ip_get_addrlist(ip_cache_t
*node
)
2156 char **addrlist
= NULL
;
2158 size_t addrlistsize
;
2159 char addrstr
[INET6_ADDRSTRLEN
];
2161 rcm_log_message(RCM_TRACE2
, "IP: ip_get_addrlist(%s)\n",
2165 for (lif
= node
->ip_pif
->pi_lifs
; lif
!= NULL
; lif
= lif
->li_next
) {
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
));
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
);
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
);
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",
2209 ip_free_addrlist(char **addrlist
)
2213 if (addrlist
== NULL
)
2216 for (i
= 0; addrlist
[i
] != NULL
; i
++)
2222 * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
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
];
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"),
2244 (void) mutex_unlock(&cache_lock
);
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'.
2263 if_configure_get_linkid(datalink_id_t linkid
, char *ifinst
, size_t len
)
2265 char cached_name
[RCM_LINK_RESOURCE_MAX
];
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
);
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
);
2294 * if_configure_hostname() - Configure a physical interface after attach
2295 * based on the information in /etc/hostname.*
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"),
2309 if (if_configure_get_linkid(linkid
, ifinst
, sizeof (ifinst
)) != 0)
2312 /* Check if the interface is already configured. */
2313 if (ifinst
[0] == '\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
))
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
))
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
);
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
);
2351 (void) fclose(hostfp
);
2352 (void) fclose(host6fp
);
2353 rcm_log_message(RCM_TRACE1
, "IP: if_configure_hostname(%s) success\n",
2357 (void) fclose(hostfp
);
2358 (void) fclose(host6fp
);
2363 * if_configure_ipadm() - Configure a physical interface after attach
2364 * Queries libipadm for persistent configuration information and then
2365 * resurrects that persistent configuration.
2368 if_configure_ipadm(datalink_id_t linkid
)
2370 char ifinst
[MAXLINKNAMELEN
];
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"),
2379 if (if_configure_get_linkid(linkid
, ifinst
, sizeof (ifinst
)) != 0)
2382 /* Check if the interface is already configured. */
2383 if (ifinst
[0] == '\0')
2386 status
= ipadm_if_info(ip_handle
, ifinst
, &ifinfo
, 0, LIFC_UNDER_IPMP
);
2387 if (status
== IPADM_ENXIO
)
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
));
2395 if (ifinfo
!= NULL
) {
2397 for (ptr
= ifinfo
; ptr
; ptr
= ptr
->ifi_next
) {
2398 if (strncmp(ptr
->ifi_name
, ifinst
,
2399 sizeof (ifinst
)) == 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
);
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
));
2425 rcm_log_message(RCM_TRACE1
, "IP: if_configure_ipadm(%s) success\n",
2433 * isgrouped() - Scans the given config file to see if this interface is
2434 * using IPMP. Returns B_TRUE or B_FALSE.
2437 isgrouped(const char *cfgfile
)
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
);
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
);
2464 if ((fp
= fopen(cfgfile
, "r")) == NULL
) {
2465 rcm_log_message(RCM_ERROR
,
2466 _("IP: Cannot open configuration file(%s): %s\n"), cfgfile
,
2471 if ((buf
= malloc(statb
.st_size
)) == NULL
) {
2472 rcm_log_message(RCM_ERROR
,
2473 _("IP: malloc failure(%s): %s\n"), cfgfile
,
2478 while (fgets(buf
, statb
.st_size
, fp
) != NULL
) {
2479 if ((nlp
= strrchr(buf
, '\n')) != NULL
)
2483 while ((token
= strtok_r(line
, " \t", &lasts
)) != NULL
) {
2485 if (STREQ("group", token
) &&
2486 strtok_r(NULL
, " \t", &lasts
) != NULL
) {
2496 rcm_log_message(RCM_TRACE1
, "IP: isgrouped(%s): %d\n", cfgfile
,
2503 * if_config_inst() - Configure an interface instance as specified by the
2504 * address family af and if it is grouped (ipmp).
2507 if_config_inst(const char *ifinst
, FILE *hfp
, int af
, boolean_t ipmp
)
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",
2520 if (fstat(fileno(hfp
), &statb
) != 0) {
2521 rcm_log_message(RCM_ERROR
,
2522 _("IP: Cannot fstat file(%s)\n"), ifinst
);
2538 * The hostname file exists; plumb the physical interface.
2540 if (!ifconfig(ifinst
, fstr
, "plumb", B_FALSE
))
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
);
2550 if (fseek(hfp
, 0, SEEK_SET
) == -1) {
2551 rcm_log_message(RCM_ERROR
,
2552 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst
,
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
));
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
));
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");
2586 if (fseek(hfp
, 0L, SEEK_SET
) == -1) {
2587 rcm_log_message(RCM_ERROR
,
2588 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst
,
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
) {
2604 (void) ifconfig(ifinst
, fstr
, buf
, stdif
);
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
));
2617 while (fgets(buf
, statb
.st_size
, ifparsefp
) != NULL
) {
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
));
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
))
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
];
2658 (void) snprintf(dhcpfile
, MAXPATHLEN
, DHCPFILE_FMT
, ifinst
);
2659 if (stat(dhcpfile
, &statb
) == -1)
2662 if ((dhcpbuf
= copylist(dhcpfile
, &dhcpsize
)) == NULL
) {
2663 rcm_log_message(RCM_ERROR
, _("IP: cannot read "
2664 "(%s): %s\n"), dhcpfile
, strerror(errno
));
2669 * The copylist() API converts \n's to \0's, but we want them
2673 for (i
= 0; i
< dhcpsize
; i
++)
2674 if (dhcpbuf
[i
] == '\0')
2676 dhcpbuf
[dhcpsize
- 1] = '\0';
2678 (void) ifconfig(ifinst
, CFG_DHCP_CMD
, dhcpbuf
, B_FALSE
);
2684 rcm_log_message(RCM_TRACE1
, "IP: if_config_inst(%s) success\n", ifinst
);
2689 rcm_log_message(RCM_ERROR
, "IP: if_config_inst(%s) failure\n", ifinst
);
2694 * ntok() - count the number of tokens in the provided buffer.
2697 ntok(const char *cp
)
2702 while (ISSPACE(*cp
))
2710 } while (!ISSPACE(*cp
) && !ISEOL(*cp
));
2718 ifconfig(const char *ifinst
, const char *fstr
, const char *buf
, boolean_t stdif
)
2720 char syscmd
[MAX_RECONFIG_SIZE
+ MAXPATHLEN
+ 1];
2723 (void) snprintf(syscmd
, sizeof (syscmd
), SBIN_IFCONFIG
" %s %s %s",
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
));
2735 rcm_log_message(RCM_ERROR
, _("IP: Error: %s: %s\n"),
2736 syscmd
, strerror(errno
));
2744 * Return TRUE if a writeable /etc/hostname[6].ifname file exists.
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)
2755 } else if (af
== AF_INET6
) {
2756 (void) snprintf(cfgfile
, MAXPATHLEN
, CFGFILE_FMT_IPV6
, ifname
);
2757 if (access(cfgfile
, W_OK
|F_OK
) == 0)