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