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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 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, NULL, 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(1M) to offline the physical interface. 486 */ 487 if ((retval = ip_ipmp_offline(node)) != IPMP_SUCCESS) 488 ip_log_err(node, errorp, "in.mpathd offline failed"); 489 490 if (retval == IPMP_EMINRED && !detachable) { 491 /* 492 * in.mpathd(1M) could not offline the device because it was 493 * the last interface in the group. However, it's possible 494 * that it's still okay to offline it as long as there are 495 * higher-level failover mechanisms for the addresses it owns 496 * (e.g., clustering). In this case, ip_offlinelist() will 497 * return RCM_SUCCESS, and we charge on. 498 */ 499 /* Inform consumers of IP addresses being offlined */ 500 if (ip_offlinelist(hd, node, errorp, flags, 501 depend_info) == RCM_SUCCESS) { 502 rcm_log_message(RCM_DEBUG, 503 "IP: consumers agree on detach"); 504 } else { 505 ip_log_err(node, errorp, 506 "Device consumers prohibit offline"); 507 (void) mutex_unlock(&cache_lock); 508 errno = EBUSY; 509 return (RCM_FAILURE); 510 } 511 } 512 513 if (if_unplumb(node) < 0) { 514 rcm_log_message(RCM_ERROR, 515 _("IP: Unplumb failed (%s)\n"), 516 pif->pi_ifname); 517 518 /* Request in.mpathd to undo the offline */ 519 if (ip_ipmp_undo_offline(node) != IPMP_SUCCESS) { 520 ip_log_err(node, errorp, "Undo offline failed"); 521 (void) mutex_unlock(&cache_lock); 522 return (RCM_FAILURE); 523 } 524 (void) mutex_unlock(&cache_lock); 525 return (RCM_FAILURE); 526 } 527 528 node->ip_cachestate |= CACHE_IF_OFFLINED; 529 rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc); 530 (void) mutex_unlock(&cache_lock); 531 return (RCM_SUCCESS); 532 } 533 534 /* 535 * ip_undo_offline() - Undo offline of a previously offlined device. 536 */ 537 /*ARGSUSED*/ 538 static int 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 ifaddr = *(ifa->ifa_addr); 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->ss_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 (node->ip_pif->pi_ifname != NULL)) { 1412 ifname = node->ip_pif->pi_ifname; 1413 } 1414 1415 if (ifname == NULL) { 1416 rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg); 1417 errfmt = _("IP: %s"); 1418 size = strlen(errfmt) + strlen(errmsg) + 1; 1419 if (errorp != NULL && (error = malloc(size)) != NULL) 1420 (void) snprintf(error, size, errfmt, errmsg); 1421 } else { 1422 rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname); 1423 errfmt = _("IP: %s(%s)"); 1424 size = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1; 1425 if (errorp != NULL && (error = malloc(size)) != NULL) 1426 (void) snprintf(error, size, errfmt, errmsg, ifname); 1427 } 1428 1429 if (errorp != NULL) 1430 *errorp = error; 1431 } 1432 1433 /* 1434 * if_cfginfo() - Save off the config info for all interfaces 1435 */ 1436 static int 1437 if_cfginfo(ip_cache_t *node, uint_t force) 1438 { 1439 ip_lif_t *lif; 1440 ip_pif_t *pif; 1441 int i; 1442 FILE *fp; 1443 char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ]; 1444 char buf[MAX_RECONFIG_SIZE]; 1445 1446 rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource); 1447 1448 pif = node->ip_pif; 1449 lif = pif->pi_lifs; 1450 1451 while (lif != NULL) { 1452 /* Make a list of modules pushed and save */ 1453 if (lif->li_ifnum == 0) { /* physical instance */ 1454 if (get_modlist(pif->pi_ifname, lif) == -1) { 1455 rcm_log_message(RCM_ERROR, 1456 _("IP: get modlist error (%s) %s\n"), 1457 pif->pi_ifname, strerror(errno)); 1458 clr_cfg_state(pif); 1459 return (-1); 1460 } 1461 1462 if (!force) { 1463 /* Look if unknown modules have been inserted */ 1464 for (i = (lif->li_modcnt - 2); i > 0; i--) { 1465 if (modop(pif->pi_ifname, 1466 lif->li_modules[i], 1467 i, MOD_CHECK) == -1) { 1468 rcm_log_message(RCM_ERROR, 1469 _("IP: module %s@%d\n"), 1470 lif->li_modules[i], i); 1471 clr_cfg_state(pif); 1472 return (-1); 1473 } 1474 } 1475 } 1476 1477 /* Last module is the device driver, so ignore that */ 1478 for (i = (lif->li_modcnt - 2); i > 0; i--) { 1479 rcm_log_message(RCM_TRACE2, 1480 "IP: modremove Pos = %d, Module = %s \n", 1481 i, lif->li_modules[i]); 1482 if (modop(pif->pi_ifname, lif->li_modules[i], 1483 i, MOD_REMOVE) == -1) { 1484 while (i != (lif->li_modcnt - 2)) { 1485 if (modop(pif->pi_ifname, 1486 lif->li_modules[i], 1487 i, MOD_INSERT) == -1) { 1488 /* Gross error */ 1489 rcm_log_message( 1490 RCM_ERROR, 1491 _("IP: if_cfginfo" 1492 "(%s) %s\n"), 1493 pif->pi_ifname, 1494 strerror(errno)); 1495 clr_cfg_state(pif); 1496 return (-1); 1497 } 1498 i++; 1499 } 1500 rcm_log_message( 1501 RCM_ERROR, 1502 _("IP: if_cfginfo(%s): modremove " 1503 "%s failed: %s\n"), pif->pi_ifname, 1504 lif->li_modules[i], 1505 strerror(errno)); 1506 clr_cfg_state(pif); 1507 return (-1); 1508 } 1509 } 1510 } 1511 1512 /* Save reconfiguration information */ 1513 if (lif->li_ifflags & IFF_IPV4) { 1514 (void) snprintf(syscmd, sizeof (syscmd), 1515 "%s %s:%d configinfo\n", SBIN_IFCONFIG, 1516 pif->pi_ifname, lif->li_ifnum); 1517 } else if (lif->li_ifflags & IFF_IPV6) { 1518 (void) snprintf(syscmd, sizeof (syscmd), 1519 "%s %s:%d inet6 configinfo\n", SBIN_IFCONFIG, 1520 pif->pi_ifname, lif->li_ifnum); 1521 } 1522 rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd); 1523 1524 /* open a pipe to retrieve reconfiguration info */ 1525 if ((fp = popen(syscmd, "r")) == NULL) { 1526 rcm_log_message(RCM_ERROR, 1527 _("IP: ifconfig configinfo error (%s:%d) %s\n"), 1528 pif->pi_ifname, lif->li_ifnum, strerror(errno)); 1529 clr_cfg_state(pif); 1530 return (-1); 1531 } 1532 bzero(buf, MAX_RECONFIG_SIZE); 1533 1534 if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) { 1535 rcm_log_message(RCM_ERROR, 1536 _("IP: ifconfig configinfo error (%s:%d) %s\n"), 1537 pif->pi_ifname, lif->li_ifnum, strerror(errno)); 1538 (void) pclose(fp); 1539 clr_cfg_state(pif); 1540 return (-1); 1541 } 1542 (void) pclose(fp); 1543 1544 if ((lif->li_reconfig = strdup(buf)) == NULL) { 1545 rcm_log_message(RCM_ERROR, 1546 _("IP: malloc error (%s) %s\n"), 1547 pif->pi_ifname, strerror(errno)); 1548 clr_cfg_state(pif); 1549 return (-1); 1550 } 1551 rcm_log_message(RCM_DEBUG, 1552 "IP: if_cfginfo: reconfig string(%s:%d) = %s\n", 1553 pif->pi_ifname, lif->li_ifnum, lif->li_reconfig); 1554 1555 lif = lif->li_next; 1556 } 1557 1558 return (0); 1559 } 1560 1561 /* 1562 * if_unplumb() - Unplumb the interface 1563 * Save off the modlist, ifconfig options and unplumb. 1564 * Fail, if an unknown module lives between IP and driver and 1565 * force is not set 1566 * Call with cache_lock held 1567 */ 1568 static int 1569 if_unplumb(ip_cache_t *node) 1570 { 1571 ip_lif_t *lif; 1572 ip_pif_t *pif = node->ip_pif; 1573 boolean_t ipv4 = B_FALSE; 1574 boolean_t ipv6 = B_FALSE; 1575 1576 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource); 1577 1578 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) { 1579 if (lif->li_ifflags & IFF_IPV4) { 1580 ipv4 = B_TRUE; 1581 } else if (lif->li_ifflags & IFF_IPV6) { 1582 ipv6 = B_TRUE; 1583 } else { 1584 /* Unlikely case */ 1585 rcm_log_message(RCM_DEBUG, 1586 "IP: Unplumb ignored (%s:%d)\n", 1587 pif->pi_ifname, lif->li_ifnum); 1588 } 1589 } 1590 1591 if (ipv4 && !ifconfig(pif->pi_ifname, "inet", "unplumb", B_FALSE)) { 1592 rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"), 1593 pif->pi_ifname, strerror(errno)); 1594 return (-1); 1595 } 1596 1597 if (ipv6 && !ifconfig(pif->pi_ifname, "inet6", "unplumb", B_FALSE)) { 1598 rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"), 1599 pif->pi_ifname, strerror(errno)); 1600 return (-1); 1601 } 1602 1603 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n", 1604 node->ip_resource); 1605 1606 return (0); 1607 } 1608 1609 /* 1610 * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface 1611 * instances and the logical interfaces in order, restoring 1612 * all ifconfig options 1613 * Call with cache_lock held 1614 */ 1615 static int 1616 if_replumb(ip_cache_t *node) 1617 { 1618 ip_lif_t *lif; 1619 ip_pif_t *pif; 1620 int i; 1621 boolean_t success, ipmp; 1622 const char *fstr; 1623 char lifname[LIFNAMSIZ]; 1624 char buf[MAX_RECONFIG_SIZE]; 1625 int max_lifnum = 0; 1626 1627 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource); 1628 1629 /* 1630 * Be extra careful about bringing up the interfaces in the 1631 * correct order: 1632 * - First plumb in the physical interface instances 1633 * - modinsert the necessary modules@pos 1634 * - Next, add the logical interfaces being careful about 1635 * the order, (follow the cached interface number li_ifnum order) 1636 */ 1637 1638 pif = node->ip_pif; 1639 ipmp = (node->ip_pif->pi_grname[0] != '\0'); 1640 1641 /* 1642 * Make a first pass to plumb in physical interfaces and get a count 1643 * of the max logical interfaces 1644 */ 1645 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) { 1646 max_lifnum = MAX(lif->li_ifnum, max_lifnum); 1647 if (lif->li_ifflags & IFF_IPV4) { 1648 fstr = "inet"; 1649 } else if (lif->li_ifflags & IFF_IPV6) { 1650 fstr = "inet6"; 1651 } else { 1652 /* Unlikely case */ 1653 rcm_log_message(RCM_DEBUG, 1654 "IP: Re-plumb ignored (%s:%d)\n", 1655 pif->pi_ifname, lif->li_ifnum); 1656 continue; 1657 } 1658 1659 /* ignore logical interface instances */ 1660 if (lif->li_ifnum != 0) 1661 continue; 1662 1663 if ((lif->li_ifflags & IFF_NOFAILOVER) || !ipmp) { 1664 success = ifconfig("", "", lif->li_reconfig, B_FALSE); 1665 } else { 1666 (void) snprintf(buf, sizeof (buf), "plumb group %s", 1667 pif->pi_grname); 1668 success = ifconfig(pif->pi_ifname, fstr, buf, B_FALSE); 1669 } 1670 1671 if (!success) { 1672 rcm_log_message(RCM_ERROR, 1673 _("IP: Cannot plumb (%s) %s\n"), pif->pi_ifname, 1674 strerror(errno)); 1675 return (-1); 1676 } 1677 1678 /* 1679 * Restart DHCP if necessary. 1680 */ 1681 if ((lif->li_ifflags & IFF_DHCPRUNNING) && 1682 !ifconfig(pif->pi_ifname, fstr, CFG_DHCP_CMD, B_FALSE)) { 1683 rcm_log_message(RCM_ERROR, _("IP: Cannot start DHCP " 1684 "(%s) %s\n"), pif->pi_ifname, strerror(errno)); 1685 return (-1); 1686 } 1687 1688 rcm_log_message(RCM_TRACE2, 1689 "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt); 1690 /* modinsert modules in order, ignore driver(last) */ 1691 for (i = 0; i < (lif->li_modcnt - 1); i++) { 1692 rcm_log_message(RCM_TRACE2, 1693 "IP: modinsert: Pos = %d Mod = %s\n", 1694 i, lif->li_modules[i]); 1695 if (modop(pif->pi_ifname, lif->li_modules[i], i, 1696 MOD_INSERT) == -1) { 1697 rcm_log_message(RCM_ERROR, 1698 _("IP: modinsert error(%s)\n"), 1699 pif->pi_ifname); 1700 return (-1); 1701 } 1702 } 1703 } 1704 1705 /* Now, add all the logical interfaces in the correct order */ 1706 for (i = 1; i <= max_lifnum; i++) { 1707 (void) snprintf(lifname, LIFNAMSIZ, "%s:%d", pif->pi_ifname, i); 1708 1709 /* reset lif through every iteration */ 1710 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) { 1711 /* 1712 * Process entries in order. If the interface is 1713 * using IPMP, only process test addresses. 1714 */ 1715 if (lif->li_ifnum != i || 1716 (ipmp && !(lif->li_ifflags & IFF_NOFAILOVER))) 1717 continue; 1718 1719 if (!ifconfig("", "", lif->li_reconfig, B_FALSE)) { 1720 rcm_log_message(RCM_ERROR, 1721 _("IP: Cannot addif (%s) %s\n"), lifname, 1722 strerror(errno)); 1723 return (-1); 1724 } 1725 1726 /* 1727 * Restart DHCP if necessary. 1728 */ 1729 if ((lif->li_ifflags & IFF_DHCPRUNNING) && 1730 !ifconfig(lifname, fstr, CFG_DHCP_CMD, B_FALSE)) { 1731 rcm_log_message(RCM_ERROR, 1732 _("IP: Cannot start DHCP (%s) %s\n"), 1733 lifname, strerror(errno)); 1734 return (-1); 1735 } 1736 } 1737 } 1738 1739 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n", 1740 node->ip_resource); 1741 1742 return (0); 1743 } 1744 1745 /* 1746 * clr_cfg_state() - Cleanup after errors in unplumb 1747 */ 1748 static void 1749 clr_cfg_state(ip_pif_t *pif) 1750 { 1751 ip_lif_t *lif; 1752 int i; 1753 1754 lif = pif->pi_lifs; 1755 1756 while (lif != NULL) { 1757 lif->li_modcnt = 0; 1758 free(lif->li_reconfig); 1759 lif->li_reconfig = NULL; 1760 for (i = 0; i < IP_MAX_MODS; i++) { 1761 free(lif->li_modules[i]); 1762 lif->li_modules[i] = NULL; 1763 } 1764 lif = lif->li_next; 1765 } 1766 } 1767 1768 /* 1769 * Attempt to offline ip_cache_t `node'; returns an IPMP error code. 1770 */ 1771 static int 1772 ip_ipmp_offline(ip_cache_t *node) 1773 { 1774 int retval; 1775 ipmp_handle_t handle; 1776 1777 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n"); 1778 1779 if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) { 1780 rcm_log_message(RCM_ERROR, 1781 _("IP: cannot create ipmp handle: %s\n"), 1782 ipmp_errmsg(retval)); 1783 return (retval); 1784 } 1785 1786 retval = ipmp_offline(handle, node->ip_pif->pi_ifname, node->ip_ifred); 1787 if (retval != IPMP_SUCCESS) { 1788 rcm_log_message(RCM_ERROR, _("IP: ipmp_offline error: %s\n"), 1789 ipmp_errmsg(retval)); 1790 } else { 1791 rcm_log_message(RCM_TRACE1, "IP: ipmp_offline success\n"); 1792 } 1793 1794 ipmp_close(handle); 1795 return (retval); 1796 } 1797 1798 /* 1799 * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code. 1800 */ 1801 static int 1802 ip_ipmp_undo_offline(ip_cache_t *node) 1803 { 1804 int retval; 1805 ipmp_handle_t handle; 1806 1807 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_undo_offline\n"); 1808 1809 if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) { 1810 rcm_log_message(RCM_ERROR, 1811 _("IP: cannot create ipmp handle: %s\n"), 1812 ipmp_errmsg(retval)); 1813 return (retval); 1814 } 1815 1816 retval = ipmp_undo_offline(handle, node->ip_pif->pi_ifname); 1817 if (retval != IPMP_SUCCESS) { 1818 rcm_log_message(RCM_ERROR, 1819 _("IP: ipmp_undo_offline error: %s\n"), 1820 ipmp_errmsg(retval)); 1821 } else { 1822 rcm_log_message(RCM_TRACE1, "IP: ipmp_undo_offline success\n"); 1823 } 1824 1825 ipmp_close(handle); 1826 return (retval); 1827 } 1828 1829 /* 1830 * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a 1831 * dynamically allocated string containing the associated link resource 1832 * name ("SUNW_datalink/<linkid>"). 1833 */ 1834 static char * 1835 get_link_resource(const char *link) 1836 { 1837 char errmsg[DLADM_STRSIZE]; 1838 datalink_id_t linkid; 1839 uint32_t flags; 1840 char *resource; 1841 dladm_status_t status; 1842 1843 status = dladm_name2info(dld_handle, link, &linkid, &flags, NULL, NULL); 1844 if (status != DLADM_STATUS_OK) 1845 goto fail; 1846 1847 if (!(flags & DLADM_OPT_ACTIVE)) { 1848 status = DLADM_STATUS_FAILED; 1849 goto fail; 1850 } 1851 1852 resource = malloc(RCM_LINK_RESOURCE_MAX); 1853 if (resource == NULL) { 1854 rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"), 1855 strerror(errno), link); 1856 return (NULL); 1857 } 1858 1859 (void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u", 1860 RCM_LINK_PREFIX, linkid); 1861 1862 return (resource); 1863 1864 fail: 1865 rcm_log_message(RCM_ERROR, 1866 _("IP: get_link_resource for %s error(%s)\n"), 1867 link, dladm_status2str(status, errmsg)); 1868 return (NULL); 1869 } 1870 1871 /* 1872 * modop() - Remove/insert a module 1873 */ 1874 static int 1875 modop(char *name, char *arg, int pos, char op) 1876 { 1877 char syscmd[LIFNAMSIZ+MAXPATHLEN]; /* must be big enough */ 1878 1879 rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name); 1880 1881 /* Nothing to do with "ip", "arp" */ 1882 if ((arg == NULL) || (strcmp(arg, "") == 0) || 1883 STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) { 1884 rcm_log_message(RCM_TRACE1, "IP: modop success\n"); 1885 return (0); 1886 } 1887 1888 if (op == MOD_CHECK) { 1889 /* 1890 * No known good modules (yet) apart from ip and arp 1891 * which are handled above 1892 */ 1893 return (-1); 1894 } 1895 1896 if (op == MOD_REMOVE) { 1897 (void) snprintf(syscmd, sizeof (syscmd), 1898 "%s %s modremove %s@%d\n", SBIN_IFCONFIG, name, arg, pos); 1899 } else if (op == MOD_INSERT) { 1900 (void) snprintf(syscmd, sizeof (syscmd), 1901 "%s %s modinsert %s@%d\n", SBIN_IFCONFIG, name, arg, pos); 1902 } else { 1903 rcm_log_message(RCM_ERROR, 1904 _("IP: modop(%s): unknown operation\n"), name); 1905 return (-1); 1906 } 1907 1908 rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd); 1909 if (rcm_exec_cmd(syscmd) == -1) { 1910 rcm_log_message(RCM_ERROR, 1911 _("IP: modop(%s): %s\n"), name, strerror(errno)); 1912 return (-1); 1913 } 1914 1915 rcm_log_message(RCM_TRACE1, "IP: modop success\n"); 1916 return (0); 1917 } 1918 1919 /* 1920 * get_modlist() - return a list of pushed mid-stream modules 1921 * Required memory is malloced to construct the list, 1922 * Caller must free this memory list 1923 * Call with cache_lock held 1924 */ 1925 static int 1926 get_modlist(char *name, ip_lif_t *lif) 1927 { 1928 int mux_fd; 1929 int muxid_fd; 1930 int fd; 1931 int i; 1932 int num_mods; 1933 struct lifreq lifr; 1934 struct str_list strlist = { 0 }; 1935 1936 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name); 1937 1938 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1939 lifr.lifr_flags = lif->li_ifflags; 1940 if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) { 1941 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name); 1942 return (-1); 1943 } 1944 1945 if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) { 1946 rcm_log_message(RCM_ERROR, 1947 _("IP: get_modlist(%s): I_LIST(%s) \n"), 1948 name, strerror(errno)); 1949 goto fail; 1950 } 1951 1952 strlist.sl_nmods = num_mods; 1953 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods); 1954 if (strlist.sl_modlist == NULL) { 1955 rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"), 1956 name, strerror(errno)); 1957 goto fail; 1958 } 1959 1960 if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) { 1961 rcm_log_message(RCM_ERROR, 1962 _("IP: get_modlist(%s): I_LIST error: %s\n"), 1963 name, strerror(errno)); 1964 goto fail; 1965 } 1966 1967 for (i = 0; i < strlist.sl_nmods; i++) { 1968 lif->li_modules[i] = strdup(strlist.sl_modlist[i].l_name); 1969 if (lif->li_modules[i] == NULL) { 1970 rcm_log_message(RCM_ERROR, 1971 _("IP: get_modlist(%s): %s\n"), 1972 name, strerror(errno)); 1973 while (i > 0) 1974 free(lif->li_modules[--i]); 1975 goto fail; 1976 } 1977 } 1978 1979 lif->li_modcnt = strlist.sl_nmods; 1980 free(strlist.sl_modlist); 1981 1982 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name); 1983 return (ip_plink(mux_fd, muxid_fd, fd, &lifr)); 1984 fail: 1985 free(strlist.sl_modlist); 1986 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr); 1987 return (-1); 1988 } 1989 1990 /* 1991 * ip_domux2fd() - Helper function for mod*() functions 1992 * Stolen from ifconfig.c 1993 */ 1994 static int 1995 ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr) 1996 { 1997 int muxid_fd; 1998 char *udp_dev_name; 1999 2000 if (lifr->lifr_flags & IFF_IPV6) { 2001 udp_dev_name = UDP6_DEV_NAME; 2002 } else { 2003 udp_dev_name = UDP_DEV_NAME; 2004 } 2005 2006 if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) { 2007 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"), 2008 udp_dev_name, strerror(errno)); 2009 return (-1); 2010 } 2011 if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) { 2012 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"), 2013 udp_dev_name, strerror(errno)); 2014 (void) close(muxid_fd); 2015 return (-1); 2016 } 2017 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) { 2018 rcm_log_message(RCM_ERROR, 2019 _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"), 2020 udp_dev_name, strerror(errno)); 2021 (void) close(*mux_fd); 2022 (void) close(muxid_fd); 2023 return (-1); 2024 } 2025 2026 rcm_log_message(RCM_TRACE2, 2027 "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n", 2028 lifr->lifr_arp_muxid, lifr->lifr_ip_muxid); 2029 2030 if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) { 2031 rcm_log_message(RCM_ERROR, 2032 _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"), 2033 udp_dev_name, strerror(errno)); 2034 (void) close(*mux_fd); 2035 (void) close(muxid_fd); 2036 return (-1); 2037 } 2038 if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) { 2039 rcm_log_message(RCM_ERROR, 2040 _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"), 2041 udp_dev_name, strerror(errno)); 2042 (void) close(*mux_fd); 2043 (void) close(muxid_fd); 2044 return (-1); 2045 } 2046 2047 /* Note: mux_fd and muxid_fd are closed in ip_plink below */ 2048 *muxid_fdp = muxid_fd; 2049 return (0); 2050 } 2051 2052 /* 2053 * ip_plink() - Helper function for mod*() functions. 2054 * Stolen from ifconfig.c 2055 */ 2056 static int 2057 ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr) 2058 { 2059 int mux_id; 2060 2061 if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) { 2062 rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"), 2063 UDP_DEV_NAME, strerror(errno)); 2064 (void) close(mux_fd); 2065 (void) close(muxid_fd); 2066 (void) close(fd); 2067 return (-1); 2068 } 2069 2070 lifr->lifr_ip_muxid = mux_id; 2071 if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) { 2072 rcm_log_message(RCM_ERROR, 2073 _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"), 2074 UDP_DEV_NAME, strerror(errno)); 2075 (void) close(mux_fd); 2076 (void) close(muxid_fd); 2077 (void) close(fd); 2078 return (-1); 2079 } 2080 2081 (void) close(mux_fd); 2082 (void) close(muxid_fd); 2083 (void) close(fd); 2084 return (0); 2085 } 2086 2087 /* 2088 * ip_onlinelist() 2089 * 2090 * Notify online to IP address consumers. 2091 */ 2092 /*ARGSUSED*/ 2093 static int 2094 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags, 2095 rcm_info_t **depend_info) 2096 { 2097 char **addrlist; 2098 int ret = RCM_SUCCESS; 2099 2100 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n"); 2101 2102 addrlist = ip_get_addrlist(node); 2103 if (addrlist == NULL || addrlist[0] == NULL) { 2104 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n"); 2105 ip_free_addrlist(addrlist); 2106 return (ret); 2107 } 2108 2109 ret = rcm_notify_online_list(hd, addrlist, 0, depend_info); 2110 2111 ip_free_addrlist(addrlist); 2112 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n"); 2113 return (ret); 2114 } 2115 2116 /* 2117 * ip_offlinelist() 2118 * 2119 * Offline IP address consumers. 2120 */ 2121 /*ARGSUSED*/ 2122 static int 2123 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags, 2124 rcm_info_t **depend_info) 2125 { 2126 char **addrlist; 2127 int ret = RCM_SUCCESS; 2128 2129 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n"); 2130 2131 addrlist = ip_get_addrlist(node); 2132 if (addrlist == NULL || addrlist[0] == NULL) { 2133 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n"); 2134 ip_free_addrlist(addrlist); 2135 return (RCM_SUCCESS); 2136 } 2137 2138 if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info)) 2139 != RCM_SUCCESS) { 2140 if (ret == RCM_FAILURE) 2141 (void) rcm_notify_online_list(hd, addrlist, 0, NULL); 2142 2143 ret = RCM_FAILURE; 2144 } 2145 2146 ip_free_addrlist(addrlist); 2147 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n"); 2148 return (ret); 2149 } 2150 2151 /* 2152 * ip_get_addrlist() - Get the list of IP addresses on this interface (node); 2153 * This routine malloc()s required memory for the list. 2154 * Returns the list on success, NULL on failure. 2155 * Call with cache_lock held. 2156 */ 2157 static char ** 2158 ip_get_addrlist(ip_cache_t *node) 2159 { 2160 ip_lif_t *lif; 2161 char **addrlist = NULL; 2162 int i, numifs; 2163 size_t addrlistsize; 2164 char addrstr[INET6_ADDRSTRLEN]; 2165 2166 rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n", 2167 node->ip_resource); 2168 2169 numifs = 0; 2170 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) { 2171 numifs++; 2172 } 2173 2174 /* 2175 * Allocate space for resource names list; add 1 and use calloc() 2176 * so that the list is NULL-terminated. 2177 */ 2178 if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) { 2179 rcm_log_message(RCM_ERROR, 2180 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"), 2181 node->ip_resource, strerror(errno)); 2182 return (NULL); 2183 } 2184 2185 for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL; 2186 lif = lif->li_next, i++) { 2187 2188 if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) { 2189 ip_free_addrlist(addrlist); 2190 return (NULL); 2191 } 2192 2193 addrlistsize = strlen(addrstr) + sizeof (RCM_STR_SUNW_IP); 2194 if ((addrlist[i] = malloc(addrlistsize)) == NULL) { 2195 rcm_log_message(RCM_ERROR, 2196 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"), 2197 node->ip_resource, strerror(errno)); 2198 ip_free_addrlist(addrlist); 2199 return (NULL); 2200 } 2201 (void) snprintf(addrlist[i], addrlistsize, "%s%s", 2202 RCM_STR_SUNW_IP, addrstr); 2203 2204 rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]); 2205 } 2206 2207 rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n", 2208 node->ip_resource); 2209 2210 return (addrlist); 2211 } 2212 2213 static void 2214 ip_free_addrlist(char **addrlist) 2215 { 2216 int i; 2217 2218 if (addrlist == NULL) 2219 return; 2220 2221 for (i = 0; addrlist[i] != NULL; i++) 2222 free(addrlist[i]); 2223 free(addrlist); 2224 } 2225 2226 /* 2227 * ip_consumer_notify() - Notify consumers of IP addresses coming back online. 2228 */ 2229 2230 static void 2231 ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp, 2232 uint_t flags, rcm_info_t **depend_info) 2233 { 2234 char cached_name[RCM_LINK_RESOURCE_MAX]; 2235 ip_cache_t *node; 2236 2237 assert(linkid != DATALINK_INVALID_LINKID); 2238 2239 rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid); 2240 2241 /* Check for the interface in the cache */ 2242 (void) snprintf(cached_name, sizeof (cached_name), "%s/%u", 2243 RCM_LINK_PREFIX, linkid); 2244 2245 (void) mutex_lock(&cache_lock); 2246 if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) { 2247 rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"), 2248 linkid); 2249 (void) mutex_unlock(&cache_lock); 2250 return; 2251 } 2252 /* 2253 * Inform anonymous consumers about IP addresses being onlined. 2254 */ 2255 (void) ip_onlinelist(hd, node, errorp, flags, depend_info); 2256 2257 (void) mutex_unlock(&cache_lock); 2258 2259 rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n"); 2260 } 2261 2262 /* 2263 * Gets the interface name for the given linkid. Returns -1 if there is 2264 * any error. It fills in the interface name in `ifinst' if the interface 2265 * is not already configured. Otherwise, it puts a null string in `ifinst'. 2266 */ 2267 static int 2268 if_configure_get_linkid(datalink_id_t linkid, char *ifinst, size_t len) 2269 { 2270 char cached_name[RCM_LINK_RESOURCE_MAX]; 2271 ip_cache_t *node; 2272 2273 /* Check for the interface in the cache */ 2274 (void) snprintf(cached_name, sizeof (cached_name), "%s/%u", 2275 RCM_LINK_PREFIX, linkid); 2276 2277 /* Check if the interface is new or was not previously offlined */ 2278 (void) mutex_lock(&cache_lock); 2279 if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) && 2280 (!(node->ip_cachestate & CACHE_IF_OFFLINED))) { 2281 rcm_log_message(RCM_TRACE1, 2282 _("IP: Skipping configured interface(%u)\n"), linkid); 2283 (void) mutex_unlock(&cache_lock); 2284 *ifinst = '\0'; 2285 return (0); 2286 } 2287 (void) mutex_unlock(&cache_lock); 2288 2289 if (dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, NULL, ifinst, 2290 len) != DLADM_STATUS_OK) { 2291 rcm_log_message(RCM_ERROR, 2292 _("IP: get %u link name failed\n"), linkid); 2293 return (-1); 2294 } 2295 return (0); 2296 } 2297 2298 /* 2299 * if_configure_hostname() - Configure a physical interface after attach 2300 * based on the information in /etc/hostname.* 2301 */ 2302 static int 2303 if_configure_hostname(datalink_id_t linkid) 2304 { 2305 FILE *hostfp, *host6fp; 2306 boolean_t ipmp = B_FALSE; 2307 char ifinst[MAXLINKNAMELEN]; 2308 char cfgfile[MAXPATHLEN]; 2309 2310 assert(linkid != DATALINK_INVALID_LINKID); 2311 rcm_log_message(RCM_TRACE1, _("IP: if_configure_hostname(%u)\n"), 2312 linkid); 2313 2314 if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0) 2315 return (-1); 2316 2317 /* Check if the interface is already configured. */ 2318 if (ifinst[0] == '\0') 2319 return (0); 2320 2321 /* 2322 * Scan the IPv4 and IPv6 hostname files to see if (a) they exist 2323 * and (b) if either one places the interface into an IPMP group. 2324 */ 2325 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifinst); 2326 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile); 2327 if ((hostfp = fopen(cfgfile, "r")) != NULL) { 2328 if (isgrouped(cfgfile)) 2329 ipmp = B_TRUE; 2330 } 2331 2332 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifinst); 2333 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile); 2334 if ((host6fp = fopen(cfgfile, "r")) != NULL) { 2335 if (!ipmp && isgrouped(cfgfile)) 2336 ipmp = B_TRUE; 2337 } 2338 2339 /* 2340 * Configure the interface according to its hostname files. 2341 */ 2342 if (hostfp != NULL && 2343 if_config_inst(ifinst, hostfp, AF_INET, ipmp) == -1) { 2344 rcm_log_message(RCM_ERROR, 2345 _("IP: IPv4 Post-attach failed (%s)\n"), ifinst); 2346 goto fail; 2347 } 2348 2349 if (host6fp != NULL && 2350 if_config_inst(ifinst, host6fp, AF_INET6, ipmp) == -1) { 2351 rcm_log_message(RCM_ERROR, 2352 _("IP: IPv6 Post-attach failed (%s)\n"), ifinst); 2353 goto fail; 2354 } 2355 2356 (void) fclose(hostfp); 2357 (void) fclose(host6fp); 2358 rcm_log_message(RCM_TRACE1, "IP: if_configure_hostname(%s) success\n", 2359 ifinst); 2360 return (0); 2361 fail: 2362 (void) fclose(hostfp); 2363 (void) fclose(host6fp); 2364 return (-1); 2365 } 2366 2367 /* 2368 * if_configure_ipadm() - Configure a physical interface after attach 2369 * Queries libipadm for persistent configuration information and then 2370 * resurrects that persistent configuration. 2371 */ 2372 static int 2373 if_configure_ipadm(datalink_id_t linkid) 2374 { 2375 char ifinst[MAXLINKNAMELEN]; 2376 boolean_t found; 2377 ipadm_if_info_t *ifinfo, *ptr; 2378 ipadm_status_t status; 2379 2380 assert(linkid != DATALINK_INVALID_LINKID); 2381 rcm_log_message(RCM_TRACE1, _("IP: if_configure_ipadm(%u)\n"), 2382 linkid); 2383 2384 if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0) 2385 return (-1); 2386 2387 /* Check if the interface is already configured. */ 2388 if (ifinst[0] == '\0') 2389 return (0); 2390 2391 status = ipadm_if_info(ip_handle, ifinst, &ifinfo, 0, LIFC_UNDER_IPMP); 2392 if (status == IPADM_ENXIO) 2393 goto done; 2394 if (status != IPADM_SUCCESS) { 2395 rcm_log_message(RCM_ERROR, 2396 _("IP: IPv4 Post-attach failed (%s) Error %s\n"), 2397 ifinst, ipadm_status2str(status)); 2398 goto fail; 2399 } 2400 if (ifinfo != NULL) { 2401 found = B_FALSE; 2402 for (ptr = ifinfo; ptr; ptr = ptr->ifi_next) { 2403 if (strncmp(ptr->ifi_name, ifinst, 2404 sizeof (ifinst)) == 0) { 2405 found = B_TRUE; 2406 break; 2407 } 2408 } 2409 free(ifinfo); 2410 if (!found) { 2411 return (0); 2412 } 2413 if (if_hostname_exists(ifinst, AF_INET) || 2414 if_hostname_exists(ifinst, AF_INET6)) { 2415 rcm_log_message(RCM_WARNING, 2416 _("IP: IPv4 Post-attach (%s) found both " 2417 "/etc/hostname and ipadm persistent configuration. " 2418 "Ignoring ipadm config\n"), ifinst); 2419 return (0); 2420 } 2421 status = ipadm_enable_if(ip_handle, ifinst, IPADM_OPT_ACTIVE); 2422 if (status != IPADM_SUCCESS) { 2423 rcm_log_message(RCM_ERROR, 2424 _("IP: Post-attach failed (%s) Error %s\n"), 2425 ifinst, ipadm_status2str(status)); 2426 goto fail; 2427 } 2428 } 2429 done: 2430 rcm_log_message(RCM_TRACE1, "IP: if_configure_ipadm(%s) success\n", 2431 ifinst); 2432 return (0); 2433 fail: 2434 return (-1); 2435 } 2436 2437 /* 2438 * isgrouped() - Scans the given config file to see if this interface is 2439 * using IPMP. Returns B_TRUE or B_FALSE. 2440 */ 2441 static boolean_t 2442 isgrouped(const char *cfgfile) 2443 { 2444 FILE *fp; 2445 struct stat statb; 2446 char *nlp, *line, *token, *lasts, *buf; 2447 boolean_t grouped = B_FALSE; 2448 2449 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile); 2450 2451 if (stat(cfgfile, &statb) != 0) { 2452 rcm_log_message(RCM_TRACE1, 2453 _("IP: No config file(%s)\n"), cfgfile); 2454 return (B_FALSE); 2455 } 2456 2457 /* 2458 * We also ignore single-byte config files because the file should 2459 * always be newline-terminated, so we know there's nothing of 2460 * interest. Further, a single-byte file would cause the fgets() loop 2461 * below to spin forever. 2462 */ 2463 if (statb.st_size <= 1) { 2464 rcm_log_message(RCM_TRACE1, 2465 _("IP: Empty config file(%s)\n"), cfgfile); 2466 return (B_FALSE); 2467 } 2468 2469 if ((fp = fopen(cfgfile, "r")) == NULL) { 2470 rcm_log_message(RCM_ERROR, 2471 _("IP: Cannot open configuration file(%s): %s\n"), cfgfile, 2472 strerror(errno)); 2473 return (B_FALSE); 2474 } 2475 2476 if ((buf = malloc(statb.st_size)) == NULL) { 2477 rcm_log_message(RCM_ERROR, 2478 _("IP: malloc failure(%s): %s\n"), cfgfile, 2479 strerror(errno)); 2480 goto out; 2481 } 2482 2483 while (fgets(buf, statb.st_size, fp) != NULL) { 2484 if ((nlp = strrchr(buf, '\n')) != NULL) 2485 *nlp = '\0'; 2486 2487 line = buf; 2488 while ((token = strtok_r(line, " \t", &lasts)) != NULL) { 2489 line = NULL; 2490 if (STREQ("group", token) && 2491 strtok_r(NULL, " \t", &lasts) != NULL) { 2492 grouped = B_TRUE; 2493 goto out; 2494 } 2495 } 2496 } 2497 out: 2498 free(buf); 2499 (void) fclose(fp); 2500 2501 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s): %d\n", cfgfile, 2502 grouped); 2503 2504 return (grouped); 2505 } 2506 2507 /* 2508 * if_config_inst() - Configure an interface instance as specified by the 2509 * address family af and if it is grouped (ipmp). 2510 */ 2511 static int 2512 if_config_inst(const char *ifinst, FILE *hfp, int af, boolean_t ipmp) 2513 { 2514 FILE *ifparsefp; 2515 struct stat statb; 2516 char *buf = NULL; 2517 char *ifparsebuf = NULL; 2518 uint_t ifparsebufsize; 2519 const char *fstr; /* address family string */ 2520 boolean_t stdif = B_FALSE; 2521 2522 rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) ipmp = %d\n", 2523 ifinst, ipmp); 2524 2525 if (fstat(fileno(hfp), &statb) != 0) { 2526 rcm_log_message(RCM_ERROR, 2527 _("IP: Cannot fstat file(%s)\n"), ifinst); 2528 goto fail; 2529 } 2530 2531 switch (af) { 2532 case AF_INET: 2533 fstr = "inet"; 2534 break; 2535 case AF_INET6: 2536 fstr = "inet6"; 2537 break; 2538 default: 2539 assert(0); 2540 } 2541 2542 /* 2543 * The hostname file exists; plumb the physical interface. 2544 */ 2545 if (!ifconfig(ifinst, fstr, "plumb", B_FALSE)) 2546 goto fail; 2547 2548 /* Skip static configuration if the hostname file is empty */ 2549 if (statb.st_size <= 1) { 2550 rcm_log_message(RCM_TRACE1, 2551 _("IP: Zero size hostname file(%s)\n"), ifinst); 2552 goto configured; 2553 } 2554 2555 if (fseek(hfp, 0, SEEK_SET) == -1) { 2556 rcm_log_message(RCM_ERROR, 2557 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst, 2558 strerror(errno)); 2559 goto fail; 2560 } 2561 2562 /* 2563 * Allocate the worst-case single-line buffer sizes. A bit skanky, 2564 * but since hostname files are small, this should suffice. 2565 */ 2566 if ((buf = calloc(1, statb.st_size)) == NULL) { 2567 rcm_log_message(RCM_ERROR, 2568 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno)); 2569 goto fail; 2570 } 2571 2572 ifparsebufsize = statb.st_size + sizeof (SBIN_IFPARSE " -s inet6 "); 2573 if ((ifparsebuf = calloc(1, ifparsebufsize)) == NULL) { 2574 rcm_log_message(RCM_ERROR, 2575 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno)); 2576 goto fail; 2577 } 2578 2579 /* 2580 * For IPv4, determine whether the hostname file consists of a single 2581 * line. We need to handle these specially since they should 2582 * automatically be suffixed with "netmask + broadcast + up". 2583 */ 2584 if (af == AF_INET && 2585 fgets(buf, statb.st_size, hfp) != NULL && 2586 fgets(buf, statb.st_size, hfp) == NULL) { 2587 rcm_log_message(RCM_TRACE1, "IP: one-line hostname file\n"); 2588 stdif = B_TRUE; 2589 } 2590 2591 if (fseek(hfp, 0L, SEEK_SET) == -1) { 2592 rcm_log_message(RCM_ERROR, 2593 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst, 2594 strerror(errno)); 2595 goto fail; 2596 } 2597 2598 /* 2599 * Loop through the file one line at a time and feed it to ifconfig. 2600 * If the interface is using IPMP, then we use /sbin/ifparse -s to 2601 * weed out all of the data addresses, since those are already on the 2602 * IPMP meta-interface. 2603 */ 2604 while (fgets(buf, statb.st_size, hfp) != NULL) { 2605 if (ntok(buf) == 0) 2606 continue; 2607 2608 if (!ipmp) { 2609 (void) ifconfig(ifinst, fstr, buf, stdif); 2610 continue; 2611 } 2612 2613 (void) snprintf(ifparsebuf, ifparsebufsize, SBIN_IFPARSE 2614 " -s %s %s", fstr, buf); 2615 if ((ifparsefp = popen(ifparsebuf, "r")) == NULL) { 2616 rcm_log_message(RCM_ERROR, 2617 _("IP: cannot configure %s: popen \"%s\" " 2618 "failed: %s\n"), ifinst, buf, strerror(errno)); 2619 goto fail; 2620 } 2621 2622 while (fgets(buf, statb.st_size, ifparsefp) != NULL) { 2623 if (ntok(buf) > 0) 2624 (void) ifconfig(ifinst, fstr, buf, stdif); 2625 } 2626 2627 if (pclose(ifparsefp) == -1) { 2628 rcm_log_message(RCM_ERROR, 2629 _("IP: cannot configure %s: pclose \"%s\" " 2630 "failed: %s\n"), ifinst, buf, strerror(errno)); 2631 goto fail; 2632 } 2633 } 2634 2635 configured: 2636 /* 2637 * Bring up the interface (it may already be up) 2638 * 2639 * Technically, since the boot scripts only unconditionally bring up 2640 * IPv6 interfaces, we should only unconditionally bring up IPv6 here. 2641 * However, if we don't bring up IPv4, and a legacy IPMP configuration 2642 * without test addresses is being used, we will never bring the 2643 * interface up even though we would've at boot. One fix is to check 2644 * if the IPv4 hostname file contains data addresses that we would've 2645 * brought up, but there's no simple way to do that. Given that it's 2646 * rare to have persistent IP configuration for an interface that 2647 * leaves it down, we cheap out and always bring it up for IPMP. 2648 */ 2649 if ((af == AF_INET6 || ipmp) && !ifconfig(ifinst, fstr, "up", B_FALSE)) 2650 goto fail; 2651 2652 /* 2653 * For IPv4, if a DHCP configuration file exists, have DHCP configure 2654 * the interface. As with the boot scripts, this is done after the 2655 * hostname files are processed so that configuration in those files 2656 * (such as IPMP group names) will be applied first. 2657 */ 2658 if (af == AF_INET) { 2659 char dhcpfile[MAXPATHLEN]; 2660 char *dhcpbuf; 2661 off_t i, dhcpsize; 2662 2663 (void) snprintf(dhcpfile, MAXPATHLEN, DHCPFILE_FMT, ifinst); 2664 if (stat(dhcpfile, &statb) == -1) 2665 goto out; 2666 2667 if ((dhcpbuf = copylist(dhcpfile, &dhcpsize)) == NULL) { 2668 rcm_log_message(RCM_ERROR, _("IP: cannot read " 2669 "(%s): %s\n"), dhcpfile, strerror(errno)); 2670 goto fail; 2671 } 2672 2673 /* 2674 * The copylist() API converts \n's to \0's, but we want them 2675 * to be spaces. 2676 */ 2677 if (dhcpsize > 0) { 2678 for (i = 0; i < dhcpsize; i++) 2679 if (dhcpbuf[i] == '\0') 2680 dhcpbuf[i] = ' '; 2681 dhcpbuf[dhcpsize - 1] = '\0'; 2682 } 2683 (void) ifconfig(ifinst, CFG_DHCP_CMD, dhcpbuf, B_FALSE); 2684 free(dhcpbuf); 2685 } 2686 out: 2687 free(ifparsebuf); 2688 free(buf); 2689 rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) success\n", ifinst); 2690 return (0); 2691 fail: 2692 free(ifparsebuf); 2693 free(buf); 2694 rcm_log_message(RCM_ERROR, "IP: if_config_inst(%s) failure\n", ifinst); 2695 return (-1); 2696 } 2697 2698 /* 2699 * ntok() - count the number of tokens in the provided buffer. 2700 */ 2701 static uint_t 2702 ntok(const char *cp) 2703 { 2704 uint_t ntok = 0; 2705 2706 for (;;) { 2707 while (ISSPACE(*cp)) 2708 cp++; 2709 2710 if (ISEOL(*cp)) 2711 break; 2712 2713 do { 2714 cp++; 2715 } while (!ISSPACE(*cp) && !ISEOL(*cp)); 2716 2717 ntok++; 2718 } 2719 return (ntok); 2720 } 2721 2722 static boolean_t 2723 ifconfig(const char *ifinst, const char *fstr, const char *buf, boolean_t stdif) 2724 { 2725 char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1]; 2726 int status; 2727 2728 (void) snprintf(syscmd, sizeof (syscmd), SBIN_IFCONFIG " %s %s %s", 2729 ifinst, fstr, buf); 2730 2731 if (stdif) 2732 (void) strlcat(syscmd, CFG_CMDS_STD, sizeof (syscmd)); 2733 2734 rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd); 2735 if ((status = rcm_exec_cmd(syscmd)) != 0) { 2736 if (WIFEXITED(status)) { 2737 rcm_log_message(RCM_ERROR, _("IP: \"%s\" failed with " 2738 "exit status %d\n"), syscmd, WEXITSTATUS(status)); 2739 } else { 2740 rcm_log_message(RCM_ERROR, _("IP: Error: %s: %s\n"), 2741 syscmd, strerror(errno)); 2742 } 2743 return (B_FALSE); 2744 } 2745 return (B_TRUE); 2746 } 2747 2748 /* 2749 * Return TRUE if a writeable /etc/hostname[6].ifname file exists. 2750 */ 2751 static boolean_t 2752 if_hostname_exists(char *ifname, sa_family_t af) 2753 { 2754 char cfgfile[MAXPATHLEN]; 2755 2756 if (af == AF_INET) { 2757 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifname); 2758 if (access(cfgfile, W_OK|F_OK) == 0) 2759 return (B_TRUE); 2760 } else if (af == AF_INET6) { 2761 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifname); 2762 if (access(cfgfile, W_OK|F_OK) == 0) 2763 return (B_TRUE); 2764 } 2765 return (B_FALSE); 2766 } 2767