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