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