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 * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
24 */
25
26 /*
27 * This RCM module adds support to the RCM framework for IP managed
28 * interfaces.
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <assert.h>
35 #include <string.h>
36 #include <synch.h>
37 #include <libintl.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <sys/types.h>
41 #include <sys/wait.h>
42 #include <sys/stat.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <stropts.h>
49 #include <strings.h>
50 #include <sys/sysmacros.h>
51 #include <inet/ip.h>
52 #include <libinetutil.h>
53 #include <libdllink.h>
54 #include <libgen.h>
55 #include <ipmp_admin.h>
56 #include <libipadm.h>
57
58 #include "rcm_module.h"
59
60 /*
61 * Definitions
62 */
63 #ifndef lint
64 #define _(x) gettext(x)
65 #else
66 #define _(x) x
67 #endif
68
69 /* Some generic well-knowns and defaults used in this module */
70 #define ARP_MOD_NAME "arp" /* arp module */
71 #define IP_MAX_MODS 9 /* max modules pushed on intr */
72 #define MAX_RECONFIG_SIZE 1024 /* Max. reconfig string size */
73
74 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
75 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
76
77 #define RCM_STR_SUNW_IP "SUNW_ip/" /* IP address export prefix */
78
79 #define SBIN_IFCONFIG "/sbin/ifconfig" /* ifconfig command */
80 #define SBIN_IFPARSE "/sbin/ifparse" /* ifparse command */
81 #define DHCPFILE_FMT "/etc/dhcp.%s" /* DHCP config file */
82 #define CFGFILE_FMT_IPV4 "/etc/hostname.%s" /* IPV4 config file */
83 #define CFGFILE_FMT_IPV6 "/etc/hostname6.%s" /* IPV6 config file */
84 #define CFG_CMDS_STD " netmask + broadcast + up" /* Normal config string */
85 #define CFG_DHCP_CMD "dhcp wait 0" /* command to start DHCP */
86
87 /* Some useful macros */
88 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
89 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
90 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
91
92 /* Interface Cache state flags */
93 #define CACHE_IF_STALE 0x1 /* stale cached data */
94 #define CACHE_IF_NEW 0x2 /* new cached interface */
95 #define CACHE_IF_OFFLINED 0x4 /* interface offlined */
96 #define CACHE_IF_IGNORE 0x8 /* state held elsewhere */
97
98 /* Network Cache lookup options */
99 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
100 #define CACHE_REFRESH 0x2 /* refresh cache */
101
102 /* RCM IPMP Module specific property definitions */
103 #define RCM_IPMP_MIN_REDUNDANCY 1 /* default min. redundancy */
104
105 /* Stream module operations */
106 #define MOD_INSERT 0 /* Insert a mid-stream module */
107 #define MOD_REMOVE 1 /* Remove a mid-stream module */
108 #define MOD_CHECK 2 /* Check mid-stream module safety */
109
110 /*
111 * IP module data types
112 */
113
114 /* Physical interface representation */
115 typedef struct ip_pif {
116 char pi_ifname[LIFNAMSIZ]; /* interface name */
117 char pi_grname[LIFGRNAMSIZ]; /* IPMP group name */
118 struct ip_lif *pi_lifs; /* ptr to logical interfaces */
119 } ip_pif_t;
120
121 /* Logical interface representation */
122 typedef struct ip_lif
123 {
124 struct ip_lif *li_next; /* ptr to next lif */
125 struct ip_lif *li_prev; /* previous next ptr */
126 ip_pif_t *li_pif; /* back ptr to phy int */
127 ushort_t li_ifnum; /* interface number */
128 union {
129 sa_family_t family;
130 struct sockaddr_storage storage;
131 struct sockaddr_in ip4; /* IPv4 */
132 struct sockaddr_in6 ip6; /* IPv6 */
133 } li_addr;
134 uint64_t li_ifflags; /* current IFF_* flags */
135 int li_modcnt; /* # of modules */
136 char *li_modules[IP_MAX_MODS]; /* module list pushed */
137 char *li_reconfig; /* Reconfiguration string */
138 int32_t li_cachestate; /* cache state flags */
139 } ip_lif_t;
140
141 /* Cache element */
142 typedef struct ip_cache
143 {
144 struct ip_cache *ip_next; /* next cached resource */
145 struct ip_cache *ip_prev; /* prev cached resource */
146 char *ip_resource; /* resource name */
147 ip_pif_t *ip_pif; /* ptr to phy int */
148 int32_t ip_ifred; /* min. redundancy */
149 int ip_cachestate; /* cache state flags */
150 } ip_cache_t;
151
152 /*
153 * Global cache for network interfaces
154 */
155 static ip_cache_t cache_head;
156 static ip_cache_t cache_tail;
157 static mutex_t cache_lock;
158 static int events_registered = 0;
159
160 static dladm_handle_t dld_handle = NULL;
161 static ipadm_handle_t ip_handle = NULL;
162
163 /*
164 * RCM module interface prototypes
165 */
166 static int ip_register(rcm_handle_t *);
167 static int ip_unregister(rcm_handle_t *);
168 static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t,
169 char **, char **, nvlist_t *, rcm_info_t **);
170 static int ip_suspend(rcm_handle_t *, char *, id_t,
171 timespec_t *, uint_t, char **, rcm_info_t **);
172 static int ip_resume(rcm_handle_t *, char *, id_t, uint_t,
173 char **, rcm_info_t **);
174 static int ip_offline(rcm_handle_t *, char *, id_t, uint_t,
175 char **, rcm_info_t **);
176 static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
177 char **, rcm_info_t **);
178 static int ip_remove(rcm_handle_t *, char *, id_t, uint_t,
179 char **, rcm_info_t **);
180 static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t,
181 char **, nvlist_t *, rcm_info_t **);
182
183 /* Module private routines */
184 static void free_cache();
185 static int update_cache(rcm_handle_t *);
186 static void cache_remove(ip_cache_t *);
187 static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char);
188 static void free_node(ip_cache_t *);
189 static void cache_insert(ip_cache_t *);
190 static char *ip_usage(ip_cache_t *);
191 static int update_pif(rcm_handle_t *, int, int, struct ifaddrs *);
192 static int ip_ipmp_offline(ip_cache_t *);
193 static int ip_ipmp_undo_offline(ip_cache_t *);
194 static int if_cfginfo(ip_cache_t *, uint_t);
195 static int if_unplumb(ip_cache_t *);
196 static int if_replumb(ip_cache_t *);
197 static void ip_log_err(ip_cache_t *, char **, char *);
198 static char *get_link_resource(const char *);
199 static void clr_cfg_state(ip_pif_t *);
200 static int modop(char *, char *, int, char);
201 static int get_modlist(char *, ip_lif_t *);
202 static int ip_domux2fd(int *, int *, int *, struct lifreq *);
203 static int ip_plink(int, int, int, struct lifreq *);
204 static int ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
205 rcm_info_t **);
206 static int ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
207 rcm_info_t **);
208 static char **ip_get_addrlist(ip_cache_t *);
209 static void ip_free_addrlist(char **);
210 static void ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **,
211 uint_t, rcm_info_t **);
212 static boolean_t ip_addrstr(ip_lif_t *, char *, size_t);
213
214 static int if_configure_hostname(datalink_id_t);
215 static int if_configure_ipadm(datalink_id_t);
216 static boolean_t if_hostname_exists(char *, sa_family_t);
217 static boolean_t isgrouped(const char *);
218 static int if_config_inst(const char *, FILE *, int, boolean_t);
219 static uint_t ntok(const char *cp);
220 static boolean_t ifconfig(const char *, const char *, const char *, boolean_t);
221
222 /* Module-Private data */
223 static struct rcm_mod_ops ip_ops =
224 {
225 RCM_MOD_OPS_VERSION,
226 ip_register,
227 ip_unregister,
228 ip_get_info,
229 ip_suspend,
230 ip_resume,
231 ip_offline,
232 ip_undo_offline,
233 ip_remove,
234 NULL,
235 NULL,
236 ip_notify_event
237 };
238
239 /*
240 * rcm_mod_init() - Update registrations, and return the ops structure.
241 */
242 struct rcm_mod_ops *
rcm_mod_init(void)243 rcm_mod_init(void)
244 {
245 char errmsg[DLADM_STRSIZE];
246 dladm_status_t status;
247 ipadm_status_t iph_status;
248
249 rcm_log_message(RCM_TRACE1, "IP: mod_init\n");
250
251 cache_head.ip_next = &cache_tail;
252 cache_head.ip_prev = NULL;
253 cache_tail.ip_prev = &cache_head;
254 cache_tail.ip_next = NULL;
255 (void) mutex_init(&cache_lock, USYNC_THREAD, NULL);
256
257 if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
258 rcm_log_message(RCM_WARNING,
259 "IP: mod_init failed: cannot get datalink handle: %s\n",
260 dladm_status2str(status, errmsg));
261 return (NULL);
262 }
263
264 if ((iph_status = ipadm_open(&ip_handle, 0)) != IPADM_SUCCESS) {
265 rcm_log_message(RCM_ERROR,
266 "IP: mod_init failed: cannot get IP handle: %s\n",
267 ipadm_status2str(iph_status));
268 dladm_close(dld_handle);
269 dld_handle = NULL;
270 return (NULL);
271 }
272
273 /* Return the ops vectors */
274 return (&ip_ops);
275 }
276
277 /*
278 * rcm_mod_info() - Return a string describing this module.
279 */
280 const char *
rcm_mod_info(void)281 rcm_mod_info(void)
282 {
283 rcm_log_message(RCM_TRACE1, "IP: mod_info\n");
284
285 return ("IP Multipathing module version 1.23");
286 }
287
288 /*
289 * rcm_mod_fini() - Destroy the network interfaces cache.
290 */
291 int
rcm_mod_fini(void)292 rcm_mod_fini(void)
293 {
294 rcm_log_message(RCM_TRACE1, "IP: mod_fini\n");
295
296 free_cache();
297 (void) mutex_destroy(&cache_lock);
298
299 dladm_close(dld_handle);
300 ipadm_close(ip_handle);
301 return (RCM_SUCCESS);
302 }
303
304 /*
305 * ip_register() - Make sure the cache is properly sync'ed, and its
306 * registrations are in order.
307 */
308 static int
ip_register(rcm_handle_t * hd)309 ip_register(rcm_handle_t *hd)
310 {
311 rcm_log_message(RCM_TRACE1, "IP: register\n");
312
313 /* Guard against bad arguments */
314 assert(hd != NULL);
315
316 if (update_cache(hd) < 0)
317 return (RCM_FAILURE);
318
319 /*
320 * Need to register interest in all new resources
321 * getting attached, so we get attach event notifications
322 */
323 if (!events_registered) {
324 if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
325 != RCM_SUCCESS) {
326 rcm_log_message(RCM_ERROR,
327 _("IP: failed to register %s\n"),
328 RCM_RESOURCE_LINK_NEW);
329 return (RCM_FAILURE);
330 } else {
331 rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
332 RCM_RESOURCE_LINK_NEW);
333 events_registered++;
334 }
335 }
336
337 return (RCM_SUCCESS);
338 }
339
340 /*
341 * ip_unregister() - Walk the cache, unregistering all the networks.
342 */
343 static int
ip_unregister(rcm_handle_t * hd)344 ip_unregister(rcm_handle_t *hd)
345 {
346 ip_cache_t *probe;
347
348 rcm_log_message(RCM_TRACE1, "IP: unregister\n");
349
350 /* Guard against bad arguments */
351 assert(hd != NULL);
352
353 /* Walk the cache, unregistering everything */
354 (void) mutex_lock(&cache_lock);
355 probe = cache_head.ip_next;
356 while (probe != &cache_tail) {
357 if (rcm_unregister_interest(hd, probe->ip_resource, 0)
358 != RCM_SUCCESS) {
359 /* unregister failed for whatever reason */
360 (void) mutex_unlock(&cache_lock);
361 return (RCM_FAILURE);
362 }
363 cache_remove(probe);
364 free_node(probe);
365 probe = cache_head.ip_next;
366 }
367 (void) mutex_unlock(&cache_lock);
368
369 /*
370 * Need to unregister interest in all new resources
371 */
372 if (events_registered) {
373 if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
374 != RCM_SUCCESS) {
375 rcm_log_message(RCM_ERROR,
376 _("IP: failed to unregister %s\n"),
377 RCM_RESOURCE_LINK_NEW);
378 return (RCM_FAILURE);
379 } else {
380 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
381 RCM_RESOURCE_LINK_NEW);
382 events_registered--;
383 }
384 }
385
386 return (RCM_SUCCESS);
387 }
388
389 /*
390 * ip_offline() - Offline an interface.
391 */
392 static int
ip_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)393 ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
394 char **errorp, rcm_info_t **depend_info)
395 {
396 ip_cache_t *node;
397 ip_pif_t *pif;
398 boolean_t detachable = B_FALSE;
399 boolean_t ipmp;
400 int retval;
401
402 rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc);
403
404 /* Guard against bad arguments */
405 assert(hd != NULL);
406 assert(rsrc != NULL);
407 assert(id == (id_t)0);
408 assert(errorp != NULL);
409 assert(depend_info != NULL);
410
411 /* Lock the cache and lookup the resource */
412 (void) mutex_lock(&cache_lock);
413 node = cache_lookup(hd, rsrc, CACHE_REFRESH);
414 if (node == NULL) {
415 ip_log_err(node, errorp, "Unrecognized resource");
416 errno = ENOENT;
417 (void) mutex_unlock(&cache_lock);
418 return (RCM_SUCCESS);
419 }
420
421 pif = node->ip_pif;
422
423 /* Establish default detachability criteria */
424 if (flags & RCM_FORCE)
425 detachable = B_TRUE;
426
427 /* Check if the interface is under IPMP */
428 ipmp = (pif->pi_grname[0] != '\0');
429
430 /*
431 * Even if the interface is not under IPMP, it's possible that it's
432 * still okay to offline it as long as there are higher-level failover
433 * mechanisms for the addresses it owns (e.g., clustering). In this
434 * case, ip_offlinelist() will return RCM_SUCCESS, and we charge on.
435 */
436 if (!ipmp && !detachable) {
437 /* Inform consumers of IP addresses being offlined */
438 if (ip_offlinelist(hd, node, errorp, flags, depend_info) ==
439 RCM_SUCCESS) {
440 rcm_log_message(RCM_DEBUG,
441 "IP: consumers agree on detach");
442 } else {
443 ip_log_err(node, errorp,
444 "Device consumers prohibit offline");
445 (void) mutex_unlock(&cache_lock);
446 return (RCM_FAILURE);
447 }
448 }
449
450 /* Check if it's a query */
451 if (flags & RCM_QUERY) {
452 rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n",
453 rsrc);
454 (void) mutex_unlock(&cache_lock);
455 return (RCM_SUCCESS);
456 }
457
458 /* Check detachability, save configuration if detachable */
459 if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) {
460 node->ip_cachestate |= CACHE_IF_IGNORE;
461 rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc);
462 (void) mutex_unlock(&cache_lock);
463 return (RCM_SUCCESS);
464 }
465
466 /* standalone detachable device */
467 if (!ipmp) {
468 if (if_unplumb(node) < 0) {
469 ip_log_err(node, errorp,
470 "Failed to unplumb the device");
471
472 errno = EIO;
473 (void) mutex_unlock(&cache_lock);
474 return (RCM_FAILURE);
475 }
476
477 node->ip_cachestate |= CACHE_IF_OFFLINED;
478 rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc);
479 (void) mutex_unlock(&cache_lock);
480 return (RCM_SUCCESS);
481 }
482
483 /*
484 * This is an IPMP interface that can be offlined.
485 * Request in.mpathd(1M) to offline the physical interface.
486 */
487 if ((retval = ip_ipmp_offline(node)) != IPMP_SUCCESS)
488 ip_log_err(node, errorp, "in.mpathd offline failed");
489
490 if (retval == IPMP_EMINRED && !detachable) {
491 /*
492 * in.mpathd(1M) could not offline the device because it was
493 * the last interface in the group. However, it's possible
494 * that it's still okay to offline it as long as there are
495 * higher-level failover mechanisms for the addresses it owns
496 * (e.g., clustering). In this case, ip_offlinelist() will
497 * return RCM_SUCCESS, and we charge on.
498 */
499 /* Inform consumers of IP addresses being offlined */
500 if (ip_offlinelist(hd, node, errorp, flags,
501 depend_info) == RCM_SUCCESS) {
502 rcm_log_message(RCM_DEBUG,
503 "IP: consumers agree on detach");
504 } else {
505 ip_log_err(node, errorp,
506 "Device consumers prohibit offline");
507 (void) mutex_unlock(&cache_lock);
508 errno = EBUSY;
509 return (RCM_FAILURE);
510 }
511 }
512
513 if (if_unplumb(node) < 0) {
514 rcm_log_message(RCM_ERROR,
515 _("IP: Unplumb failed (%s)\n"),
516 pif->pi_ifname);
517
518 /* Request in.mpathd to undo the offline */
519 if (ip_ipmp_undo_offline(node) != IPMP_SUCCESS) {
520 ip_log_err(node, errorp, "Undo offline failed");
521 (void) mutex_unlock(&cache_lock);
522 return (RCM_FAILURE);
523 }
524 (void) mutex_unlock(&cache_lock);
525 return (RCM_FAILURE);
526 }
527
528 node->ip_cachestate |= CACHE_IF_OFFLINED;
529 rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc);
530 (void) mutex_unlock(&cache_lock);
531 return (RCM_SUCCESS);
532 }
533
534 /*
535 * ip_undo_offline() - Undo offline of a previously offlined device.
536 */
537 /*ARGSUSED*/
538 static int
ip_undo_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)539 ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
540 char **errorp, rcm_info_t **depend_info)
541 {
542 ip_cache_t *node;
543
544 rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc);
545
546 /* Guard against bad arguments */
547 assert(hd != NULL);
548 assert(rsrc != NULL);
549 assert(id == (id_t)0);
550 assert(errorp != NULL);
551 assert(depend_info != NULL);
552
553 (void) mutex_lock(&cache_lock);
554 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
555
556 if (node == NULL) {
557 ip_log_err(node, errorp, "No such device");
558 (void) mutex_unlock(&cache_lock);
559 errno = ENOENT;
560 return (RCM_FAILURE);
561 }
562
563 /* Check if no attempt should be made to online the device here */
564 if (node->ip_cachestate & CACHE_IF_IGNORE) {
565 node->ip_cachestate &= ~(CACHE_IF_IGNORE);
566 (void) mutex_unlock(&cache_lock);
567 return (RCM_SUCCESS);
568 }
569
570 /* Check if the interface was previously offlined */
571 if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) {
572 ip_log_err(node, errorp, "Device not offlined");
573 (void) mutex_unlock(&cache_lock);
574 errno = ENOTSUP;
575 return (RCM_FAILURE);
576 }
577
578 if (if_replumb(node) == -1) {
579 /* re-plumb failed */
580 ip_log_err(node, errorp, "Replumb failed");
581 (void) mutex_unlock(&cache_lock);
582 errno = EIO;
583 return (RCM_FAILURE);
584
585 }
586
587 /* Inform consumers about IP addresses being un-offlined */
588 (void) ip_onlinelist(hd, node, errorp, flags, depend_info);
589
590 node->ip_cachestate &= ~(CACHE_IF_OFFLINED);
591 rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc);
592 (void) mutex_unlock(&cache_lock);
593 return (RCM_SUCCESS);
594 }
595
596 /*
597 * ip_get_info() - Gather usage information for this resource.
598 */
599 /*ARGSUSED*/
600 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)601 ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
602 char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info)
603 {
604 ip_cache_t *node;
605 char *infostr;
606
607 /* Guard against bad arguments */
608 assert(hd != NULL);
609 assert(rsrc != NULL);
610 assert(id == (id_t)0);
611 assert(usagep != NULL);
612 assert(errorp != NULL);
613 assert(depend_info != NULL);
614
615 rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc);
616
617 (void) mutex_lock(&cache_lock);
618 node = cache_lookup(hd, rsrc, CACHE_REFRESH);
619 if (!node) {
620 rcm_log_message(RCM_INFO,
621 _("IP: get_info(%s) unrecognized resource\n"), rsrc);
622 (void) mutex_unlock(&cache_lock);
623 errno = ENOENT;
624 return (RCM_FAILURE);
625 }
626
627 infostr = ip_usage(node);
628
629 if (infostr == NULL) {
630 /* most likely malloc failure */
631 rcm_log_message(RCM_ERROR,
632 _("IP: get_info(%s) malloc failure\n"), rsrc);
633 (void) mutex_unlock(&cache_lock);
634 errno = ENOMEM;
635 *errorp = NULL;
636 return (RCM_FAILURE);
637 }
638
639 /* Set client/role properties */
640 (void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP");
641
642 /* Set usage property, infostr will be freed by caller */
643 *usagep = infostr;
644
645 rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n",
646 rsrc, infostr);
647
648 (void) mutex_unlock(&cache_lock);
649 return (RCM_SUCCESS);
650 }
651
652 /*
653 * ip_suspend() - Nothing to do, always okay
654 */
655 /*ARGSUSED*/
656 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)657 ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
658 uint_t flags, char **errorp, rcm_info_t **depend_info)
659 {
660 /* Guard against bad arguments */
661 assert(hd != NULL);
662 assert(rsrc != NULL);
663 assert(id == (id_t)0);
664 assert(interval != NULL);
665 assert(errorp != NULL);
666 assert(depend_info != NULL);
667
668 rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc);
669 return (RCM_SUCCESS);
670 }
671
672 /*
673 * ip_resume() - Nothing to do, always okay
674 */
675 /*ARGSUSED*/
676 static int
ip_resume(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)677 ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
678 char **errorp, rcm_info_t ** depend_info)
679 {
680 /* Guard against bad arguments */
681 assert(hd != NULL);
682 assert(rsrc != NULL);
683 assert(id == (id_t)0);
684 assert(errorp != NULL);
685 assert(depend_info != NULL);
686
687 rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc);
688
689 return (RCM_SUCCESS);
690 }
691
692 /*
693 * ip_remove() - remove a resource from cache
694 */
695 /*ARGSUSED*/
696 static int
ip_remove(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)697 ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
698 char **errorp, rcm_info_t **depend_info)
699 {
700 ip_cache_t *node;
701
702 /* Guard against bad arguments */
703 assert(hd != NULL);
704 assert(rsrc != NULL);
705 assert(id == (id_t)0);
706 assert(errorp != NULL);
707 assert(depend_info != NULL);
708
709 rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc);
710
711 (void) mutex_lock(&cache_lock);
712 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
713 if (!node) {
714 rcm_log_message(RCM_INFO,
715 _("IP: remove(%s) unrecognized resource\n"), rsrc);
716 (void) mutex_unlock(&cache_lock);
717 errno = ENOENT;
718 return (RCM_FAILURE);
719 }
720
721 /* remove the cached entry for the resource */
722 cache_remove(node);
723 free_node(node);
724
725 (void) mutex_unlock(&cache_lock);
726 return (RCM_SUCCESS);
727 }
728
729 /*
730 * ip_notify_event - Project private implementation to receive new resource
731 * events. It intercepts all new resource events. If the
732 * new resource is a network resource, pass up a notify
733 * for it too. The new resource need not be cached, since
734 * it is done at register again.
735 */
736 /*ARGSUSED*/
737 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)738 ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
739 char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
740 {
741 datalink_id_t linkid;
742 nvpair_t *nvp = NULL;
743 uint64_t id64;
744
745 assert(hd != NULL);
746 assert(rsrc != NULL);
747 assert(id == (id_t)0);
748 assert(nvl != NULL);
749
750 rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc);
751
752 if (!STREQ(rsrc, RCM_RESOURCE_LINK_NEW)) {
753 rcm_log_message(RCM_INFO,
754 _("IP: unrecognized event for %s\n"), rsrc);
755 ip_log_err(NULL, errorp, "unrecognized event");
756 errno = EINVAL;
757 return (RCM_FAILURE);
758 }
759
760 /* Update cache to reflect latest interfaces */
761 if (update_cache(hd) < 0) {
762 rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n"));
763 ip_log_err(NULL, errorp, "Private Cache update failed");
764 return (RCM_FAILURE);
765 }
766
767 rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n");
768 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
769 if (STREQ(nvpair_name(nvp), RCM_NV_LINKID)) {
770 if (nvpair_value_uint64(nvp, &id64) != 0) {
771 rcm_log_message(RCM_WARNING,
772 _("IP: cannot get linkid\n"));
773 return (RCM_FAILURE);
774 }
775 linkid = (datalink_id_t)id64;
776 /*
777 * Grovel through /etc/hostname* files and configure
778 * interface in the same way that they would be handled
779 * by network/physical.
780 */
781 if (if_configure_hostname(linkid) != 0) {
782 rcm_log_message(RCM_ERROR,
783 _("IP: Configuration failed (%u)\n"),
784 linkid);
785 ip_log_err(NULL, errorp,
786 "Failed configuring one or more IP "
787 "addresses");
788 }
789
790 /*
791 * Query libipadm for persistent configuration info
792 * and resurrect that persistent configuration.
793 */
794 if (if_configure_ipadm(linkid) != 0) {
795 rcm_log_message(RCM_ERROR,
796 _("IP: Configuration failed (%u)\n"),
797 linkid);
798 ip_log_err(NULL, errorp,
799 "Failed configuring one or more IP "
800 "addresses");
801 }
802
803 /* Notify all IP address consumers */
804 ip_consumer_notify(hd, linkid, errorp, flags,
805 depend_info);
806 }
807 }
808
809 rcm_log_message(RCM_TRACE1,
810 "IP: notify_event: device configuration complete\n");
811
812 return (RCM_SUCCESS);
813 }
814
815 /*
816 * ip_usage - Determine the usage of a device. Call with cache_lock held.
817 * The returned buffer is owned by caller, and the caller
818 * must free it up when done.
819 */
820 static char *
ip_usage(ip_cache_t * node)821 ip_usage(ip_cache_t *node)
822 {
823 ip_lif_t *lif;
824 uint_t numup;
825 char *sep, *buf, *linkidstr;
826 datalink_id_t linkid;
827 const char *msg;
828 char link[MAXLINKNAMELEN];
829 char addrstr[INET6_ADDRSTRLEN];
830 char errmsg[DLADM_STRSIZE];
831 dladm_status_t status;
832 boolean_t offline, ipmp;
833 size_t bufsz = 0;
834
835 rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource);
836
837 /*
838 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid>
839 */
840 linkidstr = strchr(node->ip_resource, '/');
841 assert(linkidstr != NULL);
842 linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource;
843
844 errno = 0;
845 linkid = strtol(linkidstr, &buf, 10);
846 if (errno != 0 || *buf != '\0') {
847 rcm_log_message(RCM_ERROR,
848 _("IP: usage(%s) parse linkid failure (%s)\n"),
849 node->ip_resource, strerror(errno));
850 return (NULL);
851 }
852
853 if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL, NULL,
854 NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
855 rcm_log_message(RCM_ERROR,
856 _("IP: usage(%s) get link name failure(%s)\n"),
857 node->ip_resource, dladm_status2str(status, errmsg));
858 return (NULL);
859 }
860
861 /* TRANSLATION_NOTE: separator used between IP addresses */
862 sep = _(", ");
863
864 numup = 0;
865 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next)
866 if (lif->li_ifflags & IFF_UP)
867 numup++;
868
869 ipmp = (node->ip_pif->pi_grname[0] != '\0');
870 offline = ((node->ip_cachestate & CACHE_IF_OFFLINED) != 0);
871
872 if (offline) {
873 msg = _("offlined");
874 } else if (numup == 0) {
875 msg = _("plumbed but down");
876 } else {
877 if (ipmp) {
878 msg = _("providing connectivity for IPMP group ");
879 bufsz += LIFGRNAMSIZ;
880 } else {
881 msg = _("hosts IP addresses: ");
882 bufsz += (numup * (INET6_ADDRSTRLEN + strlen(sep)));
883 }
884 }
885
886 bufsz += strlen(link) + strlen(msg) + 1;
887 if ((buf = malloc(bufsz)) == NULL) {
888 rcm_log_message(RCM_ERROR,
889 _("IP: usage(%s) malloc failure(%s)\n"),
890 node->ip_resource, strerror(errno));
891 return (NULL);
892 }
893 (void) snprintf(buf, bufsz, "%s: %s", link, msg);
894
895 if (!offline && numup > 0) {
896 if (ipmp) {
897 (void) strlcat(buf, node->ip_pif->pi_grname, bufsz);
898 } else {
899 lif = node->ip_pif->pi_lifs;
900 for (; lif != NULL; lif = lif->li_next) {
901 if (!(lif->li_ifflags & IFF_UP))
902 continue;
903
904 if (!ip_addrstr(lif, addrstr, sizeof (addrstr)))
905 continue;
906
907 (void) strlcat(buf, addrstr, bufsz);
908 if (--numup > 0)
909 (void) strlcat(buf, sep, bufsz);
910 }
911 }
912 }
913
914 rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
915 node->ip_resource, buf);
916
917 return (buf);
918 }
919
920 static boolean_t
ip_addrstr(ip_lif_t * lif,char * addrstr,size_t addrsize)921 ip_addrstr(ip_lif_t *lif, char *addrstr, size_t addrsize)
922 {
923 int af = lif->li_addr.family;
924 void *addr;
925
926 if (af == AF_INET6) {
927 addr = &lif->li_addr.ip6.sin6_addr;
928 } else if (af == AF_INET) {
929 addr = &lif->li_addr.ip4.sin_addr;
930 } else {
931 rcm_log_message(RCM_DEBUG,
932 "IP: unknown addr family %d, assuming AF_INET\n", af);
933 af = AF_INET;
934 addr = &lif->li_addr.ip4.sin_addr;
935 }
936 if (inet_ntop(af, addr, addrstr, addrsize) == NULL) {
937 rcm_log_message(RCM_ERROR,
938 _("IP: inet_ntop: %s\n"), strerror(errno));
939 return (B_FALSE);
940 }
941
942 rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr);
943 return (B_TRUE);
944 }
945
946 /*
947 * Cache management routines, all cache management functions should be
948 * be called with cache_lock held.
949 */
950
951 /*
952 * cache_lookup() - Get a cache node for a resource.
953 * Call with cache lock held.
954 *
955 * This ensures that the cache is consistent with the system state and
956 * returns a pointer to the cache element corresponding to the resource.
957 */
958 static ip_cache_t *
cache_lookup(rcm_handle_t * hd,char * rsrc,char options)959 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
960 {
961 ip_cache_t *probe;
962
963 rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc);
964
965 if ((options & CACHE_REFRESH) && (hd != NULL)) {
966 /* drop lock since update locks cache again */
967 (void) mutex_unlock(&cache_lock);
968 (void) update_cache(hd);
969 (void) mutex_lock(&cache_lock);
970 }
971
972 probe = cache_head.ip_next;
973 while (probe != &cache_tail) {
974 if (probe->ip_resource &&
975 STREQ(rsrc, probe->ip_resource)) {
976 rcm_log_message(RCM_TRACE2,
977 "IP: cache lookup success(%s)\n", rsrc);
978 return (probe);
979 }
980 probe = probe->ip_next;
981 }
982 return (NULL);
983 }
984
985 /*
986 * free_node - Free a node from the cache
987 * Call with cache_lock held.
988 */
989 static void
free_node(ip_cache_t * node)990 free_node(ip_cache_t *node)
991 {
992 ip_pif_t *pif;
993 ip_lif_t *lif, *tmplif;
994
995 if (node) {
996 if (node->ip_resource) {
997 free(node->ip_resource);
998 }
999
1000 /* free the pif */
1001 pif = node->ip_pif;
1002 if (pif) {
1003 /* free logical interfaces */
1004 lif = pif->pi_lifs;
1005 while (lif) {
1006 tmplif = lif->li_next;
1007 free(lif);
1008 lif = tmplif;
1009 }
1010 free(pif);
1011 }
1012 free(node);
1013 }
1014 }
1015
1016 /*
1017 * cache_insert - Insert a resource node in cache
1018 * Call with the cache_lock held.
1019 */
1020 static void
cache_insert(ip_cache_t * node)1021 cache_insert(ip_cache_t *node)
1022 {
1023 rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n",
1024 node->ip_resource);
1025
1026 /* insert at the head for best performance */
1027 node->ip_next = cache_head.ip_next;
1028 node->ip_prev = &cache_head;
1029
1030 node->ip_next->ip_prev = node;
1031 node->ip_prev->ip_next = node;
1032 }
1033
1034 /*
1035 * cache_remove() - Remove a resource node from cache.
1036 * Call with the cache_lock held.
1037 */
1038 static void
cache_remove(ip_cache_t * node)1039 cache_remove(ip_cache_t *node)
1040 {
1041 rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n",
1042 node->ip_resource);
1043
1044 node->ip_next->ip_prev = node->ip_prev;
1045 node->ip_prev->ip_next = node->ip_next;
1046 node->ip_next = NULL;
1047 node->ip_prev = NULL;
1048 }
1049
1050 /*
1051 * update_pif() - Update physical interface properties
1052 * Call with cache_lock held
1053 */
1054 int
update_pif(rcm_handle_t * hd,int af,int sock,struct ifaddrs * ifa)1055 update_pif(rcm_handle_t *hd, int af, int sock, struct ifaddrs *ifa)
1056 {
1057 char *rsrc;
1058 ifspec_t ifspec;
1059 ushort_t ifnumber = 0;
1060 ip_cache_t *probe;
1061 ip_pif_t pif;
1062 ip_pif_t *probepif;
1063 ip_lif_t *probelif;
1064 struct lifreq lifreq;
1065 struct sockaddr_storage ifaddr;
1066 uint64_t ifflags;
1067 int lif_listed = 0;
1068
1069 rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", ifa->ifa_name);
1070
1071 if (!ifparse_ifspec(ifa->ifa_name, &ifspec)) {
1072 rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"),
1073 ifa->ifa_name);
1074 return (-1);
1075 }
1076
1077 (void) snprintf(pif.pi_ifname, sizeof (pif.pi_ifname), "%s%d",
1078 ifspec.ifsp_devnm, ifspec.ifsp_ppa);
1079 if (ifspec.ifsp_lunvalid)
1080 ifnumber = ifspec.ifsp_lun;
1081
1082 /* Get the interface flags */
1083 ifflags = ifa->ifa_flags;
1084
1085 /*
1086 * Ignore interfaces that are always incapable of DR:
1087 * - IFF_VIRTUAL: e.g., loopback and vni
1088 * - IFF_POINTOPOINT: e.g., sppp and ip.tun
1089 * - !IFF_MULTICAST: e.g., ip.6to4tun
1090 * - IFF_IPMP: IPMP meta-interfaces
1091 *
1092 * Note: The !IFF_MULTICAST check can be removed once iptun is
1093 * implemented as a datalink.
1094 */
1095 if (!(ifflags & IFF_MULTICAST) ||
1096 (ifflags & (IFF_POINTOPOINT | IFF_VIRTUAL | IFF_IPMP))) {
1097 rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n",
1098 pif.pi_ifname);
1099 return (0);
1100 }
1101
1102 /* Get the interface group name for this interface */
1103 bzero(&lifreq, sizeof (lifreq));
1104 (void) strncpy(lifreq.lifr_name, ifa->ifa_name, LIFNAMSIZ);
1105
1106 if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) {
1107 if (errno != ENXIO) {
1108 rcm_log_message(RCM_ERROR,
1109 _("IP: SIOCGLIFGROUPNAME(%s): %s\n"),
1110 lifreq.lifr_name, strerror(errno));
1111 }
1112 return (-1);
1113 }
1114
1115 /* copy the group name */
1116 (void) strlcpy(pif.pi_grname, lifreq.lifr_groupname,
1117 sizeof (pif.pi_grname));
1118
1119 /* Get the interface address for this interface */
1120 (void) memcpy(&ifaddr, ifa->ifa_addr, sizeof (ifaddr));
1121
1122 rsrc = get_link_resource(pif.pi_ifname);
1123 if (rsrc == NULL) {
1124 rcm_log_message(RCM_ERROR,
1125 _("IP: get_link_resource(%s) failed\n"),
1126 lifreq.lifr_name);
1127 return (-1);
1128 }
1129
1130 probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
1131 if (probe != NULL) {
1132 free(rsrc);
1133 probe->ip_cachestate &= ~(CACHE_IF_STALE);
1134 } else {
1135 if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) {
1136 /* malloc errors are bad */
1137 free(rsrc);
1138 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1139 strerror(errno));
1140 return (-1);
1141 }
1142
1143 probe->ip_resource = rsrc;
1144 probe->ip_pif = NULL;
1145 probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY;
1146 probe->ip_cachestate |= CACHE_IF_NEW;
1147
1148 cache_insert(probe);
1149 }
1150
1151 probepif = probe->ip_pif;
1152 if (probepif != NULL) {
1153 /* Check if lifs need to be updated */
1154 probelif = probepif->pi_lifs;
1155 while (probelif != NULL) {
1156 if ((probelif->li_ifnum == ifnumber) &&
1157 (probelif->li_addr.family == ifaddr.ss_family)) {
1158
1159 rcm_log_message(RCM_TRACE2,
1160 "IP: refreshing lifs for %s, ifnum=%d\n",
1161 pif.pi_ifname, probelif->li_ifnum);
1162
1163 /* refresh lif properties */
1164 (void) memcpy(&probelif->li_addr, &ifaddr,
1165 sizeof (probelif->li_addr));
1166
1167 probelif->li_ifflags = ifflags;
1168
1169 lif_listed++;
1170 probelif->li_cachestate &= ~(CACHE_IF_STALE);
1171 break;
1172 }
1173 probelif = probelif->li_next;
1174 }
1175 }
1176
1177 if (probepif == NULL) {
1178 if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) {
1179 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1180 strerror(errno));
1181 if (probe->ip_pif == NULL) {
1182 /* we created it, so clean it up */
1183 free(probe);
1184 }
1185 return (-1);
1186 }
1187
1188 probe->ip_pif = probepif;
1189
1190 /* Save interface name */
1191 (void) memcpy(&probepif->pi_ifname, &pif.pi_ifname,
1192 sizeof (pif.pi_ifname));
1193 }
1194
1195 /* save the group name */
1196 (void) strlcpy(probepif->pi_grname, pif.pi_grname,
1197 sizeof (pif.pi_grname));
1198
1199 /* add lif, if this is a lif and it is not in cache */
1200 if (!lif_listed) {
1201 rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n",
1202 pif.pi_ifname);
1203
1204 if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) {
1205 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1206 strerror(errno));
1207 return (-1);
1208 }
1209
1210 /* save lif properties */
1211 (void) memcpy(&probelif->li_addr, &ifaddr,
1212 sizeof (probelif->li_addr));
1213
1214 probelif->li_ifnum = ifnumber;
1215 probelif->li_ifflags = ifflags;
1216
1217 /* insert us at the head of the lif list */
1218 probelif->li_next = probepif->pi_lifs;
1219 if (probelif->li_next != NULL) {
1220 probelif->li_next->li_prev = probelif;
1221 }
1222 probelif->li_prev = NULL;
1223 probelif->li_pif = probepif;
1224
1225 probepif->pi_lifs = probelif;
1226 }
1227
1228 rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n",
1229 probe->ip_resource);
1230
1231 return (0);
1232 }
1233
1234 /*
1235 * update_ipifs() - Determine all network interfaces in the system
1236 * Call with cache_lock held
1237 */
1238 static int
update_ipifs(rcm_handle_t * hd,int af)1239 update_ipifs(rcm_handle_t *hd, int af)
1240 {
1241
1242 struct ifaddrs *ifa;
1243 ipadm_addr_info_t *ainfo;
1244 ipadm_addr_info_t *ptr;
1245 ipadm_status_t status;
1246 int sock;
1247
1248 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
1249 rcm_log_message(RCM_ERROR,
1250 _("IP: failure opening %s socket: %s\n"),
1251 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
1252 return (-1);
1253 }
1254
1255 status = ipadm_addr_info(ip_handle, NULL, &ainfo, IPADM_OPT_ZEROADDR,
1256 LIFC_UNDER_IPMP);
1257 if (status != IPADM_SUCCESS) {
1258 (void) close(sock);
1259 return (-1);
1260 }
1261 for (ptr = ainfo; ptr; ptr = IA_NEXT(ptr)) {
1262 ifa = &ptr->ia_ifa;
1263 if (ptr->ia_state != IFA_DISABLED &&
1264 af == ifa->ifa_addr->sa_family)
1265 (void) update_pif(hd, af, sock, ifa);
1266 }
1267 (void) close(sock);
1268 ipadm_free_addr_info(ainfo);
1269 return (0);
1270 }
1271
1272 /*
1273 * update_cache() - Update cache with latest interface info
1274 */
1275 static int
update_cache(rcm_handle_t * hd)1276 update_cache(rcm_handle_t *hd)
1277 {
1278 ip_cache_t *probe;
1279 struct ip_lif *lif;
1280 struct ip_lif *nextlif;
1281 int rv;
1282 int i;
1283
1284 rcm_log_message(RCM_TRACE2, "IP: update_cache\n");
1285
1286 (void) mutex_lock(&cache_lock);
1287
1288 /* first we walk the entire cache, marking each entry stale */
1289 probe = cache_head.ip_next;
1290 while (probe != &cache_tail) {
1291 probe->ip_cachestate |= CACHE_IF_STALE;
1292 if ((probe->ip_pif != NULL) &&
1293 ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1294 while (lif != NULL) {
1295 lif->li_cachestate |= CACHE_IF_STALE;
1296 lif = lif->li_next;
1297 }
1298 }
1299 probe = probe->ip_next;
1300 }
1301
1302 rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n");
1303 if (update_ipifs(hd, AF_INET) < 0) {
1304 (void) mutex_unlock(&cache_lock);
1305 return (-1);
1306 }
1307
1308 rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n");
1309 if (update_ipifs(hd, AF_INET6) < 0) {
1310 (void) mutex_unlock(&cache_lock);
1311 return (-1);
1312 }
1313
1314 probe = cache_head.ip_next;
1315 /* unregister devices that are not offlined and still in cache */
1316 while (probe != &cache_tail) {
1317 ip_cache_t *freeit;
1318 if ((probe->ip_pif != NULL) &&
1319 ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1320 /* clear stale lifs */
1321 while (lif != NULL) {
1322 if (lif->li_cachestate & CACHE_IF_STALE) {
1323 nextlif = lif->li_next;
1324 if (lif->li_prev != NULL)
1325 lif->li_prev->li_next = nextlif;
1326 if (nextlif != NULL)
1327 nextlif->li_prev = lif->li_prev;
1328 if (probe->ip_pif->pi_lifs == lif)
1329 probe->ip_pif->pi_lifs =
1330 nextlif;
1331 for (i = 0; i < IP_MAX_MODS; i++) {
1332 free(lif->li_modules[i]);
1333 }
1334 free(lif->li_reconfig);
1335 free(lif);
1336 lif = nextlif;
1337 } else {
1338 lif = lif->li_next;
1339 }
1340 }
1341 }
1342 if ((probe->ip_cachestate & CACHE_IF_STALE) &&
1343 !(probe->ip_cachestate & CACHE_IF_OFFLINED)) {
1344 (void) rcm_unregister_interest(hd, probe->ip_resource,
1345 0);
1346 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
1347 probe->ip_resource);
1348 freeit = probe;
1349 probe = probe->ip_next;
1350 cache_remove(freeit);
1351 free_node(freeit);
1352 continue;
1353 }
1354
1355 if (!(probe->ip_cachestate & CACHE_IF_NEW)) {
1356 probe = probe->ip_next;
1357 continue;
1358 }
1359
1360 rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL);
1361 if (rv != RCM_SUCCESS) {
1362 rcm_log_message(RCM_ERROR,
1363 _("IP: failed to register %s\n"),
1364 probe->ip_resource);
1365 (void) mutex_unlock(&cache_lock);
1366 return (-1);
1367 } else {
1368 rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
1369 probe->ip_resource);
1370 probe->ip_cachestate &= ~(CACHE_IF_NEW);
1371 }
1372 probe = probe->ip_next;
1373 }
1374
1375 (void) mutex_unlock(&cache_lock);
1376 return (0);
1377 }
1378
1379 /*
1380 * free_cache() - Empty the cache
1381 */
1382 static void
free_cache()1383 free_cache()
1384 {
1385 ip_cache_t *probe;
1386
1387 rcm_log_message(RCM_TRACE2, "IP: free_cache\n");
1388
1389 (void) mutex_lock(&cache_lock);
1390 probe = cache_head.ip_next;
1391 while (probe != &cache_tail) {
1392 cache_remove(probe);
1393 free_node(probe);
1394 probe = cache_head.ip_next;
1395 }
1396 (void) mutex_unlock(&cache_lock);
1397 }
1398
1399 /*
1400 * ip_log_err() - RCM error log wrapper
1401 */
1402 static void
ip_log_err(ip_cache_t * node,char ** errorp,char * errmsg)1403 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
1404 {
1405 char *ifname = NULL;
1406 int size;
1407 const char *errfmt;
1408 char *error = NULL;
1409
1410 if ((node != NULL) && (node->ip_pif != NULL) &&
1411 (node->ip_pif->pi_ifname != NULL)) {
1412 ifname = node->ip_pif->pi_ifname;
1413 }
1414
1415 if (ifname == NULL) {
1416 rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg);
1417 errfmt = _("IP: %s");
1418 size = strlen(errfmt) + strlen(errmsg) + 1;
1419 if (errorp != NULL && (error = malloc(size)) != NULL)
1420 (void) snprintf(error, size, errfmt, errmsg);
1421 } else {
1422 rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname);
1423 errfmt = _("IP: %s(%s)");
1424 size = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1;
1425 if (errorp != NULL && (error = malloc(size)) != NULL)
1426 (void) snprintf(error, size, errfmt, errmsg, ifname);
1427 }
1428
1429 if (errorp != NULL)
1430 *errorp = error;
1431 }
1432
1433 /*
1434 * if_cfginfo() - Save off the config info for all interfaces
1435 */
1436 static int
if_cfginfo(ip_cache_t * node,uint_t force)1437 if_cfginfo(ip_cache_t *node, uint_t force)
1438 {
1439 ip_lif_t *lif;
1440 ip_pif_t *pif;
1441 int i;
1442 FILE *fp;
1443 char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
1444 char buf[MAX_RECONFIG_SIZE];
1445
1446 rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource);
1447
1448 pif = node->ip_pif;
1449 lif = pif->pi_lifs;
1450
1451 while (lif != NULL) {
1452 /* Make a list of modules pushed and save */
1453 if (lif->li_ifnum == 0) { /* physical instance */
1454 if (get_modlist(pif->pi_ifname, lif) == -1) {
1455 rcm_log_message(RCM_ERROR,
1456 _("IP: get modlist error (%s) %s\n"),
1457 pif->pi_ifname, strerror(errno));
1458 clr_cfg_state(pif);
1459 return (-1);
1460 }
1461
1462 if (!force) {
1463 /* Look if unknown modules have been inserted */
1464 for (i = (lif->li_modcnt - 2); i > 0; i--) {
1465 if (modop(pif->pi_ifname,
1466 lif->li_modules[i],
1467 i, MOD_CHECK) == -1) {
1468 rcm_log_message(RCM_ERROR,
1469 _("IP: module %s@%d\n"),
1470 lif->li_modules[i], i);
1471 clr_cfg_state(pif);
1472 return (-1);
1473 }
1474 }
1475 }
1476
1477 /* Last module is the device driver, so ignore that */
1478 for (i = (lif->li_modcnt - 2); i > 0; i--) {
1479 rcm_log_message(RCM_TRACE2,
1480 "IP: modremove Pos = %d, Module = %s \n",
1481 i, lif->li_modules[i]);
1482 if (modop(pif->pi_ifname, lif->li_modules[i],
1483 i, MOD_REMOVE) == -1) {
1484 while (i != (lif->li_modcnt - 2)) {
1485 if (modop(pif->pi_ifname,
1486 lif->li_modules[i],
1487 i, MOD_INSERT) == -1) {
1488 /* Gross error */
1489 rcm_log_message(
1490 RCM_ERROR,
1491 _("IP: if_cfginfo"
1492 "(%s) %s\n"),
1493 pif->pi_ifname,
1494 strerror(errno));
1495 clr_cfg_state(pif);
1496 return (-1);
1497 }
1498 i++;
1499 }
1500 rcm_log_message(
1501 RCM_ERROR,
1502 _("IP: if_cfginfo(%s): modremove "
1503 "%s failed: %s\n"), pif->pi_ifname,
1504 lif->li_modules[i],
1505 strerror(errno));
1506 clr_cfg_state(pif);
1507 return (-1);
1508 }
1509 }
1510 }
1511
1512 /* Save reconfiguration information */
1513 if (lif->li_ifflags & IFF_IPV4) {
1514 (void) snprintf(syscmd, sizeof (syscmd),
1515 "%s %s:%d configinfo\n", SBIN_IFCONFIG,
1516 pif->pi_ifname, lif->li_ifnum);
1517 } else if (lif->li_ifflags & IFF_IPV6) {
1518 (void) snprintf(syscmd, sizeof (syscmd),
1519 "%s %s:%d inet6 configinfo\n", SBIN_IFCONFIG,
1520 pif->pi_ifname, lif->li_ifnum);
1521 }
1522 rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd);
1523
1524 /* open a pipe to retrieve reconfiguration info */
1525 if ((fp = popen(syscmd, "r")) == NULL) {
1526 rcm_log_message(RCM_ERROR,
1527 _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1528 pif->pi_ifname, lif->li_ifnum, strerror(errno));
1529 clr_cfg_state(pif);
1530 return (-1);
1531 }
1532 bzero(buf, MAX_RECONFIG_SIZE);
1533
1534 if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) {
1535 rcm_log_message(RCM_ERROR,
1536 _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1537 pif->pi_ifname, lif->li_ifnum, strerror(errno));
1538 (void) pclose(fp);
1539 clr_cfg_state(pif);
1540 return (-1);
1541 }
1542 (void) pclose(fp);
1543
1544 if ((lif->li_reconfig = strdup(buf)) == NULL) {
1545 rcm_log_message(RCM_ERROR,
1546 _("IP: malloc error (%s) %s\n"),
1547 pif->pi_ifname, strerror(errno));
1548 clr_cfg_state(pif);
1549 return (-1);
1550 }
1551 rcm_log_message(RCM_DEBUG,
1552 "IP: if_cfginfo: reconfig string(%s:%d) = %s\n",
1553 pif->pi_ifname, lif->li_ifnum, lif->li_reconfig);
1554
1555 lif = lif->li_next;
1556 }
1557
1558 return (0);
1559 }
1560
1561 /*
1562 * if_unplumb() - Unplumb the interface
1563 * Save off the modlist, ifconfig options and unplumb.
1564 * Fail, if an unknown module lives between IP and driver and
1565 * force is not set
1566 * Call with cache_lock held
1567 */
1568 static int
if_unplumb(ip_cache_t * node)1569 if_unplumb(ip_cache_t *node)
1570 {
1571 ip_lif_t *lif;
1572 ip_pif_t *pif = node->ip_pif;
1573 boolean_t ipv4 = B_FALSE;
1574 boolean_t ipv6 = B_FALSE;
1575
1576 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource);
1577
1578 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1579 if (lif->li_ifflags & IFF_IPV4) {
1580 ipv4 = B_TRUE;
1581 } else if (lif->li_ifflags & IFF_IPV6) {
1582 ipv6 = B_TRUE;
1583 } else {
1584 /* Unlikely case */
1585 rcm_log_message(RCM_DEBUG,
1586 "IP: Unplumb ignored (%s:%d)\n",
1587 pif->pi_ifname, lif->li_ifnum);
1588 }
1589 }
1590
1591 if (ipv4 && !ifconfig(pif->pi_ifname, "inet", "unplumb", B_FALSE)) {
1592 rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
1593 pif->pi_ifname, strerror(errno));
1594 return (-1);
1595 }
1596
1597 if (ipv6 && !ifconfig(pif->pi_ifname, "inet6", "unplumb", B_FALSE)) {
1598 rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
1599 pif->pi_ifname, strerror(errno));
1600 return (-1);
1601 }
1602
1603 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n",
1604 node->ip_resource);
1605
1606 return (0);
1607 }
1608
1609 /*
1610 * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface
1611 * instances and the logical interfaces in order, restoring
1612 * all ifconfig options
1613 * Call with cache_lock held
1614 */
1615 static int
if_replumb(ip_cache_t * node)1616 if_replumb(ip_cache_t *node)
1617 {
1618 ip_lif_t *lif;
1619 ip_pif_t *pif;
1620 int i;
1621 boolean_t success, ipmp;
1622 const char *fstr;
1623 char lifname[LIFNAMSIZ];
1624 char buf[MAX_RECONFIG_SIZE];
1625 int max_lifnum = 0;
1626
1627 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource);
1628
1629 /*
1630 * Be extra careful about bringing up the interfaces in the
1631 * correct order:
1632 * - First plumb in the physical interface instances
1633 * - modinsert the necessary modules@pos
1634 * - Next, add the logical interfaces being careful about
1635 * the order, (follow the cached interface number li_ifnum order)
1636 */
1637
1638 pif = node->ip_pif;
1639 ipmp = (node->ip_pif->pi_grname[0] != '\0');
1640
1641 /*
1642 * Make a first pass to plumb in physical interfaces and get a count
1643 * of the max logical interfaces
1644 */
1645 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1646 max_lifnum = MAX(lif->li_ifnum, max_lifnum);
1647 if (lif->li_ifflags & IFF_IPV4) {
1648 fstr = "inet";
1649 } else if (lif->li_ifflags & IFF_IPV6) {
1650 fstr = "inet6";
1651 } else {
1652 /* Unlikely case */
1653 rcm_log_message(RCM_DEBUG,
1654 "IP: Re-plumb ignored (%s:%d)\n",
1655 pif->pi_ifname, lif->li_ifnum);
1656 continue;
1657 }
1658
1659 /* ignore logical interface instances */
1660 if (lif->li_ifnum != 0)
1661 continue;
1662
1663 if ((lif->li_ifflags & IFF_NOFAILOVER) || !ipmp) {
1664 success = ifconfig("", "", lif->li_reconfig, B_FALSE);
1665 } else {
1666 (void) snprintf(buf, sizeof (buf), "plumb group %s",
1667 pif->pi_grname);
1668 success = ifconfig(pif->pi_ifname, fstr, buf, B_FALSE);
1669 }
1670
1671 if (!success) {
1672 rcm_log_message(RCM_ERROR,
1673 _("IP: Cannot plumb (%s) %s\n"), pif->pi_ifname,
1674 strerror(errno));
1675 return (-1);
1676 }
1677
1678 /*
1679 * Restart DHCP if necessary.
1680 */
1681 if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1682 !ifconfig(pif->pi_ifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1683 rcm_log_message(RCM_ERROR, _("IP: Cannot start DHCP "
1684 "(%s) %s\n"), pif->pi_ifname, strerror(errno));
1685 return (-1);
1686 }
1687
1688 rcm_log_message(RCM_TRACE2,
1689 "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt);
1690 /* modinsert modules in order, ignore driver(last) */
1691 for (i = 0; i < (lif->li_modcnt - 1); i++) {
1692 rcm_log_message(RCM_TRACE2,
1693 "IP: modinsert: Pos = %d Mod = %s\n",
1694 i, lif->li_modules[i]);
1695 if (modop(pif->pi_ifname, lif->li_modules[i], i,
1696 MOD_INSERT) == -1) {
1697 rcm_log_message(RCM_ERROR,
1698 _("IP: modinsert error(%s)\n"),
1699 pif->pi_ifname);
1700 return (-1);
1701 }
1702 }
1703 }
1704
1705 /* Now, add all the logical interfaces in the correct order */
1706 for (i = 1; i <= max_lifnum; i++) {
1707 (void) snprintf(lifname, LIFNAMSIZ, "%s:%d", pif->pi_ifname, i);
1708
1709 /* reset lif through every iteration */
1710 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1711 /*
1712 * Process entries in order. If the interface is
1713 * using IPMP, only process test addresses.
1714 */
1715 if (lif->li_ifnum != i ||
1716 (ipmp && !(lif->li_ifflags & IFF_NOFAILOVER)))
1717 continue;
1718
1719 if (!ifconfig("", "", lif->li_reconfig, B_FALSE)) {
1720 rcm_log_message(RCM_ERROR,
1721 _("IP: Cannot addif (%s) %s\n"), lifname,
1722 strerror(errno));
1723 return (-1);
1724 }
1725
1726 /*
1727 * Restart DHCP if necessary.
1728 */
1729 if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1730 !ifconfig(lifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1731 rcm_log_message(RCM_ERROR,
1732 _("IP: Cannot start DHCP (%s) %s\n"),
1733 lifname, strerror(errno));
1734 return (-1);
1735 }
1736 }
1737 }
1738
1739 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n",
1740 node->ip_resource);
1741
1742 return (0);
1743 }
1744
1745 /*
1746 * clr_cfg_state() - Cleanup after errors in unplumb
1747 */
1748 static void
clr_cfg_state(ip_pif_t * pif)1749 clr_cfg_state(ip_pif_t *pif)
1750 {
1751 ip_lif_t *lif;
1752 int i;
1753
1754 lif = pif->pi_lifs;
1755
1756 while (lif != NULL) {
1757 lif->li_modcnt = 0;
1758 free(lif->li_reconfig);
1759 lif->li_reconfig = NULL;
1760 for (i = 0; i < IP_MAX_MODS; i++) {
1761 free(lif->li_modules[i]);
1762 lif->li_modules[i] = NULL;
1763 }
1764 lif = lif->li_next;
1765 }
1766 }
1767
1768 /*
1769 * Attempt to offline ip_cache_t `node'; returns an IPMP error code.
1770 */
1771 static int
ip_ipmp_offline(ip_cache_t * node)1772 ip_ipmp_offline(ip_cache_t *node)
1773 {
1774 int retval;
1775 ipmp_handle_t handle;
1776
1777 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n");
1778
1779 if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
1780 rcm_log_message(RCM_ERROR,
1781 _("IP: cannot create ipmp handle: %s\n"),
1782 ipmp_errmsg(retval));
1783 return (retval);
1784 }
1785
1786 retval = ipmp_offline(handle, node->ip_pif->pi_ifname, node->ip_ifred);
1787 if (retval != IPMP_SUCCESS) {
1788 rcm_log_message(RCM_ERROR, _("IP: ipmp_offline error: %s\n"),
1789 ipmp_errmsg(retval));
1790 } else {
1791 rcm_log_message(RCM_TRACE1, "IP: ipmp_offline success\n");
1792 }
1793
1794 ipmp_close(handle);
1795 return (retval);
1796 }
1797
1798 /*
1799 * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code.
1800 */
1801 static int
ip_ipmp_undo_offline(ip_cache_t * node)1802 ip_ipmp_undo_offline(ip_cache_t *node)
1803 {
1804 int retval;
1805 ipmp_handle_t handle;
1806
1807 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_undo_offline\n");
1808
1809 if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
1810 rcm_log_message(RCM_ERROR,
1811 _("IP: cannot create ipmp handle: %s\n"),
1812 ipmp_errmsg(retval));
1813 return (retval);
1814 }
1815
1816 retval = ipmp_undo_offline(handle, node->ip_pif->pi_ifname);
1817 if (retval != IPMP_SUCCESS) {
1818 rcm_log_message(RCM_ERROR,
1819 _("IP: ipmp_undo_offline error: %s\n"),
1820 ipmp_errmsg(retval));
1821 } else {
1822 rcm_log_message(RCM_TRACE1, "IP: ipmp_undo_offline success\n");
1823 }
1824
1825 ipmp_close(handle);
1826 return (retval);
1827 }
1828
1829 /*
1830 * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a
1831 * dynamically allocated string containing the associated link resource
1832 * name ("SUNW_datalink/<linkid>").
1833 */
1834 static char *
get_link_resource(const char * link)1835 get_link_resource(const char *link)
1836 {
1837 char errmsg[DLADM_STRSIZE];
1838 datalink_id_t linkid;
1839 uint32_t flags;
1840 char *resource;
1841 dladm_status_t status;
1842
1843 status = dladm_name2info(dld_handle, link, &linkid, &flags, NULL, NULL);
1844 if (status != DLADM_STATUS_OK)
1845 goto fail;
1846
1847 if (!(flags & DLADM_OPT_ACTIVE)) {
1848 status = DLADM_STATUS_FAILED;
1849 goto fail;
1850 }
1851
1852 resource = malloc(RCM_LINK_RESOURCE_MAX);
1853 if (resource == NULL) {
1854 rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"),
1855 strerror(errno), link);
1856 return (NULL);
1857 }
1858
1859 (void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u",
1860 RCM_LINK_PREFIX, linkid);
1861
1862 return (resource);
1863
1864 fail:
1865 rcm_log_message(RCM_ERROR,
1866 _("IP: get_link_resource for %s error(%s)\n"),
1867 link, dladm_status2str(status, errmsg));
1868 return (NULL);
1869 }
1870
1871 /*
1872 * modop() - Remove/insert a module
1873 */
1874 static int
modop(char * name,char * arg,int pos,char op)1875 modop(char *name, char *arg, int pos, char op)
1876 {
1877 char syscmd[LIFNAMSIZ+MAXPATHLEN]; /* must be big enough */
1878
1879 rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name);
1880
1881 /* Nothing to do with "ip", "arp" */
1882 if ((arg == NULL) || (strcmp(arg, "") == 0) ||
1883 STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) {
1884 rcm_log_message(RCM_TRACE1, "IP: modop success\n");
1885 return (0);
1886 }
1887
1888 if (op == MOD_CHECK) {
1889 /*
1890 * No known good modules (yet) apart from ip and arp
1891 * which are handled above
1892 */
1893 return (-1);
1894 }
1895
1896 if (op == MOD_REMOVE) {
1897 (void) snprintf(syscmd, sizeof (syscmd),
1898 "%s %s modremove %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
1899 } else if (op == MOD_INSERT) {
1900 (void) snprintf(syscmd, sizeof (syscmd),
1901 "%s %s modinsert %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
1902 } else {
1903 rcm_log_message(RCM_ERROR,
1904 _("IP: modop(%s): unknown operation\n"), name);
1905 return (-1);
1906 }
1907
1908 rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd);
1909 if (rcm_exec_cmd(syscmd) == -1) {
1910 rcm_log_message(RCM_ERROR,
1911 _("IP: modop(%s): %s\n"), name, strerror(errno));
1912 return (-1);
1913 }
1914
1915 rcm_log_message(RCM_TRACE1, "IP: modop success\n");
1916 return (0);
1917 }
1918
1919 /*
1920 * get_modlist() - return a list of pushed mid-stream modules
1921 * Required memory is malloced to construct the list,
1922 * Caller must free this memory list
1923 * Call with cache_lock held
1924 */
1925 static int
get_modlist(char * name,ip_lif_t * lif)1926 get_modlist(char *name, ip_lif_t *lif)
1927 {
1928 int mux_fd;
1929 int muxid_fd;
1930 int fd;
1931 int i;
1932 int num_mods;
1933 struct lifreq lifr;
1934 struct str_list strlist = { 0 };
1935
1936 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name);
1937
1938 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1939 lifr.lifr_flags = lif->li_ifflags;
1940 if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) {
1941 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name);
1942 return (-1);
1943 }
1944
1945 if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) {
1946 rcm_log_message(RCM_ERROR,
1947 _("IP: get_modlist(%s): I_LIST(%s) \n"),
1948 name, strerror(errno));
1949 goto fail;
1950 }
1951
1952 strlist.sl_nmods = num_mods;
1953 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods);
1954 if (strlist.sl_modlist == NULL) {
1955 rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"),
1956 name, strerror(errno));
1957 goto fail;
1958 }
1959
1960 if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
1961 rcm_log_message(RCM_ERROR,
1962 _("IP: get_modlist(%s): I_LIST error: %s\n"),
1963 name, strerror(errno));
1964 goto fail;
1965 }
1966
1967 for (i = 0; i < strlist.sl_nmods; i++) {
1968 lif->li_modules[i] = strdup(strlist.sl_modlist[i].l_name);
1969 if (lif->li_modules[i] == NULL) {
1970 rcm_log_message(RCM_ERROR,
1971 _("IP: get_modlist(%s): %s\n"),
1972 name, strerror(errno));
1973 while (i > 0)
1974 free(lif->li_modules[--i]);
1975 goto fail;
1976 }
1977 }
1978
1979 lif->li_modcnt = strlist.sl_nmods;
1980 free(strlist.sl_modlist);
1981
1982 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name);
1983 return (ip_plink(mux_fd, muxid_fd, fd, &lifr));
1984 fail:
1985 free(strlist.sl_modlist);
1986 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
1987 return (-1);
1988 }
1989
1990 /*
1991 * ip_domux2fd() - Helper function for mod*() functions
1992 * Stolen from ifconfig.c
1993 */
1994 static int
ip_domux2fd(int * mux_fd,int * muxid_fdp,int * fd,struct lifreq * lifr)1995 ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr)
1996 {
1997 int muxid_fd;
1998 char *udp_dev_name;
1999
2000 if (lifr->lifr_flags & IFF_IPV6) {
2001 udp_dev_name = UDP6_DEV_NAME;
2002 } else {
2003 udp_dev_name = UDP_DEV_NAME;
2004 }
2005
2006 if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) {
2007 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2008 udp_dev_name, strerror(errno));
2009 return (-1);
2010 }
2011 if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) {
2012 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2013 udp_dev_name, strerror(errno));
2014 (void) close(muxid_fd);
2015 return (-1);
2016 }
2017 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) {
2018 rcm_log_message(RCM_ERROR,
2019 _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"),
2020 udp_dev_name, strerror(errno));
2021 (void) close(*mux_fd);
2022 (void) close(muxid_fd);
2023 return (-1);
2024 }
2025
2026 rcm_log_message(RCM_TRACE2,
2027 "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n",
2028 lifr->lifr_arp_muxid, lifr->lifr_ip_muxid);
2029
2030 if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) {
2031 rcm_log_message(RCM_ERROR,
2032 _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"),
2033 udp_dev_name, strerror(errno));
2034 (void) close(*mux_fd);
2035 (void) close(muxid_fd);
2036 return (-1);
2037 }
2038 if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) {
2039 rcm_log_message(RCM_ERROR,
2040 _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"),
2041 udp_dev_name, strerror(errno));
2042 (void) close(*mux_fd);
2043 (void) close(muxid_fd);
2044 return (-1);
2045 }
2046
2047 /* Note: mux_fd and muxid_fd are closed in ip_plink below */
2048 *muxid_fdp = muxid_fd;
2049 return (0);
2050 }
2051
2052 /*
2053 * ip_plink() - Helper function for mod*() functions.
2054 * Stolen from ifconfig.c
2055 */
2056 static int
ip_plink(int mux_fd,int muxid_fd,int fd,struct lifreq * lifr)2057 ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr)
2058 {
2059 int mux_id;
2060
2061 if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) {
2062 rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"),
2063 UDP_DEV_NAME, strerror(errno));
2064 (void) close(mux_fd);
2065 (void) close(muxid_fd);
2066 (void) close(fd);
2067 return (-1);
2068 }
2069
2070 lifr->lifr_ip_muxid = mux_id;
2071 if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) {
2072 rcm_log_message(RCM_ERROR,
2073 _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"),
2074 UDP_DEV_NAME, strerror(errno));
2075 (void) close(mux_fd);
2076 (void) close(muxid_fd);
2077 (void) close(fd);
2078 return (-1);
2079 }
2080
2081 (void) close(mux_fd);
2082 (void) close(muxid_fd);
2083 (void) close(fd);
2084 return (0);
2085 }
2086
2087 /*
2088 * ip_onlinelist()
2089 *
2090 * Notify online to IP address consumers.
2091 */
2092 /*ARGSUSED*/
2093 static int
ip_onlinelist(rcm_handle_t * hd,ip_cache_t * node,char ** errorp,uint_t flags,rcm_info_t ** depend_info)2094 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2095 rcm_info_t **depend_info)
2096 {
2097 char **addrlist;
2098 int ret = RCM_SUCCESS;
2099
2100 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n");
2101
2102 addrlist = ip_get_addrlist(node);
2103 if (addrlist == NULL || addrlist[0] == NULL) {
2104 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n");
2105 ip_free_addrlist(addrlist);
2106 return (ret);
2107 }
2108
2109 ret = rcm_notify_online_list(hd, addrlist, 0, depend_info);
2110
2111 ip_free_addrlist(addrlist);
2112 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n");
2113 return (ret);
2114 }
2115
2116 /*
2117 * ip_offlinelist()
2118 *
2119 * Offline IP address consumers.
2120 */
2121 /*ARGSUSED*/
2122 static int
ip_offlinelist(rcm_handle_t * hd,ip_cache_t * node,char ** errorp,uint_t flags,rcm_info_t ** depend_info)2123 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2124 rcm_info_t **depend_info)
2125 {
2126 char **addrlist;
2127 int ret = RCM_SUCCESS;
2128
2129 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n");
2130
2131 addrlist = ip_get_addrlist(node);
2132 if (addrlist == NULL || addrlist[0] == NULL) {
2133 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n");
2134 ip_free_addrlist(addrlist);
2135 return (RCM_SUCCESS);
2136 }
2137
2138 if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info))
2139 != RCM_SUCCESS) {
2140 if (ret == RCM_FAILURE)
2141 (void) rcm_notify_online_list(hd, addrlist, 0, NULL);
2142
2143 ret = RCM_FAILURE;
2144 }
2145
2146 ip_free_addrlist(addrlist);
2147 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n");
2148 return (ret);
2149 }
2150
2151 /*
2152 * ip_get_addrlist() - Get the list of IP addresses on this interface (node);
2153 * This routine malloc()s required memory for the list.
2154 * Returns the list on success, NULL on failure.
2155 * Call with cache_lock held.
2156 */
2157 static char **
ip_get_addrlist(ip_cache_t * node)2158 ip_get_addrlist(ip_cache_t *node)
2159 {
2160 ip_lif_t *lif;
2161 char **addrlist = NULL;
2162 int i, numifs;
2163 size_t addrlistsize;
2164 char addrstr[INET6_ADDRSTRLEN];
2165
2166 rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n",
2167 node->ip_resource);
2168
2169 numifs = 0;
2170 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
2171 numifs++;
2172 }
2173
2174 /*
2175 * Allocate space for resource names list; add 1 and use calloc()
2176 * so that the list is NULL-terminated.
2177 */
2178 if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) {
2179 rcm_log_message(RCM_ERROR,
2180 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2181 node->ip_resource, strerror(errno));
2182 return (NULL);
2183 }
2184
2185 for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL;
2186 lif = lif->li_next, i++) {
2187
2188 if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) {
2189 ip_free_addrlist(addrlist);
2190 return (NULL);
2191 }
2192
2193 addrlistsize = strlen(addrstr) + sizeof (RCM_STR_SUNW_IP);
2194 if ((addrlist[i] = malloc(addrlistsize)) == NULL) {
2195 rcm_log_message(RCM_ERROR,
2196 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2197 node->ip_resource, strerror(errno));
2198 ip_free_addrlist(addrlist);
2199 return (NULL);
2200 }
2201 (void) snprintf(addrlist[i], addrlistsize, "%s%s",
2202 RCM_STR_SUNW_IP, addrstr);
2203
2204 rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]);
2205 }
2206
2207 rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n",
2208 node->ip_resource);
2209
2210 return (addrlist);
2211 }
2212
2213 static void
ip_free_addrlist(char ** addrlist)2214 ip_free_addrlist(char **addrlist)
2215 {
2216 int i;
2217
2218 if (addrlist == NULL)
2219 return;
2220
2221 for (i = 0; addrlist[i] != NULL; i++)
2222 free(addrlist[i]);
2223 free(addrlist);
2224 }
2225
2226 /*
2227 * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
2228 */
2229
2230 static void
ip_consumer_notify(rcm_handle_t * hd,datalink_id_t linkid,char ** errorp,uint_t flags,rcm_info_t ** depend_info)2231 ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
2232 uint_t flags, rcm_info_t **depend_info)
2233 {
2234 char cached_name[RCM_LINK_RESOURCE_MAX];
2235 ip_cache_t *node;
2236
2237 assert(linkid != DATALINK_INVALID_LINKID);
2238
2239 rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid);
2240
2241 /* Check for the interface in the cache */
2242 (void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2243 RCM_LINK_PREFIX, linkid);
2244
2245 (void) mutex_lock(&cache_lock);
2246 if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) {
2247 rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"),
2248 linkid);
2249 (void) mutex_unlock(&cache_lock);
2250 return;
2251 }
2252 /*
2253 * Inform anonymous consumers about IP addresses being onlined.
2254 */
2255 (void) ip_onlinelist(hd, node, errorp, flags, depend_info);
2256
2257 (void) mutex_unlock(&cache_lock);
2258
2259 rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n");
2260 }
2261
2262 /*
2263 * Gets the interface name for the given linkid. Returns -1 if there is
2264 * any error. It fills in the interface name in `ifinst' if the interface
2265 * is not already configured. Otherwise, it puts a null string in `ifinst'.
2266 */
2267 static int
if_configure_get_linkid(datalink_id_t linkid,char * ifinst,size_t len)2268 if_configure_get_linkid(datalink_id_t linkid, char *ifinst, size_t len)
2269 {
2270 char cached_name[RCM_LINK_RESOURCE_MAX];
2271 ip_cache_t *node;
2272
2273 /* Check for the interface in the cache */
2274 (void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2275 RCM_LINK_PREFIX, linkid);
2276
2277 /* Check if the interface is new or was not previously offlined */
2278 (void) mutex_lock(&cache_lock);
2279 if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) &&
2280 (!(node->ip_cachestate & CACHE_IF_OFFLINED))) {
2281 rcm_log_message(RCM_TRACE1,
2282 _("IP: Skipping configured interface(%u)\n"), linkid);
2283 (void) mutex_unlock(&cache_lock);
2284 *ifinst = '\0';
2285 return (0);
2286 }
2287 (void) mutex_unlock(&cache_lock);
2288
2289 if (dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, NULL, ifinst,
2290 len) != DLADM_STATUS_OK) {
2291 rcm_log_message(RCM_ERROR,
2292 _("IP: get %u link name failed\n"), linkid);
2293 return (-1);
2294 }
2295 return (0);
2296 }
2297
2298 /*
2299 * if_configure_hostname() - Configure a physical interface after attach
2300 * based on the information in /etc/hostname.*
2301 */
2302 static int
if_configure_hostname(datalink_id_t linkid)2303 if_configure_hostname(datalink_id_t linkid)
2304 {
2305 FILE *hostfp, *host6fp;
2306 boolean_t ipmp = B_FALSE;
2307 char ifinst[MAXLINKNAMELEN];
2308 char cfgfile[MAXPATHLEN];
2309
2310 assert(linkid != DATALINK_INVALID_LINKID);
2311 rcm_log_message(RCM_TRACE1, _("IP: if_configure_hostname(%u)\n"),
2312 linkid);
2313
2314 if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
2315 return (-1);
2316
2317 /* Check if the interface is already configured. */
2318 if (ifinst[0] == '\0')
2319 return (0);
2320
2321 /*
2322 * Scan the IPv4 and IPv6 hostname files to see if (a) they exist
2323 * and (b) if either one places the interface into an IPMP group.
2324 */
2325 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifinst);
2326 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2327 if ((hostfp = fopen(cfgfile, "r")) != NULL) {
2328 if (isgrouped(cfgfile))
2329 ipmp = B_TRUE;
2330 }
2331
2332 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifinst);
2333 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2334 if ((host6fp = fopen(cfgfile, "r")) != NULL) {
2335 if (!ipmp && isgrouped(cfgfile))
2336 ipmp = B_TRUE;
2337 }
2338
2339 /*
2340 * Configure the interface according to its hostname files.
2341 */
2342 if (hostfp != NULL &&
2343 if_config_inst(ifinst, hostfp, AF_INET, ipmp) == -1) {
2344 rcm_log_message(RCM_ERROR,
2345 _("IP: IPv4 Post-attach failed (%s)\n"), ifinst);
2346 goto fail;
2347 }
2348
2349 if (host6fp != NULL &&
2350 if_config_inst(ifinst, host6fp, AF_INET6, ipmp) == -1) {
2351 rcm_log_message(RCM_ERROR,
2352 _("IP: IPv6 Post-attach failed (%s)\n"), ifinst);
2353 goto fail;
2354 }
2355
2356 (void) fclose(hostfp);
2357 (void) fclose(host6fp);
2358 rcm_log_message(RCM_TRACE1, "IP: if_configure_hostname(%s) success\n",
2359 ifinst);
2360 return (0);
2361 fail:
2362 (void) fclose(hostfp);
2363 (void) fclose(host6fp);
2364 return (-1);
2365 }
2366
2367 /*
2368 * if_configure_ipadm() - Configure a physical interface after attach
2369 * Queries libipadm for persistent configuration information and then
2370 * resurrects that persistent configuration.
2371 */
2372 static int
if_configure_ipadm(datalink_id_t linkid)2373 if_configure_ipadm(datalink_id_t linkid)
2374 {
2375 char ifinst[MAXLINKNAMELEN];
2376 boolean_t found;
2377 ipadm_if_info_t *ifinfo, *ptr;
2378 ipadm_status_t status;
2379
2380 assert(linkid != DATALINK_INVALID_LINKID);
2381 rcm_log_message(RCM_TRACE1, _("IP: if_configure_ipadm(%u)\n"),
2382 linkid);
2383
2384 if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
2385 return (-1);
2386
2387 /* Check if the interface is already configured. */
2388 if (ifinst[0] == '\0')
2389 return (0);
2390
2391 status = ipadm_if_info(ip_handle, ifinst, &ifinfo, 0, LIFC_UNDER_IPMP);
2392 if (status == IPADM_ENXIO)
2393 goto done;
2394 if (status != IPADM_SUCCESS) {
2395 rcm_log_message(RCM_ERROR,
2396 _("IP: IPv4 Post-attach failed (%s) Error %s\n"),
2397 ifinst, ipadm_status2str(status));
2398 goto fail;
2399 }
2400 if (ifinfo != NULL) {
2401 found = B_FALSE;
2402 for (ptr = ifinfo; ptr != NULL; ptr = ptr->ifi_next) {
2403 if (strncmp(ptr->ifi_name, ifinst,
2404 sizeof (ifinst)) == 0) {
2405 found = B_TRUE;
2406 break;
2407 }
2408 }
2409 ipadm_free_if_info(ifinfo);
2410 if (!found) {
2411 return (0);
2412 }
2413 if (if_hostname_exists(ifinst, AF_INET) ||
2414 if_hostname_exists(ifinst, AF_INET6)) {
2415 rcm_log_message(RCM_WARNING,
2416 _("IP: IPv4 Post-attach (%s) found both "
2417 "/etc/hostname and ipadm persistent configuration. "
2418 "Ignoring ipadm config\n"), ifinst);
2419 return (0);
2420 }
2421 status = ipadm_enable_if(ip_handle, ifinst, IPADM_OPT_ACTIVE);
2422 if (status != IPADM_SUCCESS) {
2423 rcm_log_message(RCM_ERROR,
2424 _("IP: Post-attach failed (%s) Error %s\n"),
2425 ifinst, ipadm_status2str(status));
2426 goto fail;
2427 }
2428 }
2429 done:
2430 rcm_log_message(RCM_TRACE1, "IP: if_configure_ipadm(%s) success\n",
2431 ifinst);
2432 return (0);
2433 fail:
2434 return (-1);
2435 }
2436
2437 /*
2438 * isgrouped() - Scans the given config file to see if this interface is
2439 * using IPMP. Returns B_TRUE or B_FALSE.
2440 */
2441 static boolean_t
isgrouped(const char * cfgfile)2442 isgrouped(const char *cfgfile)
2443 {
2444 FILE *fp;
2445 struct stat statb;
2446 char *nlp, *line, *token, *lasts, *buf;
2447 boolean_t grouped = B_FALSE;
2448
2449 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile);
2450
2451 if (stat(cfgfile, &statb) != 0) {
2452 rcm_log_message(RCM_TRACE1,
2453 _("IP: No config file(%s)\n"), cfgfile);
2454 return (B_FALSE);
2455 }
2456
2457 /*
2458 * We also ignore single-byte config files because the file should
2459 * always be newline-terminated, so we know there's nothing of
2460 * interest. Further, a single-byte file would cause the fgets() loop
2461 * below to spin forever.
2462 */
2463 if (statb.st_size <= 1) {
2464 rcm_log_message(RCM_TRACE1,
2465 _("IP: Empty config file(%s)\n"), cfgfile);
2466 return (B_FALSE);
2467 }
2468
2469 if ((fp = fopen(cfgfile, "r")) == NULL) {
2470 rcm_log_message(RCM_ERROR,
2471 _("IP: Cannot open configuration file(%s): %s\n"), cfgfile,
2472 strerror(errno));
2473 return (B_FALSE);
2474 }
2475
2476 if ((buf = malloc(statb.st_size)) == NULL) {
2477 rcm_log_message(RCM_ERROR,
2478 _("IP: malloc failure(%s): %s\n"), cfgfile,
2479 strerror(errno));
2480 goto out;
2481 }
2482
2483 while (fgets(buf, statb.st_size, fp) != NULL) {
2484 if ((nlp = strrchr(buf, '\n')) != NULL)
2485 *nlp = '\0';
2486
2487 line = buf;
2488 while ((token = strtok_r(line, " \t", &lasts)) != NULL) {
2489 line = NULL;
2490 if (STREQ("group", token) &&
2491 strtok_r(NULL, " \t", &lasts) != NULL) {
2492 grouped = B_TRUE;
2493 goto out;
2494 }
2495 }
2496 }
2497 out:
2498 free(buf);
2499 (void) fclose(fp);
2500
2501 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s): %d\n", cfgfile,
2502 grouped);
2503
2504 return (grouped);
2505 }
2506
2507 /*
2508 * if_config_inst() - Configure an interface instance as specified by the
2509 * address family af and if it is grouped (ipmp).
2510 */
2511 static int
if_config_inst(const char * ifinst,FILE * hfp,int af,boolean_t ipmp)2512 if_config_inst(const char *ifinst, FILE *hfp, int af, boolean_t ipmp)
2513 {
2514 FILE *ifparsefp;
2515 struct stat statb;
2516 char *buf = NULL;
2517 char *ifparsebuf = NULL;
2518 uint_t ifparsebufsize;
2519 const char *fstr; /* address family string */
2520 boolean_t stdif = B_FALSE;
2521
2522 rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) ipmp = %d\n",
2523 ifinst, ipmp);
2524
2525 if (fstat(fileno(hfp), &statb) != 0) {
2526 rcm_log_message(RCM_ERROR,
2527 _("IP: Cannot fstat file(%s)\n"), ifinst);
2528 goto fail;
2529 }
2530
2531 switch (af) {
2532 case AF_INET:
2533 fstr = "inet";
2534 break;
2535 case AF_INET6:
2536 fstr = "inet6";
2537 break;
2538 default:
2539 assert(0);
2540 }
2541
2542 /*
2543 * The hostname file exists; plumb the physical interface.
2544 */
2545 if (!ifconfig(ifinst, fstr, "plumb", B_FALSE))
2546 goto fail;
2547
2548 /* Skip static configuration if the hostname file is empty */
2549 if (statb.st_size <= 1) {
2550 rcm_log_message(RCM_TRACE1,
2551 _("IP: Zero size hostname file(%s)\n"), ifinst);
2552 goto configured;
2553 }
2554
2555 if (fseek(hfp, 0, SEEK_SET) == -1) {
2556 rcm_log_message(RCM_ERROR,
2557 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2558 strerror(errno));
2559 goto fail;
2560 }
2561
2562 /*
2563 * Allocate the worst-case single-line buffer sizes. A bit skanky,
2564 * but since hostname files are small, this should suffice.
2565 */
2566 if ((buf = calloc(1, statb.st_size)) == NULL) {
2567 rcm_log_message(RCM_ERROR,
2568 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2569 goto fail;
2570 }
2571
2572 ifparsebufsize = statb.st_size + sizeof (SBIN_IFPARSE " -s inet6 ");
2573 if ((ifparsebuf = calloc(1, ifparsebufsize)) == NULL) {
2574 rcm_log_message(RCM_ERROR,
2575 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2576 goto fail;
2577 }
2578
2579 /*
2580 * For IPv4, determine whether the hostname file consists of a single
2581 * line. We need to handle these specially since they should
2582 * automatically be suffixed with "netmask + broadcast + up".
2583 */
2584 if (af == AF_INET &&
2585 fgets(buf, statb.st_size, hfp) != NULL &&
2586 fgets(buf, statb.st_size, hfp) == NULL) {
2587 rcm_log_message(RCM_TRACE1, "IP: one-line hostname file\n");
2588 stdif = B_TRUE;
2589 }
2590
2591 if (fseek(hfp, 0L, SEEK_SET) == -1) {
2592 rcm_log_message(RCM_ERROR,
2593 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2594 strerror(errno));
2595 goto fail;
2596 }
2597
2598 /*
2599 * Loop through the file one line at a time and feed it to ifconfig.
2600 * If the interface is using IPMP, then we use /sbin/ifparse -s to
2601 * weed out all of the data addresses, since those are already on the
2602 * IPMP meta-interface.
2603 */
2604 while (fgets(buf, statb.st_size, hfp) != NULL) {
2605 if (ntok(buf) == 0)
2606 continue;
2607
2608 if (!ipmp) {
2609 (void) ifconfig(ifinst, fstr, buf, stdif);
2610 continue;
2611 }
2612
2613 (void) snprintf(ifparsebuf, ifparsebufsize, SBIN_IFPARSE
2614 " -s %s %s", fstr, buf);
2615 if ((ifparsefp = popen(ifparsebuf, "r")) == NULL) {
2616 rcm_log_message(RCM_ERROR,
2617 _("IP: cannot configure %s: popen \"%s\" "
2618 "failed: %s\n"), ifinst, buf, strerror(errno));
2619 goto fail;
2620 }
2621
2622 while (fgets(buf, statb.st_size, ifparsefp) != NULL) {
2623 if (ntok(buf) > 0)
2624 (void) ifconfig(ifinst, fstr, buf, stdif);
2625 }
2626
2627 if (pclose(ifparsefp) == -1) {
2628 rcm_log_message(RCM_ERROR,
2629 _("IP: cannot configure %s: pclose \"%s\" "
2630 "failed: %s\n"), ifinst, buf, strerror(errno));
2631 goto fail;
2632 }
2633 }
2634
2635 configured:
2636 /*
2637 * Bring up the interface (it may already be up)
2638 *
2639 * Technically, since the boot scripts only unconditionally bring up
2640 * IPv6 interfaces, we should only unconditionally bring up IPv6 here.
2641 * However, if we don't bring up IPv4, and a legacy IPMP configuration
2642 * without test addresses is being used, we will never bring the
2643 * interface up even though we would've at boot. One fix is to check
2644 * if the IPv4 hostname file contains data addresses that we would've
2645 * brought up, but there's no simple way to do that. Given that it's
2646 * rare to have persistent IP configuration for an interface that
2647 * leaves it down, we cheap out and always bring it up for IPMP.
2648 */
2649 if ((af == AF_INET6 || ipmp) && !ifconfig(ifinst, fstr, "up", B_FALSE))
2650 goto fail;
2651
2652 /*
2653 * For IPv4, if a DHCP configuration file exists, have DHCP configure
2654 * the interface. As with the boot scripts, this is done after the
2655 * hostname files are processed so that configuration in those files
2656 * (such as IPMP group names) will be applied first.
2657 */
2658 if (af == AF_INET) {
2659 char dhcpfile[MAXPATHLEN];
2660 char *dhcpbuf;
2661 off_t i, dhcpsize;
2662
2663 (void) snprintf(dhcpfile, MAXPATHLEN, DHCPFILE_FMT, ifinst);
2664 if (stat(dhcpfile, &statb) == -1)
2665 goto out;
2666
2667 if ((dhcpbuf = copylist(dhcpfile, &dhcpsize)) == NULL) {
2668 rcm_log_message(RCM_ERROR, _("IP: cannot read "
2669 "(%s): %s\n"), dhcpfile, strerror(errno));
2670 goto fail;
2671 }
2672
2673 /*
2674 * The copylist() API converts \n's to \0's, but we want them
2675 * to be spaces.
2676 */
2677 if (dhcpsize > 0) {
2678 for (i = 0; i < dhcpsize; i++)
2679 if (dhcpbuf[i] == '\0')
2680 dhcpbuf[i] = ' ';
2681 dhcpbuf[dhcpsize - 1] = '\0';
2682 }
2683 (void) ifconfig(ifinst, CFG_DHCP_CMD, dhcpbuf, B_FALSE);
2684 free(dhcpbuf);
2685 }
2686 out:
2687 free(ifparsebuf);
2688 free(buf);
2689 rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) success\n", ifinst);
2690 return (0);
2691 fail:
2692 free(ifparsebuf);
2693 free(buf);
2694 rcm_log_message(RCM_ERROR, "IP: if_config_inst(%s) failure\n", ifinst);
2695 return (-1);
2696 }
2697
2698 /*
2699 * ntok() - count the number of tokens in the provided buffer.
2700 */
2701 static uint_t
ntok(const char * cp)2702 ntok(const char *cp)
2703 {
2704 uint_t ntok = 0;
2705
2706 for (;;) {
2707 while (ISSPACE(*cp))
2708 cp++;
2709
2710 if (ISEOL(*cp))
2711 break;
2712
2713 do {
2714 cp++;
2715 } while (!ISSPACE(*cp) && !ISEOL(*cp));
2716
2717 ntok++;
2718 }
2719 return (ntok);
2720 }
2721
2722 static boolean_t
ifconfig(const char * ifinst,const char * fstr,const char * buf,boolean_t stdif)2723 ifconfig(const char *ifinst, const char *fstr, const char *buf, boolean_t stdif)
2724 {
2725 char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
2726 int status;
2727
2728 (void) snprintf(syscmd, sizeof (syscmd), SBIN_IFCONFIG " %s %s %s",
2729 ifinst, fstr, buf);
2730
2731 if (stdif)
2732 (void) strlcat(syscmd, CFG_CMDS_STD, sizeof (syscmd));
2733
2734 rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd);
2735 if ((status = rcm_exec_cmd(syscmd)) != 0) {
2736 if (WIFEXITED(status)) {
2737 rcm_log_message(RCM_ERROR, _("IP: \"%s\" failed with "
2738 "exit status %d\n"), syscmd, WEXITSTATUS(status));
2739 } else {
2740 rcm_log_message(RCM_ERROR, _("IP: Error: %s: %s\n"),
2741 syscmd, strerror(errno));
2742 }
2743 return (B_FALSE);
2744 }
2745 return (B_TRUE);
2746 }
2747
2748 /*
2749 * Return TRUE if a writeable /etc/hostname[6].ifname file exists.
2750 */
2751 static boolean_t
if_hostname_exists(char * ifname,sa_family_t af)2752 if_hostname_exists(char *ifname, sa_family_t af)
2753 {
2754 char cfgfile[MAXPATHLEN];
2755
2756 if (af == AF_INET) {
2757 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifname);
2758 if (access(cfgfile, W_OK|F_OK) == 0)
2759 return (B_TRUE);
2760 } else if (af == AF_INET6) {
2761 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifname);
2762 if (access(cfgfile, W_OK|F_OK) == 0)
2763 return (B_TRUE);
2764 }
2765 return (B_FALSE);
2766 }
2767