1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * This RCM module adds support to the RCM framework for IP managed 27 * interfaces. 28 */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <assert.h> 34 #include <string.h> 35 #include <synch.h> 36 #include <libintl.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <sys/types.h> 40 #include <sys/wait.h> 41 #include <sys/stat.h> 42 #include <sys/socket.h> 43 #include <sys/sockio.h> 44 #include <net/if.h> 45 #include <netinet/in.h> 46 #include <arpa/inet.h> 47 #include <stropts.h> 48 #include <strings.h> 49 #include <sys/sysmacros.h> 50 #include <inet/ip.h> 51 #include <libinetutil.h> 52 #include <libdllink.h> 53 #include <libgen.h> 54 #include <ipmp_admin.h> 55 #include <libipadm.h> 56 57 #include "rcm_module.h" 58 59 /* 60 * Definitions 61 */ 62 #ifndef lint 63 #define _(x) gettext(x) 64 #else 65 #define _(x) x 66 #endif 67 68 /* Some generic well-knowns and defaults used in this module */ 69 #define ARP_MOD_NAME "arp" /* arp module */ 70 #define IP_MAX_MODS 9 /* max modules pushed on intr */ 71 #define MAX_RECONFIG_SIZE 1024 /* Max. reconfig string size */ 72 73 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */ 74 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH) 75 76 #define RCM_STR_SUNW_IP "SUNW_ip/" /* IP address export prefix */ 77 78 #define SBIN_IFCONFIG "/sbin/ifconfig" /* ifconfig command */ 79 #define SBIN_IFPARSE "/sbin/ifparse" /* ifparse command */ 80 #define DHCPFILE_FMT "/etc/dhcp.%s" /* DHCP config file */ 81 #define CFGFILE_FMT_IPV4 "/etc/hostname.%s" /* IPV4 config file */ 82 #define CFGFILE_FMT_IPV6 "/etc/hostname6.%s" /* IPV6 config file */ 83 #define CFG_CMDS_STD " netmask + broadcast + up" /* Normal config string */ 84 #define CFG_DHCP_CMD "dhcp wait 0" /* command to start DHCP */ 85 86 /* Some useful macros */ 87 #define ISSPACE(c) ((c) == ' ' || (c) == '\t') 88 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 89 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 90 91 /* Interface Cache state flags */ 92 #define CACHE_IF_STALE 0x1 /* stale cached data */ 93 #define CACHE_IF_NEW 0x2 /* new cached interface */ 94 #define CACHE_IF_OFFLINED 0x4 /* interface offlined */ 95 #define CACHE_IF_IGNORE 0x8 /* state held elsewhere */ 96 97 /* Network Cache lookup options */ 98 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */ 99 #define CACHE_REFRESH 0x2 /* refresh cache */ 100 101 /* RCM IPMP Module specific property definitions */ 102 #define RCM_IPMP_MIN_REDUNDANCY 1 /* default min. redundancy */ 103 104 /* Stream module operations */ 105 #define MOD_INSERT 0 /* Insert a mid-stream module */ 106 #define MOD_REMOVE 1 /* Remove a mid-stream module */ 107 #define MOD_CHECK 2 /* Check mid-stream module safety */ 108 109 /* 110 * IP module data types 111 */ 112 113 /* Physical interface representation */ 114 typedef struct ip_pif { 115 char pi_ifname[LIFNAMSIZ]; /* interface name */ 116 char pi_grname[LIFGRNAMSIZ]; /* IPMP group name */ 117 struct ip_lif *pi_lifs; /* ptr to logical interfaces */ 118 } ip_pif_t; 119 120 /* Logical interface representation */ 121 typedef struct ip_lif 122 { 123 struct ip_lif *li_next; /* ptr to next lif */ 124 struct ip_lif *li_prev; /* previous next ptr */ 125 ip_pif_t *li_pif; /* back ptr to phy int */ 126 ushort_t li_ifnum; /* interface number */ 127 union { 128 sa_family_t family; 129 struct sockaddr_storage storage; 130 struct sockaddr_in ip4; /* IPv4 */ 131 struct sockaddr_in6 ip6; /* IPv6 */ 132 } li_addr; 133 uint64_t li_ifflags; /* current IFF_* flags */ 134 int li_modcnt; /* # of modules */ 135 char *li_modules[IP_MAX_MODS]; /* module list pushed */ 136 char *li_reconfig; /* Reconfiguration string */ 137 int32_t li_cachestate; /* cache state flags */ 138 } ip_lif_t; 139 140 /* Cache element */ 141 typedef struct ip_cache 142 { 143 struct ip_cache *ip_next; /* next cached resource */ 144 struct ip_cache *ip_prev; /* prev cached resource */ 145 char *ip_resource; /* resource name */ 146 ip_pif_t *ip_pif; /* ptr to phy int */ 147 int32_t ip_ifred; /* min. redundancy */ 148 int ip_cachestate; /* cache state flags */ 149 } ip_cache_t; 150 151 /* 152 * Global cache for network interfaces 153 */ 154 static ip_cache_t cache_head; 155 static ip_cache_t cache_tail; 156 static mutex_t cache_lock; 157 static int events_registered = 0; 158 159 static dladm_handle_t dld_handle = NULL; 160 static ipadm_handle_t ip_handle = NULL; 161 162 /* 163 * RCM module interface prototypes 164 */ 165 static int ip_register(rcm_handle_t *); 166 static int ip_unregister(rcm_handle_t *); 167 static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t, 168 char **, char **, nvlist_t *, rcm_info_t **); 169 static int ip_suspend(rcm_handle_t *, char *, id_t, 170 timespec_t *, uint_t, char **, rcm_info_t **); 171 static int ip_resume(rcm_handle_t *, char *, id_t, uint_t, 172 char **, rcm_info_t **); 173 static int ip_offline(rcm_handle_t *, char *, id_t, uint_t, 174 char **, rcm_info_t **); 175 static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t, 176 char **, rcm_info_t **); 177 static int ip_remove(rcm_handle_t *, char *, id_t, uint_t, 178 char **, rcm_info_t **); 179 static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t, 180 char **, nvlist_t *, rcm_info_t **); 181 182 /* Module private routines */ 183 static void free_cache(); 184 static int update_cache(rcm_handle_t *); 185 static void cache_remove(ip_cache_t *); 186 static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char); 187 static void free_node(ip_cache_t *); 188 static void cache_insert(ip_cache_t *); 189 static char *ip_usage(ip_cache_t *); 190 static int update_pif(rcm_handle_t *, int, int, struct ifaddrs *); 191 static int ip_ipmp_offline(ip_cache_t *); 192 static int ip_ipmp_undo_offline(ip_cache_t *); 193 static int if_cfginfo(ip_cache_t *, uint_t); 194 static int if_unplumb(ip_cache_t *); 195 static int if_replumb(ip_cache_t *); 196 static void ip_log_err(ip_cache_t *, char **, char *); 197 static char *get_link_resource(const char *); 198 static void clr_cfg_state(ip_pif_t *); 199 static int modop(char *, char *, int, char); 200 static int get_modlist(char *, ip_lif_t *); 201 static int ip_domux2fd(int *, int *, int *, struct lifreq *); 202 static int ip_plink(int, int, int, struct lifreq *); 203 static int ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t, 204 rcm_info_t **); 205 static int ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t, 206 rcm_info_t **); 207 static char **ip_get_addrlist(ip_cache_t *); 208 static void ip_free_addrlist(char **); 209 static void ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **, 210 uint_t, rcm_info_t **); 211 static boolean_t ip_addrstr(ip_lif_t *, char *, size_t); 212 213 static int if_configure_hostname(datalink_id_t); 214 static int if_configure_ipadm(datalink_id_t); 215 static boolean_t if_hostname_exists(char *, sa_family_t); 216 static boolean_t isgrouped(const char *); 217 static int if_config_inst(const char *, FILE *, int, boolean_t); 218 static uint_t ntok(const char *cp); 219 static boolean_t ifconfig(const char *, const char *, const char *, boolean_t); 220 221 /* Module-Private data */ 222 static struct rcm_mod_ops ip_ops = 223 { 224 RCM_MOD_OPS_VERSION, 225 ip_register, 226 ip_unregister, 227 ip_get_info, 228 ip_suspend, 229 ip_resume, 230 ip_offline, 231 ip_undo_offline, 232 ip_remove, 233 NULL, 234 NULL, 235 ip_notify_event 236 }; 237 238 /* 239 * rcm_mod_init() - Update registrations, and return the ops structure. 240 */ 241 struct rcm_mod_ops * 242 rcm_mod_init(void) 243 { 244 char errmsg[DLADM_STRSIZE]; 245 dladm_status_t status; 246 ipadm_status_t iph_status; 247 248 rcm_log_message(RCM_TRACE1, "IP: mod_init\n"); 249 250 cache_head.ip_next = &cache_tail; 251 cache_head.ip_prev = NULL; 252 cache_tail.ip_prev = &cache_head; 253 cache_tail.ip_next = NULL; 254 (void) mutex_init(&cache_lock, NULL, NULL); 255 256 if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) { 257 rcm_log_message(RCM_WARNING, 258 "IP: mod_init failed: cannot get datalink handle: %s\n", 259 dladm_status2str(status, errmsg)); 260 return (NULL); 261 } 262 263 if ((iph_status = ipadm_open(&ip_handle, 0)) != IPADM_SUCCESS) { 264 rcm_log_message(RCM_ERROR, 265 "IP: mod_init failed: cannot get IP handle: %s\n", 266 ipadm_status2str(iph_status)); 267 dladm_close(dld_handle); 268 dld_handle = NULL; 269 return (NULL); 270 } 271 272 /* Return the ops vectors */ 273 return (&ip_ops); 274 } 275 276 /* 277 * rcm_mod_info() - Return a string describing this module. 278 */ 279 const char * 280 rcm_mod_info(void) 281 { 282 rcm_log_message(RCM_TRACE1, "IP: mod_info\n"); 283 284 return ("IP Multipathing module version 1.23"); 285 } 286 287 /* 288 * rcm_mod_fini() - Destroy the network interfaces cache. 289 */ 290 int 291 rcm_mod_fini(void) 292 { 293 rcm_log_message(RCM_TRACE1, "IP: mod_fini\n"); 294 295 free_cache(); 296 (void) mutex_destroy(&cache_lock); 297 298 dladm_close(dld_handle); 299 ipadm_close(ip_handle); 300 return (RCM_SUCCESS); 301 } 302 303 /* 304 * ip_register() - Make sure the cache is properly sync'ed, and its 305 * registrations are in order. 306 */ 307 static int 308 ip_register(rcm_handle_t *hd) 309 { 310 rcm_log_message(RCM_TRACE1, "IP: register\n"); 311 312 /* Guard against bad arguments */ 313 assert(hd != NULL); 314 315 if (update_cache(hd) < 0) 316 return (RCM_FAILURE); 317 318 /* 319 * Need to register interest in all new resources 320 * getting attached, so we get attach event notifications 321 */ 322 if (!events_registered) { 323 if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL) 324 != RCM_SUCCESS) { 325 rcm_log_message(RCM_ERROR, 326 _("IP: failed to register %s\n"), 327 RCM_RESOURCE_LINK_NEW); 328 return (RCM_FAILURE); 329 } else { 330 rcm_log_message(RCM_DEBUG, "IP: registered %s\n", 331 RCM_RESOURCE_LINK_NEW); 332 events_registered++; 333 } 334 } 335 336 return (RCM_SUCCESS); 337 } 338 339 /* 340 * ip_unregister() - Walk the cache, unregistering all the networks. 341 */ 342 static int 343 ip_unregister(rcm_handle_t *hd) 344 { 345 ip_cache_t *probe; 346 347 rcm_log_message(RCM_TRACE1, "IP: unregister\n"); 348 349 /* Guard against bad arguments */ 350 assert(hd != NULL); 351 352 /* Walk the cache, unregistering everything */ 353 (void) mutex_lock(&cache_lock); 354 probe = cache_head.ip_next; 355 while (probe != &cache_tail) { 356 if (rcm_unregister_interest(hd, probe->ip_resource, 0) 357 != RCM_SUCCESS) { 358 /* unregister failed for whatever reason */ 359 (void) mutex_unlock(&cache_lock); 360 return (RCM_FAILURE); 361 } 362 cache_remove(probe); 363 free_node(probe); 364 probe = cache_head.ip_next; 365 } 366 (void) mutex_unlock(&cache_lock); 367 368 /* 369 * Need to unregister interest in all new resources 370 */ 371 if (events_registered) { 372 if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0) 373 != RCM_SUCCESS) { 374 rcm_log_message(RCM_ERROR, 375 _("IP: failed to unregister %s\n"), 376 RCM_RESOURCE_LINK_NEW); 377 return (RCM_FAILURE); 378 } else { 379 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n", 380 RCM_RESOURCE_LINK_NEW); 381 events_registered--; 382 } 383 } 384 385 return (RCM_SUCCESS); 386 } 387 388 /* 389 * ip_offline() - Offline an interface. 390 */ 391 static int 392 ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 393 char **errorp, rcm_info_t **depend_info) 394 { 395 ip_cache_t *node; 396 ip_pif_t *pif; 397 boolean_t detachable = B_FALSE; 398 boolean_t ipmp; 399 int retval; 400 401 rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc); 402 403 /* Guard against bad arguments */ 404 assert(hd != NULL); 405 assert(rsrc != NULL); 406 assert(id == (id_t)0); 407 assert(errorp != NULL); 408 assert(depend_info != NULL); 409 410 /* Lock the cache and lookup the resource */ 411 (void) mutex_lock(&cache_lock); 412 node = cache_lookup(hd, rsrc, CACHE_REFRESH); 413 if (node == NULL) { 414 ip_log_err(node, errorp, "Unrecognized resource"); 415 errno = ENOENT; 416 (void) mutex_unlock(&cache_lock); 417 return (RCM_SUCCESS); 418 } 419 420 pif = node->ip_pif; 421 422 /* Establish default detachability criteria */ 423 if (flags & RCM_FORCE) 424 detachable = B_TRUE; 425 426 /* Check if the interface is under IPMP */ 427 ipmp = (pif->pi_grname[0] != '\0'); 428 429 /* 430 * Even if the interface is not under IPMP, it's possible that it's 431 * still okay to offline it as long as there are higher-level failover 432 * mechanisms for the addresses it owns (e.g., clustering). In this 433 * case, ip_offlinelist() will return RCM_SUCCESS, and we charge on. 434 */ 435 if (!ipmp && !detachable) { 436 /* Inform consumers of IP addresses being offlined */ 437 if (ip_offlinelist(hd, node, errorp, flags, depend_info) == 438 RCM_SUCCESS) { 439 rcm_log_message(RCM_DEBUG, 440 "IP: consumers agree on detach"); 441 } else { 442 ip_log_err(node, errorp, 443 "Device consumers prohibit offline"); 444 (void) mutex_unlock(&cache_lock); 445 return (RCM_FAILURE); 446 } 447 } 448 449 /* Check if it's a query */ 450 if (flags & RCM_QUERY) { 451 rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n", 452 rsrc); 453 (void) mutex_unlock(&cache_lock); 454 return (RCM_SUCCESS); 455 } 456 457 /* Check detachability, save configuration if detachable */ 458 if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) { 459 node->ip_cachestate |= CACHE_IF_IGNORE; 460 rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc); 461 (void) mutex_unlock(&cache_lock); 462 return (RCM_SUCCESS); 463 } 464 465 /* standalone detachable device */ 466 if (!ipmp) { 467 if (if_unplumb(node) < 0) { 468 ip_log_err(node, errorp, 469 "Failed to unplumb the device"); 470 471 errno = EIO; 472 (void) mutex_unlock(&cache_lock); 473 return (RCM_FAILURE); 474 } 475 476 node->ip_cachestate |= CACHE_IF_OFFLINED; 477 rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc); 478 (void) mutex_unlock(&cache_lock); 479 return (RCM_SUCCESS); 480 } 481 482 /* 483 * This is an IPMP interface that can be offlined. 484 * Request in.mpathd(1M) to offline the physical interface. 485 */ 486 if ((retval = ip_ipmp_offline(node)) != IPMP_SUCCESS) 487 ip_log_err(node, errorp, "in.mpathd offline failed"); 488 489 if (retval == IPMP_EMINRED && !detachable) { 490 /* 491 * in.mpathd(1M) could not offline the device because it was 492 * the last interface in the group. However, it's possible 493 * that it's still okay to offline it as long as there are 494 * higher-level failover mechanisms for the addresses it owns 495 * (e.g., clustering). In this case, ip_offlinelist() will 496 * return RCM_SUCCESS, and we charge on. 497 */ 498 /* Inform consumers of IP addresses being offlined */ 499 if (ip_offlinelist(hd, node, errorp, flags, 500 depend_info) == RCM_SUCCESS) { 501 rcm_log_message(RCM_DEBUG, 502 "IP: consumers agree on detach"); 503 } else { 504 ip_log_err(node, errorp, 505 "Device consumers prohibit offline"); 506 (void) mutex_unlock(&cache_lock); 507 errno = EBUSY; 508 return (RCM_FAILURE); 509 } 510 } 511 512 if (if_unplumb(node) < 0) { 513 rcm_log_message(RCM_ERROR, 514 _("IP: Unplumb failed (%s)\n"), 515 pif->pi_ifname); 516 517 /* Request in.mpathd to undo the offline */ 518 if (ip_ipmp_undo_offline(node) != IPMP_SUCCESS) { 519 ip_log_err(node, errorp, "Undo offline failed"); 520 (void) mutex_unlock(&cache_lock); 521 return (RCM_FAILURE); 522 } 523 (void) mutex_unlock(&cache_lock); 524 return (RCM_FAILURE); 525 } 526 527 node->ip_cachestate |= CACHE_IF_OFFLINED; 528 rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc); 529 (void) mutex_unlock(&cache_lock); 530 return (RCM_SUCCESS); 531 } 532 533 /* 534 * ip_undo_offline() - Undo offline of a previously offlined device. 535 */ 536 /*ARGSUSED*/ 537 static int 538 ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 539 char **errorp, rcm_info_t **depend_info) 540 { 541 ip_cache_t *node; 542 543 rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc); 544 545 /* Guard against bad arguments */ 546 assert(hd != NULL); 547 assert(rsrc != NULL); 548 assert(id == (id_t)0); 549 assert(errorp != NULL); 550 assert(depend_info != NULL); 551 552 (void) mutex_lock(&cache_lock); 553 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 554 555 if (node == NULL) { 556 ip_log_err(node, errorp, "No such device"); 557 (void) mutex_unlock(&cache_lock); 558 errno = ENOENT; 559 return (RCM_FAILURE); 560 } 561 562 /* Check if no attempt should be made to online the device here */ 563 if (node->ip_cachestate & CACHE_IF_IGNORE) { 564 node->ip_cachestate &= ~(CACHE_IF_IGNORE); 565 (void) mutex_unlock(&cache_lock); 566 return (RCM_SUCCESS); 567 } 568 569 /* Check if the interface was previously offlined */ 570 if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) { 571 ip_log_err(node, errorp, "Device not offlined"); 572 (void) mutex_unlock(&cache_lock); 573 errno = ENOTSUP; 574 return (RCM_FAILURE); 575 } 576 577 if (if_replumb(node) == -1) { 578 /* re-plumb failed */ 579 ip_log_err(node, errorp, "Replumb failed"); 580 (void) mutex_unlock(&cache_lock); 581 errno = EIO; 582 return (RCM_FAILURE); 583 584 } 585 586 /* Inform consumers about IP addresses being un-offlined */ 587 (void) ip_onlinelist(hd, node, errorp, flags, depend_info); 588 589 node->ip_cachestate &= ~(CACHE_IF_OFFLINED); 590 rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc); 591 (void) mutex_unlock(&cache_lock); 592 return (RCM_SUCCESS); 593 } 594 595 /* 596 * ip_get_info() - Gather usage information for this resource. 597 */ 598 /*ARGSUSED*/ 599 int 600 ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 601 char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info) 602 { 603 ip_cache_t *node; 604 char *infostr; 605 606 /* Guard against bad arguments */ 607 assert(hd != NULL); 608 assert(rsrc != NULL); 609 assert(id == (id_t)0); 610 assert(usagep != NULL); 611 assert(errorp != NULL); 612 assert(depend_info != NULL); 613 614 rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc); 615 616 (void) mutex_lock(&cache_lock); 617 node = cache_lookup(hd, rsrc, CACHE_REFRESH); 618 if (!node) { 619 rcm_log_message(RCM_INFO, 620 _("IP: get_info(%s) unrecognized resource\n"), rsrc); 621 (void) mutex_unlock(&cache_lock); 622 errno = ENOENT; 623 return (RCM_FAILURE); 624 } 625 626 infostr = ip_usage(node); 627 628 if (infostr == NULL) { 629 /* most likely malloc failure */ 630 rcm_log_message(RCM_ERROR, 631 _("IP: get_info(%s) malloc failure\n"), rsrc); 632 (void) mutex_unlock(&cache_lock); 633 errno = ENOMEM; 634 *errorp = NULL; 635 return (RCM_FAILURE); 636 } 637 638 /* Set client/role properties */ 639 (void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP"); 640 641 /* Set usage property, infostr will be freed by caller */ 642 *usagep = infostr; 643 644 rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n", 645 rsrc, infostr); 646 647 (void) mutex_unlock(&cache_lock); 648 return (RCM_SUCCESS); 649 } 650 651 /* 652 * ip_suspend() - Nothing to do, always okay 653 */ 654 /*ARGSUSED*/ 655 static int 656 ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval, 657 uint_t flags, char **errorp, rcm_info_t **depend_info) 658 { 659 /* Guard against bad arguments */ 660 assert(hd != NULL); 661 assert(rsrc != NULL); 662 assert(id == (id_t)0); 663 assert(interval != NULL); 664 assert(errorp != NULL); 665 assert(depend_info != NULL); 666 667 rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc); 668 return (RCM_SUCCESS); 669 } 670 671 /* 672 * ip_resume() - Nothing to do, always okay 673 */ 674 /*ARGSUSED*/ 675 static int 676 ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 677 char **errorp, rcm_info_t ** depend_info) 678 { 679 /* Guard against bad arguments */ 680 assert(hd != NULL); 681 assert(rsrc != NULL); 682 assert(id == (id_t)0); 683 assert(errorp != NULL); 684 assert(depend_info != NULL); 685 686 rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc); 687 688 return (RCM_SUCCESS); 689 } 690 691 /* 692 * ip_remove() - remove a resource from cache 693 */ 694 /*ARGSUSED*/ 695 static int 696 ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 697 char **errorp, rcm_info_t **depend_info) 698 { 699 ip_cache_t *node; 700 701 /* Guard against bad arguments */ 702 assert(hd != NULL); 703 assert(rsrc != NULL); 704 assert(id == (id_t)0); 705 assert(errorp != NULL); 706 assert(depend_info != NULL); 707 708 rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc); 709 710 (void) mutex_lock(&cache_lock); 711 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 712 if (!node) { 713 rcm_log_message(RCM_INFO, 714 _("IP: remove(%s) unrecognized resource\n"), rsrc); 715 (void) mutex_unlock(&cache_lock); 716 errno = ENOENT; 717 return (RCM_FAILURE); 718 } 719 720 /* remove the cached entry for the resource */ 721 cache_remove(node); 722 free_node(node); 723 724 (void) mutex_unlock(&cache_lock); 725 return (RCM_SUCCESS); 726 } 727 728 /* 729 * ip_notify_event - Project private implementation to receive new resource 730 * events. It intercepts all new resource events. If the 731 * new resource is a network resource, pass up a notify 732 * for it too. The new resource need not be cached, since 733 * it is done at register again. 734 */ 735 /*ARGSUSED*/ 736 static int 737 ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 738 char **errorp, nvlist_t *nvl, rcm_info_t **depend_info) 739 { 740 datalink_id_t linkid; 741 nvpair_t *nvp = NULL; 742 uint64_t id64; 743 744 assert(hd != NULL); 745 assert(rsrc != NULL); 746 assert(id == (id_t)0); 747 assert(nvl != NULL); 748 749 rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc); 750 751 if (!STREQ(rsrc, RCM_RESOURCE_LINK_NEW)) { 752 rcm_log_message(RCM_INFO, 753 _("IP: unrecognized event for %s\n"), rsrc); 754 ip_log_err(NULL, errorp, "unrecognized event"); 755 errno = EINVAL; 756 return (RCM_FAILURE); 757 } 758 759 /* Update cache to reflect latest interfaces */ 760 if (update_cache(hd) < 0) { 761 rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n")); 762 ip_log_err(NULL, errorp, "Private Cache update failed"); 763 return (RCM_FAILURE); 764 } 765 766 rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n"); 767 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 768 if (STREQ(nvpair_name(nvp), RCM_NV_LINKID)) { 769 if (nvpair_value_uint64(nvp, &id64) != 0) { 770 rcm_log_message(RCM_WARNING, 771 _("IP: cannot get linkid\n")); 772 return (RCM_FAILURE); 773 } 774 linkid = (datalink_id_t)id64; 775 /* 776 * Grovel through /etc/hostname* files and configure 777 * interface in the same way that they would be handled 778 * by network/physical. 779 */ 780 if (if_configure_hostname(linkid) != 0) { 781 rcm_log_message(RCM_ERROR, 782 _("IP: Configuration failed (%u)\n"), 783 linkid); 784 ip_log_err(NULL, errorp, 785 "Failed configuring one or more IP " 786 "addresses"); 787 } 788 789 /* 790 * Query libipadm for persistent configuration info 791 * and resurrect that persistent configuration. 792 */ 793 if (if_configure_ipadm(linkid) != 0) { 794 rcm_log_message(RCM_ERROR, 795 _("IP: Configuration failed (%u)\n"), 796 linkid); 797 ip_log_err(NULL, errorp, 798 "Failed configuring one or more IP " 799 "addresses"); 800 } 801 802 /* Notify all IP address consumers */ 803 ip_consumer_notify(hd, linkid, errorp, flags, 804 depend_info); 805 } 806 } 807 808 rcm_log_message(RCM_TRACE1, 809 "IP: notify_event: device configuration complete\n"); 810 811 return (RCM_SUCCESS); 812 } 813 814 /* 815 * ip_usage - Determine the usage of a device. Call with cache_lock held. 816 * The returned buffer is owned by caller, and the caller 817 * must free it up when done. 818 */ 819 static char * 820 ip_usage(ip_cache_t *node) 821 { 822 ip_lif_t *lif; 823 uint_t numup; 824 char *sep, *buf, *linkidstr; 825 datalink_id_t linkid; 826 const char *msg; 827 char link[MAXLINKNAMELEN]; 828 char addrstr[INET6_ADDRSTRLEN]; 829 char errmsg[DLADM_STRSIZE]; 830 dladm_status_t status; 831 boolean_t offline, ipmp; 832 size_t bufsz = 0; 833 834 rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource); 835 836 /* 837 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid> 838 */ 839 linkidstr = strchr(node->ip_resource, '/'); 840 assert(linkidstr != NULL); 841 linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource; 842 843 errno = 0; 844 linkid = strtol(linkidstr, &buf, 10); 845 if (errno != 0 || *buf != '\0') { 846 rcm_log_message(RCM_ERROR, 847 _("IP: usage(%s) parse linkid failure (%s)\n"), 848 node->ip_resource, strerror(errno)); 849 return (NULL); 850 } 851 852 if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, 853 NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 854 rcm_log_message(RCM_ERROR, 855 _("IP: usage(%s) get link name failure(%s)\n"), 856 node->ip_resource, dladm_status2str(status, errmsg)); 857 return (NULL); 858 } 859 860 /* TRANSLATION_NOTE: separator used between IP addresses */ 861 sep = _(", "); 862 863 numup = 0; 864 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) 865 if (lif->li_ifflags & IFF_UP) 866 numup++; 867 868 ipmp = (node->ip_pif->pi_grname[0] != '\0'); 869 offline = ((node->ip_cachestate & CACHE_IF_OFFLINED) != 0); 870 871 if (offline) { 872 msg = _("offlined"); 873 } else if (numup == 0) { 874 msg = _("plumbed but down"); 875 } else { 876 if (ipmp) { 877 msg = _("providing connectivity for IPMP group "); 878 bufsz += LIFGRNAMSIZ; 879 } else { 880 msg = _("hosts IP addresses: "); 881 bufsz += (numup * (INET6_ADDRSTRLEN + strlen(sep))); 882 } 883 } 884 885 bufsz += strlen(link) + strlen(msg) + 1; 886 if ((buf = malloc(bufsz)) == NULL) { 887 rcm_log_message(RCM_ERROR, 888 _("IP: usage(%s) malloc failure(%s)\n"), 889 node->ip_resource, strerror(errno)); 890 return (NULL); 891 } 892 (void) snprintf(buf, bufsz, "%s: %s", link, msg); 893 894 if (!offline && numup > 0) { 895 if (ipmp) { 896 (void) strlcat(buf, node->ip_pif->pi_grname, bufsz); 897 } else { 898 lif = node->ip_pif->pi_lifs; 899 for (; lif != NULL; lif = lif->li_next) { 900 if (!(lif->li_ifflags & IFF_UP)) 901 continue; 902 903 if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) 904 continue; 905 906 (void) strlcat(buf, addrstr, bufsz); 907 if (--numup > 0) 908 (void) strlcat(buf, sep, bufsz); 909 } 910 } 911 } 912 913 rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n", 914 node->ip_resource, buf); 915 916 return (buf); 917 } 918 919 static boolean_t 920 ip_addrstr(ip_lif_t *lif, char *addrstr, size_t addrsize) 921 { 922 int af = lif->li_addr.family; 923 void *addr; 924 925 if (af == AF_INET6) { 926 addr = &lif->li_addr.ip6.sin6_addr; 927 } else if (af == AF_INET) { 928 addr = &lif->li_addr.ip4.sin_addr; 929 } else { 930 rcm_log_message(RCM_DEBUG, 931 "IP: unknown addr family %d, assuming AF_INET\n", af); 932 af = AF_INET; 933 addr = &lif->li_addr.ip4.sin_addr; 934 } 935 if (inet_ntop(af, addr, addrstr, addrsize) == NULL) { 936 rcm_log_message(RCM_ERROR, 937 _("IP: inet_ntop: %s\n"), strerror(errno)); 938 return (B_FALSE); 939 } 940 941 rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr); 942 return (B_TRUE); 943 } 944 945 /* 946 * Cache management routines, all cache management functions should be 947 * be called with cache_lock held. 948 */ 949 950 /* 951 * cache_lookup() - Get a cache node for a resource. 952 * Call with cache lock held. 953 * 954 * This ensures that the cache is consistent with the system state and 955 * returns a pointer to the cache element corresponding to the resource. 956 */ 957 static ip_cache_t * 958 cache_lookup(rcm_handle_t *hd, char *rsrc, char options) 959 { 960 ip_cache_t *probe; 961 962 rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc); 963 964 if ((options & CACHE_REFRESH) && (hd != NULL)) { 965 /* drop lock since update locks cache again */ 966 (void) mutex_unlock(&cache_lock); 967 (void) update_cache(hd); 968 (void) mutex_lock(&cache_lock); 969 } 970 971 probe = cache_head.ip_next; 972 while (probe != &cache_tail) { 973 if (probe->ip_resource && 974 STREQ(rsrc, probe->ip_resource)) { 975 rcm_log_message(RCM_TRACE2, 976 "IP: cache lookup success(%s)\n", rsrc); 977 return (probe); 978 } 979 probe = probe->ip_next; 980 } 981 return (NULL); 982 } 983 984 /* 985 * free_node - Free a node from the cache 986 * Call with cache_lock held. 987 */ 988 static void 989 free_node(ip_cache_t *node) 990 { 991 ip_pif_t *pif; 992 ip_lif_t *lif, *tmplif; 993 994 if (node) { 995 if (node->ip_resource) { 996 free(node->ip_resource); 997 } 998 999 /* free the pif */ 1000 pif = node->ip_pif; 1001 if (pif) { 1002 /* free logical interfaces */ 1003 lif = pif->pi_lifs; 1004 while (lif) { 1005 tmplif = lif->li_next; 1006 free(lif); 1007 lif = tmplif; 1008 } 1009 free(pif); 1010 } 1011 free(node); 1012 } 1013 } 1014 1015 /* 1016 * cache_insert - Insert a resource node in cache 1017 * Call with the cache_lock held. 1018 */ 1019 static void 1020 cache_insert(ip_cache_t *node) 1021 { 1022 rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n", 1023 node->ip_resource); 1024 1025 /* insert at the head for best performance */ 1026 node->ip_next = cache_head.ip_next; 1027 node->ip_prev = &cache_head; 1028 1029 node->ip_next->ip_prev = node; 1030 node->ip_prev->ip_next = node; 1031 } 1032 1033 /* 1034 * cache_remove() - Remove a resource node from cache. 1035 * Call with the cache_lock held. 1036 */ 1037 static void 1038 cache_remove(ip_cache_t *node) 1039 { 1040 rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n", 1041 node->ip_resource); 1042 1043 node->ip_next->ip_prev = node->ip_prev; 1044 node->ip_prev->ip_next = node->ip_next; 1045 node->ip_next = NULL; 1046 node->ip_prev = NULL; 1047 } 1048 1049 /* 1050 * update_pif() - Update physical interface properties 1051 * Call with cache_lock held 1052 */ 1053 int 1054 update_pif(rcm_handle_t *hd, int af, int sock, struct ifaddrs *ifa) 1055 { 1056 char *rsrc; 1057 ifspec_t ifspec; 1058 ushort_t ifnumber = 0; 1059 ip_cache_t *probe; 1060 ip_pif_t pif; 1061 ip_pif_t *probepif; 1062 ip_lif_t *probelif; 1063 struct lifreq lifreq; 1064 struct sockaddr_storage ifaddr; 1065 uint64_t ifflags; 1066 int lif_listed = 0; 1067 1068 rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", ifa->ifa_name); 1069 1070 if (!ifparse_ifspec(ifa->ifa_name, &ifspec)) { 1071 rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"), 1072 ifa->ifa_name); 1073 return (-1); 1074 } 1075 1076 (void) snprintf(pif.pi_ifname, sizeof (pif.pi_ifname), "%s%d", 1077 ifspec.ifsp_devnm, ifspec.ifsp_ppa); 1078 if (ifspec.ifsp_lunvalid) 1079 ifnumber = ifspec.ifsp_lun; 1080 1081 /* Get the interface flags */ 1082 ifflags = ifa->ifa_flags; 1083 1084 /* 1085 * Ignore interfaces that are always incapable of DR: 1086 * - IFF_VIRTUAL: e.g., loopback and vni 1087 * - IFF_POINTOPOINT: e.g., sppp and ip.tun 1088 * - !IFF_MULTICAST: e.g., ip.6to4tun 1089 * - IFF_IPMP: IPMP meta-interfaces 1090 * 1091 * Note: The !IFF_MULTICAST check can be removed once iptun is 1092 * implemented as a datalink. 1093 */ 1094 if (!(ifflags & IFF_MULTICAST) || 1095 (ifflags & (IFF_POINTOPOINT | IFF_VIRTUAL | IFF_IPMP))) { 1096 rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n", 1097 pif.pi_ifname); 1098 return (0); 1099 } 1100 1101 /* Get the interface group name for this interface */ 1102 bzero(&lifreq, sizeof (lifreq)); 1103 (void) strncpy(lifreq.lifr_name, ifa->ifa_name, LIFNAMSIZ); 1104 1105 if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) { 1106 if (errno != ENXIO) { 1107 rcm_log_message(RCM_ERROR, 1108 _("IP: SIOCGLIFGROUPNAME(%s): %s\n"), 1109 lifreq.lifr_name, strerror(errno)); 1110 } 1111 return (-1); 1112 } 1113 1114 /* copy the group name */ 1115 (void) strlcpy(pif.pi_grname, lifreq.lifr_groupname, 1116 sizeof (pif.pi_grname)); 1117 1118 /* Get the interface address for this interface */ 1119 (void) memcpy(&ifaddr, ifa->ifa_addr, sizeof (ifaddr)); 1120 1121 rsrc = get_link_resource(pif.pi_ifname); 1122 if (rsrc == NULL) { 1123 rcm_log_message(RCM_ERROR, 1124 _("IP: get_link_resource(%s) failed\n"), 1125 lifreq.lifr_name); 1126 return (-1); 1127 } 1128 1129 probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 1130 if (probe != NULL) { 1131 free(rsrc); 1132 probe->ip_cachestate &= ~(CACHE_IF_STALE); 1133 } else { 1134 if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) { 1135 /* malloc errors are bad */ 1136 free(rsrc); 1137 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"), 1138 strerror(errno)); 1139 return (-1); 1140 } 1141 1142 probe->ip_resource = rsrc; 1143 probe->ip_pif = NULL; 1144 probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY; 1145 probe->ip_cachestate |= CACHE_IF_NEW; 1146 1147 cache_insert(probe); 1148 } 1149 1150 probepif = probe->ip_pif; 1151 if (probepif != NULL) { 1152 /* Check if lifs need to be updated */ 1153 probelif = probepif->pi_lifs; 1154 while (probelif != NULL) { 1155 if ((probelif->li_ifnum == ifnumber) && 1156 (probelif->li_addr.family == ifaddr.ss_family)) { 1157 1158 rcm_log_message(RCM_TRACE2, 1159 "IP: refreshing lifs for %s, ifnum=%d\n", 1160 pif.pi_ifname, probelif->li_ifnum); 1161 1162 /* refresh lif properties */ 1163 (void) memcpy(&probelif->li_addr, &ifaddr, 1164 sizeof (probelif->li_addr)); 1165 1166 probelif->li_ifflags = ifflags; 1167 1168 lif_listed++; 1169 probelif->li_cachestate &= ~(CACHE_IF_STALE); 1170 break; 1171 } 1172 probelif = probelif->li_next; 1173 } 1174 } 1175 1176 if (probepif == NULL) { 1177 if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) { 1178 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"), 1179 strerror(errno)); 1180 if (probe->ip_pif == NULL) { 1181 /* we created it, so clean it up */ 1182 free(probe); 1183 } 1184 return (-1); 1185 } 1186 1187 probe->ip_pif = probepif; 1188 1189 /* Save interface name */ 1190 (void) memcpy(&probepif->pi_ifname, &pif.pi_ifname, 1191 sizeof (pif.pi_ifname)); 1192 } 1193 1194 /* save the group name */ 1195 (void) strlcpy(probepif->pi_grname, pif.pi_grname, 1196 sizeof (pif.pi_grname)); 1197 1198 /* add lif, if this is a lif and it is not in cache */ 1199 if (!lif_listed) { 1200 rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n", 1201 pif.pi_ifname); 1202 1203 if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) { 1204 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"), 1205 strerror(errno)); 1206 return (-1); 1207 } 1208 1209 /* save lif properties */ 1210 (void) memcpy(&probelif->li_addr, &ifaddr, 1211 sizeof (probelif->li_addr)); 1212 1213 probelif->li_ifnum = ifnumber; 1214 probelif->li_ifflags = ifflags; 1215 1216 /* insert us at the head of the lif list */ 1217 probelif->li_next = probepif->pi_lifs; 1218 if (probelif->li_next != NULL) { 1219 probelif->li_next->li_prev = probelif; 1220 } 1221 probelif->li_prev = NULL; 1222 probelif->li_pif = probepif; 1223 1224 probepif->pi_lifs = probelif; 1225 } 1226 1227 rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n", 1228 probe->ip_resource); 1229 1230 return (0); 1231 } 1232 1233 /* 1234 * update_ipifs() - Determine all network interfaces in the system 1235 * Call with cache_lock held 1236 */ 1237 static int 1238 update_ipifs(rcm_handle_t *hd, int af) 1239 { 1240 1241 struct ifaddrs *ifa; 1242 ipadm_addr_info_t *ainfo; 1243 ipadm_addr_info_t *ptr; 1244 ipadm_status_t status; 1245 int sock; 1246 1247 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) { 1248 rcm_log_message(RCM_ERROR, 1249 _("IP: failure opening %s socket: %s\n"), 1250 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno)); 1251 return (-1); 1252 } 1253 1254 status = ipadm_addr_info(ip_handle, NULL, &ainfo, IPADM_OPT_ZEROADDR, 1255 LIFC_UNDER_IPMP); 1256 if (status != IPADM_SUCCESS) { 1257 (void) close(sock); 1258 return (-1); 1259 } 1260 for (ptr = ainfo; ptr; ptr = IA_NEXT(ptr)) { 1261 ifa = &ptr->ia_ifa; 1262 if (ptr->ia_state != IFA_DISABLED && 1263 af == ifa->ifa_addr->sa_family) 1264 (void) update_pif(hd, af, sock, ifa); 1265 } 1266 (void) close(sock); 1267 ipadm_free_addr_info(ainfo); 1268 return (0); 1269 } 1270 1271 /* 1272 * update_cache() - Update cache with latest interface info 1273 */ 1274 static int 1275 update_cache(rcm_handle_t *hd) 1276 { 1277 ip_cache_t *probe; 1278 struct ip_lif *lif; 1279 struct ip_lif *nextlif; 1280 int rv; 1281 int i; 1282 1283 rcm_log_message(RCM_TRACE2, "IP: update_cache\n"); 1284 1285 (void) mutex_lock(&cache_lock); 1286 1287 /* first we walk the entire cache, marking each entry stale */ 1288 probe = cache_head.ip_next; 1289 while (probe != &cache_tail) { 1290 probe->ip_cachestate |= CACHE_IF_STALE; 1291 if ((probe->ip_pif != NULL) && 1292 ((lif = probe->ip_pif->pi_lifs) != NULL)) { 1293 while (lif != NULL) { 1294 lif->li_cachestate |= CACHE_IF_STALE; 1295 lif = lif->li_next; 1296 } 1297 } 1298 probe = probe->ip_next; 1299 } 1300 1301 rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n"); 1302 if (update_ipifs(hd, AF_INET) < 0) { 1303 (void) mutex_unlock(&cache_lock); 1304 return (-1); 1305 } 1306 1307 rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n"); 1308 if (update_ipifs(hd, AF_INET6) < 0) { 1309 (void) mutex_unlock(&cache_lock); 1310 return (-1); 1311 } 1312 1313 probe = cache_head.ip_next; 1314 /* unregister devices that are not offlined and still in cache */ 1315 while (probe != &cache_tail) { 1316 ip_cache_t *freeit; 1317 if ((probe->ip_pif != NULL) && 1318 ((lif = probe->ip_pif->pi_lifs) != NULL)) { 1319 /* clear stale lifs */ 1320 while (lif != NULL) { 1321 if (lif->li_cachestate & CACHE_IF_STALE) { 1322 nextlif = lif->li_next; 1323 if (lif->li_prev != NULL) 1324 lif->li_prev->li_next = nextlif; 1325 if (nextlif != NULL) 1326 nextlif->li_prev = lif->li_prev; 1327 if (probe->ip_pif->pi_lifs == lif) 1328 probe->ip_pif->pi_lifs = 1329 nextlif; 1330 for (i = 0; i < IP_MAX_MODS; i++) { 1331 free(lif->li_modules[i]); 1332 } 1333 free(lif->li_reconfig); 1334 free(lif); 1335 lif = nextlif; 1336 } else { 1337 lif = lif->li_next; 1338 } 1339 } 1340 } 1341 if ((probe->ip_cachestate & CACHE_IF_STALE) && 1342 !(probe->ip_cachestate & CACHE_IF_OFFLINED)) { 1343 (void) rcm_unregister_interest(hd, probe->ip_resource, 1344 0); 1345 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n", 1346 probe->ip_resource); 1347 freeit = probe; 1348 probe = probe->ip_next; 1349 cache_remove(freeit); 1350 free_node(freeit); 1351 continue; 1352 } 1353 1354 if (!(probe->ip_cachestate & CACHE_IF_NEW)) { 1355 probe = probe->ip_next; 1356 continue; 1357 } 1358 1359 rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL); 1360 if (rv != RCM_SUCCESS) { 1361 rcm_log_message(RCM_ERROR, 1362 _("IP: failed to register %s\n"), 1363 probe->ip_resource); 1364 (void) mutex_unlock(&cache_lock); 1365 return (-1); 1366 } else { 1367 rcm_log_message(RCM_DEBUG, "IP: registered %s\n", 1368 probe->ip_resource); 1369 probe->ip_cachestate &= ~(CACHE_IF_NEW); 1370 } 1371 probe = probe->ip_next; 1372 } 1373 1374 (void) mutex_unlock(&cache_lock); 1375 return (0); 1376 } 1377 1378 /* 1379 * free_cache() - Empty the cache 1380 */ 1381 static void 1382 free_cache() 1383 { 1384 ip_cache_t *probe; 1385 1386 rcm_log_message(RCM_TRACE2, "IP: free_cache\n"); 1387 1388 (void) mutex_lock(&cache_lock); 1389 probe = cache_head.ip_next; 1390 while (probe != &cache_tail) { 1391 cache_remove(probe); 1392 free_node(probe); 1393 probe = cache_head.ip_next; 1394 } 1395 (void) mutex_unlock(&cache_lock); 1396 } 1397 1398 /* 1399 * ip_log_err() - RCM error log wrapper 1400 */ 1401 static void 1402 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg) 1403 { 1404 char *ifname = NULL; 1405 int size; 1406 const char *errfmt; 1407 char *error = NULL; 1408 1409 if ((node != NULL) && (node->ip_pif != NULL) && 1410 (node->ip_pif->pi_ifname != NULL)) { 1411 ifname = node->ip_pif->pi_ifname; 1412 } 1413 1414 if (ifname == NULL) { 1415 rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg); 1416 errfmt = _("IP: %s"); 1417 size = strlen(errfmt) + strlen(errmsg) + 1; 1418 if (errorp != NULL && (error = malloc(size)) != NULL) 1419 (void) snprintf(error, size, errfmt, errmsg); 1420 } else { 1421 rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname); 1422 errfmt = _("IP: %s(%s)"); 1423 size = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1; 1424 if (errorp != NULL && (error = malloc(size)) != NULL) 1425 (void) snprintf(error, size, errfmt, errmsg, ifname); 1426 } 1427 1428 if (errorp != NULL) 1429 *errorp = error; 1430 } 1431 1432 /* 1433 * if_cfginfo() - Save off the config info for all interfaces 1434 */ 1435 static int 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; ptr = ptr->ifi_next) { 2402 if (strncmp(ptr->ifi_name, ifinst, 2403 sizeof (ifinst)) == 0) { 2404 found = B_TRUE; 2405 break; 2406 } 2407 } 2408 free(ifinfo); 2409 if (!found) { 2410 return (0); 2411 } 2412 if (if_hostname_exists(ifinst, AF_INET) || 2413 if_hostname_exists(ifinst, AF_INET6)) { 2414 rcm_log_message(RCM_WARNING, 2415 _("IP: IPv4 Post-attach (%s) found both " 2416 "/etc/hostname and ipadm persistent configuration. " 2417 "Ignoring ipadm config\n"), ifinst); 2418 return (0); 2419 } 2420 status = ipadm_enable_if(ip_handle, ifinst, IPADM_OPT_ACTIVE); 2421 if (status != IPADM_SUCCESS) { 2422 rcm_log_message(RCM_ERROR, 2423 _("IP: Post-attach failed (%s) Error %s\n"), 2424 ifinst, ipadm_status2str(status)); 2425 goto fail; 2426 } 2427 } 2428 done: 2429 rcm_log_message(RCM_TRACE1, "IP: if_configure_ipadm(%s) success\n", 2430 ifinst); 2431 return (0); 2432 fail: 2433 return (-1); 2434 } 2435 2436 /* 2437 * isgrouped() - Scans the given config file to see if this interface is 2438 * using IPMP. Returns B_TRUE or B_FALSE. 2439 */ 2440 static boolean_t 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