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 %I%"); 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 /* Ignore loopback and multipoint interfaces */ 1130 if (!(ifflags & IFF_MULTICAST) || (ifflags & IFF_LOOPBACK)) { 1131 rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n", 1132 pif.pi_ifname); 1133 return (0); 1134 } 1135 1136 /* Get the interface group name for this interface */ 1137 if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) { 1138 rcm_log_message(RCM_ERROR, 1139 _("IP: SIOCGLIFGROUPNAME(%s): %s\n"), 1140 lifreq.lifr_name, strerror(errno)); 1141 return (-1); 1142 } 1143 1144 /* copy the group name */ 1145 (void) memcpy(&pif.pi_grpname, &lifreq.lifr_groupname, 1146 sizeof (pif.pi_grpname)); 1147 pif.pi_grpname[sizeof (pif.pi_grpname) - 1] = '\0'; 1148 1149 /* Get the interface address for this interface */ 1150 if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) { 1151 rcm_log_message(RCM_ERROR, 1152 _("IP: SIOCGLIFADDR(%s): %s\n"), 1153 lifreq.lifr_name, strerror(errno)); 1154 return (-1); 1155 } 1156 (void) memcpy(&ifaddr, &lifreq.lifr_addr, sizeof (ifaddr)); 1157 1158 rsrc = get_link_resource(pif.pi_ifname); 1159 if (rsrc == NULL) { 1160 rcm_log_message(RCM_ERROR, 1161 _("IP: get_link_resource(%s) failed\n"), 1162 lifreq.lifr_name); 1163 return (-1); 1164 } 1165 1166 probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 1167 if (probe != NULL) { 1168 free(rsrc); 1169 probe->ip_cachestate &= ~(CACHE_IF_STALE); 1170 } else { 1171 if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) { 1172 /* malloc errors are bad */ 1173 free(rsrc); 1174 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"), 1175 strerror(errno)); 1176 return (-1); 1177 } 1178 1179 probe->ip_resource = rsrc; 1180 probe->ip_pif = NULL; 1181 probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY; 1182 probe->ip_cachestate |= CACHE_IF_NEW; 1183 1184 cache_insert(probe); 1185 } 1186 1187 probepif = probe->ip_pif; 1188 if (probepif != NULL) { 1189 /* Check if lifs need to be updated */ 1190 probelif = probepif->pi_lifs; 1191 while (probelif != NULL) { 1192 if ((probelif->li_ifnum == ifnumber) && 1193 (probelif->li_addr.family == ifaddr.ss_family)) { 1194 1195 rcm_log_message(RCM_TRACE2, 1196 "IP: refreshing lifs for %s, ifnum=%d\n", 1197 pif.pi_ifname, probelif->li_ifnum); 1198 1199 /* refresh lif properties */ 1200 (void) memcpy(&probelif->li_addr, &ifaddr, 1201 sizeof (probelif->li_addr)); 1202 1203 probelif->li_ifflags = ifflags; 1204 1205 lif_listed++; 1206 probelif->li_cachestate &= ~(CACHE_IF_STALE); 1207 break; 1208 } 1209 probelif = probelif->li_next; 1210 } 1211 } 1212 1213 if (probepif == NULL) { 1214 if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) { 1215 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"), 1216 strerror(errno)); 1217 if (probe->ip_pif == NULL) { 1218 /* we created it, so clean it up */ 1219 free(probe); 1220 } 1221 return (-1); 1222 } 1223 1224 probe->ip_pif = probepif; 1225 1226 /* Save interface name */ 1227 (void) memcpy(&probepif->pi_ifname, &pif.pi_ifname, 1228 sizeof (pif.pi_ifname)); 1229 } 1230 1231 /* save pif properties */ 1232 (void) memcpy(&probepif->pi_grpname, &pif.pi_grpname, 1233 sizeof (pif.pi_grpname)); 1234 1235 /* add lif, if this is a lif and it is not in cache */ 1236 if (!lif_listed) { 1237 rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n", 1238 pif.pi_ifname); 1239 1240 if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) { 1241 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"), 1242 strerror(errno)); 1243 return (-1); 1244 } 1245 1246 /* save lif properties */ 1247 (void) memcpy(&probelif->li_addr, &ifaddr, 1248 sizeof (probelif->li_addr)); 1249 1250 probelif->li_ifnum = ifnumber; 1251 probelif->li_ifflags = ifflags; 1252 1253 /* insert us at the head of the lif list */ 1254 probelif->li_next = probepif->pi_lifs; 1255 if (probelif->li_next != NULL) { 1256 probelif->li_next->li_prev = probelif; 1257 } 1258 probelif->li_prev = NULL; 1259 probelif->li_pif = probepif; 1260 1261 probepif->pi_lifs = probelif; 1262 } 1263 1264 rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n", 1265 probe->ip_resource); 1266 1267 return (0); 1268 } 1269 1270 /* 1271 * update_ipifs() - Determine all network interfaces in the system 1272 * Call with cache_lock held 1273 */ 1274 static int 1275 update_ipifs(rcm_handle_t *hd, int af) 1276 { 1277 int sock; 1278 char *buf; 1279 struct lifnum lifn; 1280 struct lifconf lifc; 1281 struct lifreq *lifrp; 1282 int i; 1283 1284 rcm_log_message(RCM_TRACE2, "IP: update_ipifs\n"); 1285 1286 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) { 1287 rcm_log_message(RCM_ERROR, 1288 _("IP: failure opening %s socket: %s\n"), 1289 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno)); 1290 return (-1); 1291 } 1292 1293 lifn.lifn_family = af; 1294 lifn.lifn_flags = 0; 1295 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 1296 rcm_log_message(RCM_ERROR, 1297 _("IP: SIOCLGIFNUM failed: %s\n"), 1298 strerror(errno)); 1299 (void) close(sock); 1300 return (-1); 1301 } 1302 1303 if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) { 1304 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"), 1305 strerror(errno)); 1306 (void) close(sock); 1307 return (-1); 1308 } 1309 1310 lifc.lifc_family = af; 1311 lifc.lifc_flags = 0; 1312 lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count; 1313 lifc.lifc_buf = buf; 1314 1315 if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 1316 rcm_log_message(RCM_ERROR, 1317 _("IP: SIOCGLIFCONF failed: %s\n"), 1318 strerror(errno)); 1319 free(buf); 1320 (void) close(sock); 1321 return (-1); 1322 } 1323 1324 /* now we need to search for active interfaces */ 1325 lifrp = lifc.lifc_req; 1326 for (i = 0; i < lifn.lifn_count; i++) { 1327 (void) update_pif(hd, af, sock, lifrp); 1328 lifrp++; 1329 } 1330 1331 free(buf); 1332 (void) close(sock); 1333 return (0); 1334 } 1335 1336 /* 1337 * update_cache() - Update cache with latest interface info 1338 */ 1339 static int 1340 update_cache(rcm_handle_t *hd) 1341 { 1342 ip_cache_t *probe; 1343 struct ip_lif *lif; 1344 struct ip_lif *nextlif; 1345 int rv; 1346 int i; 1347 1348 rcm_log_message(RCM_TRACE2, "IP: update_cache\n"); 1349 1350 (void) mutex_lock(&cache_lock); 1351 1352 /* first we walk the entire cache, marking each entry stale */ 1353 probe = cache_head.ip_next; 1354 while (probe != &cache_tail) { 1355 probe->ip_cachestate |= CACHE_IF_STALE; 1356 if ((probe->ip_pif != NULL) && 1357 ((lif = probe->ip_pif->pi_lifs) != NULL)) { 1358 while (lif != NULL) { 1359 lif->li_cachestate |= CACHE_IF_STALE; 1360 lif = lif->li_next; 1361 } 1362 } 1363 probe = probe->ip_next; 1364 } 1365 1366 rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n"); 1367 if (update_ipifs(hd, AF_INET) < 0) { 1368 (void) mutex_unlock(&cache_lock); 1369 return (-1); 1370 } 1371 1372 rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n"); 1373 if (update_ipifs(hd, AF_INET6) < 0) { 1374 (void) mutex_unlock(&cache_lock); 1375 return (-1); 1376 } 1377 1378 probe = cache_head.ip_next; 1379 /* unregister devices that are not offlined and still in cache */ 1380 while (probe != &cache_tail) { 1381 ip_cache_t *freeit; 1382 if ((probe->ip_pif != NULL) && 1383 ((lif = probe->ip_pif->pi_lifs) != NULL)) { 1384 /* clear stale lifs */ 1385 while (lif != NULL) { 1386 if (lif->li_cachestate & CACHE_IF_STALE) { 1387 nextlif = lif->li_next; 1388 if (lif->li_prev != NULL) 1389 lif->li_prev->li_next = nextlif; 1390 if (nextlif != NULL) 1391 nextlif->li_prev = lif->li_prev; 1392 if (probe->ip_pif->pi_lifs == lif) 1393 probe->ip_pif->pi_lifs = 1394 nextlif; 1395 for (i = 0; i < IP_MAX_MODS; i++) { 1396 free(lif->li_modules[i]); 1397 } 1398 free(lif->li_reconfig); 1399 free(lif); 1400 lif = nextlif; 1401 } else { 1402 lif = lif->li_next; 1403 } 1404 } 1405 } 1406 if ((probe->ip_cachestate & CACHE_IF_STALE) && 1407 !(probe->ip_cachestate & CACHE_IF_OFFLINED)) { 1408 (void) rcm_unregister_interest(hd, probe->ip_resource, 1409 0); 1410 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n", 1411 probe->ip_resource); 1412 freeit = probe; 1413 probe = probe->ip_next; 1414 cache_remove(freeit); 1415 free_node(freeit); 1416 continue; 1417 } 1418 1419 if (!(probe->ip_cachestate & CACHE_IF_NEW)) { 1420 probe = probe->ip_next; 1421 continue; 1422 } 1423 1424 rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL); 1425 if (rv != RCM_SUCCESS) { 1426 rcm_log_message(RCM_ERROR, 1427 _("IP: failed to register %s\n"), 1428 probe->ip_resource); 1429 (void) mutex_unlock(&cache_lock); 1430 return (-1); 1431 } else { 1432 rcm_log_message(RCM_DEBUG, "IP: registered %s\n", 1433 probe->ip_resource); 1434 probe->ip_cachestate &= ~(CACHE_IF_NEW); 1435 } 1436 probe = probe->ip_next; 1437 } 1438 1439 (void) mutex_unlock(&cache_lock); 1440 return (0); 1441 } 1442 1443 /* 1444 * free_cache() - Empty the cache 1445 */ 1446 static void 1447 free_cache() 1448 { 1449 ip_cache_t *probe; 1450 1451 rcm_log_message(RCM_TRACE2, "IP: free_cache\n"); 1452 1453 (void) mutex_lock(&cache_lock); 1454 probe = cache_head.ip_next; 1455 while (probe != &cache_tail) { 1456 cache_remove(probe); 1457 free_node(probe); 1458 probe = cache_head.ip_next; 1459 } 1460 (void) mutex_unlock(&cache_lock); 1461 } 1462 1463 /* 1464 * ip_log_err() - RCM error log wrapper 1465 */ 1466 static void 1467 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg) 1468 { 1469 char *ifname = NULL; 1470 int len; 1471 const char *errfmt; 1472 char *error; 1473 1474 if ((node != NULL) && (node->ip_pif != NULL) && 1475 (node->ip_pif->pi_ifname != NULL)) { 1476 ifname = node->ip_pif->pi_ifname; 1477 } 1478 1479 if (errorp != NULL) 1480 *errorp = NULL; 1481 1482 if (ifname == NULL) { 1483 rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg); 1484 errfmt = _("IP: %s"); 1485 len = strlen(errfmt) + strlen(errmsg) + 1; 1486 if (error = (char *)calloc(1, len)) { 1487 (void) sprintf(error, errfmt, errmsg); 1488 } 1489 } else { 1490 rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname); 1491 errfmt = _("IP: %s(%s)"); 1492 len = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1; 1493 if (error = (char *)calloc(1, len)) { 1494 (void) sprintf(error, errfmt, errmsg, ifname); 1495 } 1496 } 1497 1498 if (errorp != NULL) 1499 *errorp = error; 1500 } 1501 1502 1503 /* 1504 * if_cfginfo() - Save off the config info for all interfaces 1505 */ 1506 static int 1507 if_cfginfo(ip_cache_t *node, uint_t force) 1508 { 1509 ip_lif_t *lif; 1510 ip_pif_t *pif; 1511 int i; 1512 FILE *fp; 1513 char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ]; 1514 char buf[MAX_RECONFIG_SIZE]; 1515 1516 rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource); 1517 1518 pif = node->ip_pif; 1519 lif = pif->pi_lifs; 1520 1521 while (lif != NULL) { 1522 /* Make a list of modules pushed and save */ 1523 if (lif->li_ifnum == 0) { /* physical instance */ 1524 if (get_modlist(pif->pi_ifname, lif) == -1) { 1525 rcm_log_message(RCM_ERROR, 1526 _("IP: get modlist error (%s) %s\n"), 1527 pif->pi_ifname, strerror(errno)); 1528 (void) clr_cfg_state(pif); 1529 return (-1); 1530 } 1531 1532 if (!force) { 1533 /* Look if unknown modules have been inserted */ 1534 for (i = (lif->li_modcnt - 2); i > 0; i--) { 1535 if (modop(pif->pi_ifname, 1536 lif->li_modules[i], 1537 i, MOD_CHECK) == -1) { 1538 rcm_log_message(RCM_ERROR, 1539 _("IP: module %s@%d\n"), 1540 lif->li_modules[i], i); 1541 (void) clr_cfg_state(pif); 1542 return (-1); 1543 } 1544 } 1545 } 1546 1547 /* Last module is the device driver, so ignore that */ 1548 for (i = (lif->li_modcnt - 2); i > 0; i--) { 1549 rcm_log_message(RCM_TRACE2, 1550 "IP: modremove Pos = %d, Module = %s \n", 1551 i, lif->li_modules[i]); 1552 if (modop(pif->pi_ifname, lif->li_modules[i], 1553 i, MOD_REMOVE) == -1) { 1554 while (i != (lif->li_modcnt - 2)) { 1555 if (modop(pif->pi_ifname, 1556 lif->li_modules[i], 1557 i, MOD_INSERT) == -1) { 1558 /* Gross error */ 1559 rcm_log_message( 1560 RCM_ERROR, 1561 _("IP: if_cfginfo" 1562 "(%s) %s\n"), 1563 pif->pi_ifname, 1564 strerror(errno)); 1565 clr_cfg_state(pif); 1566 return (-1); 1567 } 1568 i++; 1569 } 1570 rcm_log_message( 1571 RCM_ERROR, 1572 _("IP: if_cfginfo(%s): modremove " 1573 "%s failed: %s\n"), pif->pi_ifname, 1574 lif->li_modules[i], 1575 strerror(errno)); 1576 clr_cfg_state(pif); 1577 return (-1); 1578 } 1579 } 1580 } 1581 1582 /* Save reconfiguration information */ 1583 if (lif->li_ifflags & IFF_IPV4) { 1584 (void) snprintf(syscmd, sizeof (syscmd), 1585 "%s %s:%d configinfo\n", USR_SBIN_IFCONFIG, 1586 pif->pi_ifname, lif->li_ifnum); 1587 } else if (lif->li_ifflags & IFF_IPV6) { 1588 (void) snprintf(syscmd, sizeof (syscmd), 1589 "%s %s:%d inet6 configinfo\n", USR_SBIN_IFCONFIG, 1590 pif->pi_ifname, lif->li_ifnum); 1591 } 1592 rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd); 1593 1594 /* open a pipe to retrieve reconfiguration info */ 1595 if ((fp = popen(syscmd, "r")) == NULL) { 1596 rcm_log_message(RCM_ERROR, 1597 _("IP: ifconfig configinfo error (%s:%d) %s\n"), 1598 pif->pi_ifname, lif->li_ifnum, strerror(errno)); 1599 (void) clr_cfg_state(pif); 1600 return (-1); 1601 } 1602 bzero(buf, MAX_RECONFIG_SIZE); 1603 1604 if (fgets(buf, MAX_RECONFIG_SIZE, fp) == 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) pclose(fp); 1609 (void) clr_cfg_state(pif); 1610 return (-1); 1611 } 1612 (void) pclose(fp); 1613 1614 lif->li_reconfig = malloc(strlen(buf)+1); 1615 if (lif->li_reconfig == NULL) { 1616 rcm_log_message(RCM_ERROR, 1617 _("IP: malloc error (%s) %s\n"), 1618 pif->pi_ifname, strerror(errno)); 1619 (void) clr_cfg_state(pif); 1620 return (-1); 1621 } 1622 (void) strcpy(lif->li_reconfig, buf); 1623 rcm_log_message(RCM_DEBUG, 1624 "IP: if_cfginfo: reconfig string(%s:%d) = %s\n", 1625 pif->pi_ifname, lif->li_ifnum, lif->li_reconfig); 1626 1627 lif = lif->li_next; 1628 } 1629 1630 return (0); 1631 } 1632 1633 /* 1634 * if_unplumb() - Unplumb the interface 1635 * Save off the modlist, ifconfig options and unplumb. 1636 * Fail, if an unknown module lives between IP and driver and 1637 * force is not set 1638 * Call with cache_lock held 1639 */ 1640 static int 1641 if_unplumb(ip_cache_t *node) 1642 { 1643 ip_lif_t *lif; 1644 ip_pif_t *pif; 1645 int ipv4 = 0, ipv6 = 0; 1646 char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ]; 1647 1648 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource); 1649 1650 pif = node->ip_pif; 1651 lif = pif->pi_lifs; 1652 1653 while (lif != NULL) { 1654 if (lif->li_ifflags & IFF_IPV4) { 1655 ipv4++; 1656 } else if (lif->li_ifflags & IFF_IPV6) { 1657 ipv6++; 1658 } else { 1659 /* Unlikely case */ 1660 rcm_log_message(RCM_DEBUG, 1661 "IP: Unplumb ignored (%s:%d)\n", 1662 pif->pi_ifname, lif->li_ifnum); 1663 lif = lif->li_next; 1664 continue; 1665 } 1666 lif = lif->li_next; 1667 } 1668 1669 /* Unplumb the physical interface */ 1670 if (ipv4) { 1671 rcm_log_message(RCM_TRACE2, 1672 "IP: if_unplumb: ifconfig %s unplumb\n", pif->pi_ifname); 1673 (void) snprintf(syscmd, sizeof (syscmd), "%s %s unplumb\n", 1674 USR_SBIN_IFCONFIG, pif->pi_ifname); 1675 if (rcm_exec_cmd(syscmd) != 0) { 1676 rcm_log_message(RCM_ERROR, 1677 _("IP: Cannot unplumb (%s) %s\n"), 1678 pif->pi_ifname, strerror(errno)); 1679 return (-1); 1680 } 1681 } 1682 if (ipv6) { 1683 rcm_log_message(RCM_TRACE2, 1684 "IP: if_unplumb: ifconfig %s inet6 unplumb\n", 1685 pif->pi_ifname); 1686 (void) snprintf(syscmd, sizeof (syscmd), 1687 "%s %s inet6 unplumb\n", USR_SBIN_IFCONFIG, pif->pi_ifname); 1688 if (rcm_exec_cmd(syscmd) != 0) { 1689 rcm_log_message(RCM_ERROR, 1690 _("IP: Cannot unplumb (%s) %s\n"), 1691 pif->pi_ifname, strerror(errno)); 1692 return (-1); 1693 } 1694 } 1695 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n", 1696 node->ip_resource); 1697 1698 return (0); 1699 } 1700 1701 /* 1702 * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface 1703 * instances and the logical interfaces in order, restoring 1704 * all ifconfig options 1705 * Call with cache_lock held 1706 */ 1707 static int 1708 if_replumb(ip_cache_t *node) 1709 { 1710 ip_lif_t *lif; 1711 ip_pif_t *pif; 1712 int i; 1713 char syscmd[LIFNAMSIZ+MAXPATHLEN]; /* must be big enough */ 1714 int max_ipv4 = 0, max_ipv6 = 0; 1715 1716 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource); 1717 1718 /* 1719 * Be extra careful about bringing up the interfaces in the 1720 * correct order: 1721 * - First plumb in the physical interface instances 1722 * - modinsert the necessary modules@pos 1723 * - Next, add the logical interfaces being careful about 1724 * the order, (follow the cached interface number li_ifnum order) 1725 */ 1726 1727 pif = node->ip_pif; 1728 lif = pif->pi_lifs; 1729 1730 /* 1731 * Make a first pass to plumb in physical interfaces and get a count 1732 * of the max logical interfaces 1733 */ 1734 while (lif != NULL) { 1735 if (lif->li_ifflags & IFF_IPV4) { 1736 if (lif->li_ifnum > max_ipv4) { 1737 max_ipv4 = lif->li_ifnum; 1738 } 1739 } else if (lif->li_ifflags & IFF_IPV6) { 1740 if (lif->li_ifnum > max_ipv6) { 1741 max_ipv6 = lif->li_ifnum; 1742 } 1743 } else { 1744 /* Unlikely case */ 1745 rcm_log_message(RCM_DEBUG, 1746 "IP: Re-plumb ignored (%s:%d)\n", 1747 pif->pi_ifname, lif->li_ifnum); 1748 lif = lif->li_next; 1749 continue; 1750 } 1751 1752 if (lif->li_ifnum == 0) { /* physical interface instance */ 1753 if ((lif->li_ifflags & IFF_NOFAILOVER) || 1754 (strcmp(pif->pi_grpname, "") == 0)) { 1755 (void) snprintf(syscmd, sizeof (syscmd), 1756 "%s %s\n", USR_SBIN_IFCONFIG, 1757 lif->li_reconfig); 1758 } else if (lif->li_ifflags & IFF_IPV4) { 1759 (void) snprintf(syscmd, sizeof (syscmd), 1760 "%s %s inet plumb group %s\n", 1761 USR_SBIN_IFCONFIG, 1762 pif->pi_ifname, pif->pi_grpname); 1763 } else if (lif->li_ifflags & IFF_IPV6) { 1764 (void) snprintf(syscmd, sizeof (syscmd), 1765 "%s %s inet6 plumb group %s\n", 1766 USR_SBIN_IFCONFIG, 1767 pif->pi_ifname, pif->pi_grpname); 1768 } 1769 1770 rcm_log_message(RCM_TRACE2, 1771 "IP: if_replumb: %s\n", syscmd); 1772 if (rcm_exec_cmd(syscmd) != 0) { 1773 rcm_log_message(RCM_ERROR, 1774 _("IP: Cannot plumb (%s) %s\n"), 1775 pif->pi_ifname, strerror(errno)); 1776 return (-1); 1777 } 1778 1779 rcm_log_message(RCM_TRACE2, 1780 "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt); 1781 /* modinsert modules in order, ignore driver(last) */ 1782 for (i = 0; i < (lif->li_modcnt - 1); i++) { 1783 rcm_log_message(RCM_TRACE2, 1784 "IP: modinsert: Pos = %d Mod = %s\n", 1785 i, lif->li_modules[i]); 1786 if (modop(pif->pi_ifname, lif->li_modules[i], i, 1787 MOD_INSERT) == -1) { 1788 rcm_log_message(RCM_ERROR, 1789 _("IP: modinsert error(%s)\n"), 1790 pif->pi_ifname); 1791 return (-1); 1792 } 1793 } 1794 } 1795 1796 lif = lif->li_next; 1797 } 1798 1799 /* Now, add all the logical interfaces in the correct order */ 1800 for (i = 1; i <= MAX(max_ipv6, max_ipv4); i++) { 1801 /* reset lif through every iteration */ 1802 lif = pif->pi_lifs; 1803 while (lif != NULL) { 1804 if (((lif->li_ifflags & IFF_NOFAILOVER) || 1805 (strcmp(pif->pi_grpname, "") == 0)) && 1806 (lif->li_ifnum == i)) { 1807 /* Plumb in the logical interface */ 1808 (void) snprintf(syscmd, sizeof (syscmd), 1809 "%s %s\n", USR_SBIN_IFCONFIG, 1810 lif->li_reconfig); 1811 rcm_log_message(RCM_TRACE2, 1812 "IP: if_replumb: %s\n", syscmd); 1813 if (rcm_exec_cmd(syscmd) != 0) { 1814 rcm_log_message(RCM_ERROR, 1815 _("IP: Cannot addif (%s:%d) " 1816 "%s\n"), 1817 pif->pi_ifname, i, strerror(errno)); 1818 return (-1); 1819 } 1820 } 1821 lif = lif->li_next; 1822 } 1823 } 1824 1825 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n", 1826 node->ip_resource); 1827 1828 return (0); 1829 } 1830 1831 /* 1832 * clr_cfg_state() - Cleanup after errors in unplumb 1833 */ 1834 static void 1835 clr_cfg_state(ip_pif_t *pif) 1836 { 1837 ip_lif_t *lif; 1838 int i; 1839 1840 lif = pif->pi_lifs; 1841 1842 while (lif != NULL) { 1843 lif->li_modcnt = 0; 1844 free(lif->li_reconfig); 1845 lif->li_reconfig = NULL; 1846 for (i = 0; i < IP_MAX_MODS; i++) { 1847 free(lif->li_modules[i]); 1848 lif->li_modules[i] = NULL; 1849 } 1850 lif = lif->li_next; 1851 } 1852 } 1853 1854 /* 1855 * ip_ipmp_offline() - Failover from if_from to if_to using a 1856 * minimum redudancy of min_red. This uses IPMPs 1857 * "offline" mechanism to achieve the failover. 1858 */ 1859 static int 1860 ip_ipmp_offline(ip_cache_t *if_from, ip_cache_t *if_to) 1861 { 1862 mpathd_cmd_t mpdcmd; 1863 1864 if ((if_from == NULL) || (if_from->ip_pif == NULL) || 1865 (if_from->ip_pif->pi_ifname == NULL)) { 1866 return (-1); 1867 } 1868 1869 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n"); 1870 1871 mpdcmd.cmd_command = MI_OFFLINE; 1872 (void) strcpy(mpdcmd.cmd_ifname, if_from->ip_pif->pi_ifname); 1873 1874 if ((if_to != NULL) && (if_to->ip_pif != NULL) && 1875 (if_to->ip_pif->pi_ifname != NULL)) { 1876 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline (%s)->(%s)\n", 1877 if_from->ip_pif->pi_ifname, if_to->ip_pif->pi_ifname); 1878 (void) strncpy(mpdcmd.cmd_movetoif, if_to->ip_pif->pi_ifname, 1879 sizeof (mpdcmd.cmd_movetoif)); 1880 mpdcmd.cmd_movetoif[sizeof (mpdcmd.cmd_movetoif) - 1] = '\0'; 1881 } else { 1882 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline (%s)->(any)\n", 1883 if_from->ip_pif->pi_ifname); 1884 (void) strcpy(mpdcmd.cmd_movetoif, ""); /* signifies any */ 1885 } 1886 mpdcmd.cmd_min_red = if_from->ip_ifred; 1887 1888 if (mpathd_send_cmd(&mpdcmd) < 0) { 1889 rcm_log_message(RCM_ERROR, 1890 _("IP: mpathd offline error: %s\n"), 1891 strerror(errno)); 1892 return (-1); 1893 } 1894 1895 rcm_log_message(RCM_TRACE1, "IP: ipmp offline success\n"); 1896 return (0); 1897 } 1898 1899 /* 1900 * ip_ipmp_undo_offline() - Undo prior offline of the interface. 1901 * This uses IPMPs "undo offline" feature. 1902 */ 1903 static int 1904 ip_ipmp_undo_offline(ip_cache_t *node) 1905 { 1906 mpathd_cmd_t mpdcmd; 1907 1908 mpdcmd.cmd_command = MI_UNDO_OFFLINE; 1909 (void) strcpy(mpdcmd.cmd_ifname, node->ip_pif->pi_ifname); 1910 1911 if (mpathd_send_cmd(&mpdcmd) < 0) { 1912 rcm_log_message(RCM_ERROR, 1913 _("IP: mpathd error: %s\n"), 1914 strerror(errno)); 1915 return (-1); 1916 } 1917 1918 rcm_log_message(RCM_TRACE1, "IP: ipmp undo offline success\n"); 1919 return (0); 1920 } 1921 1922 /* 1923 * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a 1924 * dynamically allocated string containing the associated link resource 1925 * name ("SUNW_datalink/<linkid>"). 1926 */ 1927 static char * 1928 get_link_resource(const char *link) 1929 { 1930 char errmsg[DLADM_STRSIZE]; 1931 datalink_id_t linkid; 1932 uint32_t flags; 1933 char *resource; 1934 dladm_status_t status; 1935 1936 if ((status = dladm_name2info(link, &linkid, &flags, NULL, NULL)) 1937 != DLADM_STATUS_OK) { 1938 goto fail; 1939 } 1940 1941 if (!(flags & DLADM_OPT_ACTIVE)) { 1942 status = DLADM_STATUS_FAILED; 1943 goto fail; 1944 } 1945 1946 resource = malloc(RCM_LINK_RESOURCE_MAX); 1947 if (resource == NULL) { 1948 rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"), 1949 strerror(errno), link); 1950 return (NULL); 1951 } 1952 1953 (void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u", 1954 RCM_LINK_PREFIX, linkid); 1955 1956 return (resource); 1957 1958 fail: 1959 rcm_log_message(RCM_ERROR, 1960 _("IP: get_link_resource for %s error(%s)\n"), 1961 link, dladm_status2str(status, errmsg)); 1962 return (NULL); 1963 } 1964 1965 /* 1966 * if_get_flags() - Return the cached physical interface flags 1967 * Call with cache_lock held 1968 */ 1969 static uint64_t 1970 if_get_flags(ip_pif_t *pif) 1971 { 1972 ip_lif_t *lif; 1973 1974 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) { 1975 if (lif->li_ifnum == 0) { 1976 return (lif->li_ifflags & RCM_PIF_FLAGS); 1977 } 1978 } 1979 return (0); 1980 } 1981 1982 /* 1983 * mpathd_send_cmd() - Sends the command to in.mpathd. 1984 */ 1985 static int 1986 mpathd_send_cmd(mpathd_cmd_t *mpd) 1987 { 1988 mpathd_unoffline_t mpc; 1989 struct mpathd_response mpr; 1990 int i; 1991 int s; 1992 1993 rcm_log_message(RCM_TRACE1, "IP: mpathd_send_cmd \n"); 1994 1995 for (i = 0; i < MPATHD_MAX_RETRIES; i++) { 1996 s = connect_to_mpathd(AF_INET); 1997 if (s == -1) { 1998 s = connect_to_mpathd(AF_INET6); 1999 if (s == -1) { 2000 rcm_log_message(RCM_ERROR, 2001 _("IP: Cannot talk to mpathd\n")); 2002 return (-1); 2003 } 2004 } 2005 switch (mpd->cmd_command) { 2006 case MI_OFFLINE : 2007 rcm_log_message(RCM_TRACE1, "IP: MI_OFFLINE: " 2008 "(%s)->(%s) redundancy = %d\n", mpd->cmd_ifname, 2009 mpd->cmd_movetoif, mpd->cmd_min_red); 2010 2011 if (write(s, mpd, sizeof (mpathd_cmd_t)) != 2012 sizeof (mpathd_cmd_t)) { 2013 rcm_log_message(RCM_ERROR, 2014 _("IP: mpathd write: %s\n"), 2015 strerror(errno)); 2016 (void) close(s); 2017 return (-1); 2018 } 2019 break; 2020 2021 case MI_SETOINDEX : 2022 rcm_log_message(RCM_TRACE1, "IP: MI_SETOINDEX: " 2023 "(%s)->(%s) family = %d\n", mpd->from_lifname, 2024 mpd->to_pifname, mpd->addr_family); 2025 2026 if (write(s, mpd, sizeof (mpathd_cmd_t)) != 2027 sizeof (mpathd_cmd_t)) { 2028 rcm_log_message(RCM_ERROR, 2029 _("IP: mpathd write: %s\n"), 2030 strerror(errno)); 2031 (void) close(s); 2032 return (-1); 2033 } 2034 break; 2035 2036 case MI_UNDO_OFFLINE: 2037 /* mpathd checks for exact size of the message */ 2038 mpc.cmd_command = mpd->cmd_command; 2039 (void) strcpy(mpc.cmd_ifname, mpd->cmd_ifname); 2040 2041 rcm_log_message(RCM_TRACE1, "IP: MI_UNDO_OFFLINE: " 2042 "(%s)\n", mpd->cmd_ifname); 2043 2044 if (write(s, &mpc, sizeof (mpathd_unoffline_t)) != 2045 sizeof (mpathd_unoffline_t)) { 2046 rcm_log_message(RCM_ERROR, 2047 _("IP: mpathd write: %s\n"), 2048 strerror(errno)); 2049 (void) close(s); 2050 return (-1); 2051 } 2052 break; 2053 default : 2054 rcm_log_message(RCM_ERROR, 2055 _("IP: unsupported mpathd command\n")); 2056 (void) close(s); 2057 return (-1); 2058 } 2059 2060 bzero(&mpr, sizeof (struct mpathd_response)); 2061 /* Read the result from mpathd */ 2062 if (read(s, &mpr, sizeof (struct mpathd_response)) != 2063 sizeof (struct mpathd_response)) { 2064 rcm_log_message(RCM_ERROR, 2065 _("IP: mpathd read : %s\n"), strerror(errno)); 2066 (void) close(s); 2067 return (-1); 2068 } 2069 2070 (void) close(s); 2071 if (mpr.resp_mpathd_err == 0) { 2072 rcm_log_message(RCM_TRACE1, 2073 "IP: mpathd_send_cmd success\n"); 2074 return (0); /* Successful */ 2075 } 2076 2077 if (mpr.resp_mpathd_err == MPATHD_SYS_ERROR) { 2078 if (mpr.resp_sys_errno == EAGAIN) { 2079 (void) sleep(1); 2080 rcm_log_message(RCM_DEBUG, 2081 "IP: mpathd retrying\n"); 2082 continue; /* Retry */ 2083 } 2084 errno = mpr.resp_sys_errno; 2085 rcm_log_message(RCM_WARNING, 2086 _("IP: mpathd_send_cmd error: %s\n"), 2087 strerror(errno)); 2088 } else if (mpr.resp_mpathd_err == MPATHD_MIN_RED_ERROR) { 2089 errno = EIO; 2090 rcm_log_message(RCM_ERROR, _("IP: in.mpathd(1M): " 2091 "Minimum redundancy not met\n")); 2092 } else { 2093 rcm_log_message(RCM_ERROR, 2094 _("IP: mpathd_send_cmd error\n")); 2095 } 2096 /* retry */ 2097 } 2098 2099 rcm_log_message(RCM_ERROR, 2100 _("IP: mpathd_send_cmd failed %d retries\n"), MPATHD_MAX_RETRIES); 2101 return (-1); 2102 } 2103 2104 /* 2105 * Returns -1 on failure. Returns the socket file descriptor on 2106 * success. 2107 */ 2108 static int 2109 connect_to_mpathd(int family) 2110 { 2111 int s; 2112 struct sockaddr_storage ss; 2113 struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 2114 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 2115 struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; 2116 int addrlen; 2117 int ret; 2118 int on; 2119 2120 rcm_log_message(RCM_TRACE1, "IP: connect_to_mpathd\n"); 2121 2122 s = socket(family, SOCK_STREAM, 0); 2123 if (s < 0) { 2124 rcm_log_message(RCM_ERROR, 2125 _("IP: mpathd socket: %s\n"), strerror(errno)); 2126 return (-1); 2127 } 2128 bzero((char *)&ss, sizeof (ss)); 2129 ss.ss_family = family; 2130 /* 2131 * Need to bind to a privelged port. For non-root, this 2132 * will fail. in.mpathd verifies that only commands coming 2133 * from priveleged ports succeed so that the ordinary user 2134 * can't issue offline commands. 2135 */ 2136 on = 1; 2137 if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on, 2138 sizeof (on)) < 0) { 2139 rcm_log_message(RCM_ERROR, 2140 _("IP: mpathd setsockopt: TCP_ANONPRIVBIND: %s\n"), 2141 strerror(errno)); 2142 return (-1); 2143 } 2144 switch (family) { 2145 case AF_INET: 2146 sin->sin_port = 0; 2147 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 2148 addrlen = sizeof (struct sockaddr_in); 2149 break; 2150 case AF_INET6: 2151 sin6->sin6_port = 0; 2152 sin6->sin6_addr = loopback_addr; 2153 addrlen = sizeof (struct sockaddr_in6); 2154 break; 2155 } 2156 ret = bind(s, (struct sockaddr *)&ss, addrlen); 2157 if (ret != 0) { 2158 rcm_log_message(RCM_ERROR, 2159 _("IP: mpathd bind: %s\n"), strerror(errno)); 2160 return (-1); 2161 } 2162 switch (family) { 2163 case AF_INET: 2164 sin->sin_port = htons(MPATHD_PORT); 2165 break; 2166 case AF_INET6: 2167 sin6->sin6_port = htons(MPATHD_PORT); 2168 break; 2169 } 2170 ret = connect(s, (struct sockaddr *)&ss, addrlen); 2171 if (ret != 0) { 2172 if (errno == ECONNREFUSED) { 2173 /* in.mpathd is not running, start it */ 2174 if (rcm_exec_cmd(MPATHD_PATH) == -1) { 2175 rcm_log_message(RCM_ERROR, 2176 _("IP: mpathd exec: %s\n"), 2177 strerror(errno)); 2178 return (-1); 2179 } 2180 ret = connect(s, (struct sockaddr *)&ss, addrlen); 2181 } 2182 if (ret != 0) { 2183 rcm_log_message(RCM_ERROR, 2184 _("IP: mpathd connect: %s\n"), strerror(errno)); 2185 return (-1); 2186 } 2187 } 2188 on = 0; 2189 if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on, 2190 sizeof (on)) < 0) { 2191 rcm_log_message(RCM_ERROR, 2192 _("IP: mpathd setsockopt TCP_ANONPRIVBIND: %s\n"), 2193 strerror(errno)); 2194 return (-1); 2195 } 2196 2197 rcm_log_message(RCM_TRACE1, "IP: connect_to_mpathd success\n"); 2198 2199 return (s); 2200 } 2201 2202 /* 2203 * modop() - Remove/insert a module 2204 */ 2205 static int 2206 modop(char *name, char *arg, int pos, char op) 2207 { 2208 char syscmd[LIFNAMSIZ+MAXPATHLEN]; /* must be big enough */ 2209 2210 rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name); 2211 2212 /* Nothing to do with "ip", "arp" */ 2213 if ((arg == NULL) || (strcmp(arg, "") == 0) || 2214 STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) { 2215 rcm_log_message(RCM_TRACE1, "IP: modop success\n"); 2216 return (0); 2217 } 2218 2219 if (op == MOD_CHECK) { 2220 /* 2221 * No known good modules (yet) apart from ip and arp 2222 * which are handled above 2223 */ 2224 return (-1); 2225 } 2226 2227 if (op == MOD_REMOVE) { 2228 (void) snprintf(syscmd, sizeof (syscmd), 2229 "%s %s modremove %s@%d\n", USR_SBIN_IFCONFIG, name, arg, 2230 pos); 2231 } else if (op == MOD_INSERT) { 2232 (void) snprintf(syscmd, sizeof (syscmd), 2233 "%s %s modinsert %s@%d\n", USR_SBIN_IFCONFIG, name, arg, 2234 pos); 2235 } else { 2236 rcm_log_message(RCM_ERROR, 2237 _("IP: modop(%s): unknown operation\n"), name); 2238 return (-1); 2239 } 2240 2241 rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd); 2242 if (rcm_exec_cmd(syscmd) == -1) { 2243 rcm_log_message(RCM_ERROR, 2244 _("IP: modop(%s): %s\n"), name, strerror(errno)); 2245 return (-1); 2246 } 2247 2248 rcm_log_message(RCM_TRACE1, "IP: modop success\n"); 2249 return (0); 2250 } 2251 2252 /* 2253 * get_modlist() - return a list of pushed mid-stream modules 2254 * Required memory is malloced to construct the list, 2255 * Caller must free this memory list 2256 * Call with cache_lock held 2257 */ 2258 static int 2259 get_modlist(char *name, ip_lif_t *lif) 2260 { 2261 int mux_fd; 2262 int muxid_fd; 2263 int fd; 2264 int i; 2265 int num_mods; 2266 struct lifreq lifr; 2267 struct str_list strlist; 2268 2269 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name); 2270 2271 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2272 lifr.lifr_flags = lif->li_ifflags; 2273 if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) { 2274 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name); 2275 return (-1); 2276 } 2277 2278 if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) { 2279 rcm_log_message(RCM_ERROR, 2280 _("IP: get_modlist(%s): I_LIST(%s) \n"), 2281 name, strerror(errno)); 2282 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr); 2283 return (-1); 2284 } 2285 2286 strlist.sl_nmods = num_mods; 2287 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods); 2288 2289 if (strlist.sl_modlist == NULL) { 2290 rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"), 2291 name, strerror(errno)); 2292 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr); 2293 return (-1); 2294 } 2295 2296 if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) { 2297 rcm_log_message(RCM_ERROR, 2298 _("IP: get_modlist(%s): I_LIST error: %s\n"), 2299 name, strerror(errno)); 2300 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr); 2301 return (-1); 2302 } 2303 2304 for (i = 0; i < strlist.sl_nmods; i++) { 2305 lif->li_modules[i] = 2306 malloc(strlen(strlist.sl_modlist[i].l_name)+1); 2307 if (lif->li_modules[i] == NULL) { 2308 rcm_log_message(RCM_ERROR, 2309 _("IP: get_modlist(%s): %s\n"), 2310 name, strerror(errno)); 2311 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr); 2312 return (-1); 2313 } 2314 (void) strcpy(lif->li_modules[i], strlist.sl_modlist[i].l_name); 2315 } 2316 2317 lif->li_modcnt = strlist.sl_nmods; 2318 free(strlist.sl_modlist); 2319 2320 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name); 2321 return (ip_plink(mux_fd, muxid_fd, fd, &lifr)); 2322 } 2323 2324 /* 2325 * ip_domux2fd() - Helper function for mod*() functions 2326 * Stolen from ifconfig.c 2327 */ 2328 static int 2329 ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr) 2330 { 2331 int muxid_fd; 2332 char *udp_dev_name; 2333 2334 if (lifr->lifr_flags & IFF_IPV6) { 2335 udp_dev_name = UDP6_DEV_NAME; 2336 } else { 2337 udp_dev_name = UDP_DEV_NAME; 2338 } 2339 2340 if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) { 2341 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"), 2342 udp_dev_name, strerror(errno)); 2343 return (-1); 2344 } 2345 if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) { 2346 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"), 2347 udp_dev_name, strerror(errno)); 2348 (void) close(muxid_fd); 2349 return (-1); 2350 } 2351 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) { 2352 rcm_log_message(RCM_ERROR, 2353 _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"), 2354 udp_dev_name, strerror(errno)); 2355 (void) close(*mux_fd); 2356 (void) close(muxid_fd); 2357 return (-1); 2358 } 2359 2360 rcm_log_message(RCM_TRACE2, 2361 "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n", 2362 lifr->lifr_arp_muxid, lifr->lifr_ip_muxid); 2363 2364 if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) { 2365 rcm_log_message(RCM_ERROR, 2366 _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"), 2367 udp_dev_name, strerror(errno)); 2368 (void) close(*mux_fd); 2369 (void) close(muxid_fd); 2370 return (-1); 2371 } 2372 if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) { 2373 rcm_log_message(RCM_ERROR, 2374 _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"), 2375 udp_dev_name, strerror(errno)); 2376 (void) close(*mux_fd); 2377 (void) close(muxid_fd); 2378 return (-1); 2379 } 2380 2381 /* Note: mux_fd and muxid_fd are closed in ip_plink below */ 2382 *muxid_fdp = muxid_fd; 2383 return (0); 2384 } 2385 2386 /* 2387 * ip_plink() - Helper function for mod*() functions. 2388 * Stolen from ifconfig.c 2389 */ 2390 static int 2391 ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr) 2392 { 2393 int mux_id; 2394 2395 if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) { 2396 rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"), 2397 UDP_DEV_NAME, strerror(errno)); 2398 (void) close(mux_fd); 2399 (void) close(muxid_fd); 2400 (void) close(fd); 2401 return (-1); 2402 } 2403 2404 lifr->lifr_ip_muxid = mux_id; 2405 if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) { 2406 rcm_log_message(RCM_ERROR, 2407 _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"), 2408 UDP_DEV_NAME, strerror(errno)); 2409 (void) close(mux_fd); 2410 (void) close(muxid_fd); 2411 (void) close(fd); 2412 return (-1); 2413 } 2414 2415 (void) close(mux_fd); 2416 (void) close(muxid_fd); 2417 (void) close(fd); 2418 return (0); 2419 } 2420 2421 /* 2422 * ip_onlinelist() 2423 * 2424 * Notify online to IP address consumers. 2425 */ 2426 static int 2427 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags, 2428 rcm_info_t **depend_info) 2429 { 2430 char **addrlist; 2431 int ret = RCM_SUCCESS; 2432 2433 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n"); 2434 2435 addrlist = ip_get_addrlist(node); 2436 if (addrlist == NULL || addrlist[0] == NULL) { 2437 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n"); 2438 ip_free_addrlist(addrlist); 2439 return (ret); 2440 } 2441 2442 ret = rcm_notify_online_list(hd, addrlist, 0, depend_info); 2443 2444 ip_free_addrlist(addrlist); 2445 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n"); 2446 return (ret); 2447 } 2448 2449 /* 2450 * ip_offlinelist() 2451 * 2452 * Offline IP address consumers. 2453 */ 2454 static int 2455 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags, 2456 rcm_info_t **depend_info) 2457 { 2458 char **addrlist; 2459 int ret = RCM_SUCCESS; 2460 2461 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n"); 2462 2463 addrlist = ip_get_addrlist(node); 2464 if (addrlist == NULL || addrlist[0] == NULL) { 2465 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n"); 2466 ip_free_addrlist(addrlist); 2467 return (RCM_SUCCESS); 2468 } 2469 2470 if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info)) 2471 != RCM_SUCCESS) { 2472 if (ret == RCM_FAILURE) 2473 (void) rcm_notify_online_list(hd, addrlist, 0, NULL); 2474 2475 ret = RCM_FAILURE; 2476 } 2477 2478 ip_free_addrlist(addrlist); 2479 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n"); 2480 return (ret); 2481 } 2482 2483 /* 2484 * ip_get_addrlist() - Compile list of IP addresses hosted on this NIC (node) 2485 * This routine malloc() required memeory for the list 2486 * Returns list on success, NULL if failed 2487 * Call with cache_lock held. 2488 */ 2489 static char ** 2490 ip_get_addrlist(ip_cache_t *node) 2491 { 2492 ip_lif_t *lif; 2493 char **addrlist = NULL; 2494 int numifs; 2495 char addrstr[INET6_ADDRSTRLEN]; 2496 void *addr; 2497 int af; 2498 int i; 2499 2500 rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n", 2501 node->ip_resource); 2502 2503 numifs = 0; 2504 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) { 2505 numifs++; 2506 } 2507 2508 /* 2509 * Allocate space for resource names list; add 1 and use calloc() 2510 * so that the list is NULL-terminated. 2511 */ 2512 if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) { 2513 rcm_log_message(RCM_ERROR, 2514 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"), 2515 node->ip_resource, strerror(errno)); 2516 return (NULL); 2517 } 2518 2519 for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL; 2520 lif = lif->li_next, i++) { 2521 2522 af = lif->li_addr.family; 2523 if (af == AF_INET6) { 2524 addr = &lif->li_addr.ip6.sin6_addr; 2525 } else if (af == AF_INET) { 2526 addr = &lif->li_addr.ip4.sin_addr; 2527 } else { 2528 rcm_log_message(RCM_DEBUG, 2529 "IP: unknown addr family %d, assuming AF_INET\n", 2530 af); 2531 af = AF_INET; 2532 addr = &lif->li_addr.ip4.sin_addr; 2533 } 2534 if (inet_ntop(af, addr, addrstr, INET6_ADDRSTRLEN) == NULL) { 2535 rcm_log_message(RCM_ERROR, 2536 _("IP: inet_ntop: %s\n"), strerror(errno)); 2537 ip_free_addrlist(addrlist); 2538 return (NULL); 2539 } 2540 2541 if ((addrlist[i] = malloc(strlen(addrstr) + RCM_SIZE_SUNW_IP)) 2542 == NULL) { 2543 rcm_log_message(RCM_ERROR, 2544 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"), 2545 node->ip_resource, strerror(errno)); 2546 ip_free_addrlist(addrlist); 2547 return (NULL); 2548 } 2549 (void) strcpy(addrlist[i], RCM_STR_SUNW_IP); /* SUNW_ip/ */ 2550 (void) strcat(addrlist[i], addrstr); /* SUNW_ip/<address> */ 2551 2552 rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]); 2553 } 2554 2555 rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n", 2556 node->ip_resource); 2557 2558 return (addrlist); 2559 } 2560 2561 static void 2562 ip_free_addrlist(char **addrlist) 2563 { 2564 int i; 2565 2566 if (addrlist == NULL) 2567 return; 2568 2569 for (i = 0; addrlist[i] != NULL; i++) 2570 free(addrlist[i]); 2571 free(addrlist); 2572 } 2573 2574 /* 2575 * ip_consumer_notify() - Notify consumers of IP addresses coming back online. 2576 */ 2577 2578 static void 2579 ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp, 2580 uint_t flags, rcm_info_t **depend_info) 2581 { 2582 char cached_name[RCM_LINK_RESOURCE_MAX]; 2583 ip_cache_t *node; 2584 2585 assert(linkid != DATALINK_INVALID_LINKID); 2586 2587 rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid); 2588 2589 /* Check for the interface in the cache */ 2590 (void) snprintf(cached_name, sizeof (cached_name), "%s/%u", 2591 RCM_LINK_PREFIX, linkid); 2592 2593 (void) mutex_lock(&cache_lock); 2594 if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) { 2595 rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"), 2596 linkid); 2597 (void) mutex_unlock(&cache_lock); 2598 return; 2599 } 2600 /* 2601 * Inform anonymous consumers about IP addresses being 2602 * onlined 2603 */ 2604 (void) ip_onlinelist(hd, node, errorp, flags, depend_info); 2605 2606 (void) mutex_unlock(&cache_lock); 2607 2608 rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n"); 2609 return; 2610 2611 } 2612 2613 /* 2614 * if_configure() - Configure a physical interface after attach 2615 */ 2616 static int 2617 if_configure(datalink_id_t linkid) 2618 { 2619 char ifinst[MAXLINKNAMELEN]; 2620 char cfgfile[MAXPATHLEN]; 2621 char cached_name[RCM_LINK_RESOURCE_MAX]; 2622 struct stat statbuf; 2623 ip_cache_t *node; 2624 int af = 0; 2625 int ipmp = 0; 2626 2627 assert(linkid != DATALINK_INVALID_LINKID); 2628 2629 rcm_log_message(RCM_TRACE1, _("IP: if_configure(%u)\n"), linkid); 2630 2631 /* Check for the interface in the cache */ 2632 (void) snprintf(cached_name, sizeof (cached_name), "%s/%u", 2633 RCM_LINK_PREFIX, linkid); 2634 2635 /* Check if the interface is new or was previously offlined */ 2636 (void) mutex_lock(&cache_lock); 2637 if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) && 2638 (!(node->ip_cachestate & CACHE_IF_OFFLINED))) { 2639 rcm_log_message(RCM_TRACE1, 2640 _("IP: Skipping configured interface(%u)\n"), linkid); 2641 (void) mutex_unlock(&cache_lock); 2642 return (0); 2643 } 2644 (void) mutex_unlock(&cache_lock); 2645 2646 if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, ifinst, 2647 sizeof (ifinst)) != DLADM_STATUS_OK) { 2648 rcm_log_message(RCM_ERROR, 2649 _("IP: get %u link name failed\n"), linkid); 2650 return (-1); 2651 } 2652 2653 /* Scan IPv4 configuration first */ 2654 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4, ifinst); 2655 cfgfile[MAXPATHLEN - 1] = '\0'; 2656 2657 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile); 2658 if (stat(cfgfile, &statbuf) == 0) { 2659 af |= CONFIG_AF_INET; 2660 if (isgrouped(cfgfile)) { 2661 ipmp++; 2662 } 2663 } 2664 2665 /* Scan IPv6 configuration details */ 2666 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV6, ifinst); 2667 cfgfile[MAXPATHLEN - 1] = '\0'; 2668 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile); 2669 if (stat(cfgfile, &statbuf) == 0) { 2670 af |= CONFIG_AF_INET6; 2671 if ((ipmp == 0) && isgrouped(cfgfile)) { 2672 ipmp++; 2673 } 2674 } 2675 2676 if (af & CONFIG_AF_INET) { 2677 if (if_ipmp_config(ifinst, CONFIG_AF_INET, ipmp) == -1) { 2678 rcm_log_message(RCM_ERROR, 2679 _("IP: IPv4 Post-attach failed (%s)\n"), ifinst); 2680 return (-1); 2681 } 2682 } 2683 2684 if (af & CONFIG_AF_INET6) { 2685 if (if_ipmp_config(ifinst, CONFIG_AF_INET6, ipmp) == -1) { 2686 rcm_log_message(RCM_ERROR, 2687 _("IP: IPv6 Post-attach failed(%s)\n"), ifinst); 2688 return (-1); 2689 } 2690 } 2691 2692 rcm_log_message(RCM_TRACE1, "IP: if_configure(%s) success\n", ifinst); 2693 2694 return (0); 2695 2696 } 2697 2698 /* 2699 * isgrouped() - Scans the given config file to see if this is a grouped 2700 * interface 2701 * Returns non-zero if true; 0 if false 2702 */ 2703 static int 2704 isgrouped(char *cfgfile) 2705 { 2706 FILE *fp; 2707 struct stat statb; 2708 char *buf = NULL; 2709 char *tokens[MAXARGS]; /* token pointers */ 2710 char tspace[MAXLINE]; /* token space */ 2711 int ntok; 2712 int group = 0; 2713 2714 if (cfgfile == NULL) 2715 return (0); 2716 2717 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile); 2718 2719 if (stat(cfgfile, &statb) != 0) { 2720 rcm_log_message(RCM_TRACE1, 2721 _("IP: No config file(%s)\n"), cfgfile); 2722 return (0); 2723 } 2724 2725 /* 2726 * We also ignore single-byte config files because the file should 2727 * always be newline-terminated, so we know there's nothing of 2728 * interest. Further, a single-byte file would cause the fgets() loop 2729 * below to spin forever. 2730 */ 2731 if (statb.st_size <= 1) { 2732 rcm_log_message(RCM_TRACE1, 2733 _("IP: Empty config file(%s)\n"), cfgfile); 2734 return (0); 2735 } 2736 2737 if ((fp = fopen(cfgfile, "r")) == NULL) { 2738 rcm_log_message(RCM_ERROR, 2739 _("IP: Cannot open configuration file(%s): %s\n"), cfgfile, 2740 strerror(errno)); 2741 return (0); 2742 } 2743 2744 if ((buf = calloc(1, statb.st_size)) == NULL) { 2745 rcm_log_message(RCM_ERROR, 2746 _("IP: calloc failure(%s): %s\n"), cfgfile, 2747 strerror(errno)); 2748 (void) fclose(fp); 2749 return (0); 2750 } 2751 2752 while (fgets(buf, statb.st_size, fp) != NULL) { 2753 if (*buf == '\0') 2754 continue; 2755 2756 tokenize(buf, tokens, tspace, &ntok); 2757 while (ntok) { 2758 if (STREQ("group", tokens[ntok - 1])) { 2759 if (tokens[ntok] != NULL) { 2760 group++; 2761 } 2762 } 2763 ntok--; 2764 } 2765 } 2766 2767 free(buf); 2768 2769 (void) fclose(fp); 2770 2771 if (group <= 0) { 2772 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s) non-grouped\n", 2773 cfgfile); 2774 return (0); 2775 } else { 2776 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s) grouped\n", 2777 cfgfile); 2778 return (1); 2779 } 2780 } 2781 2782 2783 /* 2784 * if_ipmp_config() - Configure an interface instance as specified by the 2785 * address family af and if it is grouped (ipmp). 2786 */ 2787 static int 2788 if_ipmp_config(char *ifinst, int af, int ipmp) 2789 { 2790 char cfgfile[MAXPATHLEN]; /* configuration file */ 2791 FILE *fp; 2792 struct stat statb; 2793 char *buf; 2794 char *tokens[MAXARGS]; /* list of config attributes */ 2795 char tspace[MAXLINE]; /* token space */ 2796 char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1]; 2797 char grpcmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1]; 2798 char fstr[8]; /* address family string inet or inet6 */ 2799 int nofailover = 0; 2800 int newattach = 0; 2801 int cmdvalid = 0; 2802 int ntok; 2803 int n; 2804 int stdif = 0; 2805 2806 if (ifinst == NULL) 2807 return (0); 2808 2809 rcm_log_message(RCM_TRACE1, "IP: if_ipmp_config(%s) ipmp = %d\n", 2810 ifinst, ipmp); 2811 2812 if (af & CONFIG_AF_INET) { 2813 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4, 2814 ifinst); 2815 (void) strcpy(fstr, "inet"); 2816 } else if (af & CONFIG_AF_INET6) { 2817 (void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV6, 2818 ifinst); 2819 (void) strcpy(fstr, "inet6"); 2820 } else { 2821 return (0); /* nothing to do */ 2822 } 2823 2824 cfgfile[MAXPATHLEN - 1] = '\0'; 2825 grpcmd[0] = '\0'; 2826 2827 if (stat(cfgfile, &statb) != 0) { 2828 rcm_log_message(RCM_TRACE1, 2829 "IP: No config file(%s)\n", ifinst); 2830 return (0); 2831 } 2832 2833 /* Config file exists, plumb in the physical interface */ 2834 if (af & CONFIG_AF_INET6) { 2835 if (if_getcount(AF_INET6) == 0) { 2836 /* 2837 * Configure software loopback driver if this is the 2838 * first IPv6 interface plumbed 2839 */ 2840 newattach++; 2841 (void) snprintf(syscmd, sizeof (syscmd), 2842 "%s lo0 %s plumb ::1 up", USR_SBIN_IFCONFIG, fstr); 2843 if (rcm_exec_cmd(syscmd) != 0) { 2844 rcm_log_message(RCM_ERROR, 2845 _("IP: Cannot plumb (%s) %s\n"), 2846 ifinst, strerror(errno)); 2847 return (-1); 2848 } 2849 } 2850 (void) snprintf(syscmd, sizeof (syscmd), "%s %s %s plumb up", 2851 USR_SBIN_IFCONFIG, ifinst, fstr); 2852 } else { 2853 (void) snprintf(syscmd, sizeof (syscmd), "%s %s %s plumb ", 2854 USR_SBIN_IFCONFIG, ifinst, fstr); 2855 if (if_getcount(AF_INET) == 0) { 2856 newattach++; 2857 } 2858 } 2859 rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd); 2860 2861 if (rcm_exec_cmd(syscmd) != 0) { 2862 rcm_log_message(RCM_ERROR, 2863 _("IP: Cannot plumb (%s) %s\n"), ifinst, strerror(errno)); 2864 return (-1); 2865 } 2866 2867 /* Check if config file is empty, if so, nothing else to do */ 2868 if (statb.st_size == 0) { 2869 rcm_log_message(RCM_TRACE1, 2870 "IP: Zero size config file(%s)\n", ifinst); 2871 return (0); 2872 } 2873 2874 if ((fp = fopen(cfgfile, "r")) == NULL) { 2875 rcm_log_message(RCM_ERROR, 2876 _("IP: Open error(%s): %s\n"), cfgfile, strerror(errno)); 2877 return (-1); 2878 } 2879 2880 if ((buf = calloc(1, statb.st_size)) == NULL) { 2881 rcm_log_message(RCM_ERROR, 2882 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno)); 2883 (void) fclose(fp); 2884 return (-1); 2885 } 2886 2887 /* a single line with one token implies a classical if */ 2888 if (fgets(buf, statb.st_size, fp) != NULL) { 2889 tokenize(buf, tokens, tspace, &ntok); 2890 if (ntok == 1) { 2891 rcm_log_message(RCM_TRACE1, "IP: Standard interface\n"); 2892 stdif++; 2893 } 2894 } 2895 if (fseek(fp, 0L, SEEK_SET) == -1) { 2896 rcm_log_message(RCM_ERROR, _("IP: fseek: %s\n"), 2897 strerror(errno)); 2898 return (-1); 2899 } 2900 2901 /* 2902 * Process the config command 2903 * This loop also handles multiple logical interfaces that may 2904 * be configured on a single line 2905 */ 2906 while (fgets(buf, statb.st_size, fp) != NULL) { 2907 nofailover = 0; 2908 cmdvalid = 0; 2909 2910 if (*buf == '\0') 2911 continue; 2912 2913 tokenize(buf, tokens, tspace, &ntok); 2914 if (ntok <= 0) 2915 continue; 2916 2917 /* Reset the config command */ 2918 (void) snprintf(syscmd, sizeof (syscmd), "%s %s %s ", 2919 USR_SBIN_IFCONFIG, ifinst, fstr); 2920 2921 /* No parsing if this is first interface of its kind */ 2922 if (newattach) { 2923 (void) strcat(syscmd, buf); 2924 /* Classic if */ 2925 if ((af & CONFIG_AF_INET) && (stdif == 1)) { 2926 (void) strcat(syscmd, CFG_CMDS_STD); 2927 } 2928 rcm_log_message(RCM_TRACE1, "IP: New: %s\n", syscmd); 2929 if (rcm_exec_cmd(syscmd) != 0) { 2930 rcm_log_message(RCM_ERROR, 2931 _("IP: Error: %s (%s): %s\n"), 2932 syscmd, ifinst, strerror(errno)); 2933 } 2934 continue; 2935 } 2936 2937 /* Parse the tokens to determine nature of the interface */ 2938 for (n = 0; n < ntok; n++) { 2939 /* Handle pathological failover cases */ 2940 if (STREQ("-failover", tokens[n])) 2941 nofailover++; 2942 if (STREQ("failover", tokens[n])) 2943 nofailover--; 2944 2945 /* group attribute requires special processing */ 2946 if (STREQ("group", tokens[n])) { 2947 if (tokens[n + 1] != NULL) { 2948 (void) snprintf(grpcmd, sizeof (grpcmd), 2949 "%s %s %s %s %s", USR_SBIN_IFCONFIG, 2950 ifinst, fstr, 2951 tokens[n], tokens[n + 1]); 2952 n++; /* skip next token */ 2953 continue; 2954 } 2955 } 2956 2957 /* Execute buffered command ? */ 2958 if (STREQ("set", tokens[n]) || 2959 STREQ("addif", tokens[n]) || 2960 STREQ("removeif", tokens[n]) || 2961 (n == (ntok -1))) { 2962 2963 /* config command complete ? */ 2964 if (n == (ntok -1)) { 2965 ADDSPACE(syscmd); 2966 (void) strcat(syscmd, tokens[n]); 2967 cmdvalid++; 2968 } 2969 2970 if (!cmdvalid) { 2971 ADDSPACE(syscmd); 2972 (void) strcat(syscmd, tokens[n]); 2973 cmdvalid++; 2974 continue; 2975 } 2976 /* Classic if ? */ 2977 if ((af & CONFIG_AF_INET) && (stdif == 1)) { 2978 (void) strcat(syscmd, CFG_CMDS_STD); 2979 } 2980 2981 if (nofailover > 0) { 2982 rcm_log_message(RCM_TRACE1, 2983 "IP: Interim exec: %s\n", syscmd); 2984 if (rcm_exec_cmd(syscmd) != 0) { 2985 rcm_log_message(RCM_ERROR, 2986 _("IP: %s fail(%s): %s\n"), 2987 syscmd, ifinst, 2988 strerror(errno)); 2989 } 2990 } else { 2991 /* Have mpathd configure the address */ 2992 if (if_mpathd_configure(syscmd, ifinst, 2993 af, ipmp) != 0) { 2994 rcm_log_message(RCM_ERROR, 2995 _("IP: %s fail(%s): %s\n"), 2996 syscmd, ifinst, 2997 strerror(errno)); 2998 } 2999 } 3000 3001 /* Reset config command */ 3002 (void) snprintf(syscmd, sizeof (syscmd), 3003 "%s %s %s ", USR_SBIN_IFCONFIG, ifinst, 3004 fstr); 3005 nofailover = 0; 3006 cmdvalid = 0; 3007 } 3008 /* 3009 * Note: No explicit command validation is required 3010 * since ifconfig to does it for us 3011 */ 3012 ADDSPACE(syscmd); 3013 (void) strcat(syscmd, tokens[n]); 3014 cmdvalid++; 3015 } 3016 } 3017 3018 free(buf); 3019 (void) fclose(fp); 3020 3021 /* 3022 * The group name needs to be set after all the test/nofailover 3023 * addresses have been configured. Otherwise, if IPMP detects that the 3024 * interface is failed, the addresses will be moved to a working 3025 * interface before the '-failover' flag can be set. 3026 */ 3027 if (grpcmd[0] != '\0') { 3028 rcm_log_message(RCM_TRACE1, "IP: set group name: %s\n", grpcmd); 3029 if (rcm_exec_cmd(grpcmd) != 0) { 3030 rcm_log_message(RCM_ERROR, _("IP: %s fail(%s): %s\n"), 3031 grpcmd, ifinst, strerror(errno)); 3032 } 3033 } 3034 3035 rcm_log_message(RCM_TRACE1, "IP: if_ipmp_config(%s) success\n", ifinst); 3036 3037 return (0); 3038 } 3039 3040 /* 3041 * if_mpathd_configure() - Determine configuration disposition of the interface 3042 */ 3043 static int 3044 if_mpathd_configure(char *syscmd, char *ifinst, int af, int ipmp) 3045 { 3046 char *tokens[MAXARGS]; 3047 char tspace[MAXLINE]; 3048 int ntok; 3049 char *addr; 3050 char *from_lifname; 3051 mpathd_cmd_t mpdcmd; 3052 int n; 3053 3054 rcm_log_message(RCM_TRACE1, "IP: if_mpathd_configure(%s): %s\n", 3055 ifinst, syscmd); 3056 3057 tokenize(syscmd, tokens, tspace, &ntok); 3058 if (ntok <= 0) 3059 return (0); 3060 3061 addr = tokens[3]; /* by default, third token is valid address */ 3062 for (n = 0; n < ntok; n++) { 3063 if (STREQ("set", tokens[n]) || 3064 STREQ("addif", tokens[n])) { 3065 addr = tokens[n+1]; 3066 if (addr == NULL) { /* invalid format */ 3067 return (-1); 3068 } else 3069 break; 3070 } 3071 } 3072 3073 /* Check std. commands or no failed over address */ 3074 if (STREQ("removeif", addr) || STREQ("group", addr) || 3075 ((from_lifname = get_mpathd_dest(addr, af)) == NULL)) { 3076 rcm_log_message(RCM_TRACE1, 3077 "IP: No failed-over host, exec %s\n", syscmd); 3078 if (rcm_exec_cmd(syscmd) != 0) { 3079 rcm_log_message(RCM_ERROR, 3080 _("IP: %s failed(%s): %s\n"), 3081 syscmd, ifinst, strerror(errno)); 3082 return (-1); 3083 } 3084 return (0); 3085 } 3086 3087 /* Check for non-IPMP failover scenarios */ 3088 if ((ipmp <= 0) && (from_lifname != NULL)) { 3089 /* Address already hosted on another NIC, return */ 3090 rcm_log_message(RCM_TRACE1, 3091 "IP: Non-IPMP failed-over host(%s): %s\n", 3092 ifinst, addr); 3093 return (0); 3094 } 3095 3096 /* 3097 * Valid failed-over host; have mpathd set the original index 3098 */ 3099 mpdcmd.cmd_command = MI_SETOINDEX; 3100 (void) strcpy(mpdcmd.from_lifname, from_lifname); 3101 (void) strcpy(mpdcmd.to_pifname, ifinst); 3102 if (af & CONFIG_AF_INET6) { 3103 mpdcmd.addr_family = AF_INET6; 3104 } else { 3105 mpdcmd.addr_family = AF_INET; 3106 } 3107 3108 /* Send command to in.mpathd(1M) */ 3109 rcm_log_message(RCM_TRACE1, 3110 "IP: Attempting setoindex from (%s) to (%s) ....\n", 3111 from_lifname, ifinst); 3112 3113 if (mpathd_send_cmd(&mpdcmd) < 0) { 3114 rcm_log_message(RCM_TRACE1, 3115 "IP: mpathd set original index unsuccessful: %s\n", 3116 strerror(errno)); 3117 return (-1); 3118 } 3119 3120 rcm_log_message(RCM_TRACE1, 3121 "IP: setoindex success (%s) to (%s)\n", 3122 from_lifname, ifinst); 3123 3124 return (0); 3125 } 3126 3127 /* 3128 * get_mpathd_dest() - Return current destination for lif; caller is 3129 * responsible to free memory allocated for address 3130 */ 3131 static char * 3132 get_mpathd_dest(char *addr, int family) 3133 { 3134 int sock; 3135 char *buf; 3136 struct lifnum lifn; 3137 struct lifconf lifc; 3138 struct lifreq *lifrp; 3139 sa_family_t af = AF_INET; /* IPv4 by default */ 3140 int i; 3141 struct lifreq lifreq; 3142 struct sockaddr_in *sin; 3143 struct sockaddr_in6 *sin6; 3144 struct hostent *hp; 3145 char *ifname = NULL; 3146 char *prefix = NULL; 3147 char addrstr[INET6_ADDRSTRLEN]; 3148 char ifaddr[INET6_ADDRSTRLEN]; 3149 int err; 3150 3151 if (addr == NULL) { 3152 return (NULL); 3153 } 3154 3155 rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s)\n", addr); 3156 3157 if (family & CONFIG_AF_INET6) { 3158 af = AF_INET6; 3159 } else { 3160 af = AF_INET; 3161 } 3162 3163 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) { 3164 rcm_log_message(RCM_ERROR, 3165 _("IP: failure opening %s socket: %s\n"), 3166 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno)); 3167 return (NULL); 3168 } 3169 3170 lifn.lifn_family = af; 3171 lifn.lifn_flags = 0; 3172 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 3173 rcm_log_message(RCM_ERROR, 3174 _("IP: SIOCLGIFNUM failed: %s\n"), 3175 strerror(errno)); 3176 (void) close(sock); 3177 return (NULL); 3178 } 3179 3180 if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) { 3181 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"), 3182 strerror(errno)); 3183 (void) close(sock); 3184 return (NULL); 3185 } 3186 3187 lifc.lifc_family = af; 3188 lifc.lifc_flags = 0; 3189 lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count; 3190 lifc.lifc_buf = buf; 3191 3192 if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 3193 rcm_log_message(RCM_ERROR, 3194 _("IP: SIOCGLIFCONF failed: %s\n"), 3195 strerror(errno)); 3196 free(buf); 3197 (void) close(sock); 3198 return (NULL); 3199 } 3200 3201 /* Filter out prefix address from netmask */ 3202 (void) strcpy(ifaddr, addr); 3203 if ((prefix = strchr(ifaddr, '/')) != NULL) { 3204 *prefix = '\0'; /* We care about the address part only */ 3205 } 3206 3207 /* Check for aliases */ 3208 hp = getipnodebyname(ifaddr, af, AI_DEFAULT, &err); 3209 if (hp) { 3210 if (inet_ntop(af, (void *)hp->h_addr_list[0], 3211 ifaddr, sizeof (ifaddr)) == NULL) { 3212 /* Restore original address and use it */ 3213 (void) strcpy(ifaddr, addr); 3214 if ((prefix = strchr(ifaddr, '/')) != NULL) { 3215 *prefix = '\0'; 3216 } 3217 } 3218 freehostent(hp); 3219 } 3220 rcm_log_message(RCM_TRACE2, "IP: ifaddr(%s) = %s\n", addr, ifaddr); 3221 3222 /* now search the interfaces */ 3223 lifrp = lifc.lifc_req; 3224 for (i = 0; i < lifn.lifn_count; i++, lifrp++) { 3225 (void) strcpy(lifreq.lifr_name, lifrp->lifr_name); 3226 /* Get the interface address for this interface */ 3227 if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) { 3228 rcm_log_message(RCM_ERROR, 3229 _("IP: SIOCGLIFADDR: %s\n"), strerror(errno)); 3230 free(buf); 3231 (void) close(sock); 3232 return (NULL); 3233 } 3234 3235 if (af == AF_INET6) { 3236 sin6 = (struct sockaddr_in6 *)&lifreq.lifr_addr; 3237 if (inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3238 addrstr, sizeof (addrstr)) == NULL) { 3239 continue; 3240 } 3241 } else { 3242 sin = (struct sockaddr_in *)&lifreq.lifr_addr; 3243 if (inet_ntop(AF_INET, (void *)&sin->sin_addr, 3244 addrstr, sizeof (addrstr)) == NULL) { 3245 continue; 3246 } 3247 } 3248 3249 if (STREQ(addrstr, ifaddr)) { 3250 /* Allocate memory to hold interface name */ 3251 if ((ifname = (char *)malloc(LIFNAMSIZ)) == NULL) { 3252 rcm_log_message(RCM_ERROR, 3253 _("IP: malloc: %s\n"), strerror(errno)); 3254 free(buf); 3255 (void) close(sock); 3256 return (NULL); 3257 } 3258 3259 /* Copy the interface name */ 3260 /* 3261 * (void) memcpy(ifname, lifrp->lifr_name, 3262 * sizeof (ifname)); 3263 * ifname[sizeof (ifname) - 1] = '\0'; 3264 */ 3265 (void) strcpy(ifname, lifrp->lifr_name); 3266 break; 3267 } 3268 } 3269 3270 (void) close(sock); 3271 free(buf); 3272 3273 if (ifname == NULL) 3274 rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s): none\n", 3275 addr); 3276 else 3277 rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s): %s\n", 3278 addr, ifname); 3279 3280 return (ifname); 3281 } 3282 3283 static int 3284 if_getcount(int af) 3285 { 3286 int sock; 3287 struct lifnum lifn; 3288 3289 rcm_log_message(RCM_TRACE1, "IP: if_getcount\n"); 3290 3291 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) { 3292 rcm_log_message(RCM_ERROR, 3293 _("IP: failure opening %s socket: %s\n"), 3294 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno)); 3295 return (-1); 3296 } 3297 3298 lifn.lifn_family = af; 3299 lifn.lifn_flags = 0; 3300 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 3301 rcm_log_message(RCM_ERROR, 3302 _("IP: SIOCLGIFNUM failed: %s\n"), 3303 strerror(errno)); 3304 (void) close(sock); 3305 return (-1); 3306 } 3307 (void) close(sock); 3308 3309 rcm_log_message(RCM_TRACE1, "IP: if_getcount success: %d\n", 3310 lifn.lifn_count); 3311 3312 return (lifn.lifn_count); 3313 } 3314 3315 /* 3316 * tokenize() - turn a command line into tokens; caller is responsible to 3317 * provide enough memory to hold all tokens 3318 */ 3319 static void 3320 tokenize(char *line, char **tokens, char *tspace, int *ntok) 3321 { 3322 char *cp; 3323 char *sp; 3324 3325 sp = tspace; 3326 cp = line; 3327 for (*ntok = 0; *ntok < MAXARGS; (*ntok)++) { 3328 tokens[*ntok] = sp; 3329 while (ISSPACE(*cp)) 3330 cp++; 3331 if (ISEOL(*cp)) 3332 break; 3333 do { 3334 *sp++ = *cp++; 3335 } while (!ISSPACE(*cp) && !ISEOL(*cp)); 3336 3337 *sp++ = '\0'; 3338 } 3339 } 3340