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