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 
26e11c3f44Smeem #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>
327c478bd9Sstevel@tonic-gate #include <stdio.h>
33e11c3f44Smeem #include <stdlib.h>
34e11c3f44Smeem #include <string.h>
35e11c3f44Smeem #include <unistd.h>
367c478bd9Sstevel@tonic-gate #include <sys/socket.h>
377c478bd9Sstevel@tonic-gate #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;
100*e25ac69dSmeem 		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));
1187c478bd9Sstevel@tonic-gate 
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  */
131e11c3f44Smeem 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 	}
143e11c3f44Smeem 
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);
1687c478bd9Sstevel@tonic-gate 
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);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	/*
188e11c3f44Smeem 	 * Get all the down addresses for `ifname' and bring them up.
1897c478bd9Sstevel@tonic-gate 	 */
190e11c3f44Smeem 	if (ifaddrlistx(ifname, 0, IFF_UP, &ifaddrs) == -1)
191e11c3f44Smeem 		die("cannot get addresses for %s", ifname);
1927c478bd9Sstevel@tonic-gate 
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);
1967c478bd9Sstevel@tonic-gate 
197e11c3f44Smeem 		if (!set_lifflags(ifaddrp->ia_name, ifaddrp->ia_flags | IFF_UP))
198*e25ac69dSmeem 			warn("cannot bring up address on %s", ifaddrp->ia_name);
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
201e11c3f44Smeem 	ifaddrlistx_free(ifaddrs);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	/*
204e11c3f44Smeem 	 * Undo the offline.
2057c478bd9Sstevel@tonic-gate 	 */
206e11c3f44Smeem 	if ((retval = ipmp_undo_offline(handle, ifname)) != IPMP_SUCCESS) {
207e11c3f44Smeem 		die("cannot undo-offline %s: %s\n", ifname,
208e11c3f44Smeem 		    mpadm_errmsg(retval));
2097c478bd9Sstevel@tonic-gate 	}
210e11c3f44Smeem 
211e11c3f44Smeem 	/*
212e11c3f44Smeem 	 * Verify whether IFF_OFFLINE is set as a sanity check.
213e11c3f44Smeem 	 */
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;
2297c478bd9Sstevel@tonic-gate 
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);
2427c478bd9Sstevel@tonic-gate 
243e11c3f44Smeem 	va_start(alist, format);
244e11c3f44Smeem 	(void) vfprintf(stderr, format, alist);
245e11c3f44Smeem 	va_end(alist);
2467c478bd9Sstevel@tonic-gate 
247e11c3f44Smeem 	if (strchr(format, '\n') == NULL)
248e11c3f44Smeem 		(void) fprintf(stderr, ": %s\n", errstr);
2497c478bd9Sstevel@tonic-gate 
250e11c3f44Smeem 	exit(EXIT_FAILURE);
251e11c3f44Smeem }
2527c478bd9Sstevel@tonic-gate 
253e11c3f44Smeem /* PRINTFLIKE1 */
254e11c3f44Smeem static void
warn(const char * format,...)255e11c3f44Smeem warn(const char *format, ...)
256e11c3f44Smeem {
257e11c3f44Smeem 	va_list alist;
258e11c3f44Smeem 	char *errstr = strerror(errno);
259e11c3f44Smeem 
260e11c3f44Smeem 	format = gettext(format);
261e11c3f44Smeem 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
262e11c3f44Smeem 
263e11c3f44Smeem 	va_start(alist, format);
264e11c3f44Smeem 	(void) vfprintf(stderr, format, alist);
265e11c3f44Smeem 	va_end(alist);
266e11c3f44Smeem 
267e11c3f44Smeem 	if (strchr(format, '\n') == NULL)
268e11c3f44Smeem 		(void) fprintf(stderr, ": %s\n", errstr);
2697c478bd9Sstevel@tonic-gate }
270