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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This RCM module adds support to the RCM framework for IP managed 31 * interfaces. 32 */ 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <assert.h> 38 #include <string.h> 39 #include <synch.h> 40 #include <libintl.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <sys/socket.h> 46 #include <sys/sockio.h> 47 #include <net/if.h> 48 #include <netinet/in.h> 49 #include <netinet/tcp.h> 50 #include <arpa/inet.h> 51 #include <sys/dlpi.h> 52 #include <stropts.h> 53 #include <strings.h> 54 #include <libdevinfo.h> 55 #include <sys/systeminfo.h> 56 #include <netdb.h> 57 58 #include <ipmp_mpathd.h> 59 #include "rcm_module.h" 60 61 /* 62 * Definitions 63 */ 64 #ifndef lint 65 #define _(x) gettext(x) 66 #else 67 #define _(x) x 68 #endif 69 70 /* Some generic well-knowns and defaults used in this module */ 71 #define SLASH_DEV "/dev" /* /dev directory */ 72 73 #define IP_DEV_NAME "/dev/ip" /* IPV4 ip device */ 74 #define IP6_DEV_NAME "/dev/ip6" /* IPV6 ip device */ 75 #define IP_MOD_NAME "ip" /* ip module */ 76 #define ARP_MOD_NAME "arp" /* arp module */ 77 #define UDP_DEV_NAME "/dev/udp" /* IPv4 udp device */ 78 #define UDP6_DEV_NAME "/dev/udp6" /* IPv6 udp device */ 79 #define IP_MAX_MODS 9 /* max modules pushed on intr */ 80 #define MAX_RECONFIG_SIZE 1024 /* Max. reconfig string size */ 81 82 #define RCM_NET_PREFIX "SUNW_network" /* RCM network name prefix */ 83 #define RCM_NET_RESOURCE_MAX (13 + LIFNAMSIZ) /* RCM_NET_PREFIX+LIFNAMSIZ */ 84 85 #define RCM_STR_SUNW_IP "SUNW_ip/" /* IP address export prefix */ 86 #define RCM_SIZE_SUNW_IP 9 /* strlen("SUNW_ip/") + 1 */ 87 88 /* ifconfig(1M) */ 89 #define USR_SBIN_IFCONFIG "/usr/sbin/ifconfig" /* ifconfig command */ 90 #define CFGFILE_FMT_IPV4 "/etc/hostname." /* IPV4 config file */ 91 #define CFGFILE_FMT_IPV6 "/etc/hostname6." /* IPV6 config file */ 92 #define CFG_CMDS_STD " netmask + broadcast + up" /* Normal config string */ 93 #define CONFIG_AF_INET 0x1 /* Post-configure IPv4 */ 94 #define CONFIG_AF_INET6 0x2 /* Post-configure IPv6 */ 95 #define MAXLINE 1024 /* Max. line length */ 96 #define MAXARGS 512 /* Max. args in ifconfig cmd */ 97 98 /* Physical interface flags mask */ 99 #define RCM_PIF_FLAGS (IFF_OFFLINE | IFF_INACTIVE | IFF_FAILED | \ 100 IFF_STANDBY) 101 102 /* Some useful macros */ 103 #ifndef MAX 104 #define MAX(a, b) (((a) > (b))?(a):(b)) 105 #endif /* MAX */ 106 107 #ifndef ISSPACE 108 #define ISSPACE(c) ((c) == ' ' || (c) == '\t') 109 #endif 110 111 #ifndef ISEOL 112 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 113 #endif 114 115 #ifndef STREQ 116 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 117 #endif 118 119 #ifndef ADDSPACE 120 #define ADDSPACE(a) ((void) strcat((a), " ")) 121 #endif 122 123 /* Interface Cache state flags */ 124 #define CACHE_IF_STALE 0x1 /* stale cached data */ 125 #define CACHE_IF_NEW 0x2 /* new cached interface */ 126 #define CACHE_IF_OFFLINED 0x4 /* interface offlined */ 127 #define CACHE_IF_UPDATED 0x8 /* interface props. updated */ 128 #define CACHE_IF_IGNORE 0x10 /* state held elsewhere */ 129 130 /* Network Cache lookup options */ 131 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */ 132 #define CACHE_REFRESH 0x2 /* refresh cache */ 133 134 /* RCM IPMP Module specific property definitions */ 135 #define RCM_IPMP_MIN_REDUNDANCY 1 /* default min. redundancy */ 136 137 /* in.mpathd(1M) specifics */ 138 #define MPATHD_MAX_RETRIES 5 /* Max. offline retries */ 139 #define MPATHD_OK 0 /* failback success from mpathd */ 140 #define MPATHD_FAILBACK_TIME 180 /* Time in secs. for mpathd failback */ 141 142 /* Stream module operations */ 143 #define MOD_INSERT 0 /* Insert a mid-stream module */ 144 #define MOD_REMOVE 1 /* Remove a mid-stream module */ 145 #define MOD_CHECK 2 /* Check mid-stream module safety */ 146 147 /* VLAN format support */ 148 #define VLAN_MAX_PPA_ALLOWED 1000 149 #define VLAN_GET_VID(ppa) (ppa / VLAN_MAX_PPA_ALLOWED) 150 #define VLAN_GET_PPA(ppa) (ppa % VLAN_MAX_PPA_ALLOWED) 151 152 /* devfsadm attach nvpair values */ 153 #define PROP_NV_DDI_NETWORK "ddi_network" 154 155 /* 156 * in.mpathd(1M) message passing formats 157 */ 158 typedef struct mpathd_cmd { 159 uint32_t cmd_command; /* message command */ 160 char cmd_ifname[LIFNAMSIZ]; /* this interface name */ 161 char cmd_movetoif[LIFNAMSIZ]; /* move to interface */ 162 uint32_t cmd_min_red; /* min. redundancy */ 163 /* Message passing values for MI_SETOINDEX */ 164 #define from_lifname cmd_ifname /* current logical interface */ 165 #define to_pifname cmd_movetoif /* new physical interface */ 166 #define addr_family cmd_min_red /* address family */ 167 } mpathd_cmd_t; 168 169 /* This is needed since mpathd checks message size for offline */ 170 typedef struct mpathd_unoffline { 171 uint32_t cmd_command; /* offline / undo offline */ 172 char cmd_ifname[LIFNAMSIZ]; /* this interface name */ 173 } mpathd_unoffline_t; 174 175 typedef struct mpathd_response { 176 uint32_t resp_sys_errno; /* system errno */ 177 uint32_t resp_mpathd_err; /* mpathd error information */ 178 } mpathd_response_t; 179 180 /* 181 * IP module data types 182 */ 183 184 /* Physical interface representation */ 185 typedef struct ip_pif { 186 char pi_ifname[LIFNAMSIZ+1]; /* interface name */ 187 char pi_ifindex; /* Interface index */ 188 char pi_grpname[LIFNAMSIZ+1]; /* IPMP group name */ 189 int pi_style; /* DLPI provider style */ 190 int pi_ppa; /* Phys. point of attachment */ 191 struct ip_lif *pi_lifs; /* ptr to logical interfaces */ 192 } ip_pif_t; 193 194 /* Logical interface representation */ 195 typedef struct ip_lif 196 { 197 struct ip_lif *li_next; /* ptr to next lif */ 198 struct ip_lif *li_prev; /* previous next ptr */ 199 ip_pif_t *li_pif; /* back ptr to phy int */ 200 ushort_t li_ifnum; /* interface number */ 201 union { 202 sa_family_t family; 203 struct sockaddr_storage storage; 204 struct sockaddr_in ip4; /* IPv4 */ 205 struct sockaddr_in6 ip6; /* IPv6 */ 206 } li_addr; 207 uint64_t li_ifflags; /* current IFF_* flags */ 208 uint64_t li_oldflags; /* flags prior to offline */ 209 int li_modcnt; /* # of modules */ 210 char *li_modules[IP_MAX_MODS]; /* module list pushed */ 211 char *li_reconfig; /* Reconfiguration string */ 212 int32_t li_cachestate; /* cache state flags */ 213 } ip_lif_t; 214 215 /* Cache element */ 216 typedef struct ip_cache 217 { 218 struct ip_cache *ip_next; /* next cached resource */ 219 struct ip_cache *ip_prev; /* prev cached resource */ 220 char *ip_resource; /* resource name */ 221 ip_pif_t *ip_pif; /* ptr to phy int */ 222 int32_t ip_ifred; /* min. redundancy */ 223 int ip_cachestate; /* cache state flags */ 224 } ip_cache_t; 225 226 /* 227 * Global cache for network interfaces 228 */ 229 static ip_cache_t cache_head; 230 static ip_cache_t cache_tail; 231 static mutex_t cache_lock; 232 static int events_registered = 0; 233 234 /* 235 * Global NIC list to be configured after DR-attach 236 */ 237 #define NIL_NULL ((struct ni_list *)0) 238 239 struct net_interface { 240 char *type; /* Name of type of interface (le, ie, etc.) */ 241 char *name; /* Qualified name of interface (le0, ie0, etc.) */ 242 }; 243 244 struct ni_list { 245 struct net_interface *nifp; 246 struct ni_list *next; 247 }; 248 249 static mutex_t nil_lock; /* NIC list lock */ 250 static int num_ni = 0; /* Global new interface count */ 251 static struct ni_list *nil_head = NIL_NULL; /* Global new if list */ 252 253 struct devfs_minor_data { 254 int32_t minor_type; 255 char *minor_name; 256 char *minor_node_type; 257 }; 258 259 /* 260 * RCM module interface prototypes 261 */ 262 static int ip_register(rcm_handle_t *); 263 static int ip_unregister(rcm_handle_t *); 264 static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t, 265 char **, char **, nvlist_t *, rcm_info_t **); 266 static int ip_suspend(rcm_handle_t *, char *, id_t, 267 timespec_t *, uint_t, char **, rcm_info_t **); 268 static int ip_resume(rcm_handle_t *, char *, id_t, uint_t, 269 char **, rcm_info_t **); 270 static int ip_offline(rcm_handle_t *, char *, id_t, uint_t, 271 char **, rcm_info_t **); 272 static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t, 273 char **, rcm_info_t **); 274 static int ip_remove(rcm_handle_t *, char *, id_t, uint_t, 275 char **, rcm_info_t **); 276 static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t, 277 char **, nvlist_t *, rcm_info_t **); 278 279 /* Module private routines */ 280 static void free_cache(); 281 static int update_cache(rcm_handle_t *); 282 static void cache_remove(ip_cache_t *); 283 static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char); 284 static void free_node(ip_cache_t *); 285 static void cache_insert(ip_cache_t *); 286 static char *ip_usage(ip_cache_t *); 287 static int update_pif(rcm_handle_t *, int, int, struct lifreq *); 288 static int ip_ipmp_offline(ip_cache_t *, ip_cache_t *); 289 static int ip_ipmp_undo_offline(ip_cache_t *); 290 static int if_cfginfo(ip_cache_t *, uint_t); 291 static int if_unplumb(ip_cache_t *); 292 static int if_replumb(ip_cache_t *); 293 static void ip_log_err(ip_cache_t *, char **, char *); 294 static int getdlpi_style(char *); 295 static char *get_physical_resource(char *); 296 static int get_ppa(char *); 297 static void clr_cfg_state(ip_pif_t *); 298 /*LINTED*/ 299 static int if_change_flags(ip_pif_t *, uint64_t, boolean_t); 300 static uint64_t if_get_flags(ip_pif_t *); 301 static int mpathd_send_cmd(mpathd_cmd_t *); 302 static int connect_to_mpathd(int); 303 /*LINTED*/ 304 static int get_lun(char *); 305 /*LINTED*/ 306 static void dump_node(ip_cache_t *); 307 static int modop(char *, char *, int, char); 308 static int get_modlist(char *, ip_lif_t *); 309 static int ip_domux2fd(int *, int *, struct lifreq *); 310 static int ip_plink(int, int, struct lifreq *); 311 static int ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t, 312 rcm_info_t **); 313 static int ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t, 314 rcm_info_t **); 315 static char **ip_get_addrlist(ip_cache_t *); 316 static void ip_free_addrlist(char **); 317 static void ip_consumer_notify(rcm_handle_t *, char *, char **, uint_t, 318 rcm_info_t **); 319 320 static int process_nvlist(nvlist_t *); 321 static void process_minor(char *, char *, int32_t, struct devfs_minor_data *); 322 static int if_configure(char *); 323 static int isgrouped(char *); 324 static int if_ipmp_config(char *, int, int); 325 static int if_mpathd_configure(char *, char *, int, int); 326 static char *get_mpathd_dest(char *, int); 327 static int if_getcount(int); 328 static void tokenize(char *, char **, char *, int *); 329 330 331 /* Module-Private data */ 332 static struct rcm_mod_ops ip_ops = 333 { 334 RCM_MOD_OPS_VERSION, 335 ip_register, 336 ip_unregister, 337 ip_get_info, 338 ip_suspend, 339 ip_resume, 340 ip_offline, 341 ip_undo_offline, 342 ip_remove, 343 NULL, 344 NULL, 345 ip_notify_event 346 }; 347 348 /* 349 * rcm_mod_init() - Update registrations, and return the ops structure. 350 */ 351 struct rcm_mod_ops * 352 rcm_mod_init(void) 353 { 354 rcm_log_message(RCM_TRACE1, "IP: mod_init\n"); 355 356 cache_head.ip_next = &cache_tail; 357 cache_head.ip_prev = NULL; 358 cache_tail.ip_prev = &cache_head; 359 cache_tail.ip_next = NULL; 360 (void) mutex_init(&cache_lock, NULL, NULL); 361 (void) mutex_init(&nil_lock, NULL, NULL); 362 363 /* Return the ops vectors */ 364 return (&ip_ops); 365 } 366 367 /* 368 * rcm_mod_info() - Return a string describing this module. 369 */ 370 const char * 371 rcm_mod_info(void) 372 { 373 rcm_log_message(RCM_TRACE1, "IP: mod_info\n"); 374 375 return ("IP Multipathing module version %I%"); 376 } 377 378 /* 379 * rcm_mod_fini() - Destroy the network interfaces cache. 380 */ 381 int 382 rcm_mod_fini(void) 383 { 384 rcm_log_message(RCM_TRACE1, "IP: mod_fini\n"); 385 386 free_cache(); 387 (void) mutex_destroy(&nil_lock); 388 (void) mutex_destroy(&cache_lock); 389 return (RCM_SUCCESS); 390 } 391 392 /* 393 * ip_register() - Make sure the cache is properly sync'ed, and its 394 * registrations are in order. 395 */ 396 static int 397 ip_register(rcm_handle_t *hd) 398 { 399 rcm_log_message(RCM_TRACE1, "IP: register\n"); 400 401 /* Guard against bad arguments */ 402 assert(hd != NULL); 403 404 if (update_cache(hd) < 0) 405 return (RCM_FAILURE); 406 407 /* 408 * Need to register interest in all new resources 409 * getting attached, so we get attach event notifications 410 */ 411 if (!events_registered) { 412 if (rcm_register_event(hd, RCM_RESOURCE_NETWORK_NEW, 0, NULL) 413 != RCM_SUCCESS) { 414 rcm_log_message(RCM_ERROR, 415 _("IP: failed to register %s\n"), 416 RCM_RESOURCE_NETWORK_NEW); 417 return (RCM_FAILURE); 418 } else { 419 rcm_log_message(RCM_DEBUG, "IP: registered %s\n", 420 RCM_RESOURCE_NETWORK_NEW); 421 events_registered++; 422 } 423 } 424 425 return (RCM_SUCCESS); 426 } 427 428 /* 429 * ip_unregister() - Walk the cache, unregistering all the networks. 430 */ 431 static int 432 ip_unregister(rcm_handle_t *hd) 433 { 434 ip_cache_t *probe; 435 436 rcm_log_message(RCM_TRACE1, "IP: unregister\n"); 437 438 /* Guard against bad arguments */ 439 assert(hd != NULL); 440 441 /* Walk the cache, unregistering everything */ 442 (void) mutex_lock(&cache_lock); 443 probe = cache_head.ip_next; 444 while (probe != &cache_tail) { 445 if (rcm_unregister_interest(hd, probe->ip_resource, 0) 446 != RCM_SUCCESS) { 447 /* unregister failed for whatever reason */ 448 (void) mutex_unlock(&cache_lock); 449 return (RCM_FAILURE); 450 } 451 cache_remove(probe); 452 free_node(probe); 453 probe = cache_head.ip_next; 454 } 455 (void) mutex_unlock(&cache_lock); 456 457 /* 458 * Need to unregister interest in all new resources 459 */ 460 if (events_registered) { 461 if (rcm_unregister_event(hd, RCM_RESOURCE_NETWORK_NEW, 0) 462 != RCM_SUCCESS) { 463 rcm_log_message(RCM_ERROR, 464 _("IP: failed to unregister %s\n"), 465 RCM_RESOURCE_NETWORK_NEW); 466 return (RCM_FAILURE); 467 } else { 468 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n", 469 RCM_RESOURCE_NETWORK_NEW); 470 events_registered--; 471 } 472 } 473 474 return (RCM_SUCCESS); 475 } 476 477 /* 478 * ip_offline() - Offline an interface. 479 */ 480 static int 481 ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 482 char **errorp, rcm_info_t **depend_info) 483 { 484 char *nic; 485 ip_cache_t *node; 486 ip_pif_t *pif; 487 int detachable = 0; 488 int nofailover = 0; 489 int ipmp = 0; 490 491 rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc); 492 493 /* Guard against bad arguments */ 494 assert(hd != NULL); 495 assert(rsrc != NULL); 496 assert(id == (id_t)0); 497 assert(errorp != NULL); 498 assert(depend_info != NULL); 499 500 nic = strrchr(rsrc, '/'); 501 nic = nic ? nic + 1 : rsrc; 502 503 /* Lock the cache and lookup the resource */ 504 (void) mutex_lock(&cache_lock); 505 node = cache_lookup(hd, rsrc, CACHE_REFRESH); 506 if (node == NULL) { 507 ip_log_err(node, errorp, "Unrecognized resource"); 508 errno = ENOENT; 509 (void) mutex_unlock(&cache_lock); 510 return (RCM_SUCCESS); 511 } 512 513 pif = node->ip_pif; 514 515 /* Establish default detachability criteria */ 516 if (flags & RCM_FORCE) { 517 detachable++; 518 } 519 520 /* Check if the interface is an IPMP grouped interface */ 521 if (strcmp(pif->pi_grpname, "")) { 522 ipmp++; 523 } 524 525 if (if_get_flags(pif) & IFF_NOFAILOVER) { 526 nofailover++; 527 } 528 529 /* 530 * Even if the interface is not in an IPMP group, it's possible that 531 * it's still okay to offline it as long as there are higher-level 532 * failover mechanisms for the addresses it owns (e.g., clustering). 533 * In this case, ip_offlinelist() will return RCM_SUCCESS, and we 534 * charge on. 535 */ 536 if (!ipmp && !detachable) { 537 /* Inform consumers of IP addresses being offlined */ 538 if (ip_offlinelist(hd, node, errorp, flags, depend_info) == 539 RCM_SUCCESS) { 540 rcm_log_message(RCM_DEBUG, 541 "IP: consumers agree on detach"); 542 } else { 543 ip_log_err(node, errorp, 544 "Device consumers prohibit offline"); 545 (void) mutex_unlock(&cache_lock); 546 return (RCM_FAILURE); 547 } 548 } 549 550 /* 551 * Cannot remove an IPMP interface if IFF_NOFAILOVER is set. 552 */ 553 if (ipmp && nofailover) { 554 /* Interface is part of an IPMP group, and cannot failover */ 555 ip_log_err(node, errorp, "Failover disabled"); 556 errno = EBUSY; 557 (void) mutex_unlock(&cache_lock); 558 return (RCM_FAILURE); 559 } 560 561 /* Check if it's a query */ 562 if (flags & RCM_QUERY) { 563 rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n", 564 rsrc); 565 (void) mutex_unlock(&cache_lock); 566 return (RCM_SUCCESS); 567 } 568 569 /* Check detachability, save configuration if detachable */ 570 if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) { 571 node->ip_cachestate |= CACHE_IF_IGNORE; 572 rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc); 573 (void) mutex_unlock(&cache_lock); 574 return (RCM_SUCCESS); 575 } 576 577 /* standalone detachable device */ 578 if (!ipmp) { 579 if (if_unplumb(node) < 0) { 580 ip_log_err(node, errorp, 581 "Failed to unplumb the device"); 582 583 errno = EIO; 584 (void) mutex_unlock(&cache_lock); 585 return (RCM_FAILURE); 586 } 587 588 node->ip_cachestate |= CACHE_IF_OFFLINED; 589 rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc); 590 (void) mutex_unlock(&cache_lock); 591 return (RCM_SUCCESS); 592 } 593 594 /* 595 * This an IPMP interface that can be failed over. 596 * Request in.mpathd(1M) to failover the physical interface. 597 */ 598 599 /* Failover to "any", let mpathd determine best failover candidate */ 600 if (ip_ipmp_offline(node, NULL) < 0) { 601 ip_log_err(node, errorp, "in.mpathd failover failed"); 602 /* 603 * Odds are that in.mpathd(1M) could not offline the device 604 * because it was the last interface in the group. However, 605 * it's possible that it's still okay to offline it as long as 606 * there are higher-level failover mechanisms for the 607 * addresses it owns (e.g., clustering). In this case, 608 * ip_offlinelist() will return RCM_SUCCESS, and we charge on. 609 * 610 * TODO: change ip_ipmp_offline() to return the actual failure 611 * from in.mpathd so that we can verify that it did indeed 612 * fail with IPMP_EMINRED. 613 */ 614 if (!detachable) { 615 /* Inform consumers of IP addresses being offlined */ 616 if (ip_offlinelist(hd, node, errorp, flags, 617 depend_info) == RCM_SUCCESS) { 618 rcm_log_message(RCM_DEBUG, 619 "IP: consumers agree on detach"); 620 } else { 621 ip_log_err(node, errorp, 622 "Device consumers prohibit offline"); 623 (void) mutex_unlock(&cache_lock); 624 errno = EBUSY; 625 return (RCM_FAILURE); 626 } 627 } 628 } 629 630 if (if_unplumb(node) < 0) { 631 rcm_log_message(RCM_ERROR, 632 _("IP: Unplumb failed (%s)\n"), 633 pif->pi_ifname); 634 635 /* Request mpathd to undo the offline */ 636 if (ip_ipmp_undo_offline(node) < 0) { 637 ip_log_err(node, errorp, "Undo offline failed"); 638 (void) mutex_unlock(&cache_lock); 639 return (RCM_FAILURE); 640 } 641 (void) mutex_unlock(&cache_lock); 642 return (RCM_FAILURE); 643 } 644 645 node->ip_cachestate |= CACHE_IF_OFFLINED; 646 rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc); 647 (void) mutex_unlock(&cache_lock); 648 return (RCM_SUCCESS); 649 } 650 651 /* 652 * ip_undo_offline() - Undo offline of a previously offlined device. 653 */ 654 /*ARGSUSED*/ 655 static int 656 ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 657 char **errorp, rcm_info_t **depend_info) 658 { 659 ip_cache_t *node; 660 char *nic; 661 662 rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc); 663 664 /* Guard against bad arguments */ 665 assert(hd != NULL); 666 assert(rsrc != NULL); 667 assert(id == (id_t)0); 668 assert(errorp != NULL); 669 assert(depend_info != NULL); 670 671 nic = strrchr(rsrc, '/'); 672 nic = nic ? nic + 1 : rsrc; 673 674 (void) mutex_lock(&cache_lock); 675 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 676 677 if (node == NULL) { 678 ip_log_err(node, errorp, "No such device"); 679 (void) mutex_unlock(&cache_lock); 680 errno = ENOENT; 681 return (RCM_FAILURE); 682 } 683 684 /* Check if no attempt should be made to online the device here */ 685 if (node->ip_cachestate & CACHE_IF_IGNORE) { 686 node->ip_cachestate &= ~(CACHE_IF_IGNORE); 687 (void) mutex_unlock(&cache_lock); 688 return (RCM_SUCCESS); 689 } 690 691 /* Check if the interface was previously offlined */ 692 if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) { 693 ip_log_err(node, errorp, "Device not offlined"); 694 (void) mutex_unlock(&cache_lock); 695 errno = ENOTSUP; 696 return (RCM_FAILURE); 697 } 698 699 if (if_replumb(node) == -1) { 700 /* re-plumb failed */ 701 ip_log_err(node, errorp, "Replumb failed"); 702 (void) mutex_unlock(&cache_lock); 703 errno = EIO; 704 return (RCM_FAILURE); 705 706 } 707 708 /* Inform consumers about IP addresses being un-offlined */ 709 (void) ip_onlinelist(hd, node, errorp, flags, depend_info); 710 711 node->ip_cachestate &= ~(CACHE_IF_OFFLINED); 712 rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc); 713 (void) mutex_unlock(&cache_lock); 714 return (RCM_SUCCESS); 715 } 716 717 /* 718 * ip_get_info() - Gather usage information for this resource. 719 */ 720 /*ARGSUSED*/ 721 int 722 ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 723 char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info) 724 { 725 ip_cache_t *node; 726 char *infostr; 727 728 /* Guard against bad arguments */ 729 assert(hd != NULL); 730 assert(rsrc != NULL); 731 assert(id == (id_t)0); 732 assert(usagep != NULL); 733 assert(errorp != NULL); 734 assert(depend_info != NULL); 735 736 rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc); 737 738 (void) mutex_lock(&cache_lock); 739 node = cache_lookup(hd, rsrc, CACHE_REFRESH); 740 if (!node) { 741 rcm_log_message(RCM_INFO, 742 _("IP: get_info(%s) unrecognized resource\n"), rsrc); 743 (void) mutex_unlock(&cache_lock); 744 errno = ENOENT; 745 return (RCM_FAILURE); 746 } 747 748 infostr = ip_usage(node); 749 750 if (infostr == NULL) { 751 /* most likely malloc failure */ 752 rcm_log_message(RCM_ERROR, 753 _("IP: get_info(%s) malloc failure\n"), rsrc); 754 (void) mutex_unlock(&cache_lock); 755 errno = ENOMEM; 756 *errorp = NULL; 757 return (RCM_FAILURE); 758 } 759 760 /* Set client/role properties */ 761 (void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP"); 762 763 /* Set usage property, infostr will be freed by caller */ 764 *usagep = infostr; 765 766 rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n", 767 rsrc, infostr); 768 769 (void) mutex_unlock(&cache_lock); 770 return (RCM_SUCCESS); 771 } 772 773 /* 774 * ip_suspend() - Nothing to do, always okay 775 */ 776 /*ARGSUSED*/ 777 static int 778 ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval, 779 uint_t flags, char **errorp, rcm_info_t **depend_info) 780 { 781 /* Guard against bad arguments */ 782 assert(hd != NULL); 783 assert(rsrc != NULL); 784 assert(id == (id_t)0); 785 assert(interval != NULL); 786 assert(errorp != NULL); 787 assert(depend_info != NULL); 788 789 rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc); 790 return (RCM_SUCCESS); 791 } 792 793 /* 794 * ip_resume() - Nothing to do, always okay 795 */ 796 /*ARGSUSED*/ 797 static int 798 ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 799 char **errorp, rcm_info_t ** depend_info) 800 { 801 /* Guard against bad arguments */ 802 assert(hd != NULL); 803 assert(rsrc != NULL); 804 assert(id == (id_t)0); 805 assert(errorp != NULL); 806 assert(depend_info != NULL); 807 808 rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc); 809 810 return (RCM_SUCCESS); 811 } 812 813 /* 814 * ip_remove() - remove a resource from cache 815 */ 816 /*ARGSUSED*/ 817 static int 818 ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 819 char **errorp, rcm_info_t **depend_info) 820 { 821 ip_cache_t *node; 822 823 /* Guard against bad arguments */ 824 assert(hd != NULL); 825 assert(rsrc != NULL); 826 assert(id == (id_t)0); 827 assert(errorp != NULL); 828 assert(depend_info != NULL); 829 830 rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc); 831 832 (void) mutex_lock(&cache_lock); 833 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 834 if (!node) { 835 rcm_log_message(RCM_INFO, 836 _("IP: remove(%s) unrecognized resource\n"), rsrc); 837 (void) mutex_unlock(&cache_lock); 838 errno = ENOENT; 839 return (RCM_FAILURE); 840 } 841 842 /* remove the cached entry for the resource */ 843 cache_remove(node); 844 845 (void) mutex_unlock(&cache_lock); 846 return (RCM_SUCCESS); 847 } 848 849 /* 850 * ip_notify_event - Project private implementation to receive new resource 851 * events. It intercepts all new resource events. If the 852 * new resource is a network resource, pass up a notify 853 * for it too. The new resource need not be cached, since 854 * it is done at register again. 855 */ 856 /*ARGSUSED*/ 857 static int 858 ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 859 char **errorp, nvlist_t *nvl, rcm_info_t **depend_info) 860 { 861 struct ni_list *nilp, *onilp; 862 struct net_interface *nip; 863 int n; 864 865 assert(hd != NULL); 866 assert(rsrc != NULL); 867 assert(id == (id_t)0); 868 assert(nvl != NULL); 869 870 rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc); 871 872 if (!STREQ(rsrc, RCM_RESOURCE_NETWORK_NEW)) { 873 rcm_log_message(RCM_INFO, 874 _("IP: unrecognized event for %s\n"), rsrc); 875 ip_log_err(NULL, errorp, "unrecognized event"); 876 errno = EINVAL; 877 return (RCM_FAILURE); 878 } 879 880 /* Update cache to reflect latest interfaces */ 881 if (update_cache(hd) < 0) { 882 rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n")); 883 ip_log_err(NULL, errorp, "Private Cache update failed"); 884 return (RCM_FAILURE); 885 } 886 887 /* Process the nvlist for the event */ 888 if (process_nvlist(nvl) != 0) { 889 rcm_log_message(RCM_WARNING, 890 _("IP: Error processing resource attributes(%s)\n"), rsrc); 891 rcm_log_message(RCM_WARNING, 892 _("IP: One or more devices may not be configured.\n")); 893 ip_log_err(NULL, errorp, "Error processing device properties"); 894 /* Continue processing interfaces that were valid */ 895 } 896 897 (void) mutex_lock(&nil_lock); 898 899 /* Configure all new interfaces found */ 900 for (nilp = nil_head, n = 0; n < num_ni; nilp = nilp->next, n++) { 901 nip = nilp->nifp; 902 if (if_configure(nip->name) != 0) { 903 rcm_log_message(RCM_ERROR, 904 _("IP: Configuration failed (%s)\n"), nip->name); 905 ip_log_err(NULL, errorp, 906 "Failed configuring one or more IP addresses"); 907 /* continue configuring rest of the interfaces */ 908 } 909 } 910 911 /* Notify all IP address consumers and clean up interface list */ 912 for (nilp = nil_head; nilp; ) { 913 nip = nilp->nifp; 914 if (nip != (struct net_interface *)0) { 915 if (nip->name != 0) { 916 ip_consumer_notify(hd, nip->name, errorp, flags, 917 depend_info); 918 free(nip->name); 919 } 920 if (nip->type != 0) 921 free(nip->type); 922 free((char *)nip); 923 } 924 925 onilp = nilp; 926 nilp = nilp->next; 927 free((char *)onilp); 928 } 929 930 num_ni = 0; /* reset new if count */ 931 nil_head = NIL_NULL; /* reset list head */ 932 933 (void) mutex_unlock(&nil_lock); 934 935 rcm_log_message(RCM_TRACE1, 936 "IP: notify_event: device configuration complete\n"); 937 938 return (RCM_SUCCESS); 939 } 940 941 /* 942 * ip_usage - Determine the usage of a device. Call with cache_lock held. 943 * The returned buffer is owned by caller, and the caller 944 * must free it up when done. 945 */ 946 static char * 947 ip_usage(ip_cache_t *node) 948 { 949 ip_lif_t *lif; 950 int numifs; 951 char *buf; 952 char *nic; 953 const char *fmt; 954 char *sep; 955 char addrstr[INET6_ADDRSTRLEN]; 956 int offline = 0; 957 size_t bufsz; 958 959 rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource); 960 961 nic = strchr(node->ip_resource, '/'); 962 nic = nic ? nic + 1 : node->ip_resource; 963 964 /* TRANSLATION_NOTE: separator used between IP addresses */ 965 sep = _(", "); 966 967 numifs = 0; 968 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) { 969 if (lif->li_ifflags & IFF_UP) { 970 numifs++; 971 } 972 } 973 974 if (node->ip_cachestate & CACHE_IF_OFFLINED) { 975 offline++; 976 } 977 978 if (!offline && numifs) { 979 fmt = _("%1$s hosts IP addresses: "); 980 } else if (offline) { 981 fmt = _("%1$s offlined"); 982 } else { 983 fmt = _("%1$s plumbed but down"); 984 } 985 986 /* space for addresses and separators, plus message */ 987 bufsz = ((numifs * (INET6_ADDRSTRLEN + strlen(sep))) + 988 strlen(fmt) + strlen(nic) + 1); 989 if ((buf = malloc(bufsz)) == NULL) { 990 rcm_log_message(RCM_ERROR, 991 _("IP: usage(%s) malloc failure(%s)\n"), 992 node->ip_resource, strerror(errno)); 993 return (NULL); 994 } 995 bzero(buf, bufsz); 996 (void) sprintf(buf, fmt, nic); 997 998 if (offline || (numifs == 0)) { /* Nothing else to do */ 999 rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n", 1000 node->ip_resource, buf); 1001 1002 return (buf); 1003 } 1004 1005 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) { 1006 1007 void *addr; 1008 int af; 1009 1010 if (!(lif->li_ifflags & IFF_UP)) { 1011 /* ignore interfaces not up */ 1012 continue; 1013 } 1014 af = lif->li_addr.family; 1015 if (af == AF_INET6) { 1016 addr = &lif->li_addr.ip6.sin6_addr; 1017 } else if (af == AF_INET) { 1018 addr = &lif->li_addr.ip4.sin_addr; 1019 } else { 1020 rcm_log_message(RCM_DEBUG, 1021 "IP: unknown addr family %d, assuming AF_INET\n", 1022 af); 1023 af = AF_INET; 1024 addr = &lif->li_addr.ip4.sin_addr; 1025 } 1026 if (inet_ntop(af, addr, addrstr, INET6_ADDRSTRLEN) == NULL) { 1027 rcm_log_message(RCM_ERROR, 1028 _("IP: inet_ntop: %s\n"), strerror(errno)); 1029 continue; 1030 } 1031 rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr); 1032 1033 (void) strcat(buf, addrstr); 1034 numifs--; 1035 if (numifs > 0) { 1036 (void) strcat(buf, ", "); 1037 } 1038 } 1039 1040 rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n", 1041 node->ip_resource, buf); 1042 1043 return (buf); 1044 } 1045 1046 /* 1047 * Cache management routines, all cache management functions should be 1048 * be called with cache_lock held. 1049 */ 1050 1051 /* 1052 * cache_lookup() - Get a cache node for a resource. Supports VLAN interfaces. 1053 * Call with cache lock held. 1054 * 1055 * This ensures that the cache is consistent with the system state and 1056 * returns a pointer to the cache element corresponding to the resource. 1057 */ 1058 static ip_cache_t * 1059 cache_lookup(rcm_handle_t *hd, char *rsrc, char options) 1060 { 1061 ip_cache_t *probe; 1062 char *resource; /* physical resource */ 1063 1064 rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc); 1065 1066 if ((options & CACHE_REFRESH) && (hd != NULL)) { 1067 /* drop lock since update locks cache again */ 1068 (void) mutex_unlock(&cache_lock); 1069 (void) update_cache(hd); 1070 (void) mutex_lock(&cache_lock); 1071 } 1072 1073 if ((resource = get_physical_resource(rsrc)) == NULL) { 1074 errno = ENOENT; 1075 return (NULL); 1076 } 1077 1078 probe = cache_head.ip_next; 1079 while (probe != &cache_tail) { 1080 if (probe->ip_resource && 1081 STREQ(resource, probe->ip_resource)) { 1082 rcm_log_message(RCM_TRACE2, 1083 "IP: cache lookup success(%s)\n", rsrc); 1084 free(resource); 1085 return (probe); 1086 } 1087 probe = probe->ip_next; 1088 } 1089 free(resource); 1090 return (NULL); 1091 } 1092 1093 /* 1094 * free_node - Free a node from the cache 1095 * Call with cache_lock held. 1096 */ 1097 static void 1098 free_node(ip_cache_t *node) 1099 { 1100 ip_pif_t *pif; 1101 ip_lif_t *lif, *tmplif; 1102 1103 if (node) { 1104 if (node->ip_resource) { 1105 free(node->ip_resource); 1106 } 1107 1108 /* free the pif */ 1109 pif = node->ip_pif; 1110 if (pif) { 1111 /* free logical interfaces */ 1112 lif = pif->pi_lifs; 1113 while (lif) { 1114 tmplif = lif->li_next; 1115 free(lif); 1116 lif = tmplif; 1117 } 1118 free(pif); 1119 } 1120 free(node); 1121 } 1122 } 1123 1124 /* 1125 * cache_insert - Insert a resource node in cache 1126 * Call with the cache_lock held. 1127 */ 1128 static void 1129 cache_insert(ip_cache_t *node) 1130 { 1131 /* insert at the head for best performance */ 1132 node->ip_next = cache_head.ip_next; 1133 node->ip_prev = &cache_head; 1134 1135 node->ip_next->ip_prev = node; 1136 node->ip_prev->ip_next = node; 1137 } 1138 1139 /* 1140 * cache_remove() - Remove a resource node from cache. 1141 * Call with the cache_lock held. 1142 */ 1143 static void 1144 cache_remove(ip_cache_t *node) 1145 { 1146 node->ip_next->ip_prev = node->ip_prev; 1147 node->ip_prev->ip_next = node->ip_next; 1148 node->ip_next = NULL; 1149 node->ip_prev = NULL; 1150 } 1151 1152 /* 1153 * update_pif() - Update physical interface properties 1154 * Call with cache_lock held 1155 */ 1156 /*ARGSUSED*/ 1157 static int 1158 update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr) 1159 { 1160 char ifname[RCM_NET_RESOURCE_MAX]; 1161 ushort_t ifnumber = 0; 1162 int ppa; 1163 char *cp; 1164 ip_cache_t *probe; 1165 ip_pif_t pif; 1166 ip_pif_t *probepif; 1167 ip_lif_t *probelif; 1168 struct lifreq lifreq; 1169 struct sockaddr_storage ifaddr; 1170 uint64_t ifflags; 1171 int lif_listed = 0; 1172 1173 rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", lifr->lifr_name); 1174 1175 /* Determine the interface name and lun number */ 1176 (void) memcpy(&ifname, lifr->lifr_name, sizeof (ifname)); 1177 ifname[sizeof (ifname) - 1] = '\0'; 1178 1179 /* remove LIF component */ 1180 cp = strchr(ifname, ':'); 1181 if (cp) { 1182 *cp = 0; 1183 cp++; 1184 ifnumber = atoi(cp); 1185 } 1186 1187 (void) memcpy(&pif.pi_ifname, &ifname, sizeof (pif.pi_ifname)); 1188 pif.pi_ifname[sizeof (pif.pi_ifname) - 1] = '\0'; 1189 1190 /* Determine DLPI style */ 1191 if (getdlpi_style(ifname) == DL_STYLE1) { 1192 pif.pi_ppa = 0; 1193 pif.pi_style = DL_STYLE1; 1194 rcm_log_message(RCM_DEBUG, "IP: DLPI style1 (%s)\n", ifname); 1195 } else { /* DLPI style 2 */ 1196 /* Determine the ppa */ 1197 if ((ppa = get_ppa(ifname)) < 0) { 1198 rcm_log_message(RCM_ERROR, 1199 _("IP: get_ppa(%s): %s\n"), 1200 ifname, strerror(ENXIO)); 1201 return (-1); 1202 } 1203 1204 pif.pi_style = DL_STYLE2; 1205 pif.pi_ppa = ppa; 1206 rcm_log_message(RCM_DEBUG, "IP: DLPI style2 (%s)\n", ifname); 1207 } 1208 1209 /* Get the interface flags */ 1210 (void) strcpy(lifreq.lifr_name, lifr->lifr_name); 1211 if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) { 1212 rcm_log_message(RCM_ERROR, 1213 _("IP: SIOCGLIFFLAGS(%s): %s\n"), 1214 ifname, strerror(errno)); 1215 return (-1); 1216 } 1217 (void) memcpy(&ifflags, &lifreq.lifr_flags, sizeof (ifflags)); 1218 1219 /* Ignore loopback and multipoint interfaces */ 1220 if (!(ifflags & IFF_MULTICAST) || 1221 (ifflags & IFF_LOOPBACK)) { 1222 rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n", ifname); 1223 return (0); 1224 } 1225 1226 /* Get the interface group name for this interface */ 1227 if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) { 1228 rcm_log_message(RCM_ERROR, 1229 _("IP: SIOCGLIFGROUPNAME(%s): %s\n"), 1230 lifreq.lifr_name, strerror(errno)); 1231 return (-1); 1232 } 1233 1234 /* copy the group name */ 1235 (void) memcpy(&pif.pi_grpname, &lifreq.lifr_groupname, 1236 sizeof (pif.pi_grpname)); 1237 pif.pi_grpname[sizeof (pif.pi_grpname) - 1] = '\0'; 1238 1239 /* Get the interface address for this interface */ 1240 if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) { 1241 rcm_log_message(RCM_ERROR, 1242 _("IP: SIOCGLIFADDR(%s): %s\n"), 1243 lifreq.lifr_name, strerror(errno)); 1244 return (-1); 1245 } 1246 (void) memcpy(&ifaddr, &lifreq.lifr_addr, sizeof (ifaddr)); 1247 1248 /* Get the interface index */ 1249 if (ioctl(sock, SIOCGLIFINDEX, (char *)&lifreq) < 0) { 1250 rcm_log_message(RCM_ERROR, 1251 _("IP: SIOCGLIFINDEX(%s): %s\n"), 1252 lifreq.lifr_name, strerror(errno)); 1253 return (-1); 1254 } 1255 pif.pi_ifindex = lifreq.lifr_index; 1256 1257 /* Search for the interface in our cache */ 1258 (void) snprintf(ifname, sizeof (ifname), "%s/%s", RCM_NET_PREFIX, 1259 pif.pi_ifname); 1260 1261 probe = cache_lookup(hd, ifname, CACHE_NO_REFRESH); 1262 if (probe != NULL) { 1263 probe->ip_cachestate &= ~(CACHE_IF_STALE); 1264 } else { 1265 if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) { 1266 /* malloc errors are bad */ 1267 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"), 1268 strerror(errno)); 1269 return (-1); 1270 } 1271 1272 probe->ip_resource = get_physical_resource(ifname); 1273 if (!probe->ip_resource) { 1274 rcm_log_message(RCM_ERROR, _("IP: strdup: %s\n"), 1275 strerror(errno)); 1276 free(probe); 1277 return (-1); 1278 } 1279 1280 probe->ip_pif = NULL; 1281 probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY; 1282 probe->ip_cachestate |= CACHE_IF_NEW; 1283 1284 cache_insert(probe); 1285 } 1286 1287 probepif = probe->ip_pif; 1288 if (probepif != NULL) { 1289 /* Check if lifs need to be updated */ 1290 probelif = probepif->pi_lifs; 1291 while (probelif != NULL) { 1292 if ((probelif->li_ifnum == ifnumber) && 1293 (probelif->li_addr.family == ifaddr.ss_family)) { 1294 1295 rcm_log_message(RCM_TRACE2, 1296 "IP: refreshing lifs for %s, ifnum=%d\n", 1297 pif.pi_ifname, probelif->li_ifnum); 1298 1299 /* refresh lif properties */ 1300 (void) memcpy(&probelif->li_addr, &ifaddr, 1301 sizeof (probelif->li_addr)); 1302 1303 probelif->li_ifflags = ifflags; 1304 1305 lif_listed++; 1306 probe->ip_cachestate |= CACHE_IF_UPDATED; 1307 probelif->li_cachestate &= ~(CACHE_IF_STALE); 1308 break; 1309 } 1310 probelif = probelif->li_next; 1311 } 1312 } 1313 1314 if (probepif == NULL) { 1315 if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) { 1316 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"), 1317 strerror(errno)); 1318 if (probe->ip_pif == NULL) { 1319 /* we created it, so clean it up */ 1320 free(probe); 1321 } 1322 return (-1); 1323 } 1324 1325 probe->ip_pif = probepif; 1326 1327 probe->ip_cachestate |= CACHE_IF_UPDATED; 1328 1329 /* Save interface name */ 1330 (void) memcpy(&probepif->pi_ifname, &pif.pi_ifname, 1331 sizeof (pif.pi_ifname)); 1332 } 1333 1334 /* save pif properties */ 1335 probepif->pi_ifindex = pif.pi_ifindex; 1336 (void) memcpy(&probepif->pi_grpname, &pif.pi_grpname, 1337 sizeof (pif.pi_grpname)); 1338 probepif->pi_style = pif.pi_style; 1339 probepif->pi_ppa = pif.pi_ppa; 1340 1341 /* add lif, if this is a lif and it is not in cache */ 1342 if (!lif_listed) { 1343 rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n", 1344 pif.pi_ifname); 1345 1346 if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) { 1347 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"), 1348 strerror(errno)); 1349 return (-1); 1350 } 1351 1352 /* save lif properties */ 1353 (void) memcpy(&probelif->li_addr, &ifaddr, 1354 sizeof (probelif->li_addr)); 1355 1356 probelif->li_ifnum = ifnumber; 1357 probelif->li_ifflags = ifflags; 1358 1359 /* insert us at the head of the lif list */ 1360 probelif->li_next = probepif->pi_lifs; 1361 if (probelif->li_next != NULL) { 1362 probelif->li_next->li_prev = probelif; 1363 } 1364 probelif->li_prev = NULL; 1365 probelif->li_pif = probepif; 1366 1367 probepif->pi_lifs = probelif; 1368 probelif->li_cachestate = CACHE_IF_NEW; 1369 1370 probe->ip_cachestate |= CACHE_IF_UPDATED; 1371 } 1372 1373 rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n", 1374 probe->ip_resource); 1375 1376 return (0); 1377 } 1378 1379 /* 1380 * update_ipifs() - Determine all network interfaces in the system 1381 * Call with cache_lock held 1382 */ 1383 static int 1384 update_ipifs(rcm_handle_t *hd, int af) 1385 { 1386 int sock; 1387 char *buf; 1388 struct lifnum lifn; 1389 struct lifconf lifc; 1390 struct lifreq *lifrp; 1391 int i; 1392 1393 rcm_log_message(RCM_TRACE2, "IP: update_ipifs\n"); 1394 1395 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) { 1396 rcm_log_message(RCM_ERROR, 1397 _("IP: failure opening %s socket: %s\n"), 1398 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno)); 1399 return (-1); 1400 } 1401 1402 lifn.lifn_family = af; 1403 lifn.lifn_flags = 0; 1404 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 1405 rcm_log_message(RCM_ERROR, 1406 _("IP: SIOCLGIFNUM failed: %s\n"), 1407 strerror(errno)); 1408 (void) close(sock); 1409 return (-1); 1410 } 1411 1412 if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) { 1413 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"), 1414 strerror(errno)); 1415 (void) close(sock); 1416 return (-1); 1417 } 1418 1419 lifc.lifc_family = af; 1420 lifc.lifc_flags = 0; 1421 lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count; 1422 lifc.lifc_buf = buf; 1423 1424 if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 1425 rcm_log_message(RCM_ERROR, 1426 _("IP: SIOCGLIFCONF failed: %s\n"), 1427 strerror(errno)); 1428 free(buf); 1429 (void) close(sock); 1430 return (-1); 1431 } 1432 1433 /* now we need to search for active interfaces */ 1434 lifrp = lifc.lifc_req; 1435 for (i = 0; i < lifn.lifn_count; i++) { 1436 (void) update_pif(hd, af, sock, lifrp); 1437 lifrp++; 1438 } 1439 1440 free(buf); 1441 (void) close(sock); 1442 return (0); 1443 } 1444 1445 /* 1446 * update_cache() - Update cache with latest interface info 1447 */ 1448 static int 1449 update_cache(rcm_handle_t *hd) 1450 { 1451 ip_cache_t *probe; 1452 struct ip_lif *lif; 1453 struct ip_lif *nextlif; 1454 int rv; 1455 int i; 1456 1457 rcm_log_message(RCM_TRACE2, "IP: update_cache\n"); 1458 1459 (void) mutex_lock(&cache_lock); 1460 1461 /* first we walk the entire cache, marking each entry stale */ 1462 probe = cache_head.ip_next; 1463 while (probe != &cache_tail) { 1464 probe->ip_cachestate |= CACHE_IF_STALE; 1465 if ((probe->ip_pif != NULL) && 1466 ((lif = probe->ip_pif->pi_lifs) != NULL)) { 1467 while (lif != NULL) { 1468 lif->li_cachestate |= CACHE_IF_STALE; 1469 lif = lif->li_next; 1470 } 1471 } 1472 probe = probe->ip_next; 1473 } 1474 1475 rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n"); 1476 if (update_ipifs(hd, AF_INET) < 0) { 1477 (void) mutex_unlock(&cache_lock); 1478 return (-1); 1479 } 1480 1481 rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n"); 1482 if (update_ipifs(hd, AF_INET6) < 0) { 1483 (void) mutex_unlock(&cache_lock); 1484 return (-1); 1485 } 1486 1487 probe = cache_head.ip_next; 1488 /* unregister devices that are not offlined and still in cache */ 1489 while (probe != &cache_tail) { 1490 ip_cache_t *freeit; 1491 if ((probe->ip_pif != NULL) && 1492 ((lif = probe->ip_pif->pi_lifs) != NULL)) { 1493 /* clear stale lifs */ 1494 while (lif != NULL) { 1495 if (lif->li_cachestate & CACHE_IF_STALE) { 1496 nextlif = lif->li_next; 1497 if (lif->li_prev != NULL) 1498 lif->li_prev->li_next = nextlif; 1499 if (nextlif != NULL) 1500 nextlif->li_prev = lif->li_prev; 1501 if (probe->ip_pif->pi_lifs == lif) 1502 probe->ip_pif->pi_lifs = 1503 nextlif; 1504 for (i = 0; i < IP_MAX_MODS; i++) { 1505 free(lif->li_modules[i]); 1506 } 1507 free(lif->li_reconfig); 1508 free(lif); 1509 lif = nextlif; 1510 } else { 1511 lif = lif->li_next; 1512 } 1513 } 1514 } 1515 if ((probe->ip_cachestate & CACHE_IF_STALE) && 1516 !(probe->ip_cachestate & CACHE_IF_OFFLINED)) { 1517 (void) rcm_unregister_interest(hd, probe->ip_resource, 1518 0); 1519 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n", 1520 probe->ip_resource); 1521 freeit = probe; 1522 probe = probe->ip_next; 1523 cache_remove(freeit); 1524 free_node(freeit); 1525 continue; 1526 } 1527 1528 if (!(probe->ip_cachestate & CACHE_IF_NEW)) { 1529 probe = probe->ip_next; 1530 continue; 1531 } 1532 1533 rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL); 1534 if (rv != RCM_SUCCESS) { 1535 rcm_log_message(RCM_ERROR, 1536 _("IP: failed to register %s\n"), 1537 probe->ip_resource); 1538 (void) mutex_unlock(&cache_lock); 1539 return (-1); 1540 } else { 1541 rcm_log_message(RCM_DEBUG, "IP: registered %s\n", 1542 probe->ip_resource); 1543 probe->ip_cachestate &= ~(CACHE_IF_NEW); 1544 } 1545 probe = probe->ip_next; 1546 } 1547 1548 (void) mutex_unlock(&cache_lock); 1549 return (0); 1550 } 1551 1552 /* 1553 * free_cache() - Empty the cache 1554 */ 1555 static void 1556 free_cache() 1557 { 1558 ip_cache_t *probe; 1559 1560 rcm_log_message(RCM_TRACE2, "IP: free_cache\n"); 1561 1562 (void) mutex_lock(&cache_lock); 1563 probe = cache_head.ip_next; 1564 while (probe != &cache_tail) { 1565 cache_remove(probe); 1566 free_node(probe); 1567 probe = cache_head.ip_next; 1568 } 1569 (void) mutex_unlock(&cache_lock); 1570 } 1571 1572 /* 1573 * ip_log_err() - RCM error log wrapper 1574 */ 1575 static void 1576 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg) 1577 { 1578 char *nic = NULL; 1579 int len; 1580 const char *errfmt; 1581 char *error; 1582 1583 if ((node != NULL) && (node->ip_pif != NULL) && 1584 (node->ip_pif->pi_ifname != NULL)) { 1585 nic = strrchr(node->ip_pif->pi_ifname, '/'); 1586 nic = nic ? nic + 1 : node->ip_pif->pi_ifname; 1587 } 1588 1589 if (errorp != NULL) 1590 *errorp = NULL; 1591 1592 if (nic == NULL) { 1593 rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg); 1594 errfmt = _("IP: %s"); 1595 len = strlen(errfmt) + strlen(errmsg) + 1; 1596 if (error = (char *)calloc(1, len)) { 1597 (void) sprintf(error, errfmt, errmsg); 1598 } 1599 } else { 1600 rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, nic); 1601 errfmt = _("IP: %s(%s)"); 1602 len = strlen(errfmt) + strlen(errmsg) + strlen(nic) + 1; 1603 if (error = (char *)calloc(1, len)) { 1604 (void) sprintf(error, errfmt, errmsg, nic); 1605 } 1606 } 1607 1608 if (errorp != NULL) 1609 *errorp = error; 1610 } 1611 1612 1613 /* 1614 * if_cfginfo() - Save off the config info for all interfaces 1615 */ 1616 static int 1617 if_cfginfo(ip_cache_t *node, uint_t force) 1618 { 1619 ip_lif_t *lif; 1620 ip_pif_t *pif; 1621 int i; 1622 FILE *fp; 1623 char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ]; 1624 char buf[MAX_RECONFIG_SIZE]; 1625 1626 rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource); 1627 1628 pif = node->ip_pif; 1629 lif = pif->pi_lifs; 1630 1631 while (lif != NULL) { 1632 /* Make a list of modules pushed and save */ 1633 if (lif->li_ifnum == 0) { /* physical instance */ 1634 if (get_modlist(pif->pi_ifname, lif) == -1) { 1635 rcm_log_message(RCM_ERROR, 1636 _("IP: get modlist error (%s) %s\n"), 1637 pif->pi_ifname, strerror(errno)); 1638 (void) clr_cfg_state(pif); 1639 return (-1); 1640 } 1641 1642 if (!force) { 1643 /* Look if unknown modules have been inserted */ 1644 for (i = (lif->li_modcnt - 2); i > 0; i--) { 1645 if (modop(pif->pi_ifname, 1646 lif->li_modules[i], 1647 i, MOD_CHECK) == -1) { 1648 rcm_log_message(RCM_ERROR, 1649 _("IP: module %s@%d\n"), 1650 lif->li_modules[i], i); 1651 (void) clr_cfg_state(pif); 1652 return (-1); 1653 } 1654 } 1655 } 1656 1657 /* Last module is the device driver, so ignore that */ 1658 for (i = (lif->li_modcnt - 2); i > 0; i--) { 1659 rcm_log_message(RCM_TRACE2, 1660 "IP: modremove Pos = %d, Module = %s \n", 1661 i, lif->li_modules[i]); 1662 if (modop(pif->pi_ifname, lif->li_modules[i], 1663 i, MOD_REMOVE) == -1) { 1664 while (i != (lif->li_modcnt - 2)) { 1665 if (modop(pif->pi_ifname, 1666 lif->li_modules[i], 1667 i, MOD_INSERT) == -1) { 1668 /* Gross error */ 1669 rcm_log_message( 1670 RCM_ERROR, 1671 _("IP: if_cfginfo" 1672 "(%s) %s\n"), 1673 pif->pi_ifname, 1674 strerror(errno)); 1675 clr_cfg_state(pif); 1676 return (-1); 1677 } 1678 i++; 1679 } 1680 rcm_log_message( 1681 RCM_ERROR, 1682 _("IP: if_cfginfo(%s): modremove " 1683 "%s failed: %s\n"), pif->pi_ifname, 1684 lif->li_modules[i], 1685 strerror(errno)); 1686 clr_cfg_state(pif); 1687 return (-1); 1688 } 1689 } 1690 } 1691 1692 /* Save reconfiguration information */ 1693 if (lif->li_ifflags & IFF_IPV4) { 1694 (void) snprintf(syscmd, sizeof (syscmd), 1695 "%s %s:%d configinfo\n", USR_SBIN_IFCONFIG, 1696 pif->pi_ifname, lif->li_ifnum); 1697 } else if (lif->li_ifflags & IFF_IPV6) { 1698 (void) snprintf(syscmd, sizeof (syscmd), 1699 "%s %s:%d inet6 configinfo\n", USR_SBIN_IFCONFIG, 1700 pif->pi_ifname, lif->li_ifnum); 1701 } 1702 rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd); 1703 1704 /* open a pipe to retrieve reconfiguration info */ 1705 if ((fp = popen(syscmd, "r")) == NULL) { 1706 rcm_log_message(RCM_ERROR, 1707 _("IP: ifconfig configinfo error (%s:%d) %s\n"), 1708 pif->pi_ifname, lif->li_ifnum, strerror(errno)); 1709 (void) clr_cfg_state(pif); 1710 return (-1); 1711 } 1712 bzero(buf, MAX_RECONFIG_SIZE); 1713 1714 if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) { 1715 rcm_log_message(RCM_ERROR, 1716 _("IP: ifconfig configinfo error (%s:%d) %s\n"), 1717 pif->pi_ifname, lif->li_ifnum, strerror(errno)); 1718 (void) pclose(fp); 1719 (void) clr_cfg_state(pif); 1720 return (-1); 1721 } 1722 (void) pclose(fp); 1723 1724 lif->li_reconfig = malloc(strlen(buf)+1); 1725 if (lif->li_reconfig == NULL) { 1726 rcm_log_message(RCM_ERROR, 1727 _("IP: malloc error (%s) %s\n"), 1728 pif->pi_ifname, strerror(errno)); 1729 (void) clr_cfg_state(pif); 1730 return (-1); 1731 } 1732 (void) strcpy(lif->li_reconfig, buf); 1733 rcm_log_message(RCM_DEBUG, 1734 "IP: if_cfginfo: reconfig string(%s:%d) = %s\n", 1735 pif->pi_ifname, lif->li_ifnum, lif->li_reconfig); 1736 1737 lif = lif->li_next; 1738 } 1739 1740 return (0); 1741 } 1742 1743 /* 1744 * if_unplumb() - Unplumb the interface 1745 * Save off the modlist, ifconfig options and unplumb. 1746 * Fail, if an unknown module lives between IP and driver and 1747 * force is not set 1748 * Call with cache_lock held 1749 */ 1750 static int 1751 if_unplumb(ip_cache_t *node) 1752 { 1753 ip_lif_t *lif; 1754 ip_pif_t *pif; 1755 int ipv4 = 0, ipv6 = 0; 1756 char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ]; 1757 1758 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource); 1759 1760 pif = node->ip_pif; 1761 lif = pif->pi_lifs; 1762 1763 while (lif != NULL) { 1764 if (lif->li_ifflags & IFF_IPV4) { 1765 ipv4++; 1766 } else if (lif->li_ifflags & IFF_IPV6) { 1767 ipv6++; 1768 } else { 1769 /* Unlikely case */ 1770 rcm_log_message(RCM_DEBUG, 1771 _("IP: Unplumb ignored (%s:%d)\n"), 1772 pif->pi_ifname, lif->li_ifnum); 1773 lif = lif->li_next; 1774 continue; 1775 } 1776 lif = lif->li_next; 1777 } 1778 1779 /* Unplumb the physical interface */ 1780 if (ipv4) { 1781 rcm_log_message(RCM_TRACE2, 1782 "IP: if_unplumb: ifconfig %s unplumb\n", pif->pi_ifname); 1783 (void) snprintf(syscmd, sizeof (syscmd), "%s %s unplumb\n", 1784 USR_SBIN_IFCONFIG, pif->pi_ifname); 1785 if (rcm_exec_cmd(syscmd) != 0) { 1786 rcm_log_message(RCM_ERROR, 1787 _("IP: Cannot unplumb (%s) %s\n"), 1788 pif->pi_ifname, strerror(errno)); 1789 return (-1); 1790 } 1791 } 1792 if (ipv6) { 1793 rcm_log_message(RCM_TRACE2, 1794 "IP: if_unplumb: ifconfig %s inet6 unplumb\n", 1795 pif->pi_ifname); 1796 (void) snprintf(syscmd, sizeof (syscmd), 1797 "%s %s inet6 unplumb\n", USR_SBIN_IFCONFIG, pif->pi_ifname); 1798 if (rcm_exec_cmd(syscmd) != 0) { 1799 rcm_log_message(RCM_ERROR, 1800 _("IP: Cannot unplumb (%s) %s\n"), 1801 pif->pi_ifname, strerror(errno)); 1802 return (-1); 1803 } 1804 } 1805 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n", 1806 node->ip_resource); 1807 1808 return (0); 1809 } 1810 1811 /* 1812 * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface 1813 * instances and the logical interfaces in order, restoring 1814 * all ifconfig options 1815 * Call with cache_lock held 1816 */ 1817 static int 1818 if_replumb(ip_cache_t *node) 1819 { 1820 ip_lif_t *lif; 1821 ip_pif_t *pif; 1822 int i; 1823 char syscmd[LIFNAMSIZ+MAXPATHLEN]; /* must be big enough */ 1824 int max_ipv4 = 0, max_ipv6 = 0; 1825 1826 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource); 1827 1828 /* 1829 * Be extra careful about bringing up the interfaces in the 1830 * correct order: 1831 * - First plumb in the physical interface instances 1832 * - modinsert the necessary modules@pos 1833 * - Next, add the logical interfaces being careful about 1834 * the order, (follow the cached interface number li_ifnum order) 1835 */ 1836 1837 pif = node->ip_pif; 1838 lif = pif->pi_lifs; 1839 1840 /* 1841 * Make a first pass to plumb in physical interfaces and get a count 1842 * of the max logical interfaces 1843 */ 1844 while (lif != NULL) { 1845 if (lif->li_ifflags & IFF_IPV4) { 1846 if (lif->li_ifnum > max_ipv4) { 1847 max_ipv4 = lif->li_ifnum; 1848 } 1849 } else if (lif->li_ifflags & IFF_IPV6) { 1850 if (lif->li_ifnum > max_ipv6) { 1851 max_ipv6 = lif->li_ifnum; 1852 } 1853 } else { 1854 /* Unlikely case */ 1855 rcm_log_message(RCM_DEBUG, 1856 _("IP: Re-plumb ignored (%s:%d)\n"), 1857 pif->pi_ifname, lif->li_ifnum); 1858 lif = lif->li_next; 1859 continue; 1860 } 1861 1862 if (lif->li_ifnum == 0) { /* physical interface instance */ 1863 if ((lif->li_ifflags & IFF_NOFAILOVER) || 1864 (strcmp(pif->pi_grpname, "") == 0)) { 1865 (void) snprintf(syscmd, sizeof (syscmd), 1866 "%s %s\n", USR_SBIN_IFCONFIG, 1867 lif->li_reconfig); 1868 } else if (lif->li_ifflags & IFF_IPV4) { 1869 (void) snprintf(syscmd, sizeof (syscmd), 1870 "%s %s inet plumb group %s\n", 1871 USR_SBIN_IFCONFIG, 1872 pif->pi_ifname, pif->pi_grpname); 1873 } else if (lif->li_ifflags & IFF_IPV6) { 1874 (void) snprintf(syscmd, sizeof (syscmd), 1875 "%s %s inet6 plumb group %s\n", 1876 USR_SBIN_IFCONFIG, 1877 pif->pi_ifname, pif->pi_grpname); 1878 } 1879 1880 rcm_log_message(RCM_TRACE2, 1881 "IP: if_replumb: %s\n", syscmd); 1882 if (rcm_exec_cmd(syscmd) != 0) { 1883 rcm_log_message(RCM_ERROR, 1884 _("IP: Cannot plumb (%s) %s\n"), 1885 pif->pi_ifname, strerror(errno)); 1886 return (-1); 1887 } 1888 1889 rcm_log_message(RCM_TRACE2, 1890 "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt); 1891 /* modinsert modules in order, ignore driver(last) */ 1892 for (i = 0; i < (lif->li_modcnt - 1); i++) { 1893 rcm_log_message(RCM_TRACE2, 1894 "IP: modinsert: Pos = %d Mod = %s\n", 1895 i, lif->li_modules[i]); 1896 if (modop(pif->pi_ifname, lif->li_modules[i], i, 1897 MOD_INSERT) == -1) { 1898 rcm_log_message(RCM_ERROR, 1899 _("IP: modinsert error(%s)\n"), 1900 pif->pi_ifname); 1901 return (-1); 1902 } 1903 } 1904 } 1905 1906 lif = lif->li_next; 1907 } 1908 1909 /* Now, add all the logical interfaces in the correct order */ 1910 for (i = 1; i <= MAX(max_ipv6, max_ipv4); i++) { 1911 /* reset lif through every iteration */ 1912 lif = pif->pi_lifs; 1913 while (lif != NULL) { 1914 if (((lif->li_ifflags & IFF_NOFAILOVER) || 1915 (strcmp(pif->pi_grpname, "") == 0)) && 1916 (lif->li_ifnum == i)) { 1917 /* Plumb in the logical interface */ 1918 (void) snprintf(syscmd, sizeof (syscmd), 1919 "%s %s\n", USR_SBIN_IFCONFIG, 1920 lif->li_reconfig); 1921 rcm_log_message(RCM_TRACE2, 1922 "IP: if_replumb: %s\n", syscmd); 1923 if (rcm_exec_cmd(syscmd) != 0) { 1924 rcm_log_message(RCM_ERROR, 1925 _("IP: Cannot addif (%s:%d) " 1926 "%s\n"), 1927 pif->pi_ifname, i, strerror(errno)); 1928 return (-1); 1929 } 1930 } 1931 lif = lif->li_next; 1932 } 1933 } 1934 1935 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n", 1936 node->ip_resource); 1937 1938 return (0); 1939 } 1940 1941 /* 1942 * clr_cfg_state() - Cleanup after errors in unplumb 1943 */ 1944 static void 1945 clr_cfg_state(ip_pif_t *pif) 1946 { 1947 ip_lif_t *lif; 1948 int i; 1949 1950 lif = pif->pi_lifs; 1951 1952 while (lif != NULL) { 1953 lif->li_modcnt = 0; 1954 free(lif->li_reconfig); 1955 lif->li_reconfig = NULL; 1956 for (i = 0; i < IP_MAX_MODS; i++) { 1957 free(lif->li_modules[i]); 1958 lif->li_modules[i] = NULL; 1959 } 1960 lif = lif->li_next; 1961 } 1962 } 1963 1964 /* 1965 * ip_ipmp_offline() - Failover from if_from to if_to using a 1966 * minimum redudancy of min_red. This uses IPMPs 1967 * "offline" mechanism to achieve the failover. 1968 */ 1969 static int 1970 ip_ipmp_offline(ip_cache_t *if_from, ip_cache_t *if_to) 1971 { 1972 mpathd_cmd_t mpdcmd; 1973 1974 if ((if_from == NULL) || (if_from->ip_pif == NULL) || 1975 (if_from->ip_pif->pi_ifname == NULL)) { 1976 return (-1); 1977 } 1978 1979 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n"); 1980 1981 mpdcmd.cmd_command = MI_OFFLINE; 1982 (void) strcpy(mpdcmd.cmd_ifname, if_from->ip_pif->pi_ifname); 1983 1984 if ((if_to != NULL) && (if_to->ip_pif != NULL) && 1985 (if_to->ip_pif->pi_ifname != NULL)) { 1986 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline (%s)->(%s)\n", 1987 if_from->ip_pif->pi_ifname, if_to->ip_pif->pi_ifname); 1988 (void) strncpy(mpdcmd.cmd_movetoif, if_to->ip_pif->pi_ifname, 1989 sizeof (mpdcmd.cmd_movetoif)); 1990 mpdcmd.cmd_movetoif[sizeof (mpdcmd.cmd_movetoif) - 1] = '\0'; 1991 } else { 1992 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline (%s)->(any)\n", 1993 if_from->ip_pif->pi_ifname); 1994 (void) strcpy(mpdcmd.cmd_movetoif, ""); /* signifies any */ 1995 } 1996 mpdcmd.cmd_min_red = if_from->ip_ifred; 1997 1998 if (mpathd_send_cmd(&mpdcmd) < 0) { 1999 rcm_log_message(RCM_ERROR, 2000 _("IP: mpathd offline error: %s\n"), 2001 strerror(errno)); 2002 return (-1); 2003 } 2004 2005 rcm_log_message(RCM_TRACE1, "IP: ipmp offline success\n"); 2006 return (0); 2007 } 2008 2009 /* 2010 * ip_ipmp_undo_offline() - Undo prior offline of the interface. 2011 * This uses IPMPs "undo offline" feature. 2012 */ 2013 static int 2014 ip_ipmp_undo_offline(ip_cache_t *node) 2015 { 2016 mpathd_cmd_t mpdcmd; 2017 2018 mpdcmd.cmd_command = MI_UNDO_OFFLINE; 2019 (void) strcpy(mpdcmd.cmd_ifname, node->ip_pif->pi_ifname); 2020 2021 if (mpathd_send_cmd(&mpdcmd) < 0) { 2022 rcm_log_message(RCM_ERROR, 2023 _("IP: mpathd error: %s\n"), 2024 strerror(errno)); 2025 return (-1); 2026 } 2027 2028 rcm_log_message(RCM_TRACE1, "IP: ipmp undo offline success\n"); 2029 return (0); 2030 } 2031 2032 /* 2033 * getdlpi_style() - Determine the DLPI provider style of the interface 2034 */ 2035 static int 2036 getdlpi_style(char *ifname) 2037 { 2038 int local_fd; 2039 char devname[RCM_NET_RESOURCE_MAX]; 2040 2041 (void) snprintf(devname, sizeof (devname), "%s/%s", SLASH_DEV, ifname); 2042 2043 /* First try DLPI style 1 */ 2044 if ((local_fd = open(devname, O_RDWR)) != -1) { 2045 (void) close(local_fd); 2046 return (DL_STYLE1); 2047 } 2048 2049 return (DL_STYLE2); 2050 } 2051 2052 /* 2053 * get_ppa() - Determine the ppa for an interface, DLPI style 2 only 2054 */ 2055 static int 2056 get_ppa(char *rsrc) 2057 { 2058 int i; 2059 uint_t p = 0; 2060 unsigned int m = 1; 2061 2062 i = strlen(rsrc) - 1; 2063 while (i >= 0 && '0' <= rsrc[i] && rsrc[i] <= '9') { 2064 p += (rsrc[i] - '0')*m; 2065 m *= 10; 2066 i--; 2067 } 2068 if (m == 1) { 2069 return (-1); 2070 } 2071 return (VLAN_GET_PPA(p)); /* VLAN support */ 2072 } 2073 2074 /* 2075 * get_lun() - Determine the logical interface number 2076 */ 2077 static int 2078 get_lun(char *rsrc) 2079 { 2080 char resource[RCM_NET_RESOURCE_MAX]; 2081 char *cp; 2082 2083 (void) strcpy(resource, rsrc); 2084 2085 /* remove LIF component */ 2086 cp = strchr(resource, ':'); 2087 if (cp) { 2088 cp++; 2089 return (atoi(cp)); 2090 } 2091 2092 return (0); 2093 } 2094 2095 /* 2096 * get_physical_resource() - Determine the actual physical interface name. 2097 * Supports VLAN interfaces. 2098 * Caller must free the malloced space for the string. 2099 */ 2100 static char * 2101 get_physical_resource(char *rsrc) 2102 { 2103 char *resource; 2104 char *ifname; 2105 char *nic; 2106 int ppa; 2107 2108 resource = (char *)malloc(strlen(rsrc) + 1); 2109 if (resource == NULL) { 2110 rcm_log_message(RCM_ERROR, 2111 _("IP: malloc error(%s): %s\n"), strerror(errno), rsrc); 2112 return (NULL); 2113 } 2114 (void) strcpy(resource, rsrc); 2115 2116 /* remove LIF component if any */ 2117 nic = strchr(resource, ':'); 2118 if (nic) { 2119 *nic = 0; 2120 } 2121 2122 ppa = get_ppa(resource); 2123 2124 /* Determine device name */ 2125 nic = resource; 2126 while (nic++) { 2127 if (('0' <= *nic) && (*nic <= '9')) { 2128 *nic = 0; 2129 break; 2130 } 2131 } 2132 2133 ifname = (char *)malloc(RCM_NET_RESOURCE_MAX); 2134 if (ifname == NULL) { 2135 rcm_log_message(RCM_ERROR, 2136 _("IP: malloc error(%s): %s\n"), strerror(errno), rsrc); 2137 free(resource); 2138 return (NULL); 2139 } 2140 2141 if (ppa < 0) { 2142 /* This could be a network group */ 2143 (void) snprintf(ifname, RCM_NET_RESOURCE_MAX, "%s", resource); 2144 } else { 2145 (void) snprintf(ifname, RCM_NET_RESOURCE_MAX, "%s%d", 2146 resource, ppa); 2147 } 2148 2149 free(resource); 2150 return (ifname); 2151 } 2152 2153 /* 2154 * if_change_flags() - set/clear the flag specified for the physical interface 2155 * Call with cache_lock held 2156 */ 2157 static int 2158 if_change_flags(ip_pif_t *pif, uint64_t flags, boolean_t set) 2159 { 2160 int sock; 2161 struct lifreq lifr; 2162 ip_lif_t *lif; 2163 2164 if (!(flags & RCM_PIF_FLAGS)) { 2165 rcm_log_message(RCM_DEBUG, 2166 "IP: if_change_flags: Not a physical interface flag\n"); 2167 return (-1); 2168 } 2169 2170 /* IPv4 is ok, since we only manipulate physical interface flags */ 2171 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 2172 rcm_log_message(RCM_ERROR, 2173 _("IPv4 socket open: %s\n"), strerror(errno)); 2174 return (-1); 2175 } 2176 2177 /* 2178 * Get the current flags from the kernel, and set/clear the 2179 * desired phyint flags. 2180 */ 2181 (void) strncpy(lifr.lifr_name, pif->pi_ifname, sizeof (lifr.lifr_name)); 2182 lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 2183 if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 2184 rcm_log_message(RCM_DEBUG, 2185 "ioctl SIOCGLIFFLAGS: %s\n", strerror(errno)); 2186 (void) close(sock); 2187 return (-1); 2188 } 2189 if (set) 2190 lifr.lifr_flags |= flags; 2191 else 2192 lifr.lifr_flags &= ~flags; 2193 if (ioctl(sock, SIOCSLIFFLAGS, (char *)&lifr) < 0) { 2194 rcm_log_message(RCM_DEBUG, 2195 "ioctl SIOCSLIFFLAGS: %s\n", strerror(errno)); 2196 (void) close(sock); 2197 return (-1); 2198 } 2199 2200 (void) close(sock); 2201 2202 /* Keep cached flags consistent. */ 2203 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) { 2204 if (lif->li_ifnum == 0) { 2205 if (set) 2206 lif->li_ifflags |= flags; 2207 else 2208 lif->li_ifflags &= ~flags; 2209 } 2210 } 2211 2212 return (0); 2213 } 2214 2215 /* 2216 * if_get_flags() - Return the cached physical interface flags 2217 * Call with cache_lock held 2218 */ 2219 static uint64_t 2220 if_get_flags(ip_pif_t *pif) 2221 { 2222 ip_lif_t *lif; 2223 2224 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) { 2225 if (lif->li_ifnum == 0) { 2226 return (lif->li_ifflags & RCM_PIF_FLAGS); 2227 } 2228 } 2229 return (0); 2230 } 2231 2232 /* 2233 * mpathd_send_cmd() - Sends the command to in.mpathd. 2234 */ 2235 static int 2236 mpathd_send_cmd(mpathd_cmd_t *mpd) 2237 { 2238 mpathd_unoffline_t mpc; 2239 struct mpathd_response mpr; 2240 int i; 2241 int s; 2242 2243 rcm_log_message(RCM_TRACE1, "IP: mpathd_send_cmd \n"); 2244 2245 for (i = 0; i < MPATHD_MAX_RETRIES; i++) { 2246 s = connect_to_mpathd(AF_INET); 2247 if (s == -1) { 2248 s = connect_to_mpathd(AF_INET6); 2249 if (s == -1) { 2250 rcm_log_message(RCM_ERROR, 2251 _("IP: Cannot talk to mpathd\n")); 2252 return (-1); 2253 } 2254 } 2255 switch (mpd->cmd_command) { 2256 case MI_OFFLINE : 2257 rcm_log_message(RCM_TRACE1, "IP: MI_OFFLINE: " 2258 "(%s)->(%s) redundancy = %d\n", mpd->cmd_ifname, 2259 mpd->cmd_movetoif, mpd->cmd_min_red); 2260 2261 if (write(s, mpd, sizeof (mpathd_cmd_t)) != 2262 sizeof (mpathd_cmd_t)) { 2263 rcm_log_message(RCM_ERROR, 2264 _("IP: mpathd write: %s\n"), 2265 strerror(errno)); 2266 (void) close(s); 2267 return (-1); 2268 } 2269 break; 2270 2271 case MI_SETOINDEX : 2272 rcm_log_message(RCM_TRACE1, "IP: MI_SETOINDEX: " 2273 "(%s)->(%s) family = %d\n", mpd->from_lifname, 2274 mpd->to_pifname, mpd->addr_family); 2275 2276 if (write(s, mpd, sizeof (mpathd_cmd_t)) != 2277 sizeof (mpathd_cmd_t)) { 2278 rcm_log_message(RCM_ERROR, 2279 _("IP: mpathd write: %s\n"), 2280 strerror(errno)); 2281 (void) close(s); 2282 return (-1); 2283 } 2284 break; 2285 2286 case MI_UNDO_OFFLINE: 2287 /* mpathd checks for exact size of the message */ 2288 mpc.cmd_command = mpd->cmd_command; 2289 (void) strcpy(mpc.cmd_ifname, mpd->cmd_ifname); 2290 2291 rcm_log_message(RCM_TRACE1, "IP: MI_UNDO_OFFLINE: " 2292 "(%s)\n", mpd->cmd_ifname); 2293 2294 if (write(s, &mpc, sizeof (mpathd_unoffline_t)) != 2295 sizeof (mpathd_unoffline_t)) { 2296 rcm_log_message(RCM_ERROR, 2297 _("IP: mpathd write: %s\n"), 2298 strerror(errno)); 2299 (void) close(s); 2300 return (-1); 2301 } 2302 break; 2303 default : 2304 rcm_log_message(RCM_ERROR, 2305 _("IP: unsupported mpathd command\n")); 2306 (void) close(s); 2307 return (-1); 2308 } 2309 2310 bzero(&mpr, sizeof (struct mpathd_response)); 2311 /* Read the result from mpathd */ 2312 if (read(s, &mpr, sizeof (struct mpathd_response)) != 2313 sizeof (struct mpathd_response)) { 2314 rcm_log_message(RCM_ERROR, 2315 _("IP: mpathd read : %s\n"), strerror(errno)); 2316 (void) close(s); 2317 return (-1); 2318 } 2319 2320 (void) close(s); 2321 if (mpr.resp_mpathd_err == 0) { 2322 rcm_log_message(RCM_TRACE1, 2323 "IP: mpathd_send_cmd success\n"); 2324 return (0); /* Successful */ 2325 } 2326 2327 if (mpr.resp_mpathd_err == MPATHD_SYS_ERROR) { 2328 if (mpr.resp_sys_errno == EAGAIN) { 2329 (void) sleep(1); 2330 rcm_log_message(RCM_DEBUG, 2331 _("IP: mpathd retrying\n")); 2332 continue; /* Retry */ 2333 } 2334 errno = mpr.resp_sys_errno; 2335 rcm_log_message(RCM_WARNING, 2336 _("IP: mpathd_send_cmd error: %s\n"), 2337 strerror(errno)); 2338 } else if (mpr.resp_mpathd_err == MPATHD_MIN_RED_ERROR) { 2339 errno = EIO; 2340 rcm_log_message(RCM_ERROR, _("IP: in.mpathd(1M): " 2341 "Minimum redundancy not met\n")); 2342 } else { 2343 rcm_log_message(RCM_ERROR, 2344 _("IP: mpathd_send_cmd error\n")); 2345 } 2346 /* retry */ 2347 } 2348 2349 rcm_log_message(RCM_ERROR, 2350 _("IP: mpathd_send_cmd failed %d retries\n"), MPATHD_MAX_RETRIES); 2351 return (-1); 2352 } 2353 2354 /* 2355 * Returns -1 on failure. Returns the socket file descriptor on 2356 * success. 2357 */ 2358 static int 2359 connect_to_mpathd(int family) 2360 { 2361 int s; 2362 struct sockaddr_storage ss; 2363 struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 2364 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 2365 struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; 2366 int addrlen; 2367 int ret; 2368 int on; 2369 2370 rcm_log_message(RCM_TRACE1, "IP: connect_to_mpathd\n"); 2371 2372 s = socket(family, SOCK_STREAM, 0); 2373 if (s < 0) { 2374 rcm_log_message(RCM_ERROR, 2375 _("IP: mpathd socket: %s\n"), strerror(errno)); 2376 return (-1); 2377 } 2378 bzero((char *)&ss, sizeof (ss)); 2379 ss.ss_family = family; 2380 /* 2381 * Need to bind to a privelged port. For non-root, this 2382 * will fail. in.mpathd verifies that only commands coming 2383 * from priveleged ports succeed so that the ordinary user 2384 * can't issue offline commands. 2385 */ 2386 on = 1; 2387 if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on, 2388 sizeof (on)) < 0) { 2389 rcm_log_message(RCM_ERROR, 2390 _("IP: mpathd setsockopt: TCP_ANONPRIVBIND: %s\n"), 2391 strerror(errno)); 2392 return (-1); 2393 } 2394 switch (family) { 2395 case AF_INET: 2396 sin->sin_port = 0; 2397 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 2398 addrlen = sizeof (struct sockaddr_in); 2399 break; 2400 case AF_INET6: 2401 sin6->sin6_port = 0; 2402 sin6->sin6_addr = loopback_addr; 2403 addrlen = sizeof (struct sockaddr_in6); 2404 break; 2405 } 2406 ret = bind(s, (struct sockaddr *)&ss, addrlen); 2407 if (ret != 0) { 2408 rcm_log_message(RCM_ERROR, 2409 _("IP: mpathd bind: %s\n"), strerror(errno)); 2410 return (-1); 2411 } 2412 switch (family) { 2413 case AF_INET: 2414 sin->sin_port = htons(MPATHD_PORT); 2415 break; 2416 case AF_INET6: 2417 sin6->sin6_port = htons(MPATHD_PORT); 2418 break; 2419 } 2420 ret = connect(s, (struct sockaddr *)&ss, addrlen); 2421 if (ret != 0) { 2422 if (errno == ECONNREFUSED) { 2423 /* in.mpathd is not running, start it */ 2424 if (rcm_exec_cmd(MPATHD_PATH) == -1) { 2425 rcm_log_message(RCM_ERROR, 2426 _("IP: mpathd exec: %s\n"), 2427 strerror(errno)); 2428 return (-1); 2429 } 2430 ret = connect(s, (struct sockaddr *)&ss, addrlen); 2431 } 2432 if (ret != 0) { 2433 rcm_log_message(RCM_ERROR, 2434 _("IP: mpathd connect: %s\n"), strerror(errno)); 2435 return (-1); 2436 } 2437 } 2438 on = 0; 2439 if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on, 2440 sizeof (on)) < 0) { 2441 rcm_log_message(RCM_ERROR, 2442 _("IP: mpathd setsockopt TCP_ANONPRIVBIND: %s\n"), 2443 strerror(errno)); 2444 return (-1); 2445 } 2446 2447 rcm_log_message(RCM_TRACE1, "IP: connect_to_mpathd success\n"); 2448 2449 return (s); 2450 } 2451 2452 /* 2453 * modop() - Remove/insert a module 2454 */ 2455 static int 2456 modop(char *name, char *arg, int pos, char op) 2457 { 2458 char syscmd[LIFNAMSIZ+MAXPATHLEN]; /* must be big enough */ 2459 2460 rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name); 2461 2462 /* Nothing to do with "ip", "arp" */ 2463 if ((arg == NULL) || (strcmp(arg, "") == 0) || 2464 STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) { 2465 rcm_log_message(RCM_TRACE1, "IP: modop success\n"); 2466 return (0); 2467 } 2468 2469 if (op == MOD_CHECK) { 2470 /* 2471 * No known good modules (yet) apart from ip and arp 2472 * which are handled above 2473 */ 2474 return (-1); 2475 } 2476 2477 if (op == MOD_REMOVE) { 2478 (void) snprintf(syscmd, sizeof (syscmd), 2479 "%s %s modremove %s@%d\n", USR_SBIN_IFCONFIG, name, arg, 2480 pos); 2481 } else if (op == MOD_INSERT) { 2482 (void) snprintf(syscmd, sizeof (syscmd), 2483 "%s %s modinsert %s@%d\n", USR_SBIN_IFCONFIG, name, arg, 2484 pos); 2485 } else { 2486 rcm_log_message(RCM_ERROR, 2487 _("IP: modop(%s): unknown operation\n"), name); 2488 return (-1); 2489 } 2490 2491 rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd); 2492 if (rcm_exec_cmd(syscmd) == -1) { 2493 rcm_log_message(RCM_ERROR, 2494 _("IP: modop(%s): %s\n"), name, strerror(errno)); 2495 return (-1); 2496 } 2497 2498 rcm_log_message(RCM_TRACE1, "IP: modop success\n"); 2499 return (0); 2500 } 2501 2502 /* 2503 * get_modlist() - return a list of pushed mid-stream modules 2504 * Required memory is malloced to construct the list, 2505 * Caller must free this memory list 2506 * Call with cache_lock held 2507 */ 2508 static int 2509 get_modlist(char *name, ip_lif_t *lif) 2510 { 2511 int udp_fd; 2512 int fd; 2513 int i; 2514 int num_mods; 2515 struct lifreq lifr; 2516 struct str_list strlist; 2517 2518 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name); 2519 2520 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2521 lifr.lifr_flags = lif->li_ifflags; 2522 if (ip_domux2fd(&udp_fd, &fd, &lifr) < 0) { 2523 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name); 2524 return (-1); 2525 } 2526 2527 if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) { 2528 rcm_log_message(RCM_ERROR, 2529 _("IP: get_modlist(%s): I_LIST(%s) \n"), 2530 name, strerror(errno)); 2531 (void) ip_plink(udp_fd, fd, &lifr); 2532 return (-1); 2533 } 2534 2535 strlist.sl_nmods = num_mods; 2536 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods); 2537 2538 if (strlist.sl_modlist == NULL) { 2539 rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"), 2540 name, strerror(errno)); 2541 (void) ip_plink(udp_fd, fd, &lifr); 2542 return (-1); 2543 } 2544 2545 if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) { 2546 rcm_log_message(RCM_ERROR, 2547 _("IP: get_modlist(%s): I_LIST error: %s\n"), 2548 name, strerror(errno)); 2549 (void) ip_plink(udp_fd, fd, &lifr); 2550 return (-1); 2551 } 2552 2553 for (i = 0; i < strlist.sl_nmods; i++) { 2554 lif->li_modules[i] = 2555 malloc(strlen(strlist.sl_modlist[i].l_name)+1); 2556 if (lif->li_modules[i] == NULL) { 2557 rcm_log_message(RCM_ERROR, 2558 _("IP: get_modlist(%s): %s\n"), 2559 name, strerror(errno)); 2560 (void) ip_plink(udp_fd, fd, &lifr); 2561 return (-1); 2562 } 2563 (void) strcpy(lif->li_modules[i], strlist.sl_modlist[i].l_name); 2564 } 2565 2566 lif->li_modcnt = strlist.sl_nmods; 2567 free(strlist.sl_modlist); 2568 2569 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name); 2570 return (ip_plink(udp_fd, fd, &lifr)); 2571 } 2572 2573 /* 2574 * ip_domux2fd() - Helper function for mod*() functions 2575 * Stolen from ifconfig.c 2576 */ 2577 static int 2578 ip_domux2fd(int *udp_fd, int *fd, struct lifreq *lifr) 2579 { 2580 int ip_fd; 2581 char *udp_dev_name; 2582 char *ip_dev_name; 2583 2584 if (lifr->lifr_flags & IFF_IPV6) { 2585 udp_dev_name = UDP6_DEV_NAME; 2586 ip_dev_name = IP6_DEV_NAME; 2587 } else { 2588 udp_dev_name = UDP_DEV_NAME; 2589 ip_dev_name = IP_DEV_NAME; 2590 } 2591 2592 if ((ip_fd = open(ip_dev_name, O_RDWR)) < 0) { 2593 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"), 2594 ip_dev_name, strerror(errno)); 2595 return (-1); 2596 } 2597 if ((*udp_fd = open(udp_dev_name, O_RDWR)) < 0) { 2598 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"), 2599 udp_dev_name, strerror(errno)); 2600 (void) close(ip_fd); 2601 return (-1); 2602 } 2603 if (ioctl(ip_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) { 2604 rcm_log_message(RCM_ERROR, 2605 _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"), 2606 ip_dev_name, strerror(errno)); 2607 (void) close(*udp_fd); 2608 (void) close(ip_fd); 2609 return (-1); 2610 } 2611 2612 rcm_log_message(RCM_TRACE2, 2613 "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n", 2614 lifr->lifr_arp_muxid, lifr->lifr_ip_muxid); 2615 2616 if ((*fd = ioctl(*udp_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) { 2617 rcm_log_message(RCM_ERROR, 2618 _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"), 2619 udp_dev_name, strerror(errno)); 2620 (void) close(*udp_fd); 2621 (void) close(ip_fd); 2622 return (-1); 2623 } 2624 if (ioctl(*udp_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) { 2625 rcm_log_message(RCM_ERROR, 2626 _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"), 2627 udp_dev_name, strerror(errno)); 2628 (void) close(*udp_fd); 2629 (void) close(ip_fd); 2630 return (-1); 2631 } 2632 2633 /* Note: udp_fd is closed in ip_plink below */ 2634 (void) close(ip_fd); 2635 return (0); 2636 } 2637 2638 /* 2639 * ip_plink() - Helper function for mod*() functions. 2640 * Stolen from ifconfig.c 2641 */ 2642 static int 2643 ip_plink(int udp_fd, int fd, struct lifreq *lifr) 2644 { 2645 int mux_id; 2646 2647 if ((mux_id = ioctl(udp_fd, I_PLINK, fd)) < 0) { 2648 rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"), 2649 UDP_DEV_NAME, strerror(errno)); 2650 (void) close(udp_fd); 2651 (void) close(fd); 2652 return (-1); 2653 } 2654 2655 lifr->lifr_ip_muxid = mux_id; 2656 if (ioctl(udp_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) { 2657 rcm_log_message(RCM_ERROR, 2658 _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"), 2659 UDP_DEV_NAME, strerror(errno)); 2660 (void) close(udp_fd); 2661 (void) close(fd); 2662 return (-1); 2663 } 2664 2665 (void) close(udp_fd); 2666 (void) close(fd); 2667 return (0); 2668 } 2669 2670 /* 2671 * ip_onlinelist() 2672 * 2673 * Notify online to IP address consumers. 2674 */ 2675 static int 2676 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags, 2677 rcm_info_t **depend_info) 2678 { 2679 char **addrlist; 2680 int ret = RCM_SUCCESS; 2681 2682 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n"); 2683 2684 addrlist = ip_get_addrlist(node); 2685 if (addrlist == NULL || addrlist[0] == NULL) { 2686 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n"); 2687 ip_free_addrlist(addrlist); 2688 return (ret); 2689 } 2690 2691 ret = rcm_notify_online_list(hd, addrlist, 0, depend_info); 2692 2693 ip_free_addrlist(addrlist); 2694 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n"); 2695 return (ret); 2696 } 2697 2698 /* 2699 * ip_offlinelist() 2700 * 2701 * Offline IP address consumers. 2702 */ 2703 static int 2704 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags, 2705 rcm_info_t **depend_info) 2706 { 2707 char **addrlist; 2708 int ret = RCM_SUCCESS; 2709 2710 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n"); 2711 2712 addrlist = ip_get_addrlist(node); 2713 if (addrlist == NULL || addrlist[0] == NULL) { 2714 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n"); 2715 ip_free_addrlist(addrlist); 2716 return (RCM_SUCCESS); 2717 } 2718 2719 if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info)) 2720 != RCM_SUCCESS) { 2721 if (ret == RCM_FAILURE) 2722 (void) rcm_notify_online_list(hd, addrlist, 0, NULL); 2723 2724 ret = RCM_FAILURE; 2725 } 2726 2727 ip_free_addrlist(addrlist); 2728 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n"); 2729 return (ret); 2730 } 2731 2732 /* 2733 * ip_get_addrlist() - Compile list of IP addresses hosted on this NIC (node) 2734 * This routine malloc() required memeory for the list 2735 * Returns list on success, NULL if failed 2736 * Call with cache_lock held. 2737 */ 2738 static char ** 2739 ip_get_addrlist(ip_cache_t *node) 2740 { 2741 ip_lif_t *lif; 2742 char **addrlist = NULL; 2743 int numifs; 2744 char addrstr[INET6_ADDRSTRLEN]; 2745 void *addr; 2746 int af; 2747 int i; 2748 2749 rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n", 2750 node->ip_resource); 2751 2752 numifs = 0; 2753 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) { 2754 numifs++; 2755 } 2756 2757 /* 2758 * Allocate space for resource names list; add 1 and use calloc() 2759 * so that the list is NULL-terminated. 2760 */ 2761 if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) { 2762 rcm_log_message(RCM_ERROR, 2763 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"), 2764 node->ip_resource, strerror(errno)); 2765 return (NULL); 2766 } 2767 2768 for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL; 2769 lif = lif->li_next, i++) { 2770 2771 af = lif->li_addr.family; 2772 if (af == AF_INET6) { 2773 addr = &lif->li_addr.ip6.sin6_addr; 2774 } else if (af == AF_INET) { 2775 addr = &lif->li_addr.ip4.sin_addr; 2776 } else { 2777 rcm_log_message(RCM_DEBUG, 2778 "IP: unknown addr family %d, assuming AF_INET\n", 2779 af); 2780 af = AF_INET; 2781 addr = &lif->li_addr.ip4.sin_addr; 2782 } 2783 if (inet_ntop(af, addr, addrstr, INET6_ADDRSTRLEN) == NULL) { 2784 rcm_log_message(RCM_ERROR, 2785 _("IP: inet_ntop: %s\n"), strerror(errno)); 2786 ip_free_addrlist(addrlist); 2787 return (NULL); 2788 } 2789 2790 if ((addrlist[i] = malloc(strlen(addrstr) + RCM_SIZE_SUNW_IP)) 2791 == NULL) { 2792 rcm_log_message(RCM_ERROR, 2793 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"), 2794 node->ip_resource, strerror(errno)); 2795 ip_free_addrlist(addrlist); 2796 return (NULL); 2797 } 2798 (void) strcpy(addrlist[i], RCM_STR_SUNW_IP); /* SUNW_ip/ */ 2799 (void) strcat(addrlist[i], addrstr); /* SUNW_ip/<address> */ 2800 2801 rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]); 2802 } 2803 2804 rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n", 2805 node->ip_resource); 2806 2807 return (addrlist); 2808 } 2809 2810 static void 2811 ip_free_addrlist(char **addrlist) 2812 { 2813 int i; 2814 2815 if (addrlist == NULL) 2816 return; 2817 2818 for (i = 0; addrlist[i] != NULL; i++) 2819 free(addrlist[i]); 2820 free(addrlist); 2821 } 2822 2823 /* 2824 * ip_consumer_notify() - Notify consumers of IP addresses coming back online. 2825 */ 2826 2827 static void 2828 ip_consumer_notify(rcm_handle_t *hd, char *ifinst, char **errorp, uint_t flags, 2829 rcm_info_t **depend_info) 2830 { 2831 char ifname[LIFNAMSIZ + 1]; 2832 char cached_name[RCM_NET_RESOURCE_MAX]; 2833 ip_cache_t *node; 2834 char *cp; 2835 2836 rcm_log_message(RCM_TRACE1, "IP: ip_consumer_notify(%s)\n", ifinst); 2837 2838 if (ifinst == NULL) 2839 return; 2840 2841 (void) memcpy(&ifname, ifinst, sizeof (ifname)); 2842 ifname[sizeof (ifname) - 1] = '\0'; 2843 2844 /* remove LIF component */ 2845 cp = strchr(ifname, ':'); 2846 if (cp) { 2847 *cp = 0; 2848 } 2849 2850 /* Check for the interface in the cache */ 2851 (void) snprintf(cached_name, sizeof (cached_name), "%s/%s", 2852 RCM_NET_PREFIX, ifname); 2853 2854 (void) mutex_lock(&cache_lock); 2855 if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) { 2856 rcm_log_message(RCM_TRACE1, "IP: Skipping interface(%s) \n", 2857 ifname); 2858 (void) mutex_unlock(&cache_lock); 2859 return; 2860 } 2861 /* 2862 * Inform anonymous consumers about IP addresses being 2863 * onlined 2864 */ 2865 (void) ip_onlinelist(hd, node, errorp, flags, depend_info); 2866 2867 (void) mutex_unlock(&cache_lock); 2868 2869 rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n"); 2870 return; 2871 2872 } 2873 /* 2874 * process_nvlist() - Determine network interfaces on a new attach by 2875 * processing the nvlist 2876 */ 2877 /*ARGSUSED*/ 2878 static int 2879 process_nvlist(nvlist_t *nvl) 2880 { 2881 nvpair_t *nvp = NULL; 2882 char *driver_name; 2883 char *devfs_path; 2884 int32_t instance; 2885 char *minor_byte_array; /* packed nvlist of minor_data */ 2886 uint_t nminor; /* # of minor nodes */ 2887 struct devfs_minor_data *mdata; 2888 nvlist_t *mnvl; 2889 nvpair_t *mnvp = NULL; 2890 2891 rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n"); 2892 2893 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 2894 /* Get driver name */ 2895 if (STREQ(nvpair_name(nvp), RCM_NV_DRIVER_NAME)) { 2896 if (nvpair_value_string(nvp, &driver_name) != 0) { 2897 rcm_log_message(RCM_WARNING, 2898 _("IP: cannot get driver name\n")); 2899 return (-1); 2900 } 2901 } 2902 /* Get instance */ 2903 if (STREQ(nvpair_name(nvp), RCM_NV_INSTANCE)) { 2904 if (nvpair_value_int32(nvp, &instance) != 0) { 2905 rcm_log_message(RCM_WARNING, 2906 _("IP: cannot get device instance\n")); 2907 return (-1); 2908 } 2909 } 2910 /* Get devfs_path */ 2911 if (STREQ(nvpair_name(nvp), RCM_NV_DEVFS_PATH)) { 2912 if (nvpair_value_string(nvp, &devfs_path) != 0) { 2913 rcm_log_message(RCM_WARNING, 2914 _("IP: cannot get device path\n")); 2915 return (-1); 2916 } 2917 } 2918 /* Get minor data */ 2919 if (STREQ(nvpair_name(nvp), RCM_NV_MINOR_DATA)) { 2920 if (nvpair_value_byte_array(nvp, 2921 (uchar_t **)&minor_byte_array, &nminor) != 0) { 2922 rcm_log_message(RCM_WARNING, 2923 _("IP: cannot get device minor data\n")); 2924 return (-1); 2925 } 2926 if (nvlist_unpack(minor_byte_array, 2927 nminor, &mnvl, 0) != 0) { 2928 rcm_log_message(RCM_WARNING, 2929 _("IP: cannot get minor node data\n")); 2930 return (-1); 2931 } 2932 mdata = (struct devfs_minor_data *)calloc(1, 2933 sizeof (struct devfs_minor_data)); 2934 if (mdata == NULL) { 2935 rcm_log_message(RCM_WARNING, 2936 _("IP: calloc error(%s)\n"), 2937 strerror(errno)); 2938 nvlist_free(mnvl); 2939 return (-1); 2940 } 2941 /* Enumerate minor node data */ 2942 while ((mnvp = nvlist_next_nvpair(mnvl, mnvp)) != 2943 NULL) { 2944 /* Get minor type */ 2945 if (STREQ(nvpair_name(mnvp), 2946 RCM_NV_MINOR_TYPE)) { 2947 if (nvpair_value_int32(mnvp, 2948 &mdata->minor_type) != 0) { 2949 rcm_log_message(RCM_WARNING, 2950 _("IP: cannot get minor " 2951 "type \n")); 2952 nvlist_free(mnvl); 2953 return (-1); 2954 } 2955 } 2956 /* Get minor name */ 2957 if (STREQ(nvpair_name(mnvp), 2958 RCM_NV_MINOR_NAME)) { 2959 if (nvpair_value_string(mnvp, 2960 &mdata->minor_name) != 0) { 2961 rcm_log_message(RCM_WARNING, 2962 _("IP: cannot get minor " 2963 "name \n")); 2964 nvlist_free(mnvl); 2965 return (-1); 2966 } 2967 } 2968 /* Get minor node type */ 2969 if (STREQ(nvpair_name(mnvp), 2970 RCM_NV_MINOR_NODE_TYPE)) { 2971 if (nvpair_value_string(mnvp, 2972 &mdata->minor_node_type) != 0) { 2973 rcm_log_message(RCM_WARNING, 2974 _("IP: cannot get minor " 2975 "node type \n")); 2976 nvlist_free(mnvl); 2977 return (-1); 2978 } 2979 } 2980 } 2981 (void) process_minor(devfs_path, driver_name, instance, 2982 mdata); 2983 nvlist_free(mnvl); 2984 } 2985 } 2986 2987 rcm_log_message(RCM_TRACE1, "IP: process_nvlist success\n"); 2988 return (0); 2989 } 2990 2991 static void 2992 process_minor(char *devfs_path, char *name, int instance, 2993 struct devfs_minor_data *mdata) 2994 { 2995 struct net_interface *nip; 2996 struct ni_list *nilp; 2997 struct ni_list *p; 2998 struct ni_list **pp; 2999 char *cname; 3000 size_t cnamelen; 3001 3002 rcm_log_message(RCM_TRACE1, "IP: process_minor\n"); 3003 3004 if ((mdata->minor_node_type != NULL) && 3005 !STREQ(mdata->minor_node_type, PROP_NV_DDI_NETWORK)) { 3006 /* Process network devices only */ 3007 return; 3008 } 3009 3010 rcm_log_message(RCM_TRACE1, "IP: Examining %s (%s)\n", 3011 devfs_path, mdata->minor_name); 3012 3013 /* Sanity check, instances > 999 are illegal */ 3014 if (instance > 999) { 3015 errno = EINVAL; 3016 rcm_log_message(RCM_ERROR, _("IP: invalid instance %d(%s)\n"), 3017 instance, strerror(errno)); 3018 return; 3019 } 3020 3021 /* Now, let's add the node to the interface list */ 3022 if ((nip = malloc(sizeof (struct net_interface))) == NULL) { 3023 rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"), 3024 strerror(errno)); 3025 return; 3026 } 3027 (void) memset(nip, 0, sizeof (struct net_interface)); 3028 3029 cnamelen = strlen(name) + 1; 3030 /* Set NIC type */ 3031 if ((nip->type = (char *)malloc(cnamelen)) == NULL) { 3032 free(nip); 3033 rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"), 3034 strerror(errno)); 3035 return; 3036 } 3037 (void) memcpy(nip->type, name, cnamelen); 3038 3039 cnamelen += 3; 3040 if ((cname = (char *)malloc(cnamelen)) == NULL) { 3041 free(nip->type); 3042 free(nip); 3043 rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"), 3044 strerror(errno)); 3045 return; 3046 } 3047 (void) snprintf(cname, cnamelen, "%s%d", name, instance); 3048 3049 rcm_log_message(RCM_TRACE1, "IP: Found SUNW_network/%s%d\n", name, 3050 instance); 3051 3052 /* Set NIC name */ 3053 if ((nip->name = strdup(cname)) == NULL) { 3054 free(nip->type); 3055 free(nip); 3056 free(cname); 3057 rcm_log_message(RCM_ERROR, _("IP: strdup failure(%s)\n"), 3058 strerror(errno)); 3059 return; 3060 } 3061 free(cname); 3062 3063 /* Add new interface to the list */ 3064 (void) mutex_lock(&nil_lock); 3065 for (pp = &nil_head; (p = *pp) != NULL; pp = &(p->next)) { 3066 cname = p->nifp->name; 3067 if (strcmp(cname, nip->name) == 0) 3068 break; 3069 } 3070 3071 if (p != NULL) { 3072 (void) mutex_unlock(&nil_lock); 3073 free(nip->name); 3074 free(nip->type); 3075 free(nip); 3076 rcm_log_message(RCM_TRACE1, "IP: secondary node - ignoring\n"); 3077 return; 3078 } 3079 3080 if ((nilp = malloc(sizeof (struct ni_list))) == NULL) { 3081 (void) mutex_unlock(&nil_lock); 3082 free(nip->name); 3083 free(nip->type); 3084 free(nip); 3085 rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"), 3086 strerror(errno)); 3087 return; 3088 } 3089 3090 nilp->nifp = nip; 3091 nilp->next = NULL; 3092 *pp = nilp; 3093 3094 num_ni++; /* Increment interface count */ 3095 3096 (void) mutex_unlock(&nil_lock); 3097 rcm_log_message(RCM_TRACE1, "IP: added new node\n"); 3098 } 3099 3100 /* 3101 * if_configure() - Configure a physical interface after attach 3102 */ 3103 static int 3104 if_configure(char *ifinst) 3105 { 3106 char cfgfile[MAXPATHLEN]; 3107 char ifname[LIFNAMSIZ + 1]; 3108 char cached_name[RCM_NET_RESOURCE_MAX]; 3109 struct stat statbuf; 3110 ip_cache_t *node; 3111 char *cp; 3112 int af = 0; 3113 int ipmp = 0; 3114 3115 if (ifinst == NULL) 3116 return (0); 3117 3118 rcm_log_message(RCM_TRACE1, "IP: if_configure(%s)\n", ifinst); 3119 3120 /* 3121 * Check if the interface is already configured 3122 */ 3123 3124 (void) memcpy(&ifname, ifinst, sizeof (ifname)); 3125 ifname[sizeof (ifname) - 1] = '\0'; 3126 3127 /* remove LIF component */ 3128 cp = strchr(ifname, ':'); 3129 if (cp) { 3130 *cp = 0; 3131 } 3132 3133 /* Check for the interface in the cache */ 3134 (void) snprintf(cached_name, sizeof (cached_name), "%s/%s", 3135 RCM_NET_PREFIX, ifname); 3136 3137 /* Check if the interface is new or was previously offlined */ 3138 (void) mutex_lock(&cache_lock); 3139 if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) && 3140 (!(node->ip_cachestate & CACHE_IF_OFFLINED))) { 3141 rcm_log_message(RCM_TRACE1, 3142 "IP: Skipping configured interface(%s) \n", ifname); 3143 (void) mutex_unlock(&cache_lock); 3144 return (0); 3145 } 3146 (void) mutex_unlock(&cache_lock); 3147 3148 /* Scan IPv4 configuration first */ 3149 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4, ifinst); 3150 cfgfile[MAXPATHLEN - 1] = '\0'; 3151 3152 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile); 3153 if (stat(cfgfile, &statbuf) == 0) { 3154 af |= CONFIG_AF_INET; 3155 if (isgrouped(cfgfile)) { 3156 ipmp++; 3157 } 3158 } 3159 3160 /* Scan IPv6 configuration details */ 3161 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV6, ifinst); 3162 cfgfile[MAXPATHLEN - 1] = '\0'; 3163 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile); 3164 if (stat(cfgfile, &statbuf) == 0) { 3165 af |= CONFIG_AF_INET6; 3166 if ((ipmp == 0) && isgrouped(cfgfile)) { 3167 ipmp++; 3168 } 3169 } 3170 3171 if (af & CONFIG_AF_INET) { 3172 if (if_ipmp_config(ifinst, CONFIG_AF_INET, ipmp) == -1) { 3173 rcm_log_message(RCM_ERROR, 3174 _("IP: IPv4 Post-attach failed (%s)\n"), ifinst); 3175 return (-1); 3176 } 3177 } 3178 3179 if (af & CONFIG_AF_INET6) { 3180 if (if_ipmp_config(ifinst, CONFIG_AF_INET6, ipmp) == -1) { 3181 rcm_log_message(RCM_ERROR, 3182 _("IP: IPv6 Post-attach failed(%s)\n"), ifinst); 3183 return (-1); 3184 } 3185 } 3186 3187 rcm_log_message(RCM_TRACE1, "IP: if_configure(%s) success\n", ifinst); 3188 3189 return (0); 3190 3191 } 3192 3193 /* 3194 * isgrouped() - Scans the given config file to see if this is a grouped 3195 * interface 3196 * Returns non-zero if true; 0 if false 3197 */ 3198 static int 3199 isgrouped(char *cfgfile) 3200 { 3201 FILE *fp; 3202 struct stat statb; 3203 char *buf = NULL; 3204 char *tokens[MAXARGS]; /* token pointers */ 3205 char tspace[MAXLINE]; /* token space */ 3206 int ntok; 3207 int group = 0; 3208 3209 if (cfgfile == NULL) 3210 return (0); 3211 3212 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile); 3213 3214 if (stat(cfgfile, &statb) != 0) { 3215 rcm_log_message(RCM_TRACE1, 3216 _("IP: No config file(%s)\n"), cfgfile); 3217 return (0); 3218 } 3219 3220 /* 3221 * We also ignore single-byte config files because the file should 3222 * always be newline-terminated, so we know there's nothing of 3223 * interest. Further, a single-byte file would cause the fgets() loop 3224 * below to spin forever. 3225 */ 3226 if (statb.st_size <= 1) { 3227 rcm_log_message(RCM_TRACE1, 3228 _("IP: Empty config file(%s)\n"), cfgfile); 3229 return (0); 3230 } 3231 3232 if ((fp = fopen(cfgfile, "r")) == NULL) { 3233 rcm_log_message(RCM_ERROR, 3234 _("IP: Cannot open configuration file(%s): %s\n"), cfgfile, 3235 strerror(errno)); 3236 return (0); 3237 } 3238 3239 if ((buf = calloc(1, statb.st_size)) == NULL) { 3240 rcm_log_message(RCM_ERROR, 3241 _("IP: calloc failure(%s): %s\n"), cfgfile, 3242 strerror(errno)); 3243 (void) fclose(fp); 3244 return (0); 3245 } 3246 3247 while (fgets(buf, statb.st_size, fp) != NULL) { 3248 if (*buf == '\0') 3249 continue; 3250 3251 tokenize(buf, tokens, tspace, &ntok); 3252 while (ntok) { 3253 if (STREQ("group", tokens[ntok - 1])) { 3254 if (tokens[ntok] != NULL) { 3255 group++; 3256 } 3257 } 3258 ntok--; 3259 } 3260 } 3261 3262 free(buf); 3263 3264 (void) fclose(fp); 3265 3266 if (group <= 0) { 3267 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s) non-grouped\n", 3268 cfgfile); 3269 return (0); 3270 } else { 3271 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s) grouped\n", 3272 cfgfile); 3273 return (1); 3274 } 3275 } 3276 3277 3278 /* 3279 * if_ipmp_config() - Configure an interface instance as specified by the 3280 * address family af and if it is grouped (ipmp). 3281 */ 3282 static int 3283 if_ipmp_config(char *ifinst, int af, int ipmp) 3284 { 3285 char cfgfile[MAXPATHLEN]; /* configuration file */ 3286 FILE *fp; 3287 struct stat statb; 3288 char *buf; 3289 char *tokens[MAXARGS]; /* list of config attributes */ 3290 char tspace[MAXLINE]; /* token space */ 3291 char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1]; 3292 char grpcmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1]; 3293 char fstr[8]; /* address family string inet or inet6 */ 3294 int nofailover = 0; 3295 int newattach = 0; 3296 int cmdvalid = 0; 3297 int ntok; 3298 int n; 3299 int stdif = 0; 3300 3301 if (ifinst == NULL) 3302 return (0); 3303 3304 rcm_log_message(RCM_TRACE1, "IP: if_ipmp_config(%s) ipmp = %d\n", 3305 ifinst, ipmp); 3306 3307 if (af & CONFIG_AF_INET) { 3308 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4, 3309 ifinst); 3310 (void) strcpy(fstr, "inet"); 3311 } else if (af & CONFIG_AF_INET6) { 3312 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV6, 3313 ifinst); 3314 (void) strcpy(fstr, "inet6"); 3315 } else { 3316 return (0); /* nothing to do */ 3317 } 3318 3319 cfgfile[MAXPATHLEN - 1] = '\0'; 3320 grpcmd[0] = '\0'; 3321 3322 if (stat(cfgfile, &statb) != 0) { 3323 rcm_log_message(RCM_TRACE1, 3324 _("IP: No config file(%s)\n"), ifinst); 3325 return (0); 3326 } 3327 3328 /* Config file exists, plumb in the physical interface */ 3329 if (af & CONFIG_AF_INET6) { 3330 if (if_getcount(AF_INET6) == 0) { 3331 /* 3332 * Configure software loopback driver if this is the 3333 * first IPv6 interface plumbed 3334 */ 3335 newattach++; 3336 (void) snprintf(syscmd, sizeof (syscmd), 3337 "%s lo0 %s plumb ::1 up", USR_SBIN_IFCONFIG, fstr); 3338 if (rcm_exec_cmd(syscmd) != 0) { 3339 rcm_log_message(RCM_ERROR, 3340 _("IP: Cannot plumb (%s) %s\n"), 3341 ifinst, strerror(errno)); 3342 return (-1); 3343 } 3344 } 3345 (void) snprintf(syscmd, sizeof (syscmd), "%s %s %s plumb up", 3346 USR_SBIN_IFCONFIG, ifinst, fstr); 3347 } else { 3348 (void) snprintf(syscmd, sizeof (syscmd), "%s %s %s plumb ", 3349 USR_SBIN_IFCONFIG, ifinst, fstr); 3350 if (if_getcount(AF_INET) == 0) { 3351 newattach++; 3352 } 3353 } 3354 rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd); 3355 3356 if (rcm_exec_cmd(syscmd) != 0) { 3357 rcm_log_message(RCM_ERROR, 3358 _("IP: Cannot plumb (%s) %s\n"), ifinst, strerror(errno)); 3359 return (-1); 3360 } 3361 3362 /* Check if config file is empty, if so, nothing else to do */ 3363 if (statb.st_size == 0) { 3364 rcm_log_message(RCM_TRACE1, 3365 _("IP: Zero size config file(%s)\n"), ifinst); 3366 return (0); 3367 } 3368 3369 if ((fp = fopen(cfgfile, "r")) == NULL) { 3370 rcm_log_message(RCM_ERROR, 3371 _("IP: Open error(%s): %s\n"), cfgfile, strerror(errno)); 3372 return (-1); 3373 } 3374 3375 if ((buf = calloc(1, statb.st_size)) == NULL) { 3376 rcm_log_message(RCM_ERROR, 3377 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno)); 3378 (void) fclose(fp); 3379 return (-1); 3380 } 3381 3382 /* a single line with one token implies a classical if */ 3383 if (fgets(buf, statb.st_size, fp) != NULL) { 3384 tokenize(buf, tokens, tspace, &ntok); 3385 if (ntok == 1) { 3386 rcm_log_message(RCM_TRACE1, "IP: Standard interface\n"); 3387 stdif++; 3388 } 3389 } 3390 if (fseek(fp, 0L, SEEK_SET) == -1) { 3391 rcm_log_message(RCM_ERROR, _("IP: fseek: %s\n"), 3392 strerror(errno)); 3393 return (-1); 3394 } 3395 3396 /* 3397 * Process the config command 3398 * This loop also handles multiple logical interfaces that may 3399 * be configured on a single line 3400 */ 3401 while (fgets(buf, statb.st_size, fp) != NULL) { 3402 nofailover = 0; 3403 cmdvalid = 0; 3404 3405 if (*buf == '\0') 3406 continue; 3407 3408 tokenize(buf, tokens, tspace, &ntok); 3409 if (ntok <= 0) 3410 continue; 3411 3412 /* Reset the config command */ 3413 (void) snprintf(syscmd, sizeof (syscmd), "%s %s %s ", 3414 USR_SBIN_IFCONFIG, ifinst, fstr); 3415 3416 /* No parsing if this is first interface of its kind */ 3417 if (newattach) { 3418 (void) strcat(syscmd, buf); 3419 /* Classic if */ 3420 if ((af & CONFIG_AF_INET) && (stdif == 1)) { 3421 (void) strcat(syscmd, CFG_CMDS_STD); 3422 } 3423 rcm_log_message(RCM_TRACE1, "IP: New: %s\n", syscmd); 3424 if (rcm_exec_cmd(syscmd) != 0) { 3425 rcm_log_message(RCM_ERROR, 3426 _("IP: Error: %s (%s): %s\n"), 3427 syscmd, ifinst, strerror(errno)); 3428 } 3429 continue; 3430 } 3431 3432 /* Parse the tokens to determine nature of the interface */ 3433 for (n = 0; n < ntok; n++) { 3434 /* Handle pathological failover cases */ 3435 if (STREQ("-failover", tokens[n])) 3436 nofailover++; 3437 if (STREQ("failover", tokens[n])) 3438 nofailover--; 3439 3440 /* group attribute requires special processing */ 3441 if (STREQ("group", tokens[n])) { 3442 if (tokens[n + 1] != NULL) { 3443 (void) snprintf(grpcmd, sizeof (grpcmd), 3444 "%s %s %s %s %s", USR_SBIN_IFCONFIG, 3445 ifinst, fstr, 3446 tokens[n], tokens[n + 1]); 3447 n++; /* skip next token */ 3448 continue; 3449 } 3450 } 3451 3452 /* Execute buffered command ? */ 3453 if (STREQ("set", tokens[n]) || 3454 STREQ("addif", tokens[n]) || 3455 STREQ("removeif", tokens[n]) || 3456 (n == (ntok -1))) { 3457 3458 /* config command complete ? */ 3459 if (n == (ntok -1)) { 3460 ADDSPACE(syscmd); 3461 (void) strcat(syscmd, tokens[n]); 3462 cmdvalid++; 3463 } 3464 3465 if (!cmdvalid) { 3466 ADDSPACE(syscmd); 3467 (void) strcat(syscmd, tokens[n]); 3468 cmdvalid++; 3469 continue; 3470 } 3471 /* Classic if ? */ 3472 if ((af & CONFIG_AF_INET) && (stdif == 1)) { 3473 (void) strcat(syscmd, CFG_CMDS_STD); 3474 } 3475 3476 if (nofailover > 0) { 3477 rcm_log_message(RCM_TRACE1, 3478 "IP: Interim exec: %s\n", syscmd); 3479 if (rcm_exec_cmd(syscmd) != 0) { 3480 rcm_log_message(RCM_ERROR, 3481 _("IP: %s fail(%s): %s\n"), 3482 syscmd, ifinst, 3483 strerror(errno)); 3484 } 3485 } else { 3486 /* Have mpathd configure the address */ 3487 if (if_mpathd_configure(syscmd, ifinst, 3488 af, ipmp) != 0) { 3489 rcm_log_message(RCM_ERROR, 3490 _("IP: %s fail(%s): %s\n"), 3491 syscmd, ifinst, 3492 strerror(errno)); 3493 } 3494 } 3495 3496 /* Reset config command */ 3497 (void) snprintf(syscmd, sizeof (syscmd), 3498 "%s %s %s ", USR_SBIN_IFCONFIG, ifinst, 3499 fstr); 3500 nofailover = 0; 3501 cmdvalid = 0; 3502 } 3503 /* 3504 * Note: No explicit command validation is required 3505 * since ifconfig to does it for us 3506 */ 3507 ADDSPACE(syscmd); 3508 (void) strcat(syscmd, tokens[n]); 3509 cmdvalid++; 3510 } 3511 } 3512 3513 free(buf); 3514 (void) fclose(fp); 3515 3516 /* 3517 * The group name needs to be set after all the test/nofailover 3518 * addresses have been configured. Otherwise, if IPMP detects that the 3519 * interface is failed, the addresses will be moved to a working 3520 * interface before the '-failover' flag can be set. 3521 */ 3522 if (grpcmd[0] != '\0') { 3523 rcm_log_message(RCM_TRACE1, "IP: set group name: %s\n", grpcmd); 3524 if (rcm_exec_cmd(grpcmd) != 0) { 3525 rcm_log_message(RCM_ERROR, _("IP: %s fail(%s): %s\n"), 3526 grpcmd, ifinst, strerror(errno)); 3527 } 3528 } 3529 3530 rcm_log_message(RCM_TRACE1, "IP: if_ipmp_config(%s) success\n", ifinst); 3531 3532 return (0); 3533 } 3534 3535 /* 3536 * if_mpathd_configure() - Determine configuration disposition of the interface 3537 */ 3538 static int 3539 if_mpathd_configure(char *syscmd, char *ifinst, int af, int ipmp) 3540 { 3541 char *tokens[MAXARGS]; 3542 char tspace[MAXLINE]; 3543 int ntok; 3544 char *addr; 3545 char *from_lifname; 3546 mpathd_cmd_t mpdcmd; 3547 int n; 3548 3549 rcm_log_message(RCM_TRACE1, "IP: if_mpathd_configure(%s): %s\n", 3550 ifinst, syscmd); 3551 3552 tokenize(syscmd, tokens, tspace, &ntok); 3553 if (ntok <= 0) 3554 return (0); 3555 3556 addr = tokens[3]; /* by default, third token is valid address */ 3557 for (n = 0; n < ntok; n++) { 3558 if (STREQ("set", tokens[n]) || 3559 STREQ("addif", tokens[n])) { 3560 addr = tokens[n+1]; 3561 if (addr == NULL) { /* invalid format */ 3562 return (-1); 3563 } else 3564 break; 3565 } 3566 } 3567 3568 /* Check std. commands or no failed over address */ 3569 if (STREQ("removeif", addr) || STREQ("group", addr) || 3570 ((from_lifname = get_mpathd_dest(addr, af)) == NULL)) { 3571 rcm_log_message(RCM_TRACE1, 3572 "IP: No failed-over host, exec %s\n", syscmd); 3573 if (rcm_exec_cmd(syscmd) != 0) { 3574 rcm_log_message(RCM_ERROR, 3575 _("IP: %s failed(%s): %s\n"), 3576 syscmd, ifinst, strerror(errno)); 3577 return (-1); 3578 } 3579 return (0); 3580 } 3581 3582 /* Check for non-IPMP failover scenarios */ 3583 if ((ipmp <= 0) && (from_lifname != NULL)) { 3584 /* Address already hosted on another NIC, return */ 3585 rcm_log_message(RCM_TRACE1, 3586 "IP: Non-IPMP failed-over host(%s): %s\n", 3587 ifinst, addr); 3588 return (0); 3589 } 3590 3591 /* 3592 * Valid failed-over host; have mpathd set the original index 3593 */ 3594 mpdcmd.cmd_command = MI_SETOINDEX; 3595 (void) strcpy(mpdcmd.from_lifname, from_lifname); 3596 (void) strcpy(mpdcmd.to_pifname, ifinst); 3597 if (af & CONFIG_AF_INET6) { 3598 mpdcmd.addr_family = AF_INET6; 3599 } else { 3600 mpdcmd.addr_family = AF_INET; 3601 } 3602 3603 /* Send command to in.mpathd(1M) */ 3604 rcm_log_message(RCM_TRACE1, 3605 "IP: Attempting setoindex from (%s) to (%s) ....\n", 3606 from_lifname, ifinst); 3607 3608 if (mpathd_send_cmd(&mpdcmd) < 0) { 3609 rcm_log_message(RCM_TRACE1, 3610 _("IP: mpathd set original index unsuccessful: %s\n"), 3611 strerror(errno)); 3612 return (-1); 3613 } 3614 3615 rcm_log_message(RCM_TRACE1, 3616 "IP: setoindex success (%s) to (%s)\n", 3617 from_lifname, ifinst); 3618 3619 return (0); 3620 } 3621 3622 /* 3623 * get_mpathd_addr() - Return current destination for lif; caller is 3624 * responsible to free memory allocated for address 3625 */ 3626 static char * 3627 get_mpathd_dest(char *addr, int family) 3628 { 3629 int sock; 3630 char *buf; 3631 struct lifnum lifn; 3632 struct lifconf lifc; 3633 struct lifreq *lifrp; 3634 sa_family_t af = AF_INET; /* IPv4 by default */ 3635 int i; 3636 struct lifreq lifreq; 3637 struct sockaddr_in *sin; 3638 struct sockaddr_in6 *sin6; 3639 struct hostent *hp; 3640 char *ifname = NULL; 3641 char *prefix = NULL; 3642 char addrstr[INET6_ADDRSTRLEN]; 3643 char ifaddr[INET6_ADDRSTRLEN]; 3644 int err; 3645 3646 if (addr == NULL) { 3647 return (NULL); 3648 } 3649 3650 rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s)\n", addr); 3651 3652 if (family & CONFIG_AF_INET6) { 3653 af = AF_INET6; 3654 } else { 3655 af = AF_INET; 3656 } 3657 3658 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) { 3659 rcm_log_message(RCM_ERROR, 3660 _("IP: failure opening %s socket: %s\n"), 3661 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno)); 3662 return (NULL); 3663 } 3664 3665 lifn.lifn_family = af; 3666 lifn.lifn_flags = 0; 3667 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 3668 rcm_log_message(RCM_ERROR, 3669 _("IP: SIOCLGIFNUM failed: %s\n"), 3670 strerror(errno)); 3671 (void) close(sock); 3672 return (NULL); 3673 } 3674 3675 if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) { 3676 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"), 3677 strerror(errno)); 3678 (void) close(sock); 3679 return (NULL); 3680 } 3681 3682 lifc.lifc_family = af; 3683 lifc.lifc_flags = 0; 3684 lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count; 3685 lifc.lifc_buf = buf; 3686 3687 if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 3688 rcm_log_message(RCM_ERROR, 3689 _("IP: SIOCGLIFCONF failed: %s\n"), 3690 strerror(errno)); 3691 free(buf); 3692 (void) close(sock); 3693 return (NULL); 3694 } 3695 3696 /* Filter out prefix address from netmask */ 3697 (void) strcpy(ifaddr, addr); 3698 if ((prefix = strchr(ifaddr, '/')) != NULL) { 3699 *prefix = '\0'; /* We care about the address part only */ 3700 } 3701 3702 /* Check for aliases */ 3703 hp = getipnodebyname(ifaddr, af, AI_DEFAULT, &err); 3704 if (hp) { 3705 if (inet_ntop(af, (void *)hp->h_addr_list[0], 3706 ifaddr, sizeof (ifaddr)) == NULL) { 3707 /* Restore original address and use it */ 3708 (void) strcpy(ifaddr, addr); 3709 if ((prefix = strchr(ifaddr, '/')) != NULL) { 3710 *prefix = '\0'; 3711 } 3712 } 3713 freehostent(hp); 3714 } 3715 rcm_log_message(RCM_TRACE2, "IP: ifaddr(%s) = %s\n", 3716 addr, ifaddr); 3717 3718 /* now search the interfaces */ 3719 lifrp = lifc.lifc_req; 3720 for (i = 0; i < lifn.lifn_count; i++, lifrp++) { 3721 (void) strcpy(lifreq.lifr_name, lifrp->lifr_name); 3722 /* Get the interface address for this interface */ 3723 if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) { 3724 rcm_log_message(RCM_ERROR, 3725 _("IP: SIOCGLIFADDR: %s\n"), strerror(errno)); 3726 free(buf); 3727 (void) close(sock); 3728 return (NULL); 3729 } 3730 3731 if (af == AF_INET6) { 3732 sin6 = (struct sockaddr_in6 *)&lifreq.lifr_addr; 3733 if (inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3734 addrstr, sizeof (addrstr)) == NULL) { 3735 continue; 3736 } 3737 } else { 3738 sin = (struct sockaddr_in *)&lifreq.lifr_addr; 3739 if (inet_ntop(AF_INET, (void *)&sin->sin_addr, 3740 addrstr, sizeof (addrstr)) == NULL) { 3741 continue; 3742 } 3743 } 3744 3745 if (STREQ(addrstr, ifaddr)) { 3746 /* Allocate memory to hold interface name */ 3747 if ((ifname = (char *)malloc(LIFNAMSIZ)) == NULL) { 3748 rcm_log_message(RCM_ERROR, 3749 _("IP: malloc: %s\n"), strerror(errno)); 3750 free(buf); 3751 (void) close(sock); 3752 return (NULL); 3753 } 3754 3755 /* Copy the interface name */ 3756 /* 3757 * (void) memcpy(ifname, lifrp->lifr_name, 3758 * sizeof (ifname)); 3759 * ifname[sizeof (ifname) - 1] = '\0'; 3760 */ 3761 (void) strcpy(ifname, lifrp->lifr_name); 3762 break; 3763 } 3764 } 3765 3766 (void) close(sock); 3767 free(buf); 3768 3769 if (ifname == NULL) 3770 rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s): none\n", 3771 addr); 3772 else 3773 rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s): %s\n", 3774 addr, ifname); 3775 3776 return (ifname); 3777 } 3778 3779 static int 3780 if_getcount(int af) 3781 { 3782 int sock; 3783 struct lifnum lifn; 3784 3785 rcm_log_message(RCM_TRACE1, "IP: if_getcount\n"); 3786 3787 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) { 3788 rcm_log_message(RCM_ERROR, 3789 _("IP: failure opening %s socket: %s\n"), 3790 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno)); 3791 return (-1); 3792 } 3793 3794 lifn.lifn_family = af; 3795 lifn.lifn_flags = 0; 3796 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 3797 rcm_log_message(RCM_ERROR, 3798 _("IP: SIOCLGIFNUM failed: %s\n"), 3799 strerror(errno)); 3800 (void) close(sock); 3801 return (-1); 3802 } 3803 (void) close(sock); 3804 3805 rcm_log_message(RCM_TRACE1, "IP: if_getcount success: %d\n", 3806 lifn.lifn_count); 3807 3808 return (lifn.lifn_count); 3809 } 3810 3811 /* 3812 * tokenize() - turn a command line into tokens; caller is responsible to 3813 * provide enough memory to hold all tokens 3814 */ 3815 static void 3816 tokenize(char *line, char **tokens, char *tspace, int *ntok) 3817 { 3818 char *cp; 3819 char *sp; 3820 3821 sp = tspace; 3822 cp = line; 3823 for (*ntok = 0; *ntok < MAXARGS; (*ntok)++) { 3824 tokens[*ntok] = sp; 3825 while (ISSPACE(*cp)) 3826 cp++; 3827 if (ISEOL(*cp)) 3828 break; 3829 do { 3830 *sp++ = *cp++; 3831 } while (!ISSPACE(*cp) && !ISEOL(*cp)); 3832 3833 *sp++ = '\0'; 3834 } 3835 } 3836 3837 #ifdef RCM_IPMP_DEBUG 3838 3839 static void 3840 dump_node(ip_cache_t *node) 3841 { 3842 ip_pif_t *pif; 3843 ip_lif_t *lif; 3844 3845 pif = node->ip_pif; 3846 3847 rcm_log_message(RCM_TRACE1, "Node dump:\n"); 3848 rcm_log_message(RCM_TRACE1, "resource = %s\t cache flags = 0x%x\n", 3849 node->ip_resource, node->ip_cachestate); 3850 rcm_log_message(RCM_TRACE1, "ifname = %s\t ifindex = %d\n", 3851 pif->pi_ifname, pif->pi_ifindex); 3852 rcm_log_message(RCM_TRACE1, "groupname = %s\t PPA = %d\n", 3853 pif->pi_grpname, pif->pi_ppa); 3854 if (pif->pi_style == DL_STYLE1) { 3855 rcm_log_message(RCM_TRACE1, "Provider = DLPI style 1\n"); 3856 } 3857 if (pif->pi_style == DL_STYLE2) { 3858 rcm_log_message(RCM_TRACE1, "Provider = DLPI style 2\n"); 3859 }; 3860 3861 lif = pif->pi_lifs; 3862 3863 if (lif == NULL) { 3864 rcm_log_message(RCM_TRACE1, "No lifs hosted on this device.\n"); 3865 return; 3866 } 3867 3868 rcm_log_message(RCM_TRACE1, 3869 "Logical interfaces hosted on this device - \n"); 3870 while (lif != NULL) { 3871 rcm_log_message(RCM_TRACE1, "\t ifnum = %d \t ifflags = 0x%x", 3872 lif->li_ifnum, lif->li_ifflags); 3873 if (lif->li_addr.family == AF_INET) 3874 rcm_log_message(RCM_TRACE1, "\t Family = IPv4"); 3875 else if (lif->li_addr.family == AF_INET6) 3876 rcm_log_message(RCM_TRACE1, "\t Family = IPv6"); 3877 else rcm_log_message(RCM_TRACE1, "\t Family = <Unknown>"); 3878 rcm_log_message(RCM_TRACE1, "\n"); 3879 3880 lif = lif->li_next; 3881 } 3882 } 3883 3884 #else /* !RCM_IPMP_DEBUG */ 3885 3886 /*ARGSUSED*/ 3887 static void 3888 dump_node(ip_cache_t *node) 3889 { 3890 /* do nothing */ 3891 } 3892 3893 #endif /* RCM_IPMP_DEBUG */ 3894