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 *, int *, struct lifreq *); 287 static int ip_plink(int, 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 mux_fd; 2291 int muxid_fd; 2292 int fd; 2293 int i; 2294 int num_mods; 2295 struct lifreq lifr; 2296 struct str_list strlist; 2297 2298 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name); 2299 2300 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2301 lifr.lifr_flags = lif->li_ifflags; 2302 if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) { 2303 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name); 2304 return (-1); 2305 } 2306 2307 if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) { 2308 rcm_log_message(RCM_ERROR, 2309 _("IP: get_modlist(%s): I_LIST(%s) \n"), 2310 name, strerror(errno)); 2311 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr); 2312 return (-1); 2313 } 2314 2315 strlist.sl_nmods = num_mods; 2316 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods); 2317 2318 if (strlist.sl_modlist == NULL) { 2319 rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"), 2320 name, strerror(errno)); 2321 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr); 2322 return (-1); 2323 } 2324 2325 if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) { 2326 rcm_log_message(RCM_ERROR, 2327 _("IP: get_modlist(%s): I_LIST error: %s\n"), 2328 name, strerror(errno)); 2329 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr); 2330 return (-1); 2331 } 2332 2333 for (i = 0; i < strlist.sl_nmods; i++) { 2334 lif->li_modules[i] = 2335 malloc(strlen(strlist.sl_modlist[i].l_name)+1); 2336 if (lif->li_modules[i] == NULL) { 2337 rcm_log_message(RCM_ERROR, 2338 _("IP: get_modlist(%s): %s\n"), 2339 name, strerror(errno)); 2340 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr); 2341 return (-1); 2342 } 2343 (void) strcpy(lif->li_modules[i], strlist.sl_modlist[i].l_name); 2344 } 2345 2346 lif->li_modcnt = strlist.sl_nmods; 2347 free(strlist.sl_modlist); 2348 2349 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name); 2350 return (ip_plink(mux_fd, muxid_fd, fd, &lifr)); 2351 } 2352 2353 /* 2354 * ip_domux2fd() - Helper function for mod*() functions 2355 * Stolen from ifconfig.c 2356 */ 2357 static int 2358 ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr) 2359 { 2360 int muxid_fd; 2361 char *udp_dev_name; 2362 2363 if (lifr->lifr_flags & IFF_IPV6) { 2364 udp_dev_name = UDP6_DEV_NAME; 2365 } else { 2366 udp_dev_name = UDP_DEV_NAME; 2367 } 2368 2369 if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) { 2370 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"), 2371 udp_dev_name, strerror(errno)); 2372 return (-1); 2373 } 2374 if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) { 2375 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"), 2376 udp_dev_name, strerror(errno)); 2377 (void) close(muxid_fd); 2378 return (-1); 2379 } 2380 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) { 2381 rcm_log_message(RCM_ERROR, 2382 _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"), 2383 udp_dev_name, strerror(errno)); 2384 (void) close(*mux_fd); 2385 (void) close(muxid_fd); 2386 return (-1); 2387 } 2388 2389 rcm_log_message(RCM_TRACE2, 2390 "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n", 2391 lifr->lifr_arp_muxid, lifr->lifr_ip_muxid); 2392 2393 if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) { 2394 rcm_log_message(RCM_ERROR, 2395 _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"), 2396 udp_dev_name, strerror(errno)); 2397 (void) close(*mux_fd); 2398 (void) close(muxid_fd); 2399 return (-1); 2400 } 2401 if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) { 2402 rcm_log_message(RCM_ERROR, 2403 _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"), 2404 udp_dev_name, strerror(errno)); 2405 (void) close(*mux_fd); 2406 (void) close(muxid_fd); 2407 return (-1); 2408 } 2409 2410 /* Note: mux_fd and muxid_fd are closed in ip_plink below */ 2411 *muxid_fdp = muxid_fd; 2412 return (0); 2413 } 2414 2415 /* 2416 * ip_plink() - Helper function for mod*() functions. 2417 * Stolen from ifconfig.c 2418 */ 2419 static int 2420 ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr) 2421 { 2422 int mux_id; 2423 2424 if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) { 2425 rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"), 2426 UDP_DEV_NAME, strerror(errno)); 2427 (void) close(mux_fd); 2428 (void) close(muxid_fd); 2429 (void) close(fd); 2430 return (-1); 2431 } 2432 2433 lifr->lifr_ip_muxid = mux_id; 2434 if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) { 2435 rcm_log_message(RCM_ERROR, 2436 _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"), 2437 UDP_DEV_NAME, strerror(errno)); 2438 (void) close(mux_fd); 2439 (void) close(muxid_fd); 2440 (void) close(fd); 2441 return (-1); 2442 } 2443 2444 (void) close(mux_fd); 2445 (void) close(muxid_fd); 2446 (void) close(fd); 2447 return (0); 2448 } 2449 2450 /* 2451 * ip_onlinelist() 2452 * 2453 * Notify online to IP address consumers. 2454 */ 2455 static int 2456 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags, 2457 rcm_info_t **depend_info) 2458 { 2459 char **addrlist; 2460 int ret = RCM_SUCCESS; 2461 2462 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n"); 2463 2464 addrlist = ip_get_addrlist(node); 2465 if (addrlist == NULL || addrlist[0] == NULL) { 2466 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n"); 2467 ip_free_addrlist(addrlist); 2468 return (ret); 2469 } 2470 2471 ret = rcm_notify_online_list(hd, addrlist, 0, depend_info); 2472 2473 ip_free_addrlist(addrlist); 2474 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n"); 2475 return (ret); 2476 } 2477 2478 /* 2479 * ip_offlinelist() 2480 * 2481 * Offline IP address consumers. 2482 */ 2483 static int 2484 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags, 2485 rcm_info_t **depend_info) 2486 { 2487 char **addrlist; 2488 int ret = RCM_SUCCESS; 2489 2490 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n"); 2491 2492 addrlist = ip_get_addrlist(node); 2493 if (addrlist == NULL || addrlist[0] == NULL) { 2494 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n"); 2495 ip_free_addrlist(addrlist); 2496 return (RCM_SUCCESS); 2497 } 2498 2499 if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info)) 2500 != RCM_SUCCESS) { 2501 if (ret == RCM_FAILURE) 2502 (void) rcm_notify_online_list(hd, addrlist, 0, NULL); 2503 2504 ret = RCM_FAILURE; 2505 } 2506 2507 ip_free_addrlist(addrlist); 2508 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n"); 2509 return (ret); 2510 } 2511 2512 /* 2513 * ip_get_addrlist() - Compile list of IP addresses hosted on this NIC (node) 2514 * This routine malloc() required memeory for the list 2515 * Returns list on success, NULL if failed 2516 * Call with cache_lock held. 2517 */ 2518 static char ** 2519 ip_get_addrlist(ip_cache_t *node) 2520 { 2521 ip_lif_t *lif; 2522 char **addrlist = NULL; 2523 int numifs; 2524 char addrstr[INET6_ADDRSTRLEN]; 2525 void *addr; 2526 int af; 2527 int i; 2528 2529 rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n", 2530 node->ip_resource); 2531 2532 numifs = 0; 2533 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) { 2534 numifs++; 2535 } 2536 2537 /* 2538 * Allocate space for resource names list; add 1 and use calloc() 2539 * so that the list is NULL-terminated. 2540 */ 2541 if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) { 2542 rcm_log_message(RCM_ERROR, 2543 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"), 2544 node->ip_resource, strerror(errno)); 2545 return (NULL); 2546 } 2547 2548 for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL; 2549 lif = lif->li_next, i++) { 2550 2551 af = lif->li_addr.family; 2552 if (af == AF_INET6) { 2553 addr = &lif->li_addr.ip6.sin6_addr; 2554 } else if (af == AF_INET) { 2555 addr = &lif->li_addr.ip4.sin_addr; 2556 } else { 2557 rcm_log_message(RCM_DEBUG, 2558 "IP: unknown addr family %d, assuming AF_INET\n", 2559 af); 2560 af = AF_INET; 2561 addr = &lif->li_addr.ip4.sin_addr; 2562 } 2563 if (inet_ntop(af, addr, addrstr, INET6_ADDRSTRLEN) == NULL) { 2564 rcm_log_message(RCM_ERROR, 2565 _("IP: inet_ntop: %s\n"), strerror(errno)); 2566 ip_free_addrlist(addrlist); 2567 return (NULL); 2568 } 2569 2570 if ((addrlist[i] = malloc(strlen(addrstr) + RCM_SIZE_SUNW_IP)) 2571 == NULL) { 2572 rcm_log_message(RCM_ERROR, 2573 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"), 2574 node->ip_resource, strerror(errno)); 2575 ip_free_addrlist(addrlist); 2576 return (NULL); 2577 } 2578 (void) strcpy(addrlist[i], RCM_STR_SUNW_IP); /* SUNW_ip/ */ 2579 (void) strcat(addrlist[i], addrstr); /* SUNW_ip/<address> */ 2580 2581 rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]); 2582 } 2583 2584 rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n", 2585 node->ip_resource); 2586 2587 return (addrlist); 2588 } 2589 2590 static void 2591 ip_free_addrlist(char **addrlist) 2592 { 2593 int i; 2594 2595 if (addrlist == NULL) 2596 return; 2597 2598 for (i = 0; addrlist[i] != NULL; i++) 2599 free(addrlist[i]); 2600 free(addrlist); 2601 } 2602 2603 /* 2604 * ip_consumer_notify() - Notify consumers of IP addresses coming back online. 2605 */ 2606 2607 static void 2608 ip_consumer_notify(rcm_handle_t *hd, char *ifinst, char **errorp, uint_t flags, 2609 rcm_info_t **depend_info) 2610 { 2611 char ifname[LIFNAMSIZ + 1]; 2612 char cached_name[RCM_NET_RESOURCE_MAX]; 2613 ip_cache_t *node; 2614 char *cp; 2615 2616 rcm_log_message(RCM_TRACE1, "IP: ip_consumer_notify(%s)\n", ifinst); 2617 2618 if (ifinst == NULL) 2619 return; 2620 2621 (void) memcpy(&ifname, ifinst, sizeof (ifname)); 2622 ifname[sizeof (ifname) - 1] = '\0'; 2623 2624 /* remove LIF component */ 2625 cp = strchr(ifname, ':'); 2626 if (cp) { 2627 *cp = 0; 2628 } 2629 2630 /* Check for the interface in the cache */ 2631 (void) snprintf(cached_name, sizeof (cached_name), "%s/%s", 2632 RCM_NET_PREFIX, ifname); 2633 2634 (void) mutex_lock(&cache_lock); 2635 if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) { 2636 rcm_log_message(RCM_TRACE1, "IP: Skipping interface(%s) \n", 2637 ifname); 2638 (void) mutex_unlock(&cache_lock); 2639 return; 2640 } 2641 /* 2642 * Inform anonymous consumers about IP addresses being 2643 * onlined 2644 */ 2645 (void) ip_onlinelist(hd, node, errorp, flags, depend_info); 2646 2647 (void) mutex_unlock(&cache_lock); 2648 2649 rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n"); 2650 return; 2651 2652 } 2653 /* 2654 * process_nvlist() - Determine network interfaces on a new attach by 2655 * processing the nvlist 2656 */ 2657 /*ARGSUSED*/ 2658 static int 2659 process_nvlist(nvlist_t *nvl) 2660 { 2661 nvpair_t *nvp = NULL; 2662 char *driver_name; 2663 char *devfs_path; 2664 int32_t instance; 2665 char *minor_byte_array; /* packed nvlist of minor_data */ 2666 uint_t nminor; /* # of minor nodes */ 2667 struct devfs_minor_data *mdata; 2668 nvlist_t *mnvl; 2669 nvpair_t *mnvp = NULL; 2670 2671 rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n"); 2672 2673 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 2674 /* Get driver name */ 2675 if (STREQ(nvpair_name(nvp), RCM_NV_DRIVER_NAME)) { 2676 if (nvpair_value_string(nvp, &driver_name) != 0) { 2677 rcm_log_message(RCM_WARNING, 2678 _("IP: cannot get driver name\n")); 2679 return (-1); 2680 } 2681 } 2682 /* Get instance */ 2683 if (STREQ(nvpair_name(nvp), RCM_NV_INSTANCE)) { 2684 if (nvpair_value_int32(nvp, &instance) != 0) { 2685 rcm_log_message(RCM_WARNING, 2686 _("IP: cannot get device instance\n")); 2687 return (-1); 2688 } 2689 } 2690 /* Get devfs_path */ 2691 if (STREQ(nvpair_name(nvp), RCM_NV_DEVFS_PATH)) { 2692 if (nvpair_value_string(nvp, &devfs_path) != 0) { 2693 rcm_log_message(RCM_WARNING, 2694 _("IP: cannot get device path\n")); 2695 return (-1); 2696 } 2697 } 2698 /* Get minor data */ 2699 if (STREQ(nvpair_name(nvp), RCM_NV_MINOR_DATA)) { 2700 if (nvpair_value_byte_array(nvp, 2701 (uchar_t **)&minor_byte_array, &nminor) != 0) { 2702 rcm_log_message(RCM_WARNING, 2703 _("IP: cannot get device minor data\n")); 2704 return (-1); 2705 } 2706 if (nvlist_unpack(minor_byte_array, 2707 nminor, &mnvl, 0) != 0) { 2708 rcm_log_message(RCM_WARNING, 2709 _("IP: cannot get minor node data\n")); 2710 return (-1); 2711 } 2712 mdata = (struct devfs_minor_data *)calloc(1, 2713 sizeof (struct devfs_minor_data)); 2714 if (mdata == NULL) { 2715 rcm_log_message(RCM_WARNING, 2716 _("IP: calloc error(%s)\n"), 2717 strerror(errno)); 2718 nvlist_free(mnvl); 2719 return (-1); 2720 } 2721 /* Enumerate minor node data */ 2722 while ((mnvp = nvlist_next_nvpair(mnvl, mnvp)) != 2723 NULL) { 2724 /* Get minor type */ 2725 if (STREQ(nvpair_name(mnvp), 2726 RCM_NV_MINOR_TYPE)) { 2727 if (nvpair_value_int32(mnvp, 2728 &mdata->minor_type) != 0) { 2729 rcm_log_message(RCM_WARNING, 2730 _("IP: cannot get minor " 2731 "type \n")); 2732 nvlist_free(mnvl); 2733 return (-1); 2734 } 2735 } 2736 /* Get minor name */ 2737 if (STREQ(nvpair_name(mnvp), 2738 RCM_NV_MINOR_NAME)) { 2739 if (nvpair_value_string(mnvp, 2740 &mdata->minor_name) != 0) { 2741 rcm_log_message(RCM_WARNING, 2742 _("IP: cannot get minor " 2743 "name \n")); 2744 nvlist_free(mnvl); 2745 return (-1); 2746 } 2747 } 2748 /* Get minor node type */ 2749 if (STREQ(nvpair_name(mnvp), 2750 RCM_NV_MINOR_NODE_TYPE)) { 2751 if (nvpair_value_string(mnvp, 2752 &mdata->minor_node_type) != 0) { 2753 rcm_log_message(RCM_WARNING, 2754 _("IP: cannot get minor " 2755 "node type \n")); 2756 nvlist_free(mnvl); 2757 return (-1); 2758 } 2759 } 2760 } 2761 (void) process_minor(devfs_path, driver_name, instance, 2762 mdata); 2763 nvlist_free(mnvl); 2764 } 2765 } 2766 2767 rcm_log_message(RCM_TRACE1, "IP: process_nvlist success\n"); 2768 return (0); 2769 } 2770 2771 static void 2772 process_minor(char *devfs_path, char *name, int instance, 2773 struct devfs_minor_data *mdata) 2774 { 2775 struct net_interface *nip; 2776 struct ni_list *nilp; 2777 struct ni_list *p; 2778 struct ni_list **pp; 2779 char *cname; 2780 size_t cnamelen; 2781 2782 rcm_log_message(RCM_TRACE1, "IP: process_minor\n"); 2783 2784 if ((mdata->minor_node_type != NULL) && 2785 !STREQ(mdata->minor_node_type, PROP_NV_DDI_NETWORK)) { 2786 /* Process network devices only */ 2787 return; 2788 } 2789 2790 rcm_log_message(RCM_TRACE1, "IP: Examining %s (%s)\n", 2791 devfs_path, mdata->minor_name); 2792 2793 /* Sanity check, instances > 999 are illegal */ 2794 if (instance > 999) { 2795 errno = EINVAL; 2796 rcm_log_message(RCM_ERROR, _("IP: invalid instance %d(%s)\n"), 2797 instance, strerror(errno)); 2798 return; 2799 } 2800 2801 /* Now, let's add the node to the interface list */ 2802 if ((nip = malloc(sizeof (struct net_interface))) == NULL) { 2803 rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"), 2804 strerror(errno)); 2805 return; 2806 } 2807 (void) memset(nip, 0, sizeof (struct net_interface)); 2808 2809 cnamelen = strlen(name) + 1; 2810 /* Set NIC type */ 2811 if ((nip->type = (char *)malloc(cnamelen)) == NULL) { 2812 free(nip); 2813 rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"), 2814 strerror(errno)); 2815 return; 2816 } 2817 (void) memcpy(nip->type, name, cnamelen); 2818 2819 cnamelen += 3; 2820 if ((cname = (char *)malloc(cnamelen)) == NULL) { 2821 free(nip->type); 2822 free(nip); 2823 rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"), 2824 strerror(errno)); 2825 return; 2826 } 2827 (void) snprintf(cname, cnamelen, "%s%d", name, instance); 2828 2829 rcm_log_message(RCM_TRACE1, "IP: Found SUNW_network/%s%d\n", name, 2830 instance); 2831 2832 /* Set NIC name */ 2833 if ((nip->name = strdup(cname)) == NULL) { 2834 free(nip->type); 2835 free(nip); 2836 free(cname); 2837 rcm_log_message(RCM_ERROR, _("IP: strdup failure(%s)\n"), 2838 strerror(errno)); 2839 return; 2840 } 2841 free(cname); 2842 2843 /* Add new interface to the list */ 2844 (void) mutex_lock(&nil_lock); 2845 for (pp = &nil_head; (p = *pp) != NULL; pp = &(p->next)) { 2846 cname = p->nifp->name; 2847 if (strcmp(cname, nip->name) == 0) 2848 break; 2849 } 2850 2851 if (p != NULL) { 2852 (void) mutex_unlock(&nil_lock); 2853 free(nip->name); 2854 free(nip->type); 2855 free(nip); 2856 rcm_log_message(RCM_TRACE1, "IP: secondary node - ignoring\n"); 2857 return; 2858 } 2859 2860 if ((nilp = malloc(sizeof (struct ni_list))) == NULL) { 2861 (void) mutex_unlock(&nil_lock); 2862 free(nip->name); 2863 free(nip->type); 2864 free(nip); 2865 rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"), 2866 strerror(errno)); 2867 return; 2868 } 2869 2870 nilp->nifp = nip; 2871 nilp->next = NULL; 2872 *pp = nilp; 2873 2874 num_ni++; /* Increment interface count */ 2875 2876 (void) mutex_unlock(&nil_lock); 2877 rcm_log_message(RCM_TRACE1, "IP: added new node\n"); 2878 } 2879 2880 /* 2881 * if_configure() - Configure a physical interface after attach 2882 */ 2883 static int 2884 if_configure(char *ifinst) 2885 { 2886 char cfgfile[MAXPATHLEN]; 2887 char ifname[LIFNAMSIZ + 1]; 2888 char cached_name[RCM_NET_RESOURCE_MAX]; 2889 struct stat statbuf; 2890 ip_cache_t *node; 2891 char *cp; 2892 int af = 0; 2893 int ipmp = 0; 2894 2895 if (ifinst == NULL) 2896 return (0); 2897 2898 rcm_log_message(RCM_TRACE1, "IP: if_configure(%s)\n", ifinst); 2899 2900 /* 2901 * Check if the interface is already configured 2902 */ 2903 2904 (void) memcpy(&ifname, ifinst, sizeof (ifname)); 2905 ifname[sizeof (ifname) - 1] = '\0'; 2906 2907 /* remove LIF component */ 2908 cp = strchr(ifname, ':'); 2909 if (cp) { 2910 *cp = 0; 2911 } 2912 2913 /* Check for the interface in the cache */ 2914 (void) snprintf(cached_name, sizeof (cached_name), "%s/%s", 2915 RCM_NET_PREFIX, ifname); 2916 2917 /* Check if the interface is new or was previously offlined */ 2918 (void) mutex_lock(&cache_lock); 2919 if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) && 2920 (!(node->ip_cachestate & CACHE_IF_OFFLINED))) { 2921 rcm_log_message(RCM_TRACE1, 2922 "IP: Skipping configured interface(%s) \n", ifname); 2923 (void) mutex_unlock(&cache_lock); 2924 return (0); 2925 } 2926 (void) mutex_unlock(&cache_lock); 2927 2928 /* Scan IPv4 configuration first */ 2929 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4, ifinst); 2930 cfgfile[MAXPATHLEN - 1] = '\0'; 2931 2932 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile); 2933 if (stat(cfgfile, &statbuf) == 0) { 2934 af |= CONFIG_AF_INET; 2935 if (isgrouped(cfgfile)) { 2936 ipmp++; 2937 } 2938 } 2939 2940 /* Scan IPv6 configuration details */ 2941 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV6, ifinst); 2942 cfgfile[MAXPATHLEN - 1] = '\0'; 2943 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile); 2944 if (stat(cfgfile, &statbuf) == 0) { 2945 af |= CONFIG_AF_INET6; 2946 if ((ipmp == 0) && isgrouped(cfgfile)) { 2947 ipmp++; 2948 } 2949 } 2950 2951 if (af & CONFIG_AF_INET) { 2952 if (if_ipmp_config(ifinst, CONFIG_AF_INET, ipmp) == -1) { 2953 rcm_log_message(RCM_ERROR, 2954 _("IP: IPv4 Post-attach failed (%s)\n"), ifinst); 2955 return (-1); 2956 } 2957 } 2958 2959 if (af & CONFIG_AF_INET6) { 2960 if (if_ipmp_config(ifinst, CONFIG_AF_INET6, ipmp) == -1) { 2961 rcm_log_message(RCM_ERROR, 2962 _("IP: IPv6 Post-attach failed(%s)\n"), ifinst); 2963 return (-1); 2964 } 2965 } 2966 2967 rcm_log_message(RCM_TRACE1, "IP: if_configure(%s) success\n", ifinst); 2968 2969 return (0); 2970 2971 } 2972 2973 /* 2974 * isgrouped() - Scans the given config file to see if this is a grouped 2975 * interface 2976 * Returns non-zero if true; 0 if false 2977 */ 2978 static int 2979 isgrouped(char *cfgfile) 2980 { 2981 FILE *fp; 2982 struct stat statb; 2983 char *buf = NULL; 2984 char *tokens[MAXARGS]; /* token pointers */ 2985 char tspace[MAXLINE]; /* token space */ 2986 int ntok; 2987 int group = 0; 2988 2989 if (cfgfile == NULL) 2990 return (0); 2991 2992 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile); 2993 2994 if (stat(cfgfile, &statb) != 0) { 2995 rcm_log_message(RCM_TRACE1, 2996 _("IP: No config file(%s)\n"), cfgfile); 2997 return (0); 2998 } 2999 3000 /* 3001 * We also ignore single-byte config files because the file should 3002 * always be newline-terminated, so we know there's nothing of 3003 * interest. Further, a single-byte file would cause the fgets() loop 3004 * below to spin forever. 3005 */ 3006 if (statb.st_size <= 1) { 3007 rcm_log_message(RCM_TRACE1, 3008 _("IP: Empty config file(%s)\n"), cfgfile); 3009 return (0); 3010 } 3011 3012 if ((fp = fopen(cfgfile, "r")) == NULL) { 3013 rcm_log_message(RCM_ERROR, 3014 _("IP: Cannot open configuration file(%s): %s\n"), cfgfile, 3015 strerror(errno)); 3016 return (0); 3017 } 3018 3019 if ((buf = calloc(1, statb.st_size)) == NULL) { 3020 rcm_log_message(RCM_ERROR, 3021 _("IP: calloc failure(%s): %s\n"), cfgfile, 3022 strerror(errno)); 3023 (void) fclose(fp); 3024 return (0); 3025 } 3026 3027 while (fgets(buf, statb.st_size, fp) != NULL) { 3028 if (*buf == '\0') 3029 continue; 3030 3031 tokenize(buf, tokens, tspace, &ntok); 3032 while (ntok) { 3033 if (STREQ("group", tokens[ntok - 1])) { 3034 if (tokens[ntok] != NULL) { 3035 group++; 3036 } 3037 } 3038 ntok--; 3039 } 3040 } 3041 3042 free(buf); 3043 3044 (void) fclose(fp); 3045 3046 if (group <= 0) { 3047 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s) non-grouped\n", 3048 cfgfile); 3049 return (0); 3050 } else { 3051 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s) grouped\n", 3052 cfgfile); 3053 return (1); 3054 } 3055 } 3056 3057 3058 /* 3059 * if_ipmp_config() - Configure an interface instance as specified by the 3060 * address family af and if it is grouped (ipmp). 3061 */ 3062 static int 3063 if_ipmp_config(char *ifinst, int af, int ipmp) 3064 { 3065 char cfgfile[MAXPATHLEN]; /* configuration file */ 3066 FILE *fp; 3067 struct stat statb; 3068 char *buf; 3069 char *tokens[MAXARGS]; /* list of config attributes */ 3070 char tspace[MAXLINE]; /* token space */ 3071 char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1]; 3072 char grpcmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1]; 3073 char fstr[8]; /* address family string inet or inet6 */ 3074 int nofailover = 0; 3075 int newattach = 0; 3076 int cmdvalid = 0; 3077 int ntok; 3078 int n; 3079 int stdif = 0; 3080 3081 if (ifinst == NULL) 3082 return (0); 3083 3084 rcm_log_message(RCM_TRACE1, "IP: if_ipmp_config(%s) ipmp = %d\n", 3085 ifinst, ipmp); 3086 3087 if (af & CONFIG_AF_INET) { 3088 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4, 3089 ifinst); 3090 (void) strcpy(fstr, "inet"); 3091 } else if (af & CONFIG_AF_INET6) { 3092 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV6, 3093 ifinst); 3094 (void) strcpy(fstr, "inet6"); 3095 } else { 3096 return (0); /* nothing to do */ 3097 } 3098 3099 cfgfile[MAXPATHLEN - 1] = '\0'; 3100 grpcmd[0] = '\0'; 3101 3102 if (stat(cfgfile, &statb) != 0) { 3103 rcm_log_message(RCM_TRACE1, 3104 _("IP: No config file(%s)\n"), ifinst); 3105 return (0); 3106 } 3107 3108 /* Config file exists, plumb in the physical interface */ 3109 if (af & CONFIG_AF_INET6) { 3110 if (if_getcount(AF_INET6) == 0) { 3111 /* 3112 * Configure software loopback driver if this is the 3113 * first IPv6 interface plumbed 3114 */ 3115 newattach++; 3116 (void) snprintf(syscmd, sizeof (syscmd), 3117 "%s lo0 %s plumb ::1 up", USR_SBIN_IFCONFIG, fstr); 3118 if (rcm_exec_cmd(syscmd) != 0) { 3119 rcm_log_message(RCM_ERROR, 3120 _("IP: Cannot plumb (%s) %s\n"), 3121 ifinst, strerror(errno)); 3122 return (-1); 3123 } 3124 } 3125 (void) snprintf(syscmd, sizeof (syscmd), "%s %s %s plumb up", 3126 USR_SBIN_IFCONFIG, ifinst, fstr); 3127 } else { 3128 (void) snprintf(syscmd, sizeof (syscmd), "%s %s %s plumb ", 3129 USR_SBIN_IFCONFIG, ifinst, fstr); 3130 if (if_getcount(AF_INET) == 0) { 3131 newattach++; 3132 } 3133 } 3134 rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd); 3135 3136 if (rcm_exec_cmd(syscmd) != 0) { 3137 rcm_log_message(RCM_ERROR, 3138 _("IP: Cannot plumb (%s) %s\n"), ifinst, strerror(errno)); 3139 return (-1); 3140 } 3141 3142 /* Check if config file is empty, if so, nothing else to do */ 3143 if (statb.st_size == 0) { 3144 rcm_log_message(RCM_TRACE1, 3145 _("IP: Zero size config file(%s)\n"), ifinst); 3146 return (0); 3147 } 3148 3149 if ((fp = fopen(cfgfile, "r")) == NULL) { 3150 rcm_log_message(RCM_ERROR, 3151 _("IP: Open error(%s): %s\n"), cfgfile, strerror(errno)); 3152 return (-1); 3153 } 3154 3155 if ((buf = calloc(1, statb.st_size)) == NULL) { 3156 rcm_log_message(RCM_ERROR, 3157 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno)); 3158 (void) fclose(fp); 3159 return (-1); 3160 } 3161 3162 /* a single line with one token implies a classical if */ 3163 if (fgets(buf, statb.st_size, fp) != NULL) { 3164 tokenize(buf, tokens, tspace, &ntok); 3165 if (ntok == 1) { 3166 rcm_log_message(RCM_TRACE1, "IP: Standard interface\n"); 3167 stdif++; 3168 } 3169 } 3170 if (fseek(fp, 0L, SEEK_SET) == -1) { 3171 rcm_log_message(RCM_ERROR, _("IP: fseek: %s\n"), 3172 strerror(errno)); 3173 return (-1); 3174 } 3175 3176 /* 3177 * Process the config command 3178 * This loop also handles multiple logical interfaces that may 3179 * be configured on a single line 3180 */ 3181 while (fgets(buf, statb.st_size, fp) != NULL) { 3182 nofailover = 0; 3183 cmdvalid = 0; 3184 3185 if (*buf == '\0') 3186 continue; 3187 3188 tokenize(buf, tokens, tspace, &ntok); 3189 if (ntok <= 0) 3190 continue; 3191 3192 /* Reset the config command */ 3193 (void) snprintf(syscmd, sizeof (syscmd), "%s %s %s ", 3194 USR_SBIN_IFCONFIG, ifinst, fstr); 3195 3196 /* No parsing if this is first interface of its kind */ 3197 if (newattach) { 3198 (void) strcat(syscmd, buf); 3199 /* Classic if */ 3200 if ((af & CONFIG_AF_INET) && (stdif == 1)) { 3201 (void) strcat(syscmd, CFG_CMDS_STD); 3202 } 3203 rcm_log_message(RCM_TRACE1, "IP: New: %s\n", syscmd); 3204 if (rcm_exec_cmd(syscmd) != 0) { 3205 rcm_log_message(RCM_ERROR, 3206 _("IP: Error: %s (%s): %s\n"), 3207 syscmd, ifinst, strerror(errno)); 3208 } 3209 continue; 3210 } 3211 3212 /* Parse the tokens to determine nature of the interface */ 3213 for (n = 0; n < ntok; n++) { 3214 /* Handle pathological failover cases */ 3215 if (STREQ("-failover", tokens[n])) 3216 nofailover++; 3217 if (STREQ("failover", tokens[n])) 3218 nofailover--; 3219 3220 /* group attribute requires special processing */ 3221 if (STREQ("group", tokens[n])) { 3222 if (tokens[n + 1] != NULL) { 3223 (void) snprintf(grpcmd, sizeof (grpcmd), 3224 "%s %s %s %s %s", USR_SBIN_IFCONFIG, 3225 ifinst, fstr, 3226 tokens[n], tokens[n + 1]); 3227 n++; /* skip next token */ 3228 continue; 3229 } 3230 } 3231 3232 /* Execute buffered command ? */ 3233 if (STREQ("set", tokens[n]) || 3234 STREQ("addif", tokens[n]) || 3235 STREQ("removeif", tokens[n]) || 3236 (n == (ntok -1))) { 3237 3238 /* config command complete ? */ 3239 if (n == (ntok -1)) { 3240 ADDSPACE(syscmd); 3241 (void) strcat(syscmd, tokens[n]); 3242 cmdvalid++; 3243 } 3244 3245 if (!cmdvalid) { 3246 ADDSPACE(syscmd); 3247 (void) strcat(syscmd, tokens[n]); 3248 cmdvalid++; 3249 continue; 3250 } 3251 /* Classic if ? */ 3252 if ((af & CONFIG_AF_INET) && (stdif == 1)) { 3253 (void) strcat(syscmd, CFG_CMDS_STD); 3254 } 3255 3256 if (nofailover > 0) { 3257 rcm_log_message(RCM_TRACE1, 3258 "IP: Interim exec: %s\n", syscmd); 3259 if (rcm_exec_cmd(syscmd) != 0) { 3260 rcm_log_message(RCM_ERROR, 3261 _("IP: %s fail(%s): %s\n"), 3262 syscmd, ifinst, 3263 strerror(errno)); 3264 } 3265 } else { 3266 /* Have mpathd configure the address */ 3267 if (if_mpathd_configure(syscmd, ifinst, 3268 af, ipmp) != 0) { 3269 rcm_log_message(RCM_ERROR, 3270 _("IP: %s fail(%s): %s\n"), 3271 syscmd, ifinst, 3272 strerror(errno)); 3273 } 3274 } 3275 3276 /* Reset config command */ 3277 (void) snprintf(syscmd, sizeof (syscmd), 3278 "%s %s %s ", USR_SBIN_IFCONFIG, ifinst, 3279 fstr); 3280 nofailover = 0; 3281 cmdvalid = 0; 3282 } 3283 /* 3284 * Note: No explicit command validation is required 3285 * since ifconfig to does it for us 3286 */ 3287 ADDSPACE(syscmd); 3288 (void) strcat(syscmd, tokens[n]); 3289 cmdvalid++; 3290 } 3291 } 3292 3293 free(buf); 3294 (void) fclose(fp); 3295 3296 /* 3297 * The group name needs to be set after all the test/nofailover 3298 * addresses have been configured. Otherwise, if IPMP detects that the 3299 * interface is failed, the addresses will be moved to a working 3300 * interface before the '-failover' flag can be set. 3301 */ 3302 if (grpcmd[0] != '\0') { 3303 rcm_log_message(RCM_TRACE1, "IP: set group name: %s\n", grpcmd); 3304 if (rcm_exec_cmd(grpcmd) != 0) { 3305 rcm_log_message(RCM_ERROR, _("IP: %s fail(%s): %s\n"), 3306 grpcmd, ifinst, strerror(errno)); 3307 } 3308 } 3309 3310 rcm_log_message(RCM_TRACE1, "IP: if_ipmp_config(%s) success\n", ifinst); 3311 3312 return (0); 3313 } 3314 3315 /* 3316 * if_mpathd_configure() - Determine configuration disposition of the interface 3317 */ 3318 static int 3319 if_mpathd_configure(char *syscmd, char *ifinst, int af, int ipmp) 3320 { 3321 char *tokens[MAXARGS]; 3322 char tspace[MAXLINE]; 3323 int ntok; 3324 char *addr; 3325 char *from_lifname; 3326 mpathd_cmd_t mpdcmd; 3327 int n; 3328 3329 rcm_log_message(RCM_TRACE1, "IP: if_mpathd_configure(%s): %s\n", 3330 ifinst, syscmd); 3331 3332 tokenize(syscmd, tokens, tspace, &ntok); 3333 if (ntok <= 0) 3334 return (0); 3335 3336 addr = tokens[3]; /* by default, third token is valid address */ 3337 for (n = 0; n < ntok; n++) { 3338 if (STREQ("set", tokens[n]) || 3339 STREQ("addif", tokens[n])) { 3340 addr = tokens[n+1]; 3341 if (addr == NULL) { /* invalid format */ 3342 return (-1); 3343 } else 3344 break; 3345 } 3346 } 3347 3348 /* Check std. commands or no failed over address */ 3349 if (STREQ("removeif", addr) || STREQ("group", addr) || 3350 ((from_lifname = get_mpathd_dest(addr, af)) == NULL)) { 3351 rcm_log_message(RCM_TRACE1, 3352 "IP: No failed-over host, exec %s\n", syscmd); 3353 if (rcm_exec_cmd(syscmd) != 0) { 3354 rcm_log_message(RCM_ERROR, 3355 _("IP: %s failed(%s): %s\n"), 3356 syscmd, ifinst, strerror(errno)); 3357 return (-1); 3358 } 3359 return (0); 3360 } 3361 3362 /* Check for non-IPMP failover scenarios */ 3363 if ((ipmp <= 0) && (from_lifname != NULL)) { 3364 /* Address already hosted on another NIC, return */ 3365 rcm_log_message(RCM_TRACE1, 3366 "IP: Non-IPMP failed-over host(%s): %s\n", 3367 ifinst, addr); 3368 return (0); 3369 } 3370 3371 /* 3372 * Valid failed-over host; have mpathd set the original index 3373 */ 3374 mpdcmd.cmd_command = MI_SETOINDEX; 3375 (void) strcpy(mpdcmd.from_lifname, from_lifname); 3376 (void) strcpy(mpdcmd.to_pifname, ifinst); 3377 if (af & CONFIG_AF_INET6) { 3378 mpdcmd.addr_family = AF_INET6; 3379 } else { 3380 mpdcmd.addr_family = AF_INET; 3381 } 3382 3383 /* Send command to in.mpathd(1M) */ 3384 rcm_log_message(RCM_TRACE1, 3385 "IP: Attempting setoindex from (%s) to (%s) ....\n", 3386 from_lifname, ifinst); 3387 3388 if (mpathd_send_cmd(&mpdcmd) < 0) { 3389 rcm_log_message(RCM_TRACE1, 3390 _("IP: mpathd set original index unsuccessful: %s\n"), 3391 strerror(errno)); 3392 return (-1); 3393 } 3394 3395 rcm_log_message(RCM_TRACE1, 3396 "IP: setoindex success (%s) to (%s)\n", 3397 from_lifname, ifinst); 3398 3399 return (0); 3400 } 3401 3402 /* 3403 * get_mpathd_addr() - Return current destination for lif; caller is 3404 * responsible to free memory allocated for address 3405 */ 3406 static char * 3407 get_mpathd_dest(char *addr, int family) 3408 { 3409 int sock; 3410 char *buf; 3411 struct lifnum lifn; 3412 struct lifconf lifc; 3413 struct lifreq *lifrp; 3414 sa_family_t af = AF_INET; /* IPv4 by default */ 3415 int i; 3416 struct lifreq lifreq; 3417 struct sockaddr_in *sin; 3418 struct sockaddr_in6 *sin6; 3419 struct hostent *hp; 3420 char *ifname = NULL; 3421 char *prefix = NULL; 3422 char addrstr[INET6_ADDRSTRLEN]; 3423 char ifaddr[INET6_ADDRSTRLEN]; 3424 int err; 3425 3426 if (addr == NULL) { 3427 return (NULL); 3428 } 3429 3430 rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s)\n", addr); 3431 3432 if (family & CONFIG_AF_INET6) { 3433 af = AF_INET6; 3434 } else { 3435 af = AF_INET; 3436 } 3437 3438 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) { 3439 rcm_log_message(RCM_ERROR, 3440 _("IP: failure opening %s socket: %s\n"), 3441 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno)); 3442 return (NULL); 3443 } 3444 3445 lifn.lifn_family = af; 3446 lifn.lifn_flags = 0; 3447 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 3448 rcm_log_message(RCM_ERROR, 3449 _("IP: SIOCLGIFNUM failed: %s\n"), 3450 strerror(errno)); 3451 (void) close(sock); 3452 return (NULL); 3453 } 3454 3455 if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) { 3456 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"), 3457 strerror(errno)); 3458 (void) close(sock); 3459 return (NULL); 3460 } 3461 3462 lifc.lifc_family = af; 3463 lifc.lifc_flags = 0; 3464 lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count; 3465 lifc.lifc_buf = buf; 3466 3467 if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 3468 rcm_log_message(RCM_ERROR, 3469 _("IP: SIOCGLIFCONF failed: %s\n"), 3470 strerror(errno)); 3471 free(buf); 3472 (void) close(sock); 3473 return (NULL); 3474 } 3475 3476 /* Filter out prefix address from netmask */ 3477 (void) strcpy(ifaddr, addr); 3478 if ((prefix = strchr(ifaddr, '/')) != NULL) { 3479 *prefix = '\0'; /* We care about the address part only */ 3480 } 3481 3482 /* Check for aliases */ 3483 hp = getipnodebyname(ifaddr, af, AI_DEFAULT, &err); 3484 if (hp) { 3485 if (inet_ntop(af, (void *)hp->h_addr_list[0], 3486 ifaddr, sizeof (ifaddr)) == NULL) { 3487 /* Restore original address and use it */ 3488 (void) strcpy(ifaddr, addr); 3489 if ((prefix = strchr(ifaddr, '/')) != NULL) { 3490 *prefix = '\0'; 3491 } 3492 } 3493 freehostent(hp); 3494 } 3495 rcm_log_message(RCM_TRACE2, "IP: ifaddr(%s) = %s\n", addr, ifaddr); 3496 3497 /* now search the interfaces */ 3498 lifrp = lifc.lifc_req; 3499 for (i = 0; i < lifn.lifn_count; i++, lifrp++) { 3500 (void) strcpy(lifreq.lifr_name, lifrp->lifr_name); 3501 /* Get the interface address for this interface */ 3502 if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) { 3503 rcm_log_message(RCM_ERROR, 3504 _("IP: SIOCGLIFADDR: %s\n"), strerror(errno)); 3505 free(buf); 3506 (void) close(sock); 3507 return (NULL); 3508 } 3509 3510 if (af == AF_INET6) { 3511 sin6 = (struct sockaddr_in6 *)&lifreq.lifr_addr; 3512 if (inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3513 addrstr, sizeof (addrstr)) == NULL) { 3514 continue; 3515 } 3516 } else { 3517 sin = (struct sockaddr_in *)&lifreq.lifr_addr; 3518 if (inet_ntop(AF_INET, (void *)&sin->sin_addr, 3519 addrstr, sizeof (addrstr)) == NULL) { 3520 continue; 3521 } 3522 } 3523 3524 if (STREQ(addrstr, ifaddr)) { 3525 /* Allocate memory to hold interface name */ 3526 if ((ifname = (char *)malloc(LIFNAMSIZ)) == NULL) { 3527 rcm_log_message(RCM_ERROR, 3528 _("IP: malloc: %s\n"), strerror(errno)); 3529 free(buf); 3530 (void) close(sock); 3531 return (NULL); 3532 } 3533 3534 /* Copy the interface name */ 3535 /* 3536 * (void) memcpy(ifname, lifrp->lifr_name, 3537 * sizeof (ifname)); 3538 * ifname[sizeof (ifname) - 1] = '\0'; 3539 */ 3540 (void) strcpy(ifname, lifrp->lifr_name); 3541 break; 3542 } 3543 } 3544 3545 (void) close(sock); 3546 free(buf); 3547 3548 if (ifname == NULL) 3549 rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s): none\n", 3550 addr); 3551 else 3552 rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s): %s\n", 3553 addr, ifname); 3554 3555 return (ifname); 3556 } 3557 3558 static int 3559 if_getcount(int af) 3560 { 3561 int sock; 3562 struct lifnum lifn; 3563 3564 rcm_log_message(RCM_TRACE1, "IP: if_getcount\n"); 3565 3566 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) { 3567 rcm_log_message(RCM_ERROR, 3568 _("IP: failure opening %s socket: %s\n"), 3569 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno)); 3570 return (-1); 3571 } 3572 3573 lifn.lifn_family = af; 3574 lifn.lifn_flags = 0; 3575 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 3576 rcm_log_message(RCM_ERROR, 3577 _("IP: SIOCLGIFNUM failed: %s\n"), 3578 strerror(errno)); 3579 (void) close(sock); 3580 return (-1); 3581 } 3582 (void) close(sock); 3583 3584 rcm_log_message(RCM_TRACE1, "IP: if_getcount success: %d\n", 3585 lifn.lifn_count); 3586 3587 return (lifn.lifn_count); 3588 } 3589 3590 /* 3591 * tokenize() - turn a command line into tokens; caller is responsible to 3592 * provide enough memory to hold all tokens 3593 */ 3594 static void 3595 tokenize(char *line, char **tokens, char *tspace, int *ntok) 3596 { 3597 char *cp; 3598 char *sp; 3599 3600 sp = tspace; 3601 cp = line; 3602 for (*ntok = 0; *ntok < MAXARGS; (*ntok)++) { 3603 tokens[*ntok] = sp; 3604 while (ISSPACE(*cp)) 3605 cp++; 3606 if (ISEOL(*cp)) 3607 break; 3608 do { 3609 *sp++ = *cp++; 3610 } while (!ISSPACE(*cp) && !ISEOL(*cp)); 3611 3612 *sp++ = '\0'; 3613 } 3614 } 3615