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