17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5e11c3f44Smeem * Common Development and Distribution License (the "License"). 6e11c3f44Smeem * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22e11c3f44Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <errno.h> 27e11c3f44Smeem #include <ipmp_admin.h> 28e11c3f44Smeem #include <libinetutil.h> 29e11c3f44Smeem #include <locale.h> 30e11c3f44Smeem #include <net/if.h> 31e11c3f44Smeem #include <stdarg.h> 32e11c3f44Smeem #include <stdio.h> 33e11c3f44Smeem #include <stdlib.h> 34e11c3f44Smeem #include <string.h> 35e11c3f44Smeem #include <unistd.h> 36e11c3f44Smeem #include <sys/socket.h> 37e11c3f44Smeem #include <sys/sockio.h> 38e11c3f44Smeem #include <sys/types.h> 397c478bd9Sstevel@tonic-gate 40e11c3f44Smeem typedef void offline_func_t(const char *, ipmp_handle_t); 417c478bd9Sstevel@tonic-gate 42e11c3f44Smeem static const char *progname; 43e11c3f44Smeem static int sioc4fd, sioc6fd; 44e11c3f44Smeem static offline_func_t do_offline, undo_offline; 45e11c3f44Smeem static boolean_t set_lifflags(const char *, uint64_t); 46e11c3f44Smeem static boolean_t is_offline(const char *); 47e11c3f44Smeem static void warn(const char *, ...); 48e11c3f44Smeem static void die(const char *, ...); 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate static void 51*e25ac69dSmeem usage(void) 527c478bd9Sstevel@tonic-gate { 53*e25ac69dSmeem (void) fprintf(stderr, gettext("Usage: %s -d | -r <ifname>\n"), 54*e25ac69dSmeem progname); 55*e25ac69dSmeem exit(EXIT_FAILURE); 567c478bd9Sstevel@tonic-gate } 577c478bd9Sstevel@tonic-gate 58e11c3f44Smeem static const char * 59e11c3f44Smeem mpadm_errmsg(uint32_t error) 607c478bd9Sstevel@tonic-gate { 617c478bd9Sstevel@tonic-gate switch (error) { 62e11c3f44Smeem case IPMP_EUNKIF: 63*e25ac69dSmeem return (gettext("not a physical interface or not in an " 64*e25ac69dSmeem "IPMP group")); 65e11c3f44Smeem case IPMP_EMINRED: 66*e25ac69dSmeem return (gettext("no other functioning interfaces are in its " 67*e25ac69dSmeem "IPMP group")); 687c478bd9Sstevel@tonic-gate default: 69e11c3f44Smeem return (ipmp_errmsg(error)); 707c478bd9Sstevel@tonic-gate } 717c478bd9Sstevel@tonic-gate } 727c478bd9Sstevel@tonic-gate 734b908718Smeem int 747c478bd9Sstevel@tonic-gate main(int argc, char **argv) 757c478bd9Sstevel@tonic-gate { 76e11c3f44Smeem int retval; 77e11c3f44Smeem ipmp_handle_t handle; 78e11c3f44Smeem offline_func_t *ofuncp = NULL; 79e11c3f44Smeem const char *ifname; 807c478bd9Sstevel@tonic-gate int c; 817c478bd9Sstevel@tonic-gate 82e11c3f44Smeem if ((progname = strrchr(argv[0], '/')) != NULL) 83e11c3f44Smeem progname++; 84e11c3f44Smeem else 85e11c3f44Smeem progname = argv[0]; 86e11c3f44Smeem 87e11c3f44Smeem (void) setlocale(LC_ALL, ""); 887c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "d:r:")) != EOF) { 917c478bd9Sstevel@tonic-gate switch (c) { 927c478bd9Sstevel@tonic-gate case 'd': 937c478bd9Sstevel@tonic-gate ifname = optarg; 94e11c3f44Smeem ofuncp = do_offline; 957c478bd9Sstevel@tonic-gate break; 967c478bd9Sstevel@tonic-gate case 'r': 977c478bd9Sstevel@tonic-gate ifname = optarg; 98e11c3f44Smeem ofuncp = undo_offline; 997c478bd9Sstevel@tonic-gate break; 1007c478bd9Sstevel@tonic-gate default: 1017c478bd9Sstevel@tonic-gate usage(); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate 105e11c3f44Smeem if (ofuncp == NULL) 1067c478bd9Sstevel@tonic-gate usage(); 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 109e11c3f44Smeem * Create the global V4 and V6 socket ioctl descriptors. 1107c478bd9Sstevel@tonic-gate */ 111e11c3f44Smeem sioc4fd = socket(AF_INET, SOCK_DGRAM, 0); 112e11c3f44Smeem sioc6fd = socket(AF_INET6, SOCK_DGRAM, 0); 113e11c3f44Smeem if (sioc4fd == -1 || sioc6fd == -1) 114e11c3f44Smeem die("cannot create sockets"); 1157c478bd9Sstevel@tonic-gate 116e11c3f44Smeem if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) 117e11c3f44Smeem die("cannot create ipmp handle: %s\n", ipmp_errmsg(retval)); 118e11c3f44Smeem 119e11c3f44Smeem (*ofuncp)(ifname, handle); 120e11c3f44Smeem 121e11c3f44Smeem ipmp_close(handle); 122e11c3f44Smeem (void) close(sioc4fd); 123e11c3f44Smeem (void) close(sioc6fd); 124e11c3f44Smeem 125e11c3f44Smeem return (EXIT_SUCCESS); 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 129e11c3f44Smeem * Checks whether IFF_OFFLINE is set on `ifname'. 1307c478bd9Sstevel@tonic-gate */ 1317c478bd9Sstevel@tonic-gate boolean_t 132e11c3f44Smeem is_offline(const char *ifname) 1337c478bd9Sstevel@tonic-gate { 134e11c3f44Smeem struct lifreq lifr = { 0 }; 1357c478bd9Sstevel@tonic-gate 136e11c3f44Smeem (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 137e11c3f44Smeem if (ioctl(sioc4fd, SIOCGLIFFLAGS, &lifr) == -1) { 138e11c3f44Smeem if (errno != ENXIO || 139e11c3f44Smeem ioctl(sioc6fd, SIOCGLIFFLAGS, &lifr) == -1) { 140e11c3f44Smeem die("cannot get interface flags on %s", ifname); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 144e11c3f44Smeem return ((lifr.lifr_flags & IFF_OFFLINE) != 0); 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate static void 148e11c3f44Smeem do_offline(const char *ifname, ipmp_handle_t handle) 1497c478bd9Sstevel@tonic-gate { 150e11c3f44Smeem ifaddrlistx_t *ifaddrp, *ifaddrs; 151e11c3f44Smeem int retval; 152e11c3f44Smeem 153e11c3f44Smeem if (is_offline(ifname)) 154e11c3f44Smeem die("interface %s is already offline\n", ifname); 155e11c3f44Smeem 156e11c3f44Smeem if ((retval = ipmp_offline(handle, ifname, 1)) != IPMP_SUCCESS) 157e11c3f44Smeem die("cannot offline %s: %s\n", ifname, mpadm_errmsg(retval)); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate /* 160e11c3f44Smeem * Get all the up addresses for `ifname' and bring them down. 1617c478bd9Sstevel@tonic-gate */ 162e11c3f44Smeem if (ifaddrlistx(ifname, IFF_UP, 0, &ifaddrs) == -1) 163e11c3f44Smeem die("cannot get addresses on %s", ifname); 1647c478bd9Sstevel@tonic-gate 165e11c3f44Smeem for (ifaddrp = ifaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { 166e11c3f44Smeem if (!(ifaddrp->ia_flags & IFF_OFFLINE)) 167e11c3f44Smeem warn("IFF_OFFLINE vanished on %s\n", ifaddrp->ia_name); 168e11c3f44Smeem 169e11c3f44Smeem if (!set_lifflags(ifaddrp->ia_name, 170e11c3f44Smeem ifaddrp->ia_flags & ~IFF_UP)) 171*e25ac69dSmeem warn("cannot bring down address on %s", 172e11c3f44Smeem ifaddrp->ia_name); 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate 175e11c3f44Smeem ifaddrlistx_free(ifaddrs); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate static void 179e11c3f44Smeem undo_offline(const char *ifname, ipmp_handle_t handle) 1807c478bd9Sstevel@tonic-gate { 181e11c3f44Smeem ifaddrlistx_t *ifaddrp, *ifaddrs; 182e11c3f44Smeem int retval; 183e11c3f44Smeem 184e11c3f44Smeem if (!is_offline(ifname)) 185e11c3f44Smeem die("interface %s is not offline\n", ifname); 186e11c3f44Smeem 187e11c3f44Smeem /* 188e11c3f44Smeem * Get all the down addresses for `ifname' and bring them up. 189e11c3f44Smeem */ 190e11c3f44Smeem if (ifaddrlistx(ifname, 0, IFF_UP, &ifaddrs) == -1) 191e11c3f44Smeem die("cannot get addresses for %s", ifname); 192e11c3f44Smeem 193e11c3f44Smeem for (ifaddrp = ifaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { 194e11c3f44Smeem if (!(ifaddrp->ia_flags & IFF_OFFLINE)) 195e11c3f44Smeem warn("IFF_OFFLINE vanished on %s\n", ifaddrp->ia_name); 196e11c3f44Smeem 197e11c3f44Smeem if (!set_lifflags(ifaddrp->ia_name, ifaddrp->ia_flags | IFF_UP)) 198*e25ac69dSmeem warn("cannot bring up address on %s", ifaddrp->ia_name); 199e11c3f44Smeem } 200e11c3f44Smeem 201e11c3f44Smeem ifaddrlistx_free(ifaddrs); 202e11c3f44Smeem 203e11c3f44Smeem /* 204e11c3f44Smeem * Undo the offline. 205e11c3f44Smeem */ 206e11c3f44Smeem if ((retval = ipmp_undo_offline(handle, ifname)) != IPMP_SUCCESS) { 207e11c3f44Smeem die("cannot undo-offline %s: %s\n", ifname, 208e11c3f44Smeem mpadm_errmsg(retval)); 209e11c3f44Smeem } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* 2127c478bd9Sstevel@tonic-gate * Verify whether IFF_OFFLINE is set as a sanity check. 2137c478bd9Sstevel@tonic-gate */ 214e11c3f44Smeem if (is_offline(ifname)) 215e11c3f44Smeem warn("in.mpathd has not cleared IFF_OFFLINE on %s\n", ifname); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* 219e11c3f44Smeem * Change `lifname' to have `flags' set. Returns B_TRUE on success. 2207c478bd9Sstevel@tonic-gate */ 221e11c3f44Smeem static boolean_t 222e11c3f44Smeem set_lifflags(const char *lifname, uint64_t flags) 2237c478bd9Sstevel@tonic-gate { 224e11c3f44Smeem struct lifreq lifr = { 0 }; 225e11c3f44Smeem int fd = (flags & IFF_IPV4) ? sioc4fd : sioc6fd; 2267c478bd9Sstevel@tonic-gate 227e11c3f44Smeem (void) strlcpy(lifr.lifr_name, lifname, LIFNAMSIZ); 228e11c3f44Smeem lifr.lifr_flags = flags; 229e11c3f44Smeem 230e11c3f44Smeem return (ioctl(fd, SIOCSLIFFLAGS, &lifr) >= 0); 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 233e11c3f44Smeem /* PRINTFLIKE1 */ 234e11c3f44Smeem static void 235e11c3f44Smeem die(const char *format, ...) 2367c478bd9Sstevel@tonic-gate { 237e11c3f44Smeem va_list alist; 238e11c3f44Smeem char *errstr = strerror(errno); 2397c478bd9Sstevel@tonic-gate 240e11c3f44Smeem format = gettext(format); 241e11c3f44Smeem (void) fprintf(stderr, gettext("%s: fatal: "), progname); 242e11c3f44Smeem 243e11c3f44Smeem va_start(alist, format); 244e11c3f44Smeem (void) vfprintf(stderr, format, alist); 245e11c3f44Smeem va_end(alist); 246e11c3f44Smeem 247e11c3f44Smeem if (strchr(format, '\n') == NULL) 248e11c3f44Smeem (void) fprintf(stderr, ": %s\n", errstr); 249e11c3f44Smeem 250e11c3f44Smeem exit(EXIT_FAILURE); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 253e11c3f44Smeem /* PRINTFLIKE1 */ 254e11c3f44Smeem static void 255e11c3f44Smeem warn(const char *format, ...) 2567c478bd9Sstevel@tonic-gate { 257e11c3f44Smeem va_list alist; 258e11c3f44Smeem char *errstr = strerror(errno); 2597c478bd9Sstevel@tonic-gate 260e11c3f44Smeem format = gettext(format); 261e11c3f44Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 2627c478bd9Sstevel@tonic-gate 263e11c3f44Smeem va_start(alist, format); 264e11c3f44Smeem (void) vfprintf(stderr, format, alist); 265e11c3f44Smeem va_end(alist); 2667c478bd9Sstevel@tonic-gate 267e11c3f44Smeem if (strchr(format, '\n') == NULL) 268e11c3f44Smeem (void) fprintf(stderr, ": %s\n", errstr); 2697c478bd9Sstevel@tonic-gate } 270