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"
63 #define _(x) gettext(x)
68 /* Some generic well-knowns and defaults used in this module */
69 #define ARP_MOD_NAME "arp" /* arp module */
70 #define IP_MAX_MODS 9 /* max modules pushed on intr */
71 #define MAX_RECONFIG_SIZE 1024 /* Max. reconfig string size */
73 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
74 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
76 #define RCM_STR_SUNW_IP "SUNW_ip/" /* IP address export prefix */
78 #define SBIN_IFCONFIG "/sbin/ifconfig" /* ifconfig command */
79 #define SBIN_IFPARSE "/sbin/ifparse" /* ifparse command */
80 #define DHCPFILE_FMT "/etc/dhcp.%s" /* DHCP config file */
81 #define CFGFILE_FMT_IPV4 "/etc/hostname.%s" /* IPV4 config file */
82 #define CFGFILE_FMT_IPV6 "/etc/hostname6.%s" /* IPV6 config file */
83 #define CFG_CMDS_STD " netmask + broadcast + up" /* Normal config string */
84 #define CFG_DHCP_CMD "dhcp wait 0" /* command to start DHCP */
86 /* Some useful macros */
87 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
88 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
89 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
91 /* Interface Cache state flags */
92 #define CACHE_IF_STALE 0x1 /* stale cached data */
93 #define CACHE_IF_NEW 0x2 /* new cached interface */
94 #define CACHE_IF_OFFLINED 0x4 /* interface offlined */
95 #define CACHE_IF_IGNORE 0x8 /* state held elsewhere */
97 /* Network Cache lookup options */
98 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
99 #define CACHE_REFRESH 0x2 /* refresh cache */
101 /* RCM IPMP Module specific property definitions */
102 #define RCM_IPMP_MIN_REDUNDANCY 1 /* default min. redundancy */
104 /* Stream module operations */
105 #define MOD_INSERT 0 /* Insert a mid-stream module */
106 #define MOD_REMOVE 1 /* Remove a mid-stream module */
107 #define MOD_CHECK 2 /* Check mid-stream module safety */
110 * IP module data types
113 /* Physical interface representation */
114 typedef struct ip_pif
{
115 char pi_ifname
[LIFNAMSIZ
]; /* interface name */
116 char pi_grname
[LIFGRNAMSIZ
]; /* IPMP group name */
117 struct ip_lif
*pi_lifs
; /* ptr to logical interfaces */
120 /* Logical interface representation */
121 typedef struct ip_lif
123 struct ip_lif
*li_next
; /* ptr to next lif */
124 struct ip_lif
*li_prev
; /* previous next ptr */
125 ip_pif_t
*li_pif
; /* back ptr to phy int */
126 ushort_t li_ifnum
; /* interface number */
129 struct sockaddr_storage storage
;
130 struct sockaddr_in ip4
; /* IPv4 */
131 struct sockaddr_in6 ip6
; /* IPv6 */
133 uint64_t li_ifflags
; /* current IFF_* flags */
134 int li_modcnt
; /* # of modules */
135 char *li_modules
[IP_MAX_MODS
]; /* module list pushed */
136 char *li_reconfig
; /* Reconfiguration string */
137 int32_t li_cachestate
; /* cache state flags */
141 typedef struct ip_cache
143 struct ip_cache
*ip_next
; /* next cached resource */
144 struct ip_cache
*ip_prev
; /* prev cached resource */
145 char *ip_resource
; /* resource name */
146 ip_pif_t
*ip_pif
; /* ptr to phy int */
147 int32_t ip_ifred
; /* min. redundancy */
148 int ip_cachestate
; /* cache state flags */
152 * Global cache for network interfaces
154 static ip_cache_t cache_head
;
155 static ip_cache_t cache_tail
;
156 static mutex_t cache_lock
;
157 static int events_registered
= 0;
159 static dladm_handle_t dld_handle
= NULL
;
160 static ipadm_handle_t ip_handle
= NULL
;
163 * RCM module interface prototypes
165 static int ip_register(rcm_handle_t
*);
166 static int ip_unregister(rcm_handle_t
*);
167 static int ip_get_info(rcm_handle_t
*, char *, id_t
, uint_t
,
168 char **, char **, nvlist_t
*, rcm_info_t
**);
169 static int ip_suspend(rcm_handle_t
*, char *, id_t
,
170 timespec_t
*, uint_t
, char **, rcm_info_t
**);
171 static int ip_resume(rcm_handle_t
*, char *, id_t
, uint_t
,
172 char **, rcm_info_t
**);
173 static int ip_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
174 char **, rcm_info_t
**);
175 static int ip_undo_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
176 char **, rcm_info_t
**);
177 static int ip_remove(rcm_handle_t
*, char *, id_t
, uint_t
,
178 char **, rcm_info_t
**);
179 static int ip_notify_event(rcm_handle_t
*, char *, id_t
, uint_t
,
180 char **, nvlist_t
*, rcm_info_t
**);
182 /* Module private routines */
183 static void free_cache();
184 static int update_cache(rcm_handle_t
*);
185 static void cache_remove(ip_cache_t
*);
186 static ip_cache_t
*cache_lookup(rcm_handle_t
*, char *, char);
187 static void free_node(ip_cache_t
*);
188 static void cache_insert(ip_cache_t
*);
189 static char *ip_usage(ip_cache_t
*);
190 static int update_pif(rcm_handle_t
*, int, int, struct ifaddrs
*);
191 static int ip_ipmp_offline(ip_cache_t
*);
192 static int ip_ipmp_undo_offline(ip_cache_t
*);
193 static int if_cfginfo(ip_cache_t
*, uint_t
);
194 static int if_unplumb(ip_cache_t
*);
195 static int if_replumb(ip_cache_t
*);
196 static void ip_log_err(ip_cache_t
*, char **, char *);
197 static char *get_link_resource(const char *);
198 static void clr_cfg_state(ip_pif_t
*);
199 static int modop(char *, char *, int, char);
200 static int get_modlist(char *, ip_lif_t
*);
201 static int ip_domux2fd(int *, int *, int *, struct lifreq
*);
202 static int ip_plink(int, int, int, struct lifreq
*);
203 static int ip_onlinelist(rcm_handle_t
*, ip_cache_t
*, char **, uint_t
,
205 static int ip_offlinelist(rcm_handle_t
*, ip_cache_t
*, char **, uint_t
,
207 static char **ip_get_addrlist(ip_cache_t
*);
208 static void ip_free_addrlist(char **);
209 static void ip_consumer_notify(rcm_handle_t
*, datalink_id_t
, char **,
210 uint_t
, rcm_info_t
**);
211 static boolean_t
ip_addrstr(ip_lif_t
*, char *, size_t);
213 static int if_configure_hostname(datalink_id_t
);
214 static int if_configure_ipadm(datalink_id_t
);
215 static boolean_t
if_hostname_exists(char *, sa_family_t
);
216 static boolean_t
isgrouped(const char *);
217 static int if_config_inst(const char *, FILE *, int, boolean_t
);
218 static uint_t
ntok(const char *cp
);
219 static boolean_t
ifconfig(const char *, const char *, const char *, boolean_t
);
221 /* Module-Private data */
222 static struct rcm_mod_ops ip_ops
=
239 * rcm_mod_init() - Update registrations, and return the ops structure.
244 char errmsg
[DLADM_STRSIZE
];
245 dladm_status_t status
;
246 ipadm_status_t iph_status
;
248 rcm_log_message(RCM_TRACE1
, "IP: mod_init\n");
250 cache_head
.ip_next
= &cache_tail
;
251 cache_head
.ip_prev
= NULL
;
252 cache_tail
.ip_prev
= &cache_head
;
253 cache_tail
.ip_next
= NULL
;
254 (void) mutex_init(&cache_lock
, NULL
, NULL
);
256 if ((status
= dladm_open(&dld_handle
)) != DLADM_STATUS_OK
) {
257 rcm_log_message(RCM_WARNING
,
258 "IP: mod_init failed: cannot get datalink handle: %s\n",
259 dladm_status2str(status
, errmsg
));
263 if ((iph_status
= ipadm_open(&ip_handle
, 0)) != IPADM_SUCCESS
) {
264 rcm_log_message(RCM_ERROR
,
265 "IP: mod_init failed: cannot get IP handle: %s\n",
266 ipadm_status2str(iph_status
));
267 dladm_close(dld_handle
);
272 /* Return the ops vectors */
277 * rcm_mod_info() - Return a string describing this module.
282 rcm_log_message(RCM_TRACE1
, "IP: mod_info\n");
284 return ("IP Multipathing module version 1.23");
288 * rcm_mod_fini() - Destroy the network interfaces cache.
293 rcm_log_message(RCM_TRACE1
, "IP: mod_fini\n");
296 (void) mutex_destroy(&cache_lock
);
298 dladm_close(dld_handle
);
299 ipadm_close(ip_handle
);
300 return (RCM_SUCCESS
);
304 * ip_register() - Make sure the cache is properly sync'ed, and its
305 * registrations are in order.
308 ip_register(rcm_handle_t
*hd
)
310 rcm_log_message(RCM_TRACE1
, "IP: register\n");
312 /* Guard against bad arguments */
315 if (update_cache(hd
) < 0)
316 return (RCM_FAILURE
);
319 * Need to register interest in all new resources
320 * getting attached, so we get attach event notifications
322 if (!events_registered
) {
323 if (rcm_register_event(hd
, RCM_RESOURCE_LINK_NEW
, 0, NULL
)
325 rcm_log_message(RCM_ERROR
,
326 _("IP: failed to register %s\n"),
327 RCM_RESOURCE_LINK_NEW
);
328 return (RCM_FAILURE
);
330 rcm_log_message(RCM_DEBUG
, "IP: registered %s\n",
331 RCM_RESOURCE_LINK_NEW
);
336 return (RCM_SUCCESS
);
340 * ip_unregister() - Walk the cache, unregistering all the networks.
343 ip_unregister(rcm_handle_t
*hd
)
347 rcm_log_message(RCM_TRACE1
, "IP: unregister\n");
349 /* Guard against bad arguments */
352 /* Walk the cache, unregistering everything */
353 (void) mutex_lock(&cache_lock
);
354 probe
= cache_head
.ip_next
;
355 while (probe
!= &cache_tail
) {
356 if (rcm_unregister_interest(hd
, probe
->ip_resource
, 0)
358 /* unregister failed for whatever reason */
359 (void) mutex_unlock(&cache_lock
);
360 return (RCM_FAILURE
);
364 probe
= cache_head
.ip_next
;
366 (void) mutex_unlock(&cache_lock
);
369 * Need to unregister interest in all new resources
371 if (events_registered
) {
372 if (rcm_unregister_event(hd
, RCM_RESOURCE_LINK_NEW
, 0)
374 rcm_log_message(RCM_ERROR
,
375 _("IP: failed to unregister %s\n"),
376 RCM_RESOURCE_LINK_NEW
);
377 return (RCM_FAILURE
);
379 rcm_log_message(RCM_DEBUG
, "IP: unregistered %s\n",
380 RCM_RESOURCE_LINK_NEW
);
385 return (RCM_SUCCESS
);
389 * ip_offline() - Offline an interface.
392 ip_offline(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
393 char **errorp
, rcm_info_t
**depend_info
)
397 boolean_t detachable
= B_FALSE
;
401 rcm_log_message(RCM_TRACE1
, "IP: offline(%s)\n", rsrc
);
403 /* Guard against bad arguments */
405 assert(rsrc
!= NULL
);
406 assert(id
== (id_t
)0);
407 assert(errorp
!= NULL
);
408 assert(depend_info
!= NULL
);
410 /* Lock the cache and lookup the resource */
411 (void) mutex_lock(&cache_lock
);
412 node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
);
414 ip_log_err(node
, errorp
, "Unrecognized resource");
416 (void) mutex_unlock(&cache_lock
);
417 return (RCM_SUCCESS
);
422 /* Establish default detachability criteria */
423 if (flags
& RCM_FORCE
)
426 /* Check if the interface is under IPMP */
427 ipmp
= (pif
->pi_grname
[0] != '\0');
430 * Even if the interface is not under IPMP, it's possible that it's
431 * still okay to offline it as long as there are higher-level failover
432 * mechanisms for the addresses it owns (e.g., clustering). In this
433 * case, ip_offlinelist() will return RCM_SUCCESS, and we charge on.
435 if (!ipmp
&& !detachable
) {
436 /* Inform consumers of IP addresses being offlined */
437 if (ip_offlinelist(hd
, node
, errorp
, flags
, depend_info
) ==
439 rcm_log_message(RCM_DEBUG
,
440 "IP: consumers agree on detach");
442 ip_log_err(node
, errorp
,
443 "Device consumers prohibit offline");
444 (void) mutex_unlock(&cache_lock
);
445 return (RCM_FAILURE
);
449 /* Check if it's a query */
450 if (flags
& RCM_QUERY
) {
451 rcm_log_message(RCM_TRACE1
, "IP: offline query success(%s)\n",
453 (void) mutex_unlock(&cache_lock
);
454 return (RCM_SUCCESS
);
457 /* Check detachability, save configuration if detachable */
458 if (if_cfginfo(node
, (flags
& RCM_FORCE
)) < 0) {
459 node
->ip_cachestate
|= CACHE_IF_IGNORE
;
460 rcm_log_message(RCM_TRACE1
, "IP: Ignoring node(%s)\n", rsrc
);
461 (void) mutex_unlock(&cache_lock
);
462 return (RCM_SUCCESS
);
465 /* standalone detachable device */
467 if (if_unplumb(node
) < 0) {
468 ip_log_err(node
, errorp
,
469 "Failed to unplumb the device");
472 (void) mutex_unlock(&cache_lock
);
473 return (RCM_FAILURE
);
476 node
->ip_cachestate
|= CACHE_IF_OFFLINED
;
477 rcm_log_message(RCM_TRACE1
, "IP: Offline success(%s)\n", rsrc
);
478 (void) mutex_unlock(&cache_lock
);
479 return (RCM_SUCCESS
);
483 * This is an IPMP interface that can be offlined.
484 * Request in.mpathd(1M) to offline the physical interface.
486 if ((retval
= ip_ipmp_offline(node
)) != IPMP_SUCCESS
)
487 ip_log_err(node
, errorp
, "in.mpathd offline failed");
489 if (retval
== IPMP_EMINRED
&& !detachable
) {
491 * in.mpathd(1M) could not offline the device because it was
492 * the last interface in the group. However, it's possible
493 * that it's still okay to offline it as long as there are
494 * higher-level failover mechanisms for the addresses it owns
495 * (e.g., clustering). In this case, ip_offlinelist() will
496 * return RCM_SUCCESS, and we charge on.
498 /* Inform consumers of IP addresses being offlined */
499 if (ip_offlinelist(hd
, node
, errorp
, flags
,
500 depend_info
) == RCM_SUCCESS
) {
501 rcm_log_message(RCM_DEBUG
,
502 "IP: consumers agree on detach");
504 ip_log_err(node
, errorp
,
505 "Device consumers prohibit offline");
506 (void) mutex_unlock(&cache_lock
);
508 return (RCM_FAILURE
);
512 if (if_unplumb(node
) < 0) {
513 rcm_log_message(RCM_ERROR
,
514 _("IP: Unplumb failed (%s)\n"),
517 /* Request in.mpathd to undo the offline */
518 if (ip_ipmp_undo_offline(node
) != IPMP_SUCCESS
) {
519 ip_log_err(node
, errorp
, "Undo offline failed");
520 (void) mutex_unlock(&cache_lock
);
521 return (RCM_FAILURE
);
523 (void) mutex_unlock(&cache_lock
);
524 return (RCM_FAILURE
);
527 node
->ip_cachestate
|= CACHE_IF_OFFLINED
;
528 rcm_log_message(RCM_TRACE1
, "IP: offline success(%s)\n", rsrc
);
529 (void) mutex_unlock(&cache_lock
);
530 return (RCM_SUCCESS
);
534 * ip_undo_offline() - Undo offline of a previously offlined device.
538 ip_undo_offline(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
539 char **errorp
, rcm_info_t
**depend_info
)
543 rcm_log_message(RCM_TRACE1
, "IP: online(%s)\n", rsrc
);
545 /* Guard against bad arguments */
547 assert(rsrc
!= NULL
);
548 assert(id
== (id_t
)0);
549 assert(errorp
!= NULL
);
550 assert(depend_info
!= NULL
);
552 (void) mutex_lock(&cache_lock
);
553 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
556 ip_log_err(node
, errorp
, "No such device");
557 (void) mutex_unlock(&cache_lock
);
559 return (RCM_FAILURE
);
562 /* Check if no attempt should be made to online the device here */
563 if (node
->ip_cachestate
& CACHE_IF_IGNORE
) {
564 node
->ip_cachestate
&= ~(CACHE_IF_IGNORE
);
565 (void) mutex_unlock(&cache_lock
);
566 return (RCM_SUCCESS
);
569 /* Check if the interface was previously offlined */
570 if (!(node
->ip_cachestate
& CACHE_IF_OFFLINED
)) {
571 ip_log_err(node
, errorp
, "Device not offlined");
572 (void) mutex_unlock(&cache_lock
);
574 return (RCM_FAILURE
);
577 if (if_replumb(node
) == -1) {
578 /* re-plumb failed */
579 ip_log_err(node
, errorp
, "Replumb failed");
580 (void) mutex_unlock(&cache_lock
);
582 return (RCM_FAILURE
);
586 /* Inform consumers about IP addresses being un-offlined */
587 (void) ip_onlinelist(hd
, node
, errorp
, flags
, depend_info
);
589 node
->ip_cachestate
&= ~(CACHE_IF_OFFLINED
);
590 rcm_log_message(RCM_TRACE1
, "IP: online success(%s)\n", rsrc
);
591 (void) mutex_unlock(&cache_lock
);
592 return (RCM_SUCCESS
);
596 * ip_get_info() - Gather usage information for this resource.
600 ip_get_info(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
601 char **usagep
, char **errorp
, nvlist_t
*props
, rcm_info_t
**depend_info
)
606 /* Guard against bad arguments */
608 assert(rsrc
!= NULL
);
609 assert(id
== (id_t
)0);
610 assert(usagep
!= NULL
);
611 assert(errorp
!= NULL
);
612 assert(depend_info
!= NULL
);
614 rcm_log_message(RCM_TRACE1
, "IP: get_info(%s)\n", rsrc
);
616 (void) mutex_lock(&cache_lock
);
617 node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
);
619 rcm_log_message(RCM_INFO
,
620 _("IP: get_info(%s) unrecognized resource\n"), rsrc
);
621 (void) mutex_unlock(&cache_lock
);
623 return (RCM_FAILURE
);
626 infostr
= ip_usage(node
);
628 if (infostr
== NULL
) {
629 /* most likely malloc failure */
630 rcm_log_message(RCM_ERROR
,
631 _("IP: get_info(%s) malloc failure\n"), rsrc
);
632 (void) mutex_unlock(&cache_lock
);
635 return (RCM_FAILURE
);
638 /* Set client/role properties */
639 (void) nvlist_add_string(props
, RCM_CLIENT_NAME
, "IP");
641 /* Set usage property, infostr will be freed by caller */
644 rcm_log_message(RCM_TRACE1
, "IP: get_info(%s) info = %s \n",
647 (void) mutex_unlock(&cache_lock
);
648 return (RCM_SUCCESS
);
652 * ip_suspend() - Nothing to do, always okay
656 ip_suspend(rcm_handle_t
*hd
, char *rsrc
, id_t id
, timespec_t
*interval
,
657 uint_t flags
, char **errorp
, rcm_info_t
**depend_info
)
659 /* Guard against bad arguments */
661 assert(rsrc
!= NULL
);
662 assert(id
== (id_t
)0);
663 assert(interval
!= NULL
);
664 assert(errorp
!= NULL
);
665 assert(depend_info
!= NULL
);
667 rcm_log_message(RCM_TRACE1
, "IP: suspend(%s)\n", rsrc
);
668 return (RCM_SUCCESS
);
672 * ip_resume() - Nothing to do, always okay
676 ip_resume(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
677 char **errorp
, rcm_info_t
** depend_info
)
679 /* Guard against bad arguments */
681 assert(rsrc
!= NULL
);
682 assert(id
== (id_t
)0);
683 assert(errorp
!= NULL
);
684 assert(depend_info
!= NULL
);
686 rcm_log_message(RCM_TRACE1
, "IP: resume(%s)\n", rsrc
);
688 return (RCM_SUCCESS
);
692 * ip_remove() - remove a resource from cache
696 ip_remove(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
697 char **errorp
, rcm_info_t
**depend_info
)
701 /* Guard against bad arguments */
703 assert(rsrc
!= NULL
);
704 assert(id
== (id_t
)0);
705 assert(errorp
!= NULL
);
706 assert(depend_info
!= NULL
);
708 rcm_log_message(RCM_TRACE1
, "IP: remove(%s)\n", rsrc
);
710 (void) mutex_lock(&cache_lock
);
711 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
713 rcm_log_message(RCM_INFO
,
714 _("IP: remove(%s) unrecognized resource\n"), rsrc
);
715 (void) mutex_unlock(&cache_lock
);
717 return (RCM_FAILURE
);
720 /* remove the cached entry for the resource */
724 (void) mutex_unlock(&cache_lock
);
725 return (RCM_SUCCESS
);
729 * ip_notify_event - Project private implementation to receive new resource
730 * events. It intercepts all new resource events. If the
731 * new resource is a network resource, pass up a notify
732 * for it too. The new resource need not be cached, since
733 * it is done at register again.
737 ip_notify_event(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
738 char **errorp
, nvlist_t
*nvl
, rcm_info_t
**depend_info
)
740 datalink_id_t linkid
;
741 nvpair_t
*nvp
= NULL
;
745 assert(rsrc
!= NULL
);
746 assert(id
== (id_t
)0);
749 rcm_log_message(RCM_TRACE1
, "IP: notify_event(%s)\n", rsrc
);
751 if (!STREQ(rsrc
, RCM_RESOURCE_LINK_NEW
)) {
752 rcm_log_message(RCM_INFO
,
753 _("IP: unrecognized event for %s\n"), rsrc
);
754 ip_log_err(NULL
, errorp
, "unrecognized event");
756 return (RCM_FAILURE
);
759 /* Update cache to reflect latest interfaces */
760 if (update_cache(hd
) < 0) {
761 rcm_log_message(RCM_ERROR
, _("IP: update_cache failed\n"));
762 ip_log_err(NULL
, errorp
, "Private Cache update failed");
763 return (RCM_FAILURE
);
766 rcm_log_message(RCM_TRACE1
, "IP: process_nvlist\n");
767 while ((nvp
= nvlist_next_nvpair(nvl
, nvp
)) != NULL
) {
768 if (STREQ(nvpair_name(nvp
), RCM_NV_LINKID
)) {
769 if (nvpair_value_uint64(nvp
, &id64
) != 0) {
770 rcm_log_message(RCM_WARNING
,
771 _("IP: cannot get linkid\n"));
772 return (RCM_FAILURE
);
774 linkid
= (datalink_id_t
)id64
;
776 * Grovel through /etc/hostname* files and configure
777 * interface in the same way that they would be handled
778 * by network/physical.
780 if (if_configure_hostname(linkid
) != 0) {
781 rcm_log_message(RCM_ERROR
,
782 _("IP: Configuration failed (%u)\n"),
784 ip_log_err(NULL
, errorp
,
785 "Failed configuring one or more IP "
790 * Query libipadm for persistent configuration info
791 * and resurrect that persistent configuration.
793 if (if_configure_ipadm(linkid
) != 0) {
794 rcm_log_message(RCM_ERROR
,
795 _("IP: Configuration failed (%u)\n"),
797 ip_log_err(NULL
, errorp
,
798 "Failed configuring one or more IP "
802 /* Notify all IP address consumers */
803 ip_consumer_notify(hd
, linkid
, errorp
, flags
,
808 rcm_log_message(RCM_TRACE1
,
809 "IP: notify_event: device configuration complete\n");
811 return (RCM_SUCCESS
);
815 * ip_usage - Determine the usage of a device. Call with cache_lock held.
816 * The returned buffer is owned by caller, and the caller
817 * must free it up when done.
820 ip_usage(ip_cache_t
*node
)
824 char *sep
, *buf
, *linkidstr
;
825 datalink_id_t linkid
;
827 char link
[MAXLINKNAMELEN
];
828 char addrstr
[INET6_ADDRSTRLEN
];
829 char errmsg
[DLADM_STRSIZE
];
830 dladm_status_t status
;
831 boolean_t offline
, ipmp
;
834 rcm_log_message(RCM_TRACE2
, "IP: usage(%s)\n", node
->ip_resource
);
837 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid>
839 linkidstr
= strchr(node
->ip_resource
, '/');
840 assert(linkidstr
!= NULL
);
841 linkidstr
= linkidstr
? linkidstr
+ 1 : node
->ip_resource
;
844 linkid
= strtol(linkidstr
, &buf
, 10);
845 if (errno
!= 0 || *buf
!= '\0') {
846 rcm_log_message(RCM_ERROR
,
847 _("IP: usage(%s) parse linkid failure (%s)\n"),
848 node
->ip_resource
, strerror(errno
));
852 if ((status
= dladm_datalink_id2info(dld_handle
, linkid
, NULL
, NULL
,
853 NULL
, link
, sizeof (link
))) != DLADM_STATUS_OK
) {
854 rcm_log_message(RCM_ERROR
,
855 _("IP: usage(%s) get link name failure(%s)\n"),
856 node
->ip_resource
, dladm_status2str(status
, errmsg
));
860 /* TRANSLATION_NOTE: separator used between IP addresses */
864 for (lif
= node
->ip_pif
->pi_lifs
; lif
!= NULL
; lif
= lif
->li_next
)
865 if (lif
->li_ifflags
& IFF_UP
)
868 ipmp
= (node
->ip_pif
->pi_grname
[0] != '\0');
869 offline
= ((node
->ip_cachestate
& CACHE_IF_OFFLINED
) != 0);
873 } else if (numup
== 0) {
874 msg
= _("plumbed but down");
877 msg
= _("providing connectivity for IPMP group ");
878 bufsz
+= LIFGRNAMSIZ
;
880 msg
= _("hosts IP addresses: ");
881 bufsz
+= (numup
* (INET6_ADDRSTRLEN
+ strlen(sep
)));
885 bufsz
+= strlen(link
) + strlen(msg
) + 1;
886 if ((buf
= malloc(bufsz
)) == NULL
) {
887 rcm_log_message(RCM_ERROR
,
888 _("IP: usage(%s) malloc failure(%s)\n"),
889 node
->ip_resource
, strerror(errno
));
892 (void) snprintf(buf
, bufsz
, "%s: %s", link
, msg
);
894 if (!offline
&& numup
> 0) {
896 (void) strlcat(buf
, node
->ip_pif
->pi_grname
, bufsz
);
898 lif
= node
->ip_pif
->pi_lifs
;
899 for (; lif
!= NULL
; lif
= lif
->li_next
) {
900 if (!(lif
->li_ifflags
& IFF_UP
))
903 if (!ip_addrstr(lif
, addrstr
, sizeof (addrstr
)))
906 (void) strlcat(buf
, addrstr
, bufsz
);
908 (void) strlcat(buf
, sep
, bufsz
);
913 rcm_log_message(RCM_TRACE2
, "IP: usage (%s) info = %s\n",
914 node
->ip_resource
, buf
);
920 ip_addrstr(ip_lif_t
*lif
, char *addrstr
, size_t addrsize
)
922 int af
= lif
->li_addr
.family
;
925 if (af
== AF_INET6
) {
926 addr
= &lif
->li_addr
.ip6
.sin6_addr
;
927 } else if (af
== AF_INET
) {
928 addr
= &lif
->li_addr
.ip4
.sin_addr
;
930 rcm_log_message(RCM_DEBUG
,
931 "IP: unknown addr family %d, assuming AF_INET\n", af
);
933 addr
= &lif
->li_addr
.ip4
.sin_addr
;
935 if (inet_ntop(af
, addr
, addrstr
, addrsize
) == NULL
) {
936 rcm_log_message(RCM_ERROR
,
937 _("IP: inet_ntop: %s\n"), strerror(errno
));
941 rcm_log_message(RCM_DEBUG
, "IP addr := %s\n", addrstr
);
946 * Cache management routines, all cache management functions should be
947 * be called with cache_lock held.
951 * cache_lookup() - Get a cache node for a resource.
952 * Call with cache lock held.
954 * This ensures that the cache is consistent with the system state and
955 * returns a pointer to the cache element corresponding to the resource.
958 cache_lookup(rcm_handle_t
*hd
, char *rsrc
, char options
)
962 rcm_log_message(RCM_TRACE2
, "IP: cache lookup(%s)\n", rsrc
);
964 if ((options
& CACHE_REFRESH
) && (hd
!= NULL
)) {
965 /* drop lock since update locks cache again */
966 (void) mutex_unlock(&cache_lock
);
967 (void) update_cache(hd
);
968 (void) mutex_lock(&cache_lock
);
971 probe
= cache_head
.ip_next
;
972 while (probe
!= &cache_tail
) {
973 if (probe
->ip_resource
&&
974 STREQ(rsrc
, probe
->ip_resource
)) {
975 rcm_log_message(RCM_TRACE2
,
976 "IP: cache lookup success(%s)\n", rsrc
);
979 probe
= probe
->ip_next
;
985 * free_node - Free a node from the cache
986 * Call with cache_lock held.
989 free_node(ip_cache_t
*node
)
992 ip_lif_t
*lif
, *tmplif
;
995 if (node
->ip_resource
) {
996 free(node
->ip_resource
);
1002 /* free logical interfaces */
1005 tmplif
= lif
->li_next
;
1016 * cache_insert - Insert a resource node in cache
1017 * Call with the cache_lock held.
1020 cache_insert(ip_cache_t
*node
)
1022 rcm_log_message(RCM_TRACE2
, "IP: cache insert(%s)\n",
1025 /* insert at the head for best performance */
1026 node
->ip_next
= cache_head
.ip_next
;
1027 node
->ip_prev
= &cache_head
;
1029 node
->ip_next
->ip_prev
= node
;
1030 node
->ip_prev
->ip_next
= node
;
1034 * cache_remove() - Remove a resource node from cache.
1035 * Call with the cache_lock held.
1038 cache_remove(ip_cache_t
*node
)
1040 rcm_log_message(RCM_TRACE2
, "IP: cache remove(%s)\n",
1043 node
->ip_next
->ip_prev
= node
->ip_prev
;
1044 node
->ip_prev
->ip_next
= node
->ip_next
;
1045 node
->ip_next
= NULL
;
1046 node
->ip_prev
= NULL
;
1050 * update_pif() - Update physical interface properties
1051 * Call with cache_lock held
1054 update_pif(rcm_handle_t
*hd
, int af
, int sock
, struct ifaddrs
*ifa
)
1058 ushort_t ifnumber
= 0;
1063 struct lifreq lifreq
;
1064 struct sockaddr_storage ifaddr
;
1068 rcm_log_message(RCM_TRACE1
, "IP: update_pif(%s)\n", ifa
->ifa_name
);
1070 if (!ifparse_ifspec(ifa
->ifa_name
, &ifspec
)) {
1071 rcm_log_message(RCM_ERROR
, _("IP: bad network interface: %s\n"),
1076 (void) snprintf(pif
.pi_ifname
, sizeof (pif
.pi_ifname
), "%s%d",
1077 ifspec
.ifsp_devnm
, ifspec
.ifsp_ppa
);
1078 if (ifspec
.ifsp_lunvalid
)
1079 ifnumber
= ifspec
.ifsp_lun
;
1081 /* Get the interface flags */
1082 ifflags
= ifa
->ifa_flags
;
1085 * Ignore interfaces that are always incapable of DR:
1086 * - IFF_VIRTUAL: e.g., loopback and vni
1087 * - IFF_POINTOPOINT: e.g., sppp and ip.tun
1088 * - !IFF_MULTICAST: e.g., ip.6to4tun
1089 * - IFF_IPMP: IPMP meta-interfaces
1091 * Note: The !IFF_MULTICAST check can be removed once iptun is
1092 * implemented as a datalink.
1094 if (!(ifflags
& IFF_MULTICAST
) ||
1095 (ifflags
& (IFF_POINTOPOINT
| IFF_VIRTUAL
| IFF_IPMP
))) {
1096 rcm_log_message(RCM_TRACE3
, "IP: if ignored (%s)\n",
1101 /* Get the interface group name for this interface */
1102 bzero(&lifreq
, sizeof (lifreq
));
1103 (void) strncpy(lifreq
.lifr_name
, ifa
->ifa_name
, LIFNAMSIZ
);
1105 if (ioctl(sock
, SIOCGLIFGROUPNAME
, (char *)&lifreq
) < 0) {
1106 if (errno
!= ENXIO
) {
1107 rcm_log_message(RCM_ERROR
,
1108 _("IP: SIOCGLIFGROUPNAME(%s): %s\n"),
1109 lifreq
.lifr_name
, strerror(errno
));
1114 /* copy the group name */
1115 (void) strlcpy(pif
.pi_grname
, lifreq
.lifr_groupname
,
1116 sizeof (pif
.pi_grname
));
1118 /* Get the interface address for this interface */
1119 (void) memcpy(&ifaddr
, ifa
->ifa_addr
, sizeof (ifaddr
));
1121 rsrc
= get_link_resource(pif
.pi_ifname
);
1123 rcm_log_message(RCM_ERROR
,
1124 _("IP: get_link_resource(%s) failed\n"),
1129 probe
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
1130 if (probe
!= NULL
) {
1132 probe
->ip_cachestate
&= ~(CACHE_IF_STALE
);
1134 if ((probe
= calloc(1, sizeof (ip_cache_t
))) == NULL
) {
1135 /* malloc errors are bad */
1137 rcm_log_message(RCM_ERROR
, _("IP: calloc: %s\n"),
1142 probe
->ip_resource
= rsrc
;
1143 probe
->ip_pif
= NULL
;
1144 probe
->ip_ifred
= RCM_IPMP_MIN_REDUNDANCY
;
1145 probe
->ip_cachestate
|= CACHE_IF_NEW
;
1147 cache_insert(probe
);
1150 probepif
= probe
->ip_pif
;
1151 if (probepif
!= NULL
) {
1152 /* Check if lifs need to be updated */
1153 probelif
= probepif
->pi_lifs
;
1154 while (probelif
!= NULL
) {
1155 if ((probelif
->li_ifnum
== ifnumber
) &&
1156 (probelif
->li_addr
.family
== ifaddr
.ss_family
)) {
1158 rcm_log_message(RCM_TRACE2
,
1159 "IP: refreshing lifs for %s, ifnum=%d\n",
1160 pif
.pi_ifname
, probelif
->li_ifnum
);
1162 /* refresh lif properties */
1163 (void) memcpy(&probelif
->li_addr
, &ifaddr
,
1164 sizeof (probelif
->li_addr
));
1166 probelif
->li_ifflags
= ifflags
;
1169 probelif
->li_cachestate
&= ~(CACHE_IF_STALE
);
1172 probelif
= probelif
->li_next
;
1176 if (probepif
== NULL
) {
1177 if ((probepif
= calloc(1, sizeof (ip_pif_t
))) == NULL
) {
1178 rcm_log_message(RCM_ERROR
, _("IP: malloc: %s\n"),
1180 if (probe
->ip_pif
== NULL
) {
1181 /* we created it, so clean it up */
1187 probe
->ip_pif
= probepif
;
1189 /* Save interface name */
1190 (void) memcpy(&probepif
->pi_ifname
, &pif
.pi_ifname
,
1191 sizeof (pif
.pi_ifname
));
1194 /* save the group name */
1195 (void) strlcpy(probepif
->pi_grname
, pif
.pi_grname
,
1196 sizeof (pif
.pi_grname
));
1198 /* add lif, if this is a lif and it is not in cache */
1200 rcm_log_message(RCM_TRACE2
, "IP: adding lifs to %s\n",
1203 if ((probelif
= calloc(1, sizeof (ip_lif_t
))) == NULL
) {
1204 rcm_log_message(RCM_ERROR
, _("IP: malloc: %s\n"),
1209 /* save lif properties */
1210 (void) memcpy(&probelif
->li_addr
, &ifaddr
,
1211 sizeof (probelif
->li_addr
));
1213 probelif
->li_ifnum
= ifnumber
;
1214 probelif
->li_ifflags
= ifflags
;
1216 /* insert us at the head of the lif list */
1217 probelif
->li_next
= probepif
->pi_lifs
;
1218 if (probelif
->li_next
!= NULL
) {
1219 probelif
->li_next
->li_prev
= probelif
;
1221 probelif
->li_prev
= NULL
;
1222 probelif
->li_pif
= probepif
;
1224 probepif
->pi_lifs
= probelif
;
1227 rcm_log_message(RCM_TRACE3
, "IP: update_pif: (%s) success\n",
1228 probe
->ip_resource
);
1234 * update_ipifs() - Determine all network interfaces in the system
1235 * Call with cache_lock held
1238 update_ipifs(rcm_handle_t
*hd
, int af
)
1241 struct ifaddrs
*ifa
;
1242 ipadm_addr_info_t
*ainfo
;
1243 ipadm_addr_info_t
*ptr
;
1244 ipadm_status_t status
;
1247 if ((sock
= socket(af
, SOCK_DGRAM
, 0)) == -1) {
1248 rcm_log_message(RCM_ERROR
,
1249 _("IP: failure opening %s socket: %s\n"),
1250 af
== AF_INET6
? "IPv6" : "IPv4", strerror(errno
));
1254 status
= ipadm_addr_info(ip_handle
, NULL
, &ainfo
, IPADM_OPT_ZEROADDR
,
1256 if (status
!= IPADM_SUCCESS
) {
1260 for (ptr
= ainfo
; ptr
; ptr
= IA_NEXT(ptr
)) {
1262 if (ptr
->ia_state
!= IFA_DISABLED
&&
1263 af
== ifa
->ifa_addr
->sa_family
)
1264 (void) update_pif(hd
, af
, sock
, ifa
);
1267 ipadm_free_addr_info(ainfo
);
1272 * update_cache() - Update cache with latest interface info
1275 update_cache(rcm_handle_t
*hd
)
1279 struct ip_lif
*nextlif
;
1283 rcm_log_message(RCM_TRACE2
, "IP: update_cache\n");
1285 (void) mutex_lock(&cache_lock
);
1287 /* first we walk the entire cache, marking each entry stale */
1288 probe
= cache_head
.ip_next
;
1289 while (probe
!= &cache_tail
) {
1290 probe
->ip_cachestate
|= CACHE_IF_STALE
;
1291 if ((probe
->ip_pif
!= NULL
) &&
1292 ((lif
= probe
->ip_pif
->pi_lifs
) != NULL
)) {
1293 while (lif
!= NULL
) {
1294 lif
->li_cachestate
|= CACHE_IF_STALE
;
1298 probe
= probe
->ip_next
;
1301 rcm_log_message(RCM_TRACE2
, "IP: scanning IPv4 interfaces\n");
1302 if (update_ipifs(hd
, AF_INET
) < 0) {
1303 (void) mutex_unlock(&cache_lock
);
1307 rcm_log_message(RCM_TRACE2
, "IP: scanning IPv6 interfaces\n");
1308 if (update_ipifs(hd
, AF_INET6
) < 0) {
1309 (void) mutex_unlock(&cache_lock
);
1313 probe
= cache_head
.ip_next
;
1314 /* unregister devices that are not offlined and still in cache */
1315 while (probe
!= &cache_tail
) {
1317 if ((probe
->ip_pif
!= NULL
) &&
1318 ((lif
= probe
->ip_pif
->pi_lifs
) != NULL
)) {
1319 /* clear stale lifs */
1320 while (lif
!= NULL
) {
1321 if (lif
->li_cachestate
& CACHE_IF_STALE
) {
1322 nextlif
= lif
->li_next
;
1323 if (lif
->li_prev
!= NULL
)
1324 lif
->li_prev
->li_next
= nextlif
;
1325 if (nextlif
!= NULL
)
1326 nextlif
->li_prev
= lif
->li_prev
;
1327 if (probe
->ip_pif
->pi_lifs
== lif
)
1328 probe
->ip_pif
->pi_lifs
=
1330 for (i
= 0; i
< IP_MAX_MODS
; i
++) {
1331 free(lif
->li_modules
[i
]);
1333 free(lif
->li_reconfig
);
1341 if ((probe
->ip_cachestate
& CACHE_IF_STALE
) &&
1342 !(probe
->ip_cachestate
& CACHE_IF_OFFLINED
)) {
1343 (void) rcm_unregister_interest(hd
, probe
->ip_resource
,
1345 rcm_log_message(RCM_DEBUG
, "IP: unregistered %s\n",
1346 probe
->ip_resource
);
1348 probe
= probe
->ip_next
;
1349 cache_remove(freeit
);
1354 if (!(probe
->ip_cachestate
& CACHE_IF_NEW
)) {
1355 probe
= probe
->ip_next
;
1359 rv
= rcm_register_interest(hd
, probe
->ip_resource
, 0, NULL
);
1360 if (rv
!= RCM_SUCCESS
) {
1361 rcm_log_message(RCM_ERROR
,
1362 _("IP: failed to register %s\n"),
1363 probe
->ip_resource
);
1364 (void) mutex_unlock(&cache_lock
);
1367 rcm_log_message(RCM_DEBUG
, "IP: registered %s\n",
1368 probe
->ip_resource
);
1369 probe
->ip_cachestate
&= ~(CACHE_IF_NEW
);
1371 probe
= probe
->ip_next
;
1374 (void) mutex_unlock(&cache_lock
);
1379 * free_cache() - Empty the cache
1386 rcm_log_message(RCM_TRACE2
, "IP: free_cache\n");
1388 (void) mutex_lock(&cache_lock
);
1389 probe
= cache_head
.ip_next
;
1390 while (probe
!= &cache_tail
) {
1391 cache_remove(probe
);
1393 probe
= cache_head
.ip_next
;
1395 (void) mutex_unlock(&cache_lock
);
1399 * ip_log_err() - RCM error log wrapper
1402 ip_log_err(ip_cache_t
*node
, char **errorp
, char *errmsg
)
1404 char *ifname
= NULL
;
1409 if ((node
!= NULL
) && (node
->ip_pif
!= NULL
) &&
1410 (node
->ip_pif
->pi_ifname
!= NULL
)) {
1411 ifname
= node
->ip_pif
->pi_ifname
;
1414 if (ifname
== NULL
) {
1415 rcm_log_message(RCM_ERROR
, _("IP: %s\n"), errmsg
);
1416 errfmt
= _("IP: %s");
1417 size
= strlen(errfmt
) + strlen(errmsg
) + 1;
1418 if (errorp
!= NULL
&& (error
= malloc(size
)) != NULL
)
1419 (void) snprintf(error
, size
, errfmt
, errmsg
);
1421 rcm_log_message(RCM_ERROR
, _("IP: %s(%s)\n"), errmsg
, ifname
);
1422 errfmt
= _("IP: %s(%s)");
1423 size
= strlen(errfmt
) + strlen(errmsg
) + strlen(ifname
) + 1;
1424 if (errorp
!= NULL
&& (error
= malloc(size
)) != NULL
)
1425 (void) snprintf(error
, size
, errfmt
, errmsg
, ifname
);
1433 * if_cfginfo() - Save off the config info for all interfaces
1436 if_cfginfo(ip_cache_t
*node
, uint_t force
)
1442 char syscmd
[MAX_RECONFIG_SIZE
+ LIFNAMSIZ
];
1443 char buf
[MAX_RECONFIG_SIZE
];
1445 rcm_log_message(RCM_TRACE2
, "IP: if_cfginfo(%s)\n", node
->ip_resource
);
1450 while (lif
!= NULL
) {
1451 /* Make a list of modules pushed and save */
1452 if (lif
->li_ifnum
== 0) { /* physical instance */
1453 if (get_modlist(pif
->pi_ifname
, lif
) == -1) {
1454 rcm_log_message(RCM_ERROR
,
1455 _("IP: get modlist error (%s) %s\n"),
1456 pif
->pi_ifname
, strerror(errno
));
1462 /* Look if unknown modules have been inserted */
1463 for (i
= (lif
->li_modcnt
- 2); i
> 0; i
--) {
1464 if (modop(pif
->pi_ifname
,
1466 i
, MOD_CHECK
) == -1) {
1467 rcm_log_message(RCM_ERROR
,
1468 _("IP: module %s@%d\n"),
1469 lif
->li_modules
[i
], i
);
1476 /* Last module is the device driver, so ignore that */
1477 for (i
= (lif
->li_modcnt
- 2); i
> 0; i
--) {
1478 rcm_log_message(RCM_TRACE2
,
1479 "IP: modremove Pos = %d, Module = %s \n",
1480 i
, lif
->li_modules
[i
]);
1481 if (modop(pif
->pi_ifname
, lif
->li_modules
[i
],
1482 i
, MOD_REMOVE
) == -1) {
1483 while (i
!= (lif
->li_modcnt
- 2)) {
1484 if (modop(pif
->pi_ifname
,
1486 i
, MOD_INSERT
) == -1) {
1501 _("IP: if_cfginfo(%s): modremove "
1502 "%s failed: %s\n"), pif
->pi_ifname
,
1511 /* Save reconfiguration information */
1512 if (lif
->li_ifflags
& IFF_IPV4
) {
1513 (void) snprintf(syscmd
, sizeof (syscmd
),
1514 "%s %s:%d configinfo\n", SBIN_IFCONFIG
,
1515 pif
->pi_ifname
, lif
->li_ifnum
);
1516 } else if (lif
->li_ifflags
& IFF_IPV6
) {
1517 (void) snprintf(syscmd
, sizeof (syscmd
),
1518 "%s %s:%d inet6 configinfo\n", SBIN_IFCONFIG
,
1519 pif
->pi_ifname
, lif
->li_ifnum
);
1521 rcm_log_message(RCM_TRACE2
, "IP: %s\n", syscmd
);
1523 /* open a pipe to retrieve reconfiguration info */
1524 if ((fp
= popen(syscmd
, "r")) == NULL
) {
1525 rcm_log_message(RCM_ERROR
,
1526 _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1527 pif
->pi_ifname
, lif
->li_ifnum
, strerror(errno
));
1531 bzero(buf
, MAX_RECONFIG_SIZE
);
1533 if (fgets(buf
, MAX_RECONFIG_SIZE
, fp
) == NULL
) {
1534 rcm_log_message(RCM_ERROR
,
1535 _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1536 pif
->pi_ifname
, lif
->li_ifnum
, strerror(errno
));
1543 if ((lif
->li_reconfig
= strdup(buf
)) == NULL
) {
1544 rcm_log_message(RCM_ERROR
,
1545 _("IP: malloc error (%s) %s\n"),
1546 pif
->pi_ifname
, strerror(errno
));
1550 rcm_log_message(RCM_DEBUG
,
1551 "IP: if_cfginfo: reconfig string(%s:%d) = %s\n",
1552 pif
->pi_ifname
, lif
->li_ifnum
, lif
->li_reconfig
);
1561 * if_unplumb() - Unplumb the interface
1562 * Save off the modlist, ifconfig options and unplumb.
1563 * Fail, if an unknown module lives between IP and driver and
1565 * Call with cache_lock held
1568 if_unplumb(ip_cache_t
*node
)
1571 ip_pif_t
*pif
= node
->ip_pif
;
1572 boolean_t ipv4
= B_FALSE
;
1573 boolean_t ipv6
= B_FALSE
;
1575 rcm_log_message(RCM_TRACE2
, "IP: if_unplumb(%s)\n", node
->ip_resource
);
1577 for (lif
= pif
->pi_lifs
; lif
!= NULL
; lif
= lif
->li_next
) {
1578 if (lif
->li_ifflags
& IFF_IPV4
) {
1580 } else if (lif
->li_ifflags
& IFF_IPV6
) {
1584 rcm_log_message(RCM_DEBUG
,
1585 "IP: Unplumb ignored (%s:%d)\n",
1586 pif
->pi_ifname
, lif
->li_ifnum
);
1590 if (ipv4
&& !ifconfig(pif
->pi_ifname
, "inet", "unplumb", B_FALSE
)) {
1591 rcm_log_message(RCM_ERROR
, _("IP: Cannot unplumb (%s) %s\n"),
1592 pif
->pi_ifname
, strerror(errno
));
1596 if (ipv6
&& !ifconfig(pif
->pi_ifname
, "inet6", "unplumb", B_FALSE
)) {
1597 rcm_log_message(RCM_ERROR
, _("IP: Cannot unplumb (%s) %s\n"),
1598 pif
->pi_ifname
, strerror(errno
));
1602 rcm_log_message(RCM_TRACE2
, "IP: if_unplumb(%s) success\n",
1609 * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface
1610 * instances and the logical interfaces in order, restoring
1611 * all ifconfig options
1612 * Call with cache_lock held
1615 if_replumb(ip_cache_t
*node
)
1620 boolean_t success
, ipmp
;
1622 char lifname
[LIFNAMSIZ
];
1623 char buf
[MAX_RECONFIG_SIZE
];
1626 rcm_log_message(RCM_TRACE2
, "IP: if_replumb(%s)\n", node
->ip_resource
);
1629 * Be extra careful about bringing up the interfaces in the
1631 * - First plumb in the physical interface instances
1632 * - modinsert the necessary modules@pos
1633 * - Next, add the logical interfaces being careful about
1634 * the order, (follow the cached interface number li_ifnum order)
1638 ipmp
= (node
->ip_pif
->pi_grname
[0] != '\0');
1641 * Make a first pass to plumb in physical interfaces and get a count
1642 * of the max logical interfaces
1644 for (lif
= pif
->pi_lifs
; lif
!= NULL
; lif
= lif
->li_next
) {
1645 max_lifnum
= MAX(lif
->li_ifnum
, max_lifnum
);
1646 if (lif
->li_ifflags
& IFF_IPV4
) {
1648 } else if (lif
->li_ifflags
& IFF_IPV6
) {
1652 rcm_log_message(RCM_DEBUG
,
1653 "IP: Re-plumb ignored (%s:%d)\n",
1654 pif
->pi_ifname
, lif
->li_ifnum
);
1658 /* ignore logical interface instances */
1659 if (lif
->li_ifnum
!= 0)
1662 if ((lif
->li_ifflags
& IFF_NOFAILOVER
) || !ipmp
) {
1663 success
= ifconfig("", "", lif
->li_reconfig
, B_FALSE
);
1665 (void) snprintf(buf
, sizeof (buf
), "plumb group %s",
1667 success
= ifconfig(pif
->pi_ifname
, fstr
, buf
, B_FALSE
);
1671 rcm_log_message(RCM_ERROR
,
1672 _("IP: Cannot plumb (%s) %s\n"), pif
->pi_ifname
,
1678 * Restart DHCP if necessary.
1680 if ((lif
->li_ifflags
& IFF_DHCPRUNNING
) &&
1681 !ifconfig(pif
->pi_ifname
, fstr
, CFG_DHCP_CMD
, B_FALSE
)) {
1682 rcm_log_message(RCM_ERROR
, _("IP: Cannot start DHCP "
1683 "(%s) %s\n"), pif
->pi_ifname
, strerror(errno
));
1687 rcm_log_message(RCM_TRACE2
,
1688 "IP: if_replumb: Modcnt = %d\n", lif
->li_modcnt
);
1689 /* modinsert modules in order, ignore driver(last) */
1690 for (i
= 0; i
< (lif
->li_modcnt
- 1); i
++) {
1691 rcm_log_message(RCM_TRACE2
,
1692 "IP: modinsert: Pos = %d Mod = %s\n",
1693 i
, lif
->li_modules
[i
]);
1694 if (modop(pif
->pi_ifname
, lif
->li_modules
[i
], i
,
1695 MOD_INSERT
) == -1) {
1696 rcm_log_message(RCM_ERROR
,
1697 _("IP: modinsert error(%s)\n"),
1704 /* Now, add all the logical interfaces in the correct order */
1705 for (i
= 1; i
<= max_lifnum
; i
++) {
1706 (void) snprintf(lifname
, LIFNAMSIZ
, "%s:%d", pif
->pi_ifname
, i
);
1708 /* reset lif through every iteration */
1709 for (lif
= pif
->pi_lifs
; lif
!= NULL
; lif
= lif
->li_next
) {
1711 * Process entries in order. If the interface is
1712 * using IPMP, only process test addresses.
1714 if (lif
->li_ifnum
!= i
||
1715 (ipmp
&& !(lif
->li_ifflags
& IFF_NOFAILOVER
)))
1718 if (!ifconfig("", "", lif
->li_reconfig
, B_FALSE
)) {
1719 rcm_log_message(RCM_ERROR
,
1720 _("IP: Cannot addif (%s) %s\n"), lifname
,
1726 * Restart DHCP if necessary.
1728 if ((lif
->li_ifflags
& IFF_DHCPRUNNING
) &&
1729 !ifconfig(lifname
, fstr
, CFG_DHCP_CMD
, B_FALSE
)) {
1730 rcm_log_message(RCM_ERROR
,
1731 _("IP: Cannot start DHCP (%s) %s\n"),
1732 lifname
, strerror(errno
));
1738 rcm_log_message(RCM_TRACE2
, "IP: if_replumb(%s) success \n",
1745 * clr_cfg_state() - Cleanup after errors in unplumb
1748 clr_cfg_state(ip_pif_t
*pif
)
1755 while (lif
!= NULL
) {
1757 free(lif
->li_reconfig
);
1758 lif
->li_reconfig
= NULL
;
1759 for (i
= 0; i
< IP_MAX_MODS
; i
++) {
1760 free(lif
->li_modules
[i
]);
1761 lif
->li_modules
[i
] = NULL
;
1768 * Attempt to offline ip_cache_t `node'; returns an IPMP error code.
1771 ip_ipmp_offline(ip_cache_t
*node
)
1774 ipmp_handle_t handle
;
1776 rcm_log_message(RCM_TRACE1
, "IP: ip_ipmp_offline\n");
1778 if ((retval
= ipmp_open(&handle
)) != IPMP_SUCCESS
) {
1779 rcm_log_message(RCM_ERROR
,
1780 _("IP: cannot create ipmp handle: %s\n"),
1781 ipmp_errmsg(retval
));
1785 retval
= ipmp_offline(handle
, node
->ip_pif
->pi_ifname
, node
->ip_ifred
);
1786 if (retval
!= IPMP_SUCCESS
) {
1787 rcm_log_message(RCM_ERROR
, _("IP: ipmp_offline error: %s\n"),
1788 ipmp_errmsg(retval
));
1790 rcm_log_message(RCM_TRACE1
, "IP: ipmp_offline success\n");
1798 * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code.
1801 ip_ipmp_undo_offline(ip_cache_t
*node
)
1804 ipmp_handle_t handle
;
1806 rcm_log_message(RCM_TRACE1
, "IP: ip_ipmp_undo_offline\n");
1808 if ((retval
= ipmp_open(&handle
)) != IPMP_SUCCESS
) {
1809 rcm_log_message(RCM_ERROR
,
1810 _("IP: cannot create ipmp handle: %s\n"),
1811 ipmp_errmsg(retval
));
1815 retval
= ipmp_undo_offline(handle
, node
->ip_pif
->pi_ifname
);
1816 if (retval
!= IPMP_SUCCESS
) {
1817 rcm_log_message(RCM_ERROR
,
1818 _("IP: ipmp_undo_offline error: %s\n"),
1819 ipmp_errmsg(retval
));
1821 rcm_log_message(RCM_TRACE1
, "IP: ipmp_undo_offline success\n");
1829 * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a
1830 * dynamically allocated string containing the associated link resource
1831 * name ("SUNW_datalink/<linkid>").
1834 get_link_resource(const char *link
)
1836 char errmsg
[DLADM_STRSIZE
];
1837 datalink_id_t linkid
;
1840 dladm_status_t status
;
1842 status
= dladm_name2info(dld_handle
, link
, &linkid
, &flags
, NULL
, NULL
);
1843 if (status
!= DLADM_STATUS_OK
)
1846 if (!(flags
& DLADM_OPT_ACTIVE
)) {
1847 status
= DLADM_STATUS_FAILED
;
1851 resource
= malloc(RCM_LINK_RESOURCE_MAX
);
1852 if (resource
== NULL
) {
1853 rcm_log_message(RCM_ERROR
, _("IP: malloc error(%s): %s\n"),
1854 strerror(errno
), link
);
1858 (void) snprintf(resource
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
1859 RCM_LINK_PREFIX
, linkid
);
1864 rcm_log_message(RCM_ERROR
,
1865 _("IP: get_link_resource for %s error(%s)\n"),
1866 link
, dladm_status2str(status
, errmsg
));
1871 * modop() - Remove/insert a module
1874 modop(char *name
, char *arg
, int pos
, char op
)
1876 char syscmd
[LIFNAMSIZ
+MAXPATHLEN
]; /* must be big enough */
1878 rcm_log_message(RCM_TRACE1
, "IP: modop(%s)\n", name
);
1880 /* Nothing to do with "ip", "arp" */
1881 if ((arg
== NULL
) || (strcmp(arg
, "") == 0) ||
1882 STREQ(arg
, IP_MOD_NAME
) || STREQ(arg
, ARP_MOD_NAME
)) {
1883 rcm_log_message(RCM_TRACE1
, "IP: modop success\n");
1887 if (op
== MOD_CHECK
) {
1889 * No known good modules (yet) apart from ip and arp
1890 * which are handled above
1895 if (op
== MOD_REMOVE
) {
1896 (void) snprintf(syscmd
, sizeof (syscmd
),
1897 "%s %s modremove %s@%d\n", SBIN_IFCONFIG
, name
, arg
, pos
);
1898 } else if (op
== MOD_INSERT
) {
1899 (void) snprintf(syscmd
, sizeof (syscmd
),
1900 "%s %s modinsert %s@%d\n", SBIN_IFCONFIG
, name
, arg
, pos
);
1902 rcm_log_message(RCM_ERROR
,
1903 _("IP: modop(%s): unknown operation\n"), name
);
1907 rcm_log_message(RCM_TRACE1
, "IP: modop(%s): %s\n", name
, syscmd
);
1908 if (rcm_exec_cmd(syscmd
) == -1) {
1909 rcm_log_message(RCM_ERROR
,
1910 _("IP: modop(%s): %s\n"), name
, strerror(errno
));
1914 rcm_log_message(RCM_TRACE1
, "IP: modop success\n");
1919 * get_modlist() - return a list of pushed mid-stream modules
1920 * Required memory is malloced to construct the list,
1921 * Caller must free this memory list
1922 * Call with cache_lock held
1925 get_modlist(char *name
, ip_lif_t
*lif
)
1933 struct str_list strlist
= { 0 };
1935 rcm_log_message(RCM_TRACE1
, "IP: getmodlist(%s)\n", name
);
1937 (void) strlcpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1938 lifr
.lifr_flags
= lif
->li_ifflags
;
1939 if (ip_domux2fd(&mux_fd
, &muxid_fd
, &fd
, &lifr
) < 0) {
1940 rcm_log_message(RCM_ERROR
, _("IP: ip_domux2fd(%s)\n"), name
);
1944 if ((num_mods
= ioctl(fd
, I_LIST
, NULL
)) < 0) {
1945 rcm_log_message(RCM_ERROR
,
1946 _("IP: get_modlist(%s): I_LIST(%s) \n"),
1947 name
, strerror(errno
));
1951 strlist
.sl_nmods
= num_mods
;
1952 strlist
.sl_modlist
= malloc(sizeof (struct str_mlist
) * num_mods
);
1953 if (strlist
.sl_modlist
== NULL
) {
1954 rcm_log_message(RCM_ERROR
, _("IP: get_modlist(%s): %s\n"),
1955 name
, strerror(errno
));
1959 if (ioctl(fd
, I_LIST
, (caddr_t
)&strlist
) < 0) {
1960 rcm_log_message(RCM_ERROR
,
1961 _("IP: get_modlist(%s): I_LIST error: %s\n"),
1962 name
, strerror(errno
));
1966 for (i
= 0; i
< strlist
.sl_nmods
; i
++) {
1967 lif
->li_modules
[i
] = strdup(strlist
.sl_modlist
[i
].l_name
);
1968 if (lif
->li_modules
[i
] == NULL
) {
1969 rcm_log_message(RCM_ERROR
,
1970 _("IP: get_modlist(%s): %s\n"),
1971 name
, strerror(errno
));
1973 free(lif
->li_modules
[--i
]);
1978 lif
->li_modcnt
= strlist
.sl_nmods
;
1979 free(strlist
.sl_modlist
);
1981 rcm_log_message(RCM_TRACE1
, "IP: getmodlist(%s) success\n", name
);
1982 return (ip_plink(mux_fd
, muxid_fd
, fd
, &lifr
));
1984 free(strlist
.sl_modlist
);
1985 (void) ip_plink(mux_fd
, muxid_fd
, fd
, &lifr
);
1990 * ip_domux2fd() - Helper function for mod*() functions
1991 * Stolen from ifconfig.c
1994 ip_domux2fd(int *mux_fd
, int *muxid_fdp
, int *fd
, struct lifreq
*lifr
)
1999 if (lifr
->lifr_flags
& IFF_IPV6
) {
2000 udp_dev_name
= UDP6_DEV_NAME
;
2002 udp_dev_name
= UDP_DEV_NAME
;
2005 if ((muxid_fd
= open(udp_dev_name
, O_RDWR
)) < 0) {
2006 rcm_log_message(RCM_ERROR
, _("IP: ip_domux2fd: open(%s) %s\n"),
2007 udp_dev_name
, strerror(errno
));
2010 if ((*mux_fd
= open(udp_dev_name
, O_RDWR
)) < 0) {
2011 rcm_log_message(RCM_ERROR
, _("IP: ip_domux2fd: open(%s) %s\n"),
2012 udp_dev_name
, strerror(errno
));
2013 (void) close(muxid_fd
);
2016 if (ioctl(muxid_fd
, SIOCGLIFMUXID
, (caddr_t
)lifr
) < 0) {
2017 rcm_log_message(RCM_ERROR
,
2018 _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"),
2019 udp_dev_name
, strerror(errno
));
2020 (void) close(*mux_fd
);
2021 (void) close(muxid_fd
);
2025 rcm_log_message(RCM_TRACE2
,
2026 "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n",
2027 lifr
->lifr_arp_muxid
, lifr
->lifr_ip_muxid
);
2029 if ((*fd
= ioctl(*mux_fd
, _I_MUXID2FD
, lifr
->lifr_ip_muxid
)) < 0) {
2030 rcm_log_message(RCM_ERROR
,
2031 _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"),
2032 udp_dev_name
, strerror(errno
));
2033 (void) close(*mux_fd
);
2034 (void) close(muxid_fd
);
2037 if (ioctl(*mux_fd
, I_PUNLINK
, lifr
->lifr_ip_muxid
) < 0) {
2038 rcm_log_message(RCM_ERROR
,
2039 _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"),
2040 udp_dev_name
, strerror(errno
));
2041 (void) close(*mux_fd
);
2042 (void) close(muxid_fd
);
2046 /* Note: mux_fd and muxid_fd are closed in ip_plink below */
2047 *muxid_fdp
= muxid_fd
;
2052 * ip_plink() - Helper function for mod*() functions.
2053 * Stolen from ifconfig.c
2056 ip_plink(int mux_fd
, int muxid_fd
, int fd
, struct lifreq
*lifr
)
2060 if ((mux_id
= ioctl(mux_fd
, I_PLINK
, fd
)) < 0) {
2061 rcm_log_message(RCM_ERROR
, _("IP: ip_plink I_PLINK(%s): %s\n"),
2062 UDP_DEV_NAME
, strerror(errno
));
2063 (void) close(mux_fd
);
2064 (void) close(muxid_fd
);
2069 lifr
->lifr_ip_muxid
= mux_id
;
2070 if (ioctl(muxid_fd
, SIOCSLIFMUXID
, (caddr_t
)lifr
) < 0) {
2071 rcm_log_message(RCM_ERROR
,
2072 _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"),
2073 UDP_DEV_NAME
, strerror(errno
));
2074 (void) close(mux_fd
);
2075 (void) close(muxid_fd
);
2080 (void) close(mux_fd
);
2081 (void) close(muxid_fd
);
2089 * Notify online to IP address consumers.
2093 ip_onlinelist(rcm_handle_t
*hd
, ip_cache_t
*node
, char **errorp
, uint_t flags
,
2094 rcm_info_t
**depend_info
)
2097 int ret
= RCM_SUCCESS
;
2099 rcm_log_message(RCM_TRACE2
, "IP: ip_onlinelist\n");
2101 addrlist
= ip_get_addrlist(node
);
2102 if (addrlist
== NULL
|| addrlist
[0] == NULL
) {
2103 rcm_log_message(RCM_TRACE2
, "IP: ip_onlinelist none\n");
2104 ip_free_addrlist(addrlist
);
2108 ret
= rcm_notify_online_list(hd
, addrlist
, 0, depend_info
);
2110 ip_free_addrlist(addrlist
);
2111 rcm_log_message(RCM_TRACE2
, "IP: ip_onlinelist done\n");
2118 * Offline IP address consumers.
2122 ip_offlinelist(rcm_handle_t
*hd
, ip_cache_t
*node
, char **errorp
, uint_t flags
,
2123 rcm_info_t
**depend_info
)
2126 int ret
= RCM_SUCCESS
;
2128 rcm_log_message(RCM_TRACE2
, "IP: ip_offlinelist\n");
2130 addrlist
= ip_get_addrlist(node
);
2131 if (addrlist
== NULL
|| addrlist
[0] == NULL
) {
2132 rcm_log_message(RCM_TRACE2
, "IP: ip_offlinelist none\n");
2133 ip_free_addrlist(addrlist
);
2134 return (RCM_SUCCESS
);
2137 if ((ret
= rcm_request_offline_list(hd
, addrlist
, flags
, depend_info
))
2139 if (ret
== RCM_FAILURE
)
2140 (void) rcm_notify_online_list(hd
, addrlist
, 0, NULL
);
2145 ip_free_addrlist(addrlist
);
2146 rcm_log_message(RCM_TRACE2
, "IP: ip_offlinelist done\n");
2151 * ip_get_addrlist() - Get the list of IP addresses on this interface (node);
2152 * This routine malloc()s required memory for the list.
2153 * Returns the list on success, NULL on failure.
2154 * Call with cache_lock held.
2157 ip_get_addrlist(ip_cache_t
*node
)
2160 char **addrlist
= NULL
;
2162 size_t addrlistsize
;
2163 char addrstr
[INET6_ADDRSTRLEN
];
2165 rcm_log_message(RCM_TRACE2
, "IP: ip_get_addrlist(%s)\n",
2169 for (lif
= node
->ip_pif
->pi_lifs
; lif
!= NULL
; lif
= lif
->li_next
) {
2174 * Allocate space for resource names list; add 1 and use calloc()
2175 * so that the list is NULL-terminated.
2177 if ((addrlist
= calloc(numifs
+ 1, sizeof (char *))) == NULL
) {
2178 rcm_log_message(RCM_ERROR
,
2179 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2180 node
->ip_resource
, strerror(errno
));
2184 for (lif
= node
->ip_pif
->pi_lifs
, i
= 0; lif
!= NULL
;
2185 lif
= lif
->li_next
, i
++) {
2187 if (!ip_addrstr(lif
, addrstr
, sizeof (addrstr
))) {
2188 ip_free_addrlist(addrlist
);
2192 addrlistsize
= strlen(addrstr
) + sizeof (RCM_STR_SUNW_IP
);
2193 if ((addrlist
[i
] = malloc(addrlistsize
)) == NULL
) {
2194 rcm_log_message(RCM_ERROR
,
2195 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2196 node
->ip_resource
, strerror(errno
));
2197 ip_free_addrlist(addrlist
);
2200 (void) snprintf(addrlist
[i
], addrlistsize
, "%s%s",
2201 RCM_STR_SUNW_IP
, addrstr
);
2203 rcm_log_message(RCM_DEBUG
, "Anon Address: %s\n", addrlist
[i
]);
2206 rcm_log_message(RCM_TRACE2
, "IP: get_addrlist (%s) done\n",
2213 ip_free_addrlist(char **addrlist
)
2217 if (addrlist
== NULL
)
2220 for (i
= 0; addrlist
[i
] != NULL
; i
++)
2226 * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
2230 ip_consumer_notify(rcm_handle_t
*hd
, datalink_id_t linkid
, char **errorp
,
2231 uint_t flags
, rcm_info_t
**depend_info
)
2233 char cached_name
[RCM_LINK_RESOURCE_MAX
];
2236 assert(linkid
!= DATALINK_INVALID_LINKID
);
2238 rcm_log_message(RCM_TRACE1
, _("IP: ip_consumer_notify(%u)\n"), linkid
);
2240 /* Check for the interface in the cache */
2241 (void) snprintf(cached_name
, sizeof (cached_name
), "%s/%u",
2242 RCM_LINK_PREFIX
, linkid
);
2244 (void) mutex_lock(&cache_lock
);
2245 if ((node
= cache_lookup(hd
, cached_name
, CACHE_REFRESH
)) == NULL
) {
2246 rcm_log_message(RCM_TRACE1
, _("IP: Skipping interface(%u)\n"),
2248 (void) mutex_unlock(&cache_lock
);
2252 * Inform anonymous consumers about IP addresses being onlined.
2254 (void) ip_onlinelist(hd
, node
, errorp
, flags
, depend_info
);
2256 (void) mutex_unlock(&cache_lock
);
2258 rcm_log_message(RCM_TRACE2
, "IP: ip_consumer_notify success\n");
2262 * Gets the interface name for the given linkid. Returns -1 if there is
2263 * any error. It fills in the interface name in `ifinst' if the interface
2264 * is not already configured. Otherwise, it puts a null string in `ifinst'.
2267 if_configure_get_linkid(datalink_id_t linkid
, char *ifinst
, size_t len
)
2269 char cached_name
[RCM_LINK_RESOURCE_MAX
];
2272 /* Check for the interface in the cache */
2273 (void) snprintf(cached_name
, sizeof (cached_name
), "%s/%u",
2274 RCM_LINK_PREFIX
, linkid
);
2276 /* Check if the interface is new or was not previously offlined */
2277 (void) mutex_lock(&cache_lock
);
2278 if (((node
= cache_lookup(NULL
, cached_name
, CACHE_REFRESH
)) != NULL
) &&
2279 (!(node
->ip_cachestate
& CACHE_IF_OFFLINED
))) {
2280 rcm_log_message(RCM_TRACE1
,
2281 _("IP: Skipping configured interface(%u)\n"), linkid
);
2282 (void) mutex_unlock(&cache_lock
);
2286 (void) mutex_unlock(&cache_lock
);
2288 if (dladm_datalink_id2info(dld_handle
, linkid
, NULL
, NULL
, NULL
, ifinst
,
2289 len
) != DLADM_STATUS_OK
) {
2290 rcm_log_message(RCM_ERROR
,
2291 _("IP: get %u link name failed\n"), linkid
);
2298 * if_configure_hostname() - Configure a physical interface after attach
2299 * based on the information in /etc/hostname.*
2302 if_configure_hostname(datalink_id_t linkid
)
2304 FILE *hostfp
, *host6fp
;
2305 boolean_t ipmp
= B_FALSE
;
2306 char ifinst
[MAXLINKNAMELEN
];
2307 char cfgfile
[MAXPATHLEN
];
2309 assert(linkid
!= DATALINK_INVALID_LINKID
);
2310 rcm_log_message(RCM_TRACE1
, _("IP: if_configure_hostname(%u)\n"),
2313 if (if_configure_get_linkid(linkid
, ifinst
, sizeof (ifinst
)) != 0)
2316 /* Check if the interface is already configured. */
2317 if (ifinst
[0] == '\0')
2321 * Scan the IPv4 and IPv6 hostname files to see if (a) they exist
2322 * and (b) if either one places the interface into an IPMP group.
2324 (void) snprintf(cfgfile
, MAXPATHLEN
, CFGFILE_FMT_IPV4
, ifinst
);
2325 rcm_log_message(RCM_TRACE1
, "IP: Scanning %s\n", cfgfile
);
2326 if ((hostfp
= fopen(cfgfile
, "r")) != NULL
) {
2327 if (isgrouped(cfgfile
))
2331 (void) snprintf(cfgfile
, MAXPATHLEN
, CFGFILE_FMT_IPV6
, ifinst
);
2332 rcm_log_message(RCM_TRACE1
, "IP: Scanning %s\n", cfgfile
);
2333 if ((host6fp
= fopen(cfgfile
, "r")) != NULL
) {
2334 if (!ipmp
&& isgrouped(cfgfile
))
2339 * Configure the interface according to its hostname files.
2341 if (hostfp
!= NULL
&&
2342 if_config_inst(ifinst
, hostfp
, AF_INET
, ipmp
) == -1) {
2343 rcm_log_message(RCM_ERROR
,
2344 _("IP: IPv4 Post-attach failed (%s)\n"), ifinst
);
2348 if (host6fp
!= NULL
&&
2349 if_config_inst(ifinst
, host6fp
, AF_INET6
, ipmp
) == -1) {
2350 rcm_log_message(RCM_ERROR
,
2351 _("IP: IPv6 Post-attach failed (%s)\n"), ifinst
);
2355 (void) fclose(hostfp
);
2356 (void) fclose(host6fp
);
2357 rcm_log_message(RCM_TRACE1
, "IP: if_configure_hostname(%s) success\n",
2361 (void) fclose(hostfp
);
2362 (void) fclose(host6fp
);
2367 * if_configure_ipadm() - Configure a physical interface after attach
2368 * Queries libipadm for persistent configuration information and then
2369 * resurrects that persistent configuration.
2372 if_configure_ipadm(datalink_id_t linkid
)
2374 char ifinst
[MAXLINKNAMELEN
];
2376 ipadm_if_info_t
*ifinfo
, *ptr
;
2377 ipadm_status_t status
;
2379 assert(linkid
!= DATALINK_INVALID_LINKID
);
2380 rcm_log_message(RCM_TRACE1
, _("IP: if_configure_ipadm(%u)\n"),
2383 if (if_configure_get_linkid(linkid
, ifinst
, sizeof (ifinst
)) != 0)
2386 /* Check if the interface is already configured. */
2387 if (ifinst
[0] == '\0')
2390 status
= ipadm_if_info(ip_handle
, ifinst
, &ifinfo
, 0, LIFC_UNDER_IPMP
);
2391 if (status
== IPADM_ENXIO
)
2393 if (status
!= IPADM_SUCCESS
) {
2394 rcm_log_message(RCM_ERROR
,
2395 _("IP: IPv4 Post-attach failed (%s) Error %s\n"),
2396 ifinst
, ipadm_status2str(status
));
2399 if (ifinfo
!= NULL
) {
2401 for (ptr
= ifinfo
; ptr
; ptr
= ptr
->ifi_next
) {
2402 if (strncmp(ptr
->ifi_name
, ifinst
,
2403 sizeof (ifinst
)) == 0) {
2412 if (if_hostname_exists(ifinst
, AF_INET
) ||
2413 if_hostname_exists(ifinst
, AF_INET6
)) {
2414 rcm_log_message(RCM_WARNING
,
2415 _("IP: IPv4 Post-attach (%s) found both "
2416 "/etc/hostname and ipadm persistent configuration. "
2417 "Ignoring ipadm config\n"), ifinst
);
2420 status
= ipadm_enable_if(ip_handle
, ifinst
, IPADM_OPT_ACTIVE
);
2421 if (status
!= IPADM_SUCCESS
) {
2422 rcm_log_message(RCM_ERROR
,
2423 _("IP: Post-attach failed (%s) Error %s\n"),
2424 ifinst
, ipadm_status2str(status
));
2429 rcm_log_message(RCM_TRACE1
, "IP: if_configure_ipadm(%s) success\n",
2437 * isgrouped() - Scans the given config file to see if this interface is
2438 * using IPMP. Returns B_TRUE or B_FALSE.
2441 isgrouped(const char *cfgfile
)
2445 char *nlp
, *line
, *token
, *lasts
, *buf
;
2446 boolean_t grouped
= B_FALSE
;
2448 rcm_log_message(RCM_TRACE1
, "IP: isgrouped(%s)\n", cfgfile
);
2450 if (stat(cfgfile
, &statb
) != 0) {
2451 rcm_log_message(RCM_TRACE1
,
2452 _("IP: No config file(%s)\n"), cfgfile
);
2457 * We also ignore single-byte config files because the file should
2458 * always be newline-terminated, so we know there's nothing of
2459 * interest. Further, a single-byte file would cause the fgets() loop
2460 * below to spin forever.
2462 if (statb
.st_size
<= 1) {
2463 rcm_log_message(RCM_TRACE1
,
2464 _("IP: Empty config file(%s)\n"), cfgfile
);
2468 if ((fp
= fopen(cfgfile
, "r")) == NULL
) {
2469 rcm_log_message(RCM_ERROR
,
2470 _("IP: Cannot open configuration file(%s): %s\n"), cfgfile
,
2475 if ((buf
= malloc(statb
.st_size
)) == NULL
) {
2476 rcm_log_message(RCM_ERROR
,
2477 _("IP: malloc failure(%s): %s\n"), cfgfile
,
2482 while (fgets(buf
, statb
.st_size
, fp
) != NULL
) {
2483 if ((nlp
= strrchr(buf
, '\n')) != NULL
)
2487 while ((token
= strtok_r(line
, " \t", &lasts
)) != NULL
) {
2489 if (STREQ("group", token
) &&
2490 strtok_r(NULL
, " \t", &lasts
) != NULL
) {
2500 rcm_log_message(RCM_TRACE1
, "IP: isgrouped(%s): %d\n", cfgfile
,
2507 * if_config_inst() - Configure an interface instance as specified by the
2508 * address family af and if it is grouped (ipmp).
2511 if_config_inst(const char *ifinst
, FILE *hfp
, int af
, boolean_t ipmp
)
2516 char *ifparsebuf
= NULL
;
2517 uint_t ifparsebufsize
;
2518 const char *fstr
; /* address family string */
2519 boolean_t stdif
= B_FALSE
;
2521 rcm_log_message(RCM_TRACE1
, "IP: if_config_inst(%s) ipmp = %d\n",
2524 if (fstat(fileno(hfp
), &statb
) != 0) {
2525 rcm_log_message(RCM_ERROR
,
2526 _("IP: Cannot fstat file(%s)\n"), ifinst
);
2542 * The hostname file exists; plumb the physical interface.
2544 if (!ifconfig(ifinst
, fstr
, "plumb", B_FALSE
))
2547 /* Skip static configuration if the hostname file is empty */
2548 if (statb
.st_size
<= 1) {
2549 rcm_log_message(RCM_TRACE1
,
2550 _("IP: Zero size hostname file(%s)\n"), ifinst
);
2554 if (fseek(hfp
, 0, SEEK_SET
) == -1) {
2555 rcm_log_message(RCM_ERROR
,
2556 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst
,
2562 * Allocate the worst-case single-line buffer sizes. A bit skanky,
2563 * but since hostname files are small, this should suffice.
2565 if ((buf
= calloc(1, statb
.st_size
)) == NULL
) {
2566 rcm_log_message(RCM_ERROR
,
2567 _("IP: calloc(%s): %s\n"), ifinst
, strerror(errno
));
2571 ifparsebufsize
= statb
.st_size
+ sizeof (SBIN_IFPARSE
" -s inet6 ");
2572 if ((ifparsebuf
= calloc(1, ifparsebufsize
)) == NULL
) {
2573 rcm_log_message(RCM_ERROR
,
2574 _("IP: calloc(%s): %s\n"), ifinst
, strerror(errno
));
2579 * For IPv4, determine whether the hostname file consists of a single
2580 * line. We need to handle these specially since they should
2581 * automatically be suffixed with "netmask + broadcast + up".
2583 if (af
== AF_INET
&&
2584 fgets(buf
, statb
.st_size
, hfp
) != NULL
&&
2585 fgets(buf
, statb
.st_size
, hfp
) == NULL
) {
2586 rcm_log_message(RCM_TRACE1
, "IP: one-line hostname file\n");
2590 if (fseek(hfp
, 0L, SEEK_SET
) == -1) {
2591 rcm_log_message(RCM_ERROR
,
2592 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst
,
2598 * Loop through the file one line at a time and feed it to ifconfig.
2599 * If the interface is using IPMP, then we use /sbin/ifparse -s to
2600 * weed out all of the data addresses, since those are already on the
2601 * IPMP meta-interface.
2603 while (fgets(buf
, statb
.st_size
, hfp
) != NULL
) {
2608 (void) ifconfig(ifinst
, fstr
, buf
, stdif
);
2612 (void) snprintf(ifparsebuf
, ifparsebufsize
, SBIN_IFPARSE
2613 " -s %s %s", fstr
, buf
);
2614 if ((ifparsefp
= popen(ifparsebuf
, "r")) == NULL
) {
2615 rcm_log_message(RCM_ERROR
,
2616 _("IP: cannot configure %s: popen \"%s\" "
2617 "failed: %s\n"), ifinst
, buf
, strerror(errno
));
2621 while (fgets(buf
, statb
.st_size
, ifparsefp
) != NULL
) {
2623 (void) ifconfig(ifinst
, fstr
, buf
, stdif
);
2626 if (pclose(ifparsefp
) == -1) {
2627 rcm_log_message(RCM_ERROR
,
2628 _("IP: cannot configure %s: pclose \"%s\" "
2629 "failed: %s\n"), ifinst
, buf
, strerror(errno
));
2636 * Bring up the interface (it may already be up)
2638 * Technically, since the boot scripts only unconditionally bring up
2639 * IPv6 interfaces, we should only unconditionally bring up IPv6 here.
2640 * However, if we don't bring up IPv4, and a legacy IPMP configuration
2641 * without test addresses is being used, we will never bring the
2642 * interface up even though we would've at boot. One fix is to check
2643 * if the IPv4 hostname file contains data addresses that we would've
2644 * brought up, but there's no simple way to do that. Given that it's
2645 * rare to have persistent IP configuration for an interface that
2646 * leaves it down, we cheap out and always bring it up for IPMP.
2648 if ((af
== AF_INET6
|| ipmp
) && !ifconfig(ifinst
, fstr
, "up", B_FALSE
))
2652 * For IPv4, if a DHCP configuration file exists, have DHCP configure
2653 * the interface. As with the boot scripts, this is done after the
2654 * hostname files are processed so that configuration in those files
2655 * (such as IPMP group names) will be applied first.
2657 if (af
== AF_INET
) {
2658 char dhcpfile
[MAXPATHLEN
];
2662 (void) snprintf(dhcpfile
, MAXPATHLEN
, DHCPFILE_FMT
, ifinst
);
2663 if (stat(dhcpfile
, &statb
) == -1)
2666 if ((dhcpbuf
= copylist(dhcpfile
, &dhcpsize
)) == NULL
) {
2667 rcm_log_message(RCM_ERROR
, _("IP: cannot read "
2668 "(%s): %s\n"), dhcpfile
, strerror(errno
));
2673 * The copylist() API converts \n's to \0's, but we want them
2677 for (i
= 0; i
< dhcpsize
; i
++)
2678 if (dhcpbuf
[i
] == '\0')
2680 dhcpbuf
[dhcpsize
- 1] = '\0';
2682 (void) ifconfig(ifinst
, CFG_DHCP_CMD
, dhcpbuf
, B_FALSE
);
2688 rcm_log_message(RCM_TRACE1
, "IP: if_config_inst(%s) success\n", ifinst
);
2693 rcm_log_message(RCM_ERROR
, "IP: if_config_inst(%s) failure\n", ifinst
);
2698 * ntok() - count the number of tokens in the provided buffer.
2701 ntok(const char *cp
)
2706 while (ISSPACE(*cp
))
2714 } while (!ISSPACE(*cp
) && !ISEOL(*cp
));
2722 ifconfig(const char *ifinst
, const char *fstr
, const char *buf
, boolean_t stdif
)
2724 char syscmd
[MAX_RECONFIG_SIZE
+ MAXPATHLEN
+ 1];
2727 (void) snprintf(syscmd
, sizeof (syscmd
), SBIN_IFCONFIG
" %s %s %s",
2731 (void) strlcat(syscmd
, CFG_CMDS_STD
, sizeof (syscmd
));
2733 rcm_log_message(RCM_TRACE1
, "IP: Exec: %s\n", syscmd
);
2734 if ((status
= rcm_exec_cmd(syscmd
)) != 0) {
2735 if (WIFEXITED(status
)) {
2736 rcm_log_message(RCM_ERROR
, _("IP: \"%s\" failed with "
2737 "exit status %d\n"), syscmd
, WEXITSTATUS(status
));
2739 rcm_log_message(RCM_ERROR
, _("IP: Error: %s: %s\n"),
2740 syscmd
, strerror(errno
));
2748 * Return TRUE if a writeable /etc/hostname[6].ifname file exists.
2751 if_hostname_exists(char *ifname
, sa_family_t af
)
2753 char cfgfile
[MAXPATHLEN
];
2755 if (af
== AF_INET
) {
2756 (void) snprintf(cfgfile
, MAXPATHLEN
, CFGFILE_FMT_IPV4
, ifname
);
2757 if (access(cfgfile
, W_OK
|F_OK
) == 0)
2759 } else if (af
== AF_INET6
) {
2760 (void) snprintf(cfgfile
, MAXPATHLEN
, CFGFILE_FMT_IPV6
, ifname
);
2761 if (access(cfgfile
, W_OK
|F_OK
) == 0)