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