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