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
usage(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 *
mpadm_errmsg(uint32_t error)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
main(int argc,char ** argv)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
is_offline(const char * ifname)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
do_offline(const char * ifname,ipmp_handle_t handle)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
undo_offline(const char * ifname,ipmp_handle_t handle)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
set_lifflags(const char * lifname,uint64_t flags)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
die(const char * format,...)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
warn(const char * format,...)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