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 * 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 * 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 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 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 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 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(8) 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(8) 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 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 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 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 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 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 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 * 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 ** 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 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 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 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 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 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 != NULL; ptr = ptr->ifi_next) { 2402 if (strncmp(ptr->ifi_name, ifinst, 2403 sizeof (ifinst)) == 0) { 2404 found = B_TRUE; 2405 break; 2406 } 2407 } 2408 ipadm_free_if_info(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 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 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 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 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 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