1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <errno.h> 27 #include <ipmp_admin.h> 28 #include <libinetutil.h> 29 #include <locale.h> 30 #include <net/if.h> 31 #include <stdarg.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <unistd.h> 36 #include <sys/socket.h> 37 #include <sys/sockio.h> 38 #include <sys/types.h> 39 40 typedef void offline_func_t(const char *, ipmp_handle_t); 41 42 static const char *progname; 43 static int sioc4fd, sioc6fd; 44 static offline_func_t do_offline, undo_offline; 45 static boolean_t set_lifflags(const char *, uint64_t); 46 static boolean_t is_offline(const char *); 47 static void warn(const char *, ...); 48 static void die(const char *, ...); 49 50 static void 51 usage(void) 52 { 53 (void) fprintf(stderr, gettext("Usage: %s -d | -r <ifname>\n"), 54 progname); 55 exit(EXIT_FAILURE); 56 } 57 58 static const char * 59 mpadm_errmsg(uint32_t error) 60 { 61 switch (error) { 62 case IPMP_EUNKIF: 63 return (gettext("not a physical interface or not in an " 64 "IPMP group")); 65 case IPMP_EMINRED: 66 return (gettext("no other functioning interfaces are in its " 67 "IPMP group")); 68 default: 69 return (ipmp_errmsg(error)); 70 } 71 } 72 73 int 74 main(int argc, char **argv) 75 { 76 int retval; 77 ipmp_handle_t handle; 78 offline_func_t *ofuncp = NULL; 79 const char *ifname; 80 int c; 81 82 if ((progname = strrchr(argv[0], '/')) != NULL) 83 progname++; 84 else 85 progname = argv[0]; 86 87 (void) setlocale(LC_ALL, ""); 88 (void) textdomain(TEXT_DOMAIN); 89 90 while ((c = getopt(argc, argv, "d:r:")) != EOF) { 91 switch (c) { 92 case 'd': 93 ifname = optarg; 94 ofuncp = do_offline; 95 break; 96 case 'r': 97 ifname = optarg; 98 ofuncp = undo_offline; 99 break; 100 default: 101 usage(); 102 } 103 } 104 105 if (ofuncp == NULL) 106 usage(); 107 108 /* 109 * Create the global V4 and V6 socket ioctl descriptors. 110 */ 111 sioc4fd = socket(AF_INET, SOCK_DGRAM, 0); 112 sioc6fd = socket(AF_INET6, SOCK_DGRAM, 0); 113 if (sioc4fd == -1 || sioc6fd == -1) 114 die("cannot create sockets"); 115 116 if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) 117 die("cannot create ipmp handle: %s\n", ipmp_errmsg(retval)); 118 119 (*ofuncp)(ifname, handle); 120 121 ipmp_close(handle); 122 (void) close(sioc4fd); 123 (void) close(sioc6fd); 124 125 return (EXIT_SUCCESS); 126 } 127 128 /* 129 * Checks whether IFF_OFFLINE is set on `ifname'. 130 */ 131 boolean_t 132 is_offline(const char *ifname) 133 { 134 struct lifreq lifr = { 0 }; 135 136 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 137 if (ioctl(sioc4fd, SIOCGLIFFLAGS, &lifr) == -1) { 138 if (errno != ENXIO || 139 ioctl(sioc6fd, SIOCGLIFFLAGS, &lifr) == -1) { 140 die("cannot get interface flags on %s", ifname); 141 } 142 } 143 144 return ((lifr.lifr_flags & IFF_OFFLINE) != 0); 145 } 146 147 static void 148 do_offline(const char *ifname, ipmp_handle_t handle) 149 { 150 ifaddrlistx_t *ifaddrp, *ifaddrs; 151 int retval; 152 153 if (is_offline(ifname)) 154 die("interface %s is already offline\n", ifname); 155 156 if ((retval = ipmp_offline(handle, ifname, 1)) != IPMP_SUCCESS) 157 die("cannot offline %s: %s\n", ifname, mpadm_errmsg(retval)); 158 159 /* 160 * Get all the up addresses for `ifname' and bring them down. 161 */ 162 if (ifaddrlistx(ifname, IFF_UP, 0, &ifaddrs) == -1) 163 die("cannot get addresses on %s", ifname); 164 165 for (ifaddrp = ifaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { 166 if (!(ifaddrp->ia_flags & IFF_OFFLINE)) 167 warn("IFF_OFFLINE vanished on %s\n", ifaddrp->ia_name); 168 169 if (!set_lifflags(ifaddrp->ia_name, 170 ifaddrp->ia_flags & ~IFF_UP)) 171 warn("cannot bring down address on %s", 172 ifaddrp->ia_name); 173 } 174 175 ifaddrlistx_free(ifaddrs); 176 } 177 178 static void 179 undo_offline(const char *ifname, ipmp_handle_t handle) 180 { 181 ifaddrlistx_t *ifaddrp, *ifaddrs; 182 int retval; 183 184 if (!is_offline(ifname)) 185 die("interface %s is not offline\n", ifname); 186 187 /* 188 * Get all the down addresses for `ifname' and bring them up. 189 */ 190 if (ifaddrlistx(ifname, 0, IFF_UP, &ifaddrs) == -1) 191 die("cannot get addresses for %s", ifname); 192 193 for (ifaddrp = ifaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { 194 if (!(ifaddrp->ia_flags & IFF_OFFLINE)) 195 warn("IFF_OFFLINE vanished on %s\n", ifaddrp->ia_name); 196 197 if (!set_lifflags(ifaddrp->ia_name, ifaddrp->ia_flags | IFF_UP)) 198 warn("cannot bring up address on %s", ifaddrp->ia_name); 199 } 200 201 ifaddrlistx_free(ifaddrs); 202 203 /* 204 * Undo the offline. 205 */ 206 if ((retval = ipmp_undo_offline(handle, ifname)) != IPMP_SUCCESS) { 207 die("cannot undo-offline %s: %s\n", ifname, 208 mpadm_errmsg(retval)); 209 } 210 211 /* 212 * Verify whether IFF_OFFLINE is set as a sanity check. 213 */ 214 if (is_offline(ifname)) 215 warn("in.mpathd has not cleared IFF_OFFLINE on %s\n", ifname); 216 } 217 218 /* 219 * Change `lifname' to have `flags' set. Returns B_TRUE on success. 220 */ 221 static boolean_t 222 set_lifflags(const char *lifname, uint64_t flags) 223 { 224 struct lifreq lifr = { 0 }; 225 int fd = (flags & IFF_IPV4) ? sioc4fd : sioc6fd; 226 227 (void) strlcpy(lifr.lifr_name, lifname, LIFNAMSIZ); 228 lifr.lifr_flags = flags; 229 230 return (ioctl(fd, SIOCSLIFFLAGS, &lifr) >= 0); 231 } 232 233 /* PRINTFLIKE1 */ 234 static void 235 die(const char *format, ...) 236 { 237 va_list alist; 238 char *errstr = strerror(errno); 239 240 format = gettext(format); 241 (void) fprintf(stderr, gettext("%s: fatal: "), progname); 242 243 va_start(alist, format); 244 (void) vfprintf(stderr, format, alist); 245 va_end(alist); 246 247 if (strchr(format, '\n') == NULL) 248 (void) fprintf(stderr, ": %s\n", errstr); 249 250 exit(EXIT_FAILURE); 251 } 252 253 /* PRINTFLIKE1 */ 254 static void 255 warn(const char *format, ...) 256 { 257 va_list alist; 258 char *errstr = strerror(errno); 259 260 format = gettext(format); 261 (void) fprintf(stderr, gettext("%s: warning: "), progname); 262 263 va_start(alist, format); 264 (void) vfprintf(stderr, format, alist); 265 va_end(alist); 266 267 if (strchr(format, '\n') == NULL) 268 (void) fprintf(stderr, ": %s\n", errstr); 269 } 270