xref: /titanic_41/usr/src/cmd/rcm_daemon/common/ip_rcm.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * This RCM module adds support to the RCM framework for IP managed
27  * interfaces.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <assert.h>
34 #include <string.h>
35 #include <synch.h>
36 #include <libintl.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <sys/types.h>
40 #include <sys/wait.h>
41 #include <sys/stat.h>
42 #include <sys/socket.h>
43 #include <sys/sockio.h>
44 #include <net/if.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <stropts.h>
48 #include <strings.h>
49 #include <sys/sysmacros.h>
50 #include <inet/ip.h>
51 #include <libinetutil.h>
52 #include <libdllink.h>
53 #include <libgen.h>
54 #include <ipmp_admin.h>
55 #include <libipadm.h>
56 
57 #include "rcm_module.h"
58 
59 /*
60  * Definitions
61  */
62 #ifndef lint
63 #define	_(x)	gettext(x)
64 #else
65 #define	_(x)	x
66 #endif
67 
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 */
72 
73 #define	RCM_LINK_PREFIX		"SUNW_datalink"	/* RCM datalink name prefix */
74 #define	RCM_LINK_RESOURCE_MAX	(13 + LINKID_STR_WIDTH)
75 
76 #define	RCM_STR_SUNW_IP		"SUNW_ip/"	/* IP address export prefix */
77 
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 */
85 
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)
90 
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 */
96 
97 /* Network Cache lookup options */
98 #define	CACHE_NO_REFRESH	0x1		/* cache refresh not needed */
99 #define	CACHE_REFRESH		0x2		/* refresh cache */
100 
101 /* RCM IPMP Module specific property definitions */
102 #define	RCM_IPMP_MIN_REDUNDANCY	1		/* default min. redundancy */
103 
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 */
108 
109 /*
110  * IP module data types
111  */
112 
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 */
118 } ip_pif_t;
119 
120 /* Logical interface representation */
121 typedef struct ip_lif
122 {
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 */
127 	union {
128 		sa_family_t		family;
129 		struct sockaddr_storage storage;
130 		struct sockaddr_in	ip4;    /* IPv4 */
131 		struct sockaddr_in6	ip6;    /* IPv6 */
132 	} li_addr;
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 */
138 } ip_lif_t;
139 
140 /* Cache element */
141 typedef struct ip_cache
142 {
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 */
149 } ip_cache_t;
150 
151 /*
152  * Global cache for network interfaces
153  */
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;
158 
159 static dladm_handle_t	dld_handle = NULL;
160 static ipadm_handle_t	ip_handle = NULL;
161 
162 /*
163  * RCM module interface prototypes
164  */
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 **);
181 
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,
204 			rcm_info_t **);
205 static int	ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
206 			rcm_info_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);
212 
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);
220 
221 /* Module-Private data */
222 static struct rcm_mod_ops ip_ops =
223 {
224 	RCM_MOD_OPS_VERSION,
225 	ip_register,
226 	ip_unregister,
227 	ip_get_info,
228 	ip_suspend,
229 	ip_resume,
230 	ip_offline,
231 	ip_undo_offline,
232 	ip_remove,
233 	NULL,
234 	NULL,
235 	ip_notify_event
236 };
237 
238 /*
239  * rcm_mod_init() - Update registrations, and return the ops structure.
240  */
241 struct rcm_mod_ops *
rcm_mod_init(void)242 rcm_mod_init(void)
243 {
244 	char errmsg[DLADM_STRSIZE];
245 	dladm_status_t status;
246 	ipadm_status_t iph_status;
247 
248 	rcm_log_message(RCM_TRACE1, "IP: mod_init\n");
249 
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);
255 
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));
260 		return (NULL);
261 	}
262 
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);
268 		dld_handle = NULL;
269 		return (NULL);
270 	}
271 
272 	/* Return the ops vectors */
273 	return (&ip_ops);
274 }
275 
276 /*
277  * rcm_mod_info() - Return a string describing this module.
278  */
279 const char *
rcm_mod_info(void)280 rcm_mod_info(void)
281 {
282 	rcm_log_message(RCM_TRACE1, "IP: mod_info\n");
283 
284 	return ("IP Multipathing module version 1.23");
285 }
286 
287 /*
288  * rcm_mod_fini() - Destroy the network interfaces cache.
289  */
290 int
rcm_mod_fini(void)291 rcm_mod_fini(void)
292 {
293 	rcm_log_message(RCM_TRACE1, "IP: mod_fini\n");
294 
295 	free_cache();
296 	(void) mutex_destroy(&cache_lock);
297 
298 	dladm_close(dld_handle);
299 	ipadm_close(ip_handle);
300 	return (RCM_SUCCESS);
301 }
302 
303 /*
304  * ip_register() - Make sure the cache is properly sync'ed, and its
305  *		 registrations are in order.
306  */
307 static int
ip_register(rcm_handle_t * hd)308 ip_register(rcm_handle_t *hd)
309 {
310 	rcm_log_message(RCM_TRACE1, "IP: register\n");
311 
312 	/* Guard against bad arguments */
313 	assert(hd != NULL);
314 
315 	if (update_cache(hd) < 0)
316 		return (RCM_FAILURE);
317 
318 	/*
319 	 * Need to register interest in all new resources
320 	 * getting attached, so we get attach event notifications
321 	 */
322 	if (!events_registered) {
323 		if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
324 		    != RCM_SUCCESS) {
325 			rcm_log_message(RCM_ERROR,
326 			    _("IP: failed to register %s\n"),
327 			    RCM_RESOURCE_LINK_NEW);
328 			return (RCM_FAILURE);
329 		} else {
330 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
331 			    RCM_RESOURCE_LINK_NEW);
332 			events_registered++;
333 		}
334 	}
335 
336 	return (RCM_SUCCESS);
337 }
338 
339 /*
340  * ip_unregister() - Walk the cache, unregistering all the networks.
341  */
342 static int
ip_unregister(rcm_handle_t * hd)343 ip_unregister(rcm_handle_t *hd)
344 {
345 	ip_cache_t *probe;
346 
347 	rcm_log_message(RCM_TRACE1, "IP: unregister\n");
348 
349 	/* Guard against bad arguments */
350 	assert(hd != NULL);
351 
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)
357 		    != RCM_SUCCESS) {
358 			/* unregister failed for whatever reason */
359 			(void) mutex_unlock(&cache_lock);
360 			return (RCM_FAILURE);
361 		}
362 		cache_remove(probe);
363 		free_node(probe);
364 		probe = cache_head.ip_next;
365 	}
366 	(void) mutex_unlock(&cache_lock);
367 
368 	/*
369 	 * Need to unregister interest in all new resources
370 	 */
371 	if (events_registered) {
372 		if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
373 		    != RCM_SUCCESS) {
374 			rcm_log_message(RCM_ERROR,
375 			    _("IP: failed to unregister %s\n"),
376 			    RCM_RESOURCE_LINK_NEW);
377 			return (RCM_FAILURE);
378 		} else {
379 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
380 			    RCM_RESOURCE_LINK_NEW);
381 			events_registered--;
382 		}
383 	}
384 
385 	return (RCM_SUCCESS);
386 }
387 
388 /*
389  * ip_offline() - Offline an interface.
390  */
391 static int
ip_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)392 ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
393     char **errorp, rcm_info_t **depend_info)
394 {
395 	ip_cache_t *node;
396 	ip_pif_t *pif;
397 	boolean_t detachable = B_FALSE;
398 	boolean_t ipmp;
399 	int retval;
400 
401 	rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc);
402 
403 	/* Guard against bad arguments */
404 	assert(hd != NULL);
405 	assert(rsrc != NULL);
406 	assert(id == (id_t)0);
407 	assert(errorp != NULL);
408 	assert(depend_info != NULL);
409 
410 	/* Lock the cache and lookup the resource */
411 	(void) mutex_lock(&cache_lock);
412 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
413 	if (node == NULL) {
414 		ip_log_err(node, errorp, "Unrecognized resource");
415 		errno = ENOENT;
416 		(void) mutex_unlock(&cache_lock);
417 		return (RCM_SUCCESS);
418 	}
419 
420 	pif = node->ip_pif;
421 
422 	/* Establish default detachability criteria */
423 	if (flags & RCM_FORCE)
424 		detachable = B_TRUE;
425 
426 	/* Check if the interface is under IPMP */
427 	ipmp = (pif->pi_grname[0] != '\0');
428 
429 	/*
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.
434 	 */
435 	if (!ipmp && !detachable) {
436 		/* Inform consumers of IP addresses being offlined */
437 		if (ip_offlinelist(hd, node, errorp, flags, depend_info) ==
438 		    RCM_SUCCESS) {
439 			rcm_log_message(RCM_DEBUG,
440 			    "IP: consumers agree on detach");
441 		} else {
442 			ip_log_err(node, errorp,
443 			    "Device consumers prohibit offline");
444 			(void) mutex_unlock(&cache_lock);
445 			return (RCM_FAILURE);
446 		}
447 	}
448 
449 	/* Check if it's a query */
450 	if (flags & RCM_QUERY) {
451 		rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n",
452 		    rsrc);
453 		(void) mutex_unlock(&cache_lock);
454 		return (RCM_SUCCESS);
455 	}
456 
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);
463 	}
464 
465 	/* standalone detachable device */
466 	if (!ipmp) {
467 		if (if_unplumb(node) < 0) {
468 			ip_log_err(node, errorp,
469 			    "Failed to unplumb the device");
470 
471 			errno = EIO;
472 			(void) mutex_unlock(&cache_lock);
473 			return (RCM_FAILURE);
474 		}
475 
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);
480 	}
481 
482 	/*
483 	 * This is an IPMP interface that can be offlined.
484 	 * Request in.mpathd(1M) to offline the physical interface.
485 	 */
486 	if ((retval = ip_ipmp_offline(node)) != IPMP_SUCCESS)
487 		ip_log_err(node, errorp, "in.mpathd offline failed");
488 
489 	if (retval == IPMP_EMINRED && !detachable) {
490 		/*
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.
497 		 */
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");
503 		} else {
504 			ip_log_err(node, errorp,
505 			    "Device consumers prohibit offline");
506 			(void) mutex_unlock(&cache_lock);
507 			errno = EBUSY;
508 			return (RCM_FAILURE);
509 		}
510 	}
511 
512 	if (if_unplumb(node) < 0) {
513 		rcm_log_message(RCM_ERROR,
514 		    _("IP: Unplumb failed (%s)\n"),
515 		    pif->pi_ifname);
516 
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);
522 		}
523 		(void) mutex_unlock(&cache_lock);
524 		return (RCM_FAILURE);
525 	}
526 
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);
531 }
532 
533 /*
534  * ip_undo_offline() - Undo offline of a previously offlined device.
535  */
536 /*ARGSUSED*/
537 static int
ip_undo_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)538 ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
539     char **errorp, rcm_info_t **depend_info)
540 {
541 	ip_cache_t *node;
542 
543 	rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc);
544 
545 	/* Guard against bad arguments */
546 	assert(hd != NULL);
547 	assert(rsrc != NULL);
548 	assert(id == (id_t)0);
549 	assert(errorp != NULL);
550 	assert(depend_info != NULL);
551 
552 	(void) mutex_lock(&cache_lock);
553 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
554 
555 	if (node == NULL) {
556 		ip_log_err(node, errorp, "No such device");
557 		(void) mutex_unlock(&cache_lock);
558 		errno = ENOENT;
559 		return (RCM_FAILURE);
560 	}
561 
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);
567 	}
568 
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);
573 		errno = ENOTSUP;
574 		return (RCM_FAILURE);
575 	}
576 
577 	if (if_replumb(node) == -1) {
578 		/* re-plumb failed */
579 		ip_log_err(node, errorp, "Replumb failed");
580 		(void) mutex_unlock(&cache_lock);
581 		errno = EIO;
582 		return (RCM_FAILURE);
583 
584 	}
585 
586 	/* Inform consumers about IP addresses being un-offlined */
587 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
588 
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);
593 }
594 
595 /*
596  * ip_get_info() - Gather usage information for this resource.
597  */
598 /*ARGSUSED*/
599 int
ip_get_info(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** usagep,char ** errorp,nvlist_t * props,rcm_info_t ** depend_info)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)
602 {
603 	ip_cache_t *node;
604 	char *infostr;
605 
606 	/* Guard against bad arguments */
607 	assert(hd != NULL);
608 	assert(rsrc != NULL);
609 	assert(id == (id_t)0);
610 	assert(usagep != NULL);
611 	assert(errorp != NULL);
612 	assert(depend_info != NULL);
613 
614 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc);
615 
616 	(void) mutex_lock(&cache_lock);
617 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
618 	if (!node) {
619 		rcm_log_message(RCM_INFO,
620 		    _("IP: get_info(%s) unrecognized resource\n"), rsrc);
621 		(void) mutex_unlock(&cache_lock);
622 		errno = ENOENT;
623 		return (RCM_FAILURE);
624 	}
625 
626 	infostr = ip_usage(node);
627 
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);
633 		errno = ENOMEM;
634 		*errorp = NULL;
635 		return (RCM_FAILURE);
636 	}
637 
638 	/* Set client/role properties */
639 	(void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP");
640 
641 	/* Set usage property, infostr will be freed by caller */
642 	*usagep = infostr;
643 
644 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n",
645 	    rsrc, infostr);
646 
647 	(void) mutex_unlock(&cache_lock);
648 	return (RCM_SUCCESS);
649 }
650 
651 /*
652  * ip_suspend() - Nothing to do, always okay
653  */
654 /*ARGSUSED*/
655 static int
ip_suspend(rcm_handle_t * hd,char * rsrc,id_t id,timespec_t * interval,uint_t flags,char ** errorp,rcm_info_t ** depend_info)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)
658 {
659 	/* Guard against bad arguments */
660 	assert(hd != NULL);
661 	assert(rsrc != NULL);
662 	assert(id == (id_t)0);
663 	assert(interval != NULL);
664 	assert(errorp != NULL);
665 	assert(depend_info != NULL);
666 
667 	rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc);
668 	return (RCM_SUCCESS);
669 }
670 
671 /*
672  * ip_resume() - Nothing to do, always okay
673  */
674 /*ARGSUSED*/
675 static int
ip_resume(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)676 ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
677 		char **errorp, rcm_info_t ** depend_info)
678 {
679 	/* Guard against bad arguments */
680 	assert(hd != NULL);
681 	assert(rsrc != NULL);
682 	assert(id == (id_t)0);
683 	assert(errorp != NULL);
684 	assert(depend_info != NULL);
685 
686 	rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc);
687 
688 	return (RCM_SUCCESS);
689 }
690 
691 /*
692  * ip_remove() - remove a resource from cache
693  */
694 /*ARGSUSED*/
695 static int
ip_remove(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)696 ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
697 		char **errorp, rcm_info_t **depend_info)
698 {
699 	ip_cache_t *node;
700 
701 	/* Guard against bad arguments */
702 	assert(hd != NULL);
703 	assert(rsrc != NULL);
704 	assert(id == (id_t)0);
705 	assert(errorp != NULL);
706 	assert(depend_info != NULL);
707 
708 	rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc);
709 
710 	(void) mutex_lock(&cache_lock);
711 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
712 	if (!node) {
713 		rcm_log_message(RCM_INFO,
714 		    _("IP: remove(%s) unrecognized resource\n"), rsrc);
715 		(void) mutex_unlock(&cache_lock);
716 		errno = ENOENT;
717 		return (RCM_FAILURE);
718 	}
719 
720 	/* remove the cached entry for the resource */
721 	cache_remove(node);
722 	free_node(node);
723 
724 	(void) mutex_unlock(&cache_lock);
725 	return (RCM_SUCCESS);
726 }
727 
728 /*
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.
734  */
735 /*ARGSUSED*/
736 static int
ip_notify_event(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,nvlist_t * nvl,rcm_info_t ** depend_info)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)
739 {
740 	datalink_id_t	linkid;
741 	nvpair_t *nvp = NULL;
742 	uint64_t id64;
743 
744 	assert(hd != NULL);
745 	assert(rsrc != NULL);
746 	assert(id == (id_t)0);
747 	assert(nvl != NULL);
748 
749 	rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc);
750 
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");
755 		errno = EINVAL;
756 		return (RCM_FAILURE);
757 	}
758 
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);
764 	}
765 
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);
773 			}
774 			linkid = (datalink_id_t)id64;
775 			/*
776 			 * Grovel through /etc/hostname* files and configure
777 			 * interface in the same way that they would be handled
778 			 * by network/physical.
779 			 */
780 			if (if_configure_hostname(linkid) != 0) {
781 				rcm_log_message(RCM_ERROR,
782 				    _("IP: Configuration failed (%u)\n"),
783 				    linkid);
784 				ip_log_err(NULL, errorp,
785 				    "Failed configuring one or more IP "
786 				    "addresses");
787 			}
788 
789 			/*
790 			 * Query libipadm for persistent configuration info
791 			 * and resurrect that persistent configuration.
792 			 */
793 			if (if_configure_ipadm(linkid) != 0) {
794 				rcm_log_message(RCM_ERROR,
795 				    _("IP: Configuration failed (%u)\n"),
796 				    linkid);
797 				ip_log_err(NULL, errorp,
798 				    "Failed configuring one or more IP "
799 				    "addresses");
800 			}
801 
802 			/* Notify all IP address consumers */
803 			ip_consumer_notify(hd, linkid, errorp, flags,
804 			    depend_info);
805 		}
806 	}
807 
808 	rcm_log_message(RCM_TRACE1,
809 	    "IP: notify_event: device configuration complete\n");
810 
811 	return (RCM_SUCCESS);
812 }
813 
814 /*
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.
818  */
819 static char *
ip_usage(ip_cache_t * node)820 ip_usage(ip_cache_t *node)
821 {
822 	ip_lif_t *lif;
823 	uint_t numup;
824 	char *sep, *buf, *linkidstr;
825 	datalink_id_t linkid;
826 	const char *msg;
827 	char link[MAXLINKNAMELEN];
828 	char addrstr[INET6_ADDRSTRLEN];
829 	char errmsg[DLADM_STRSIZE];
830 	dladm_status_t status;
831 	boolean_t offline, ipmp;
832 	size_t bufsz = 0;
833 
834 	rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource);
835 
836 	/*
837 	 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid>
838 	 */
839 	linkidstr = strchr(node->ip_resource, '/');
840 	assert(linkidstr != NULL);
841 	linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource;
842 
843 	errno = 0;
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));
849 		return (NULL);
850 	}
851 
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));
857 		return (NULL);
858 	}
859 
860 	/* TRANSLATION_NOTE: separator used between IP addresses */
861 	sep = _(", ");
862 
863 	numup = 0;
864 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next)
865 		if (lif->li_ifflags & IFF_UP)
866 			numup++;
867 
868 	ipmp = (node->ip_pif->pi_grname[0] != '\0');
869 	offline = ((node->ip_cachestate & CACHE_IF_OFFLINED) != 0);
870 
871 	if (offline) {
872 		msg = _("offlined");
873 	} else if (numup == 0) {
874 		msg = _("plumbed but down");
875 	} else {
876 		if (ipmp) {
877 			msg = _("providing connectivity for IPMP group ");
878 			bufsz += LIFGRNAMSIZ;
879 		} else {
880 			msg = _("hosts IP addresses: ");
881 			bufsz += (numup * (INET6_ADDRSTRLEN + strlen(sep)));
882 		}
883 	}
884 
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));
890 		return (NULL);
891 	}
892 	(void) snprintf(buf, bufsz, "%s: %s", link, msg);
893 
894 	if (!offline && numup > 0) {
895 		if (ipmp) {
896 			(void) strlcat(buf, node->ip_pif->pi_grname, bufsz);
897 		} else {
898 			lif = node->ip_pif->pi_lifs;
899 			for (; lif != NULL; lif = lif->li_next) {
900 				if (!(lif->li_ifflags & IFF_UP))
901 					continue;
902 
903 				if (!ip_addrstr(lif, addrstr, sizeof (addrstr)))
904 					continue;
905 
906 				(void) strlcat(buf, addrstr, bufsz);
907 				if (--numup > 0)
908 					(void) strlcat(buf, sep, bufsz);
909 			}
910 		}
911 	}
912 
913 	rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
914 	    node->ip_resource, buf);
915 
916 	return (buf);
917 }
918 
919 static boolean_t
ip_addrstr(ip_lif_t * lif,char * addrstr,size_t addrsize)920 ip_addrstr(ip_lif_t *lif, char *addrstr, size_t addrsize)
921 {
922 	int af = lif->li_addr.family;
923 	void *addr;
924 
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;
929 	} else {
930 		rcm_log_message(RCM_DEBUG,
931 		    "IP: unknown addr family %d, assuming AF_INET\n", af);
932 		af = AF_INET;
933 		addr = &lif->li_addr.ip4.sin_addr;
934 	}
935 	if (inet_ntop(af, addr, addrstr, addrsize) == NULL) {
936 		rcm_log_message(RCM_ERROR,
937 		    _("IP: inet_ntop: %s\n"), strerror(errno));
938 		return (B_FALSE);
939 	}
940 
941 	rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr);
942 	return (B_TRUE);
943 }
944 
945 /*
946  * Cache management routines, all cache management functions should be
947  * be called with cache_lock held.
948  */
949 
950 /*
951  * cache_lookup() - Get a cache node for a resource.
952  *		  Call with cache lock held.
953  *
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.
956  */
957 static ip_cache_t *
cache_lookup(rcm_handle_t * hd,char * rsrc,char options)958 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
959 {
960 	ip_cache_t *probe;
961 
962 	rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc);
963 
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);
969 	}
970 
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);
977 			return (probe);
978 		}
979 		probe = probe->ip_next;
980 	}
981 	return (NULL);
982 }
983 
984 /*
985  * free_node - Free a node from the cache
986  *	     Call with cache_lock held.
987  */
988 static void
free_node(ip_cache_t * node)989 free_node(ip_cache_t *node)
990 {
991 	ip_pif_t *pif;
992 	ip_lif_t *lif, *tmplif;
993 
994 	if (node) {
995 		if (node->ip_resource) {
996 			free(node->ip_resource);
997 		}
998 
999 		/* free the pif */
1000 		pif = node->ip_pif;
1001 		if (pif) {
1002 			/* free logical interfaces */
1003 			lif = pif->pi_lifs;
1004 			while (lif) {
1005 				tmplif = lif->li_next;
1006 				free(lif);
1007 				lif = tmplif;
1008 			}
1009 			free(pif);
1010 		}
1011 		free(node);
1012 	}
1013 }
1014 
1015 /*
1016  * cache_insert - Insert a resource node in cache
1017  *		Call with the cache_lock held.
1018  */
1019 static void
cache_insert(ip_cache_t * node)1020 cache_insert(ip_cache_t *node)
1021 {
1022 	rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n",
1023 	    node->ip_resource);
1024 
1025 	/* insert at the head for best performance */
1026 	node->ip_next = cache_head.ip_next;
1027 	node->ip_prev = &cache_head;
1028 
1029 	node->ip_next->ip_prev = node;
1030 	node->ip_prev->ip_next = node;
1031 }
1032 
1033 /*
1034  * cache_remove() - Remove a resource node from cache.
1035  *		  Call with the cache_lock held.
1036  */
1037 static void
cache_remove(ip_cache_t * node)1038 cache_remove(ip_cache_t *node)
1039 {
1040 	rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n",
1041 	    node->ip_resource);
1042 
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;
1047 }
1048 
1049 /*
1050  * update_pif() - Update physical interface properties
1051  *		Call with cache_lock held
1052  */
1053 int
update_pif(rcm_handle_t * hd,int af,int sock,struct ifaddrs * ifa)1054 update_pif(rcm_handle_t *hd, int af, int sock, struct ifaddrs *ifa)
1055 {
1056 	char *rsrc;
1057 	ifspec_t ifspec;
1058 	ushort_t ifnumber = 0;
1059 	ip_cache_t *probe;
1060 	ip_pif_t pif;
1061 	ip_pif_t *probepif;
1062 	ip_lif_t *probelif;
1063 	struct lifreq lifreq;
1064 	struct sockaddr_storage ifaddr;
1065 	uint64_t ifflags;
1066 	int lif_listed = 0;
1067 
1068 	rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", ifa->ifa_name);
1069 
1070 	if (!ifparse_ifspec(ifa->ifa_name, &ifspec)) {
1071 		rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"),
1072 		    ifa->ifa_name);
1073 		return (-1);
1074 	}
1075 
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;
1080 
1081 	/* Get the interface flags */
1082 	ifflags = ifa->ifa_flags;
1083 
1084 	/*
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
1090 	 *
1091 	 * Note: The !IFF_MULTICAST check can be removed once iptun is
1092 	 * implemented as a datalink.
1093 	 */
1094 	if (!(ifflags & IFF_MULTICAST) ||
1095 	    (ifflags & (IFF_POINTOPOINT | IFF_VIRTUAL | IFF_IPMP))) {
1096 		rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n",
1097 		    pif.pi_ifname);
1098 		return (0);
1099 	}
1100 
1101 	/* Get the interface group name for this interface */
1102 	bzero(&lifreq, sizeof (lifreq));
1103 	(void) strncpy(lifreq.lifr_name, ifa->ifa_name, LIFNAMSIZ);
1104 
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));
1110 		}
1111 		return (-1);
1112 	}
1113 
1114 	/* copy the group name */
1115 	(void) strlcpy(pif.pi_grname, lifreq.lifr_groupname,
1116 	    sizeof (pif.pi_grname));
1117 
1118 	/* Get the interface address for this interface */
1119 	(void) memcpy(&ifaddr, ifa->ifa_addr, sizeof (ifaddr));
1120 
1121 	rsrc = get_link_resource(pif.pi_ifname);
1122 	if (rsrc == NULL) {
1123 		rcm_log_message(RCM_ERROR,
1124 		    _("IP: get_link_resource(%s) failed\n"),
1125 		    lifreq.lifr_name);
1126 		return (-1);
1127 	}
1128 
1129 	probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
1130 	if (probe != NULL) {
1131 		free(rsrc);
1132 		probe->ip_cachestate &= ~(CACHE_IF_STALE);
1133 	} else {
1134 		if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) {
1135 			/* malloc errors are bad */
1136 			free(rsrc);
1137 			rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1138 			    strerror(errno));
1139 			return (-1);
1140 		}
1141 
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;
1146 
1147 		cache_insert(probe);
1148 	}
1149 
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)) {
1157 
1158 				rcm_log_message(RCM_TRACE2,
1159 				    "IP: refreshing lifs for %s, ifnum=%d\n",
1160 				    pif.pi_ifname, probelif->li_ifnum);
1161 
1162 				/* refresh lif properties */
1163 				(void) memcpy(&probelif->li_addr, &ifaddr,
1164 				    sizeof (probelif->li_addr));
1165 
1166 				probelif->li_ifflags = ifflags;
1167 
1168 				lif_listed++;
1169 				probelif->li_cachestate &= ~(CACHE_IF_STALE);
1170 				break;
1171 			}
1172 			probelif = probelif->li_next;
1173 		}
1174 	}
1175 
1176 	if (probepif == NULL) {
1177 		if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) {
1178 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1179 			    strerror(errno));
1180 			if (probe->ip_pif == NULL) {
1181 				/* we created it, so clean it up */
1182 				free(probe);
1183 			}
1184 			return (-1);
1185 		}
1186 
1187 		probe->ip_pif = probepif;
1188 
1189 		/* Save interface name */
1190 		(void) memcpy(&probepif->pi_ifname, &pif.pi_ifname,
1191 		    sizeof (pif.pi_ifname));
1192 	}
1193 
1194 	/* save the group name */
1195 	(void) strlcpy(probepif->pi_grname, pif.pi_grname,
1196 	    sizeof (pif.pi_grname));
1197 
1198 	/* add lif, if this is a lif and it is not in cache */
1199 	if (!lif_listed) {
1200 		rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n",
1201 		    pif.pi_ifname);
1202 
1203 		if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) {
1204 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1205 			    strerror(errno));
1206 			return (-1);
1207 		}
1208 
1209 		/* save lif properties */
1210 		(void) memcpy(&probelif->li_addr, &ifaddr,
1211 		    sizeof (probelif->li_addr));
1212 
1213 		probelif->li_ifnum = ifnumber;
1214 		probelif->li_ifflags = ifflags;
1215 
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;
1220 		}
1221 		probelif->li_prev = NULL;
1222 		probelif->li_pif = probepif;
1223 
1224 		probepif->pi_lifs = probelif;
1225 	}
1226 
1227 	rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n",
1228 	    probe->ip_resource);
1229 
1230 	return (0);
1231 }
1232 
1233 /*
1234  * update_ipifs() - Determine all network interfaces in the system
1235  *		  Call with cache_lock held
1236  */
1237 static int
update_ipifs(rcm_handle_t * hd,int af)1238 update_ipifs(rcm_handle_t *hd, int af)
1239 {
1240 
1241 	struct ifaddrs *ifa;
1242 	ipadm_addr_info_t *ainfo;
1243 	ipadm_addr_info_t *ptr;
1244 	ipadm_status_t status;
1245 	int sock;
1246 
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));
1251 		return (-1);
1252 	}
1253 
1254 	status = ipadm_addr_info(ip_handle, NULL, &ainfo, IPADM_OPT_ZEROADDR,
1255 	    LIFC_UNDER_IPMP);
1256 	if (status != IPADM_SUCCESS) {
1257 		(void) close(sock);
1258 		return (-1);
1259 	}
1260 	for (ptr = ainfo; ptr; ptr = IA_NEXT(ptr)) {
1261 		ifa = &ptr->ia_ifa;
1262 		if (ptr->ia_state != IFA_DISABLED &&
1263 		    af == ifa->ifa_addr->sa_family)
1264 			(void) update_pif(hd, af, sock, ifa);
1265 	}
1266 	(void) close(sock);
1267 	ipadm_free_addr_info(ainfo);
1268 	return (0);
1269 }
1270 
1271 /*
1272  * update_cache() - Update cache with latest interface info
1273  */
1274 static int
update_cache(rcm_handle_t * hd)1275 update_cache(rcm_handle_t *hd)
1276 {
1277 	ip_cache_t *probe;
1278 	struct ip_lif *lif;
1279 	struct ip_lif *nextlif;
1280 	int rv;
1281 	int i;
1282 
1283 	rcm_log_message(RCM_TRACE2, "IP: update_cache\n");
1284 
1285 	(void) mutex_lock(&cache_lock);
1286 
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;
1295 				lif = lif->li_next;
1296 			}
1297 		}
1298 		probe = probe->ip_next;
1299 	}
1300 
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);
1304 		return (-1);
1305 	}
1306 
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);
1310 		return (-1);
1311 	}
1312 
1313 	probe = cache_head.ip_next;
1314 	/* unregister devices that are not offlined and still in cache */
1315 	while (probe != &cache_tail) {
1316 		ip_cache_t *freeit;
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 =
1329 						    nextlif;
1330 					for (i = 0; i < IP_MAX_MODS; i++) {
1331 						free(lif->li_modules[i]);
1332 					}
1333 					free(lif->li_reconfig);
1334 					free(lif);
1335 					lif = nextlif;
1336 				} else {
1337 					lif = lif->li_next;
1338 				}
1339 			}
1340 		}
1341 		if ((probe->ip_cachestate & CACHE_IF_STALE) &&
1342 		    !(probe->ip_cachestate & CACHE_IF_OFFLINED)) {
1343 			(void) rcm_unregister_interest(hd, probe->ip_resource,
1344 			    0);
1345 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
1346 			    probe->ip_resource);
1347 			freeit = probe;
1348 			probe = probe->ip_next;
1349 			cache_remove(freeit);
1350 			free_node(freeit);
1351 			continue;
1352 		}
1353 
1354 		if (!(probe->ip_cachestate & CACHE_IF_NEW)) {
1355 			probe = probe->ip_next;
1356 			continue;
1357 		}
1358 
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);
1365 			return (-1);
1366 		} else {
1367 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
1368 			    probe->ip_resource);
1369 			probe->ip_cachestate &= ~(CACHE_IF_NEW);
1370 		}
1371 		probe = probe->ip_next;
1372 	}
1373 
1374 	(void) mutex_unlock(&cache_lock);
1375 	return (0);
1376 }
1377 
1378 /*
1379  * free_cache() - Empty the cache
1380  */
1381 static void
free_cache()1382 free_cache()
1383 {
1384 	ip_cache_t *probe;
1385 
1386 	rcm_log_message(RCM_TRACE2, "IP: free_cache\n");
1387 
1388 	(void) mutex_lock(&cache_lock);
1389 	probe = cache_head.ip_next;
1390 	while (probe != &cache_tail) {
1391 		cache_remove(probe);
1392 		free_node(probe);
1393 		probe = cache_head.ip_next;
1394 	}
1395 	(void) mutex_unlock(&cache_lock);
1396 }
1397 
1398 /*
1399  * ip_log_err() - RCM error log wrapper
1400  */
1401 static void
ip_log_err(ip_cache_t * node,char ** errorp,char * errmsg)1402 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
1403 {
1404 	char *ifname = NULL;
1405 	int size;
1406 	const char *errfmt;
1407 	char *error = NULL;
1408 
1409 	if ((node != NULL) && (node->ip_pif != NULL) &&
1410 	    (node->ip_pif->pi_ifname != NULL)) {
1411 		ifname = node->ip_pif->pi_ifname;
1412 	}
1413 
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);
1420 	} else {
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);
1426 	}
1427 
1428 	if (errorp != NULL)
1429 		*errorp = error;
1430 }
1431 
1432 /*
1433  * if_cfginfo() - Save off the config info for all interfaces
1434  */
1435 static int
if_cfginfo(ip_cache_t * node,uint_t force)1436 if_cfginfo(ip_cache_t *node, uint_t force)
1437 {
1438 	ip_lif_t *lif;
1439 	ip_pif_t *pif;
1440 	int i;
1441 	FILE *fp;
1442 	char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
1443 	char buf[MAX_RECONFIG_SIZE];
1444 
1445 	rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource);
1446 
1447 	pif = node->ip_pif;
1448 	lif = pif->pi_lifs;
1449 
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));
1457 				clr_cfg_state(pif);
1458 				return (-1);
1459 			}
1460 
1461 			if (!force) {
1462 				/* Look if unknown modules have been inserted */
1463 				for (i = (lif->li_modcnt - 2); i > 0; i--) {
1464 					if (modop(pif->pi_ifname,
1465 					    lif->li_modules[i],
1466 					    i, MOD_CHECK) == -1) {
1467 						rcm_log_message(RCM_ERROR,
1468 						    _("IP: module %s@%d\n"),
1469 						    lif->li_modules[i], i);
1470 						clr_cfg_state(pif);
1471 						return (-1);
1472 					}
1473 				}
1474 			}
1475 
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,
1485 						    lif->li_modules[i],
1486 						    i, MOD_INSERT) == -1) {
1487 							/* Gross error */
1488 							rcm_log_message(
1489 							    RCM_ERROR,
1490 							    _("IP: if_cfginfo"
1491 							    "(%s) %s\n"),
1492 							    pif->pi_ifname,
1493 							    strerror(errno));
1494 							clr_cfg_state(pif);
1495 							return (-1);
1496 						}
1497 						i++;
1498 					}
1499 					rcm_log_message(
1500 					    RCM_ERROR,
1501 					    _("IP: if_cfginfo(%s): modremove "
1502 					    "%s failed: %s\n"), pif->pi_ifname,
1503 					    lif->li_modules[i],
1504 					    strerror(errno));
1505 					clr_cfg_state(pif);
1506 					return (-1);
1507 				}
1508 			}
1509 		}
1510 
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);
1520 		}
1521 		rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd);
1522 
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));
1528 			clr_cfg_state(pif);
1529 			return (-1);
1530 		}
1531 		bzero(buf, MAX_RECONFIG_SIZE);
1532 
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));
1537 			(void) pclose(fp);
1538 			clr_cfg_state(pif);
1539 			return (-1);
1540 		}
1541 		(void) pclose(fp);
1542 
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));
1547 			clr_cfg_state(pif);
1548 			return (-1);
1549 		}
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);
1553 
1554 		lif = lif->li_next;
1555 	}
1556 
1557 	return (0);
1558 }
1559 
1560 /*
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
1564  *		force is not set
1565  *		Call with cache_lock held
1566  */
1567 static int
if_unplumb(ip_cache_t * node)1568 if_unplumb(ip_cache_t *node)
1569 {
1570 	ip_lif_t *lif;
1571 	ip_pif_t *pif = node->ip_pif;
1572 	boolean_t ipv4 = B_FALSE;
1573 	boolean_t ipv6 = B_FALSE;
1574 
1575 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource);
1576 
1577 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1578 		if (lif->li_ifflags & IFF_IPV4) {
1579 			ipv4 = B_TRUE;
1580 		} else if (lif->li_ifflags & IFF_IPV6) {
1581 			ipv6 = B_TRUE;
1582 		} else {
1583 			/* Unlikely case */
1584 			rcm_log_message(RCM_DEBUG,
1585 			    "IP: Unplumb ignored (%s:%d)\n",
1586 			    pif->pi_ifname, lif->li_ifnum);
1587 		}
1588 	}
1589 
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));
1593 		return (-1);
1594 	}
1595 
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));
1599 		return (-1);
1600 	}
1601 
1602 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n",
1603 	    node->ip_resource);
1604 
1605 	return (0);
1606 }
1607 
1608 /*
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
1613  */
1614 static int
if_replumb(ip_cache_t * node)1615 if_replumb(ip_cache_t *node)
1616 {
1617 	ip_lif_t *lif;
1618 	ip_pif_t *pif;
1619 	int i;
1620 	boolean_t success, ipmp;
1621 	const char *fstr;
1622 	char lifname[LIFNAMSIZ];
1623 	char buf[MAX_RECONFIG_SIZE];
1624 	int max_lifnum = 0;
1625 
1626 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource);
1627 
1628 	/*
1629 	 * Be extra careful about bringing up the interfaces in the
1630 	 * correct order:
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)
1635 	 */
1636 
1637 	pif = node->ip_pif;
1638 	ipmp = (node->ip_pif->pi_grname[0] != '\0');
1639 
1640 	/*
1641 	 * Make a first pass to plumb in physical interfaces and get a count
1642 	 * of the max logical interfaces
1643 	 */
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) {
1647 			fstr = "inet";
1648 		} else if (lif->li_ifflags & IFF_IPV6) {
1649 			fstr = "inet6";
1650 		} else {
1651 			/* Unlikely case */
1652 			rcm_log_message(RCM_DEBUG,
1653 			    "IP: Re-plumb ignored (%s:%d)\n",
1654 			    pif->pi_ifname, lif->li_ifnum);
1655 			continue;
1656 		}
1657 
1658 		/* ignore logical interface instances */
1659 		if (lif->li_ifnum != 0)
1660 			continue;
1661 
1662 		if ((lif->li_ifflags & IFF_NOFAILOVER) || !ipmp) {
1663 			success = ifconfig("", "", lif->li_reconfig, B_FALSE);
1664 		} else {
1665 			(void) snprintf(buf, sizeof (buf), "plumb group %s",
1666 			    pif->pi_grname);
1667 			success = ifconfig(pif->pi_ifname, fstr, buf, B_FALSE);
1668 		}
1669 
1670 		if (!success) {
1671 			rcm_log_message(RCM_ERROR,
1672 			    _("IP: Cannot plumb (%s) %s\n"), pif->pi_ifname,
1673 			    strerror(errno));
1674 			return (-1);
1675 		}
1676 
1677 		/*
1678 		 * Restart DHCP if necessary.
1679 		 */
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));
1684 			return (-1);
1685 		}
1686 
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"),
1698 				    pif->pi_ifname);
1699 				return (-1);
1700 			}
1701 		}
1702 	}
1703 
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);
1707 
1708 		/* reset lif through every iteration */
1709 		for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1710 			/*
1711 			 * Process entries in order.  If the interface is
1712 			 * using IPMP, only process test addresses.
1713 			 */
1714 			if (lif->li_ifnum != i ||
1715 			    (ipmp && !(lif->li_ifflags & IFF_NOFAILOVER)))
1716 				continue;
1717 
1718 			if (!ifconfig("", "", lif->li_reconfig, B_FALSE)) {
1719 				rcm_log_message(RCM_ERROR,
1720 				    _("IP: Cannot addif (%s) %s\n"), lifname,
1721 				    strerror(errno));
1722 				return (-1);
1723 			}
1724 
1725 			/*
1726 			 * Restart DHCP if necessary.
1727 			 */
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));
1733 				return (-1);
1734 			}
1735 		}
1736 	}
1737 
1738 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n",
1739 	    node->ip_resource);
1740 
1741 	return (0);
1742 }
1743 
1744 /*
1745  * clr_cfg_state() - Cleanup after errors in unplumb
1746  */
1747 static void
clr_cfg_state(ip_pif_t * pif)1748 clr_cfg_state(ip_pif_t *pif)
1749 {
1750 	ip_lif_t *lif;
1751 	int i;
1752 
1753 	lif = pif->pi_lifs;
1754 
1755 	while (lif != NULL) {
1756 		lif->li_modcnt = 0;
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;
1762 		}
1763 		lif = lif->li_next;
1764 	}
1765 }
1766 
1767 /*
1768  * Attempt to offline ip_cache_t `node'; returns an IPMP error code.
1769  */
1770 static int
ip_ipmp_offline(ip_cache_t * node)1771 ip_ipmp_offline(ip_cache_t *node)
1772 {
1773 	int retval;
1774 	ipmp_handle_t handle;
1775 
1776 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n");
1777 
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));
1782 		return (retval);
1783 	}
1784 
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));
1789 	} else {
1790 		rcm_log_message(RCM_TRACE1, "IP: ipmp_offline success\n");
1791 	}
1792 
1793 	ipmp_close(handle);
1794 	return (retval);
1795 }
1796 
1797 /*
1798  * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code.
1799  */
1800 static int
ip_ipmp_undo_offline(ip_cache_t * node)1801 ip_ipmp_undo_offline(ip_cache_t *node)
1802 {
1803 	int retval;
1804 	ipmp_handle_t handle;
1805 
1806 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_undo_offline\n");
1807 
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));
1812 		return (retval);
1813 	}
1814 
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));
1820 	} else {
1821 		rcm_log_message(RCM_TRACE1, "IP: ipmp_undo_offline success\n");
1822 	}
1823 
1824 	ipmp_close(handle);
1825 	return (retval);
1826 }
1827 
1828 /*
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>").
1832  */
1833 static char *
get_link_resource(const char * link)1834 get_link_resource(const char *link)
1835 {
1836 	char		errmsg[DLADM_STRSIZE];
1837 	datalink_id_t	linkid;
1838 	uint32_t	flags;
1839 	char		*resource;
1840 	dladm_status_t	status;
1841 
1842 	status = dladm_name2info(dld_handle, link, &linkid, &flags, NULL, NULL);
1843 	if (status != DLADM_STATUS_OK)
1844 		goto fail;
1845 
1846 	if (!(flags & DLADM_OPT_ACTIVE)) {
1847 		status = DLADM_STATUS_FAILED;
1848 		goto fail;
1849 	}
1850 
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);
1855 		return (NULL);
1856 	}
1857 
1858 	(void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u",
1859 	    RCM_LINK_PREFIX, linkid);
1860 
1861 	return (resource);
1862 
1863 fail:
1864 	rcm_log_message(RCM_ERROR,
1865 	    _("IP: get_link_resource for %s error(%s)\n"),
1866 	    link, dladm_status2str(status, errmsg));
1867 	return (NULL);
1868 }
1869 
1870 /*
1871  * modop() - Remove/insert a module
1872  */
1873 static int
modop(char * name,char * arg,int pos,char op)1874 modop(char *name, char *arg, int pos, char op)
1875 {
1876 	char syscmd[LIFNAMSIZ+MAXPATHLEN];	/* must be big enough */
1877 
1878 	rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name);
1879 
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");
1884 		return (0);
1885 	}
1886 
1887 	if (op == MOD_CHECK) {
1888 		/*
1889 		 * No known good modules (yet) apart from ip and arp
1890 		 * which are handled above
1891 		 */
1892 		return (-1);
1893 	}
1894 
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);
1901 	} else {
1902 		rcm_log_message(RCM_ERROR,
1903 		    _("IP: modop(%s): unknown operation\n"), name);
1904 		return (-1);
1905 	}
1906 
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));
1911 		return (-1);
1912 	}
1913 
1914 	rcm_log_message(RCM_TRACE1, "IP: modop success\n");
1915 	return (0);
1916 }
1917 
1918 /*
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
1923  */
1924 static int
get_modlist(char * name,ip_lif_t * lif)1925 get_modlist(char *name, ip_lif_t *lif)
1926 {
1927 	int mux_fd;
1928 	int muxid_fd;
1929 	int fd;
1930 	int i;
1931 	int num_mods;
1932 	struct lifreq lifr;
1933 	struct str_list strlist = { 0 };
1934 
1935 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name);
1936 
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);
1941 		return (-1);
1942 	}
1943 
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));
1948 		goto fail;
1949 	}
1950 
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));
1956 		goto fail;
1957 	}
1958 
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));
1963 		goto fail;
1964 	}
1965 
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));
1972 			while (i > 0)
1973 				free(lif->li_modules[--i]);
1974 			goto fail;
1975 		}
1976 	}
1977 
1978 	lif->li_modcnt = strlist.sl_nmods;
1979 	free(strlist.sl_modlist);
1980 
1981 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name);
1982 	return (ip_plink(mux_fd, muxid_fd, fd, &lifr));
1983 fail:
1984 	free(strlist.sl_modlist);
1985 	(void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
1986 	return (-1);
1987 }
1988 
1989 /*
1990  * ip_domux2fd() - Helper function for mod*() functions
1991  *		 Stolen from ifconfig.c
1992  */
1993 static int
ip_domux2fd(int * mux_fd,int * muxid_fdp,int * fd,struct lifreq * lifr)1994 ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr)
1995 {
1996 	int muxid_fd;
1997 	char	*udp_dev_name;
1998 
1999 	if (lifr->lifr_flags & IFF_IPV6) {
2000 		udp_dev_name  = UDP6_DEV_NAME;
2001 	} else {
2002 		udp_dev_name  = UDP_DEV_NAME;
2003 	}
2004 
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));
2008 		return (-1);
2009 	}
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);
2014 		return (-1);
2015 	}
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);
2022 		return (-1);
2023 	}
2024 
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);
2028 
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);
2035 		return (-1);
2036 	}
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);
2043 		return (-1);
2044 	}
2045 
2046 	/* Note: mux_fd and muxid_fd are closed in ip_plink below */
2047 	*muxid_fdp = muxid_fd;
2048 	return (0);
2049 }
2050 
2051 /*
2052  * ip_plink() - Helper function for mod*() functions.
2053  *	      Stolen from ifconfig.c
2054  */
2055 static int
ip_plink(int mux_fd,int muxid_fd,int fd,struct lifreq * lifr)2056 ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr)
2057 {
2058 	int mux_id;
2059 
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);
2065 		(void) close(fd);
2066 		return (-1);
2067 	}
2068 
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);
2076 		(void) close(fd);
2077 		return (-1);
2078 	}
2079 
2080 	(void) close(mux_fd);
2081 	(void) close(muxid_fd);
2082 	(void) close(fd);
2083 	return (0);
2084 }
2085 
2086 /*
2087  * ip_onlinelist()
2088  *
2089  *	Notify online to IP address consumers.
2090  */
2091 /*ARGSUSED*/
2092 static int
ip_onlinelist(rcm_handle_t * hd,ip_cache_t * node,char ** errorp,uint_t flags,rcm_info_t ** depend_info)2093 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2094 		rcm_info_t **depend_info)
2095 {
2096 	char **addrlist;
2097 	int ret = RCM_SUCCESS;
2098 
2099 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n");
2100 
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);
2105 		return (ret);
2106 	}
2107 
2108 	ret = rcm_notify_online_list(hd, addrlist, 0, depend_info);
2109 
2110 	ip_free_addrlist(addrlist);
2111 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n");
2112 	return (ret);
2113 }
2114 
2115 /*
2116  * ip_offlinelist()
2117  *
2118  *	Offline IP address consumers.
2119  */
2120 /*ARGSUSED*/
2121 static int
ip_offlinelist(rcm_handle_t * hd,ip_cache_t * node,char ** errorp,uint_t flags,rcm_info_t ** depend_info)2122 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2123 	rcm_info_t **depend_info)
2124 {
2125 	char **addrlist;
2126 	int ret = RCM_SUCCESS;
2127 
2128 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n");
2129 
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);
2135 	}
2136 
2137 	if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info))
2138 	    != RCM_SUCCESS) {
2139 		if (ret == RCM_FAILURE)
2140 			(void) rcm_notify_online_list(hd, addrlist, 0, NULL);
2141 
2142 		ret = RCM_FAILURE;
2143 	}
2144 
2145 	ip_free_addrlist(addrlist);
2146 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n");
2147 	return (ret);
2148 }
2149 
2150 /*
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.
2155  */
2156 static char **
ip_get_addrlist(ip_cache_t * node)2157 ip_get_addrlist(ip_cache_t *node)
2158 {
2159 	ip_lif_t *lif;
2160 	char **addrlist = NULL;
2161 	int i, numifs;
2162 	size_t addrlistsize;
2163 	char addrstr[INET6_ADDRSTRLEN];
2164 
2165 	rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n",
2166 	    node->ip_resource);
2167 
2168 	numifs = 0;
2169 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
2170 		numifs++;
2171 	}
2172 
2173 	/*
2174 	 * Allocate space for resource names list; add 1 and use calloc()
2175 	 * so that the list is NULL-terminated.
2176 	 */
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));
2181 		return (NULL);
2182 	}
2183 
2184 	for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL;
2185 	    lif = lif->li_next, i++) {
2186 
2187 		if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) {
2188 			ip_free_addrlist(addrlist);
2189 			return (NULL);
2190 		}
2191 
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);
2198 			return (NULL);
2199 		}
2200 		(void) snprintf(addrlist[i], addrlistsize, "%s%s",
2201 		    RCM_STR_SUNW_IP, addrstr);
2202 
2203 		rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]);
2204 	}
2205 
2206 	rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n",
2207 	    node->ip_resource);
2208 
2209 	return (addrlist);
2210 }
2211 
2212 static void
ip_free_addrlist(char ** addrlist)2213 ip_free_addrlist(char **addrlist)
2214 {
2215 	int i;
2216 
2217 	if (addrlist == NULL)
2218 		return;
2219 
2220 	for (i = 0; addrlist[i] != NULL; i++)
2221 		free(addrlist[i]);
2222 	free(addrlist);
2223 }
2224 
2225 /*
2226  * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
2227  */
2228 
2229 static void
ip_consumer_notify(rcm_handle_t * hd,datalink_id_t linkid,char ** errorp,uint_t flags,rcm_info_t ** depend_info)2230 ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
2231     uint_t flags, rcm_info_t **depend_info)
2232 {
2233 	char cached_name[RCM_LINK_RESOURCE_MAX];
2234 	ip_cache_t *node;
2235 
2236 	assert(linkid != DATALINK_INVALID_LINKID);
2237 
2238 	rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid);
2239 
2240 	/* Check for the interface in the cache */
2241 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2242 	    RCM_LINK_PREFIX, linkid);
2243 
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"),
2247 		    linkid);
2248 		(void) mutex_unlock(&cache_lock);
2249 		return;
2250 	}
2251 	/*
2252 	 * Inform anonymous consumers about IP addresses being onlined.
2253 	 */
2254 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
2255 
2256 	(void) mutex_unlock(&cache_lock);
2257 
2258 	rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n");
2259 }
2260 
2261 /*
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'.
2265  */
2266 static int
if_configure_get_linkid(datalink_id_t linkid,char * ifinst,size_t len)2267 if_configure_get_linkid(datalink_id_t linkid, char *ifinst, size_t len)
2268 {
2269 	char cached_name[RCM_LINK_RESOURCE_MAX];
2270 	ip_cache_t *node;
2271 
2272 	/* Check for the interface in the cache */
2273 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2274 	    RCM_LINK_PREFIX, linkid);
2275 
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);
2283 		*ifinst = '\0';
2284 		return (0);
2285 	}
2286 	(void) mutex_unlock(&cache_lock);
2287 
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);
2292 		return (-1);
2293 	}
2294 	return (0);
2295 }
2296 
2297 /*
2298  * if_configure_hostname() - Configure a physical interface after attach
2299  * based on the information in /etc/hostname.*
2300  */
2301 static int
if_configure_hostname(datalink_id_t linkid)2302 if_configure_hostname(datalink_id_t linkid)
2303 {
2304 	FILE *hostfp, *host6fp;
2305 	boolean_t ipmp = B_FALSE;
2306 	char ifinst[MAXLINKNAMELEN];
2307 	char cfgfile[MAXPATHLEN];
2308 
2309 	assert(linkid != DATALINK_INVALID_LINKID);
2310 	rcm_log_message(RCM_TRACE1, _("IP: if_configure_hostname(%u)\n"),
2311 	    linkid);
2312 
2313 	if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
2314 		return (-1);
2315 
2316 	/* Check if the interface is already configured. */
2317 	if (ifinst[0] == '\0')
2318 		return (0);
2319 
2320 	/*
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.
2323 	 */
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))
2328 			ipmp = B_TRUE;
2329 	}
2330 
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))
2335 			ipmp = B_TRUE;
2336 	}
2337 
2338 	/*
2339 	 * Configure the interface according to its hostname files.
2340 	 */
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);
2345 		goto fail;
2346 	}
2347 
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);
2352 		goto fail;
2353 	}
2354 
2355 	(void) fclose(hostfp);
2356 	(void) fclose(host6fp);
2357 	rcm_log_message(RCM_TRACE1, "IP: if_configure_hostname(%s) success\n",
2358 	    ifinst);
2359 	return (0);
2360 fail:
2361 	(void) fclose(hostfp);
2362 	(void) fclose(host6fp);
2363 	return (-1);
2364 }
2365 
2366 /*
2367  * if_configure_ipadm() - Configure a physical interface after attach
2368  * Queries libipadm for persistent configuration information and then
2369  * resurrects that persistent configuration.
2370  */
2371 static int
if_configure_ipadm(datalink_id_t linkid)2372 if_configure_ipadm(datalink_id_t linkid)
2373 {
2374 	char ifinst[MAXLINKNAMELEN];
2375 	boolean_t found;
2376 	ipadm_if_info_t *ifinfo, *ptr;
2377 	ipadm_status_t status;
2378 
2379 	assert(linkid != DATALINK_INVALID_LINKID);
2380 	rcm_log_message(RCM_TRACE1, _("IP: if_configure_ipadm(%u)\n"),
2381 	    linkid);
2382 
2383 	if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
2384 		return (-1);
2385 
2386 	/* Check if the interface is already configured. */
2387 	if (ifinst[0] == '\0')
2388 		return (0);
2389 
2390 	status = ipadm_if_info(ip_handle, ifinst, &ifinfo, 0, LIFC_UNDER_IPMP);
2391 	if (status == IPADM_ENXIO)
2392 		goto done;
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));
2397 		goto fail;
2398 	}
2399 	if (ifinfo != NULL) {
2400 		found = B_FALSE;
2401 		for (ptr = ifinfo; ptr; ptr = ptr->ifi_next) {
2402 			if (strncmp(ptr->ifi_name, ifinst,
2403 			    sizeof (ifinst)) == 0) {
2404 				found = B_TRUE;
2405 				break;
2406 			}
2407 		}
2408 		free(ifinfo);
2409 		if (!found) {
2410 			return (0);
2411 		}
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);
2418 			return (0);
2419 		}
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));
2425 			goto fail;
2426 		}
2427 	}
2428 done:
2429 	rcm_log_message(RCM_TRACE1, "IP: if_configure_ipadm(%s) success\n",
2430 	    ifinst);
2431 	return (0);
2432 fail:
2433 	return (-1);
2434 }
2435 
2436 /*
2437  * isgrouped() - Scans the given config file to see if this interface is
2438  *	         using IPMP.  Returns B_TRUE or B_FALSE.
2439  */
2440 static boolean_t
isgrouped(const char * cfgfile)2441 isgrouped(const char *cfgfile)
2442 {
2443 	FILE *fp;
2444 	struct stat statb;
2445 	char *nlp, *line, *token, *lasts, *buf;
2446 	boolean_t grouped = B_FALSE;
2447 
2448 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile);
2449 
2450 	if (stat(cfgfile, &statb) != 0) {
2451 		rcm_log_message(RCM_TRACE1,
2452 		    _("IP: No config file(%s)\n"), cfgfile);
2453 		return (B_FALSE);
2454 	}
2455 
2456 	/*
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.
2461 	 */
2462 	if (statb.st_size <= 1) {
2463 		rcm_log_message(RCM_TRACE1,
2464 		    _("IP: Empty config file(%s)\n"), cfgfile);
2465 		return (B_FALSE);
2466 	}
2467 
2468 	if ((fp = fopen(cfgfile, "r")) == NULL) {
2469 		rcm_log_message(RCM_ERROR,
2470 		    _("IP: Cannot open configuration file(%s): %s\n"), cfgfile,
2471 		    strerror(errno));
2472 		return (B_FALSE);
2473 	}
2474 
2475 	if ((buf = malloc(statb.st_size)) == NULL) {
2476 		rcm_log_message(RCM_ERROR,
2477 		    _("IP: malloc failure(%s): %s\n"), cfgfile,
2478 		    strerror(errno));
2479 		goto out;
2480 	}
2481 
2482 	while (fgets(buf, statb.st_size, fp) != NULL) {
2483 		if ((nlp = strrchr(buf, '\n')) != NULL)
2484 			*nlp = '\0';
2485 
2486 		line = buf;
2487 		while ((token = strtok_r(line, " \t", &lasts)) != NULL) {
2488 			line = NULL;
2489 			if (STREQ("group", token) &&
2490 			    strtok_r(NULL, " \t", &lasts) != NULL) {
2491 				grouped = B_TRUE;
2492 				goto out;
2493 			}
2494 		}
2495 	}
2496 out:
2497 	free(buf);
2498 	(void) fclose(fp);
2499 
2500 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s): %d\n", cfgfile,
2501 	    grouped);
2502 
2503 	return (grouped);
2504 }
2505 
2506 /*
2507  * if_config_inst() - Configure an interface instance as specified by the
2508  *		    address family af and if it is grouped (ipmp).
2509  */
2510 static int
if_config_inst(const char * ifinst,FILE * hfp,int af,boolean_t ipmp)2511 if_config_inst(const char *ifinst, FILE *hfp, int af, boolean_t ipmp)
2512 {
2513 	FILE *ifparsefp;
2514 	struct stat statb;
2515 	char *buf = NULL;
2516 	char *ifparsebuf = NULL;
2517 	uint_t ifparsebufsize;
2518 	const char *fstr;		/* address family string */
2519 	boolean_t stdif = B_FALSE;
2520 
2521 	rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) ipmp = %d\n",
2522 	    ifinst, ipmp);
2523 
2524 	if (fstat(fileno(hfp), &statb) != 0) {
2525 		rcm_log_message(RCM_ERROR,
2526 		    _("IP: Cannot fstat file(%s)\n"), ifinst);
2527 		goto fail;
2528 	}
2529 
2530 	switch (af) {
2531 	case AF_INET:
2532 		fstr = "inet";
2533 		break;
2534 	case AF_INET6:
2535 		fstr = "inet6";
2536 		break;
2537 	default:
2538 		assert(0);
2539 	}
2540 
2541 	/*
2542 	 * The hostname file exists; plumb the physical interface.
2543 	 */
2544 	if (!ifconfig(ifinst, fstr, "plumb", B_FALSE))
2545 		goto fail;
2546 
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);
2551 		goto configured;
2552 	}
2553 
2554 	if (fseek(hfp, 0, SEEK_SET) == -1) {
2555 		rcm_log_message(RCM_ERROR,
2556 		    _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2557 		    strerror(errno));
2558 		goto fail;
2559 	}
2560 
2561 	/*
2562 	 * Allocate the worst-case single-line buffer sizes.  A bit skanky,
2563 	 * but since hostname files are small, this should suffice.
2564 	 */
2565 	if ((buf = calloc(1, statb.st_size)) == NULL) {
2566 		rcm_log_message(RCM_ERROR,
2567 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2568 		goto fail;
2569 	}
2570 
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));
2575 		goto fail;
2576 	}
2577 
2578 	/*
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".
2582 	 */
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");
2587 		stdif = B_TRUE;
2588 	}
2589 
2590 	if (fseek(hfp, 0L, SEEK_SET) == -1) {
2591 		rcm_log_message(RCM_ERROR,
2592 		    _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2593 		    strerror(errno));
2594 		goto fail;
2595 	}
2596 
2597 	/*
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.
2602 	 */
2603 	while (fgets(buf, statb.st_size, hfp) != NULL) {
2604 		if (ntok(buf) == 0)
2605 			continue;
2606 
2607 		if (!ipmp) {
2608 			(void) ifconfig(ifinst, fstr, buf, stdif);
2609 			continue;
2610 		}
2611 
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));
2618 			goto fail;
2619 		}
2620 
2621 		while (fgets(buf, statb.st_size, ifparsefp) != NULL) {
2622 			if (ntok(buf) > 0)
2623 				(void) ifconfig(ifinst, fstr, buf, stdif);
2624 		}
2625 
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));
2630 			goto fail;
2631 		}
2632 	}
2633 
2634 configured:
2635 	/*
2636 	 * Bring up the interface (it may already be up)
2637 	 *
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.
2647 	 */
2648 	if ((af == AF_INET6 || ipmp) && !ifconfig(ifinst, fstr, "up", B_FALSE))
2649 		goto fail;
2650 
2651 	/*
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.
2656 	 */
2657 	if (af == AF_INET) {
2658 		char dhcpfile[MAXPATHLEN];
2659 		char *dhcpbuf;
2660 		off_t i, dhcpsize;
2661 
2662 		(void) snprintf(dhcpfile, MAXPATHLEN, DHCPFILE_FMT, ifinst);
2663 		if (stat(dhcpfile, &statb) == -1)
2664 			goto out;
2665 
2666 		if ((dhcpbuf = copylist(dhcpfile, &dhcpsize)) == NULL) {
2667 			rcm_log_message(RCM_ERROR, _("IP: cannot read "
2668 			    "(%s): %s\n"), dhcpfile, strerror(errno));
2669 			goto fail;
2670 		}
2671 
2672 		/*
2673 		 * The copylist() API converts \n's to \0's, but we want them
2674 		 * to be spaces.
2675 		 */
2676 		if (dhcpsize > 0) {
2677 			for (i = 0; i < dhcpsize; i++)
2678 				if (dhcpbuf[i] == '\0')
2679 					dhcpbuf[i] = ' ';
2680 			dhcpbuf[dhcpsize - 1] = '\0';
2681 		}
2682 		(void) ifconfig(ifinst, CFG_DHCP_CMD, dhcpbuf, B_FALSE);
2683 		free(dhcpbuf);
2684 	}
2685 out:
2686 	free(ifparsebuf);
2687 	free(buf);
2688 	rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) success\n", ifinst);
2689 	return (0);
2690 fail:
2691 	free(ifparsebuf);
2692 	free(buf);
2693 	rcm_log_message(RCM_ERROR, "IP: if_config_inst(%s) failure\n", ifinst);
2694 	return (-1);
2695 }
2696 
2697 /*
2698  * ntok() - count the number of tokens in the provided buffer.
2699  */
2700 static uint_t
ntok(const char * cp)2701 ntok(const char *cp)
2702 {
2703 	uint_t ntok = 0;
2704 
2705 	for (;;) {
2706 		while (ISSPACE(*cp))
2707 			cp++;
2708 
2709 		if (ISEOL(*cp))
2710 			break;
2711 
2712 		do {
2713 			cp++;
2714 		} while (!ISSPACE(*cp) && !ISEOL(*cp));
2715 
2716 		ntok++;
2717 	}
2718 	return (ntok);
2719 }
2720 
2721 static boolean_t
ifconfig(const char * ifinst,const char * fstr,const char * buf,boolean_t stdif)2722 ifconfig(const char *ifinst, const char *fstr, const char *buf, boolean_t stdif)
2723 {
2724 	char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
2725 	int status;
2726 
2727 	(void) snprintf(syscmd, sizeof (syscmd), SBIN_IFCONFIG " %s %s %s",
2728 	    ifinst, fstr, buf);
2729 
2730 	if (stdif)
2731 		(void) strlcat(syscmd, CFG_CMDS_STD, sizeof (syscmd));
2732 
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));
2738 		} else {
2739 			rcm_log_message(RCM_ERROR, _("IP: Error: %s: %s\n"),
2740 			    syscmd, strerror(errno));
2741 		}
2742 		return (B_FALSE);
2743 	}
2744 	return (B_TRUE);
2745 }
2746 
2747 /*
2748  * Return TRUE if a writeable /etc/hostname[6].ifname file exists.
2749  */
2750 static boolean_t
if_hostname_exists(char * ifname,sa_family_t af)2751 if_hostname_exists(char *ifname, sa_family_t af)
2752 {
2753 	char cfgfile[MAXPATHLEN];
2754 
2755 	if (af == AF_INET) {
2756 		(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifname);
2757 		if (access(cfgfile, W_OK|F_OK) == 0)
2758 			return (B_TRUE);
2759 	} else if (af == AF_INET6) {
2760 		(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifname);
2761 		if (access(cfgfile, W_OK|F_OK) == 0)
2762 			return (B_TRUE);
2763 	}
2764 	return (B_FALSE);
2765 }
2766