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() 52 { 53 (void) fprintf(stderr, "Usage: %s [-d | -r] <interface>\n", progname); 54 exit(1); 55 } 56 57 static const char * 58 mpadm_errmsg(uint32_t error) 59 { 60 switch (error) { 61 case IPMP_EUNKIF: 62 return ("not a physical interface or not in an IPMP group"); 63 case IPMP_EMINRED: 64 return ("no other functioning interfaces are in its IPMP " 65 "group"); 66 default: 67 return (ipmp_errmsg(error)); 68 } 69 } 70 71 int 72 main(int argc, char **argv) 73 { 74 int retval; 75 ipmp_handle_t handle; 76 offline_func_t *ofuncp = NULL; 77 const char *ifname; 78 int c; 79 80 if ((progname = strrchr(argv[0], '/')) != NULL) 81 progname++; 82 else 83 progname = argv[0]; 84 85 (void) setlocale(LC_ALL, ""); 86 (void) textdomain(TEXT_DOMAIN); 87 88 while ((c = getopt(argc, argv, "d:r:")) != EOF) { 89 switch (c) { 90 case 'd': 91 ifname = optarg; 92 ofuncp = do_offline; 93 break; 94 case 'r': 95 ifname = optarg; 96 ofuncp = undo_offline; 97 break; 98 default : 99 usage(); 100 } 101 } 102 103 if (ofuncp == NULL) 104 usage(); 105 106 /* 107 * Create the global V4 and V6 socket ioctl descriptors. 108 */ 109 sioc4fd = socket(AF_INET, SOCK_DGRAM, 0); 110 sioc6fd = socket(AF_INET6, SOCK_DGRAM, 0); 111 if (sioc4fd == -1 || sioc6fd == -1) 112 die("cannot create sockets"); 113 114 if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) 115 die("cannot create ipmp handle: %s\n", ipmp_errmsg(retval)); 116 117 (*ofuncp)(ifname, handle); 118 119 ipmp_close(handle); 120 (void) close(sioc4fd); 121 (void) close(sioc6fd); 122 123 return (EXIT_SUCCESS); 124 } 125 126 /* 127 * Checks whether IFF_OFFLINE is set on `ifname'. 128 */ 129 boolean_t 130 is_offline(const char *ifname) 131 { 132 struct lifreq lifr = { 0 }; 133 134 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 135 if (ioctl(sioc4fd, SIOCGLIFFLAGS, &lifr) == -1) { 136 if (errno != ENXIO || 137 ioctl(sioc6fd, SIOCGLIFFLAGS, &lifr) == -1) { 138 die("cannot get interface flags on %s", ifname); 139 } 140 } 141 142 return ((lifr.lifr_flags & IFF_OFFLINE) != 0); 143 } 144 145 static void 146 do_offline(const char *ifname, ipmp_handle_t handle) 147 { 148 ifaddrlistx_t *ifaddrp, *ifaddrs; 149 int retval; 150 151 if (is_offline(ifname)) 152 die("interface %s is already offline\n", ifname); 153 154 if ((retval = ipmp_offline(handle, ifname, 1)) != IPMP_SUCCESS) 155 die("cannot offline %s: %s\n", ifname, mpadm_errmsg(retval)); 156 157 /* 158 * Get all the up addresses for `ifname' and bring them down. 159 */ 160 if (ifaddrlistx(ifname, IFF_UP, 0, &ifaddrs) == -1) 161 die("cannot get addresses on %s", ifname); 162 163 for (ifaddrp = ifaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { 164 if (!(ifaddrp->ia_flags & IFF_OFFLINE)) 165 warn("IFF_OFFLINE vanished on %s\n", ifaddrp->ia_name); 166 167 if (!set_lifflags(ifaddrp->ia_name, 168 ifaddrp->ia_flags & ~IFF_UP)) 169 warn("cannot bring down address on %s\n", 170 ifaddrp->ia_name); 171 } 172 173 ifaddrlistx_free(ifaddrs); 174 } 175 176 static void 177 undo_offline(const char *ifname, ipmp_handle_t handle) 178 { 179 ifaddrlistx_t *ifaddrp, *ifaddrs; 180 int retval; 181 182 if (!is_offline(ifname)) 183 die("interface %s is not offline\n", ifname); 184 185 /* 186 * Get all the down addresses for `ifname' and bring them up. 187 */ 188 if (ifaddrlistx(ifname, 0, IFF_UP, &ifaddrs) == -1) 189 die("cannot get addresses for %s", ifname); 190 191 for (ifaddrp = ifaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { 192 if (!(ifaddrp->ia_flags & IFF_OFFLINE)) 193 warn("IFF_OFFLINE vanished on %s\n", ifaddrp->ia_name); 194 195 if (!set_lifflags(ifaddrp->ia_name, ifaddrp->ia_flags | IFF_UP)) 196 warn("cannot bring up address on %s\n", 197 ifaddrp->ia_name); 198 } 199 200 ifaddrlistx_free(ifaddrs); 201 202 /* 203 * Undo the offline. 204 */ 205 if ((retval = ipmp_undo_offline(handle, ifname)) != IPMP_SUCCESS) { 206 die("cannot undo-offline %s: %s\n", ifname, 207 mpadm_errmsg(retval)); 208 } 209 210 /* 211 * Verify whether IFF_OFFLINE is set as a sanity check. 212 */ 213 if (is_offline(ifname)) 214 warn("in.mpathd has not cleared IFF_OFFLINE on %s\n", ifname); 215 } 216 217 /* 218 * Change `lifname' to have `flags' set. Returns B_TRUE on success. 219 */ 220 static boolean_t 221 set_lifflags(const char *lifname, uint64_t flags) 222 { 223 struct lifreq lifr = { 0 }; 224 int fd = (flags & IFF_IPV4) ? sioc4fd : sioc6fd; 225 226 (void) strlcpy(lifr.lifr_name, lifname, LIFNAMSIZ); 227 lifr.lifr_flags = flags; 228 229 return (ioctl(fd, SIOCSLIFFLAGS, &lifr) >= 0); 230 } 231 232 /* PRINTFLIKE1 */ 233 static void 234 die(const char *format, ...) 235 { 236 va_list alist; 237 char *errstr = strerror(errno); 238 239 format = gettext(format); 240 (void) fprintf(stderr, gettext("%s: fatal: "), progname); 241 242 va_start(alist, format); 243 (void) vfprintf(stderr, format, alist); 244 va_end(alist); 245 246 if (strchr(format, '\n') == NULL) 247 (void) fprintf(stderr, ": %s\n", errstr); 248 249 exit(EXIT_FAILURE); 250 } 251 252 /* PRINTFLIKE1 */ 253 static void 254 warn(const char *format, ...) 255 { 256 va_list alist; 257 char *errstr = strerror(errno); 258 259 format = gettext(format); 260 (void) fprintf(stderr, gettext("%s: warning: "), progname); 261 262 va_start(alist, format); 263 (void) vfprintf(stderr, format, alist); 264 va_end(alist); 265 266 if (strchr(format, '\n') == NULL) 267 (void) fprintf(stderr, ": %s\n", errstr); 268 } 269