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