iflagg.c revision 287723
1168793Sthompsa/*-
2168793Sthompsa */
3168793Sthompsa
4168793Sthompsa#ifndef lint
5168793Sthompsastatic const char rcsid[] =
6168793Sthompsa  "$FreeBSD: stable/10/sbin/ifconfig/iflagg.c 287723 2015-09-12 20:36:39Z hrs $";
7168793Sthompsa#endif /* not lint */
8168793Sthompsa
9168793Sthompsa#include <sys/param.h>
10168793Sthompsa#include <sys/ioctl.h>
11168793Sthompsa#include <sys/socket.h>
12168793Sthompsa#include <sys/sockio.h>
13168793Sthompsa
14168793Sthompsa#include <stdlib.h>
15168793Sthompsa#include <unistd.h>
16168793Sthompsa
17168793Sthompsa#include <net/ethernet.h>
18168793Sthompsa#include <net/if.h>
19168793Sthompsa#include <net/if_lagg.h>
20287723Shrs#include <net/ieee8023ad_lacp.h>
21168793Sthompsa#include <net/route.h>
22168793Sthompsa
23168793Sthompsa#include <ctype.h>
24168793Sthompsa#include <stdio.h>
25168793Sthompsa#include <string.h>
26168793Sthompsa#include <stdlib.h>
27168793Sthompsa#include <unistd.h>
28168793Sthompsa#include <err.h>
29168793Sthompsa#include <errno.h>
30168793Sthompsa
31168793Sthompsa#include "ifconfig.h"
32168793Sthompsa
33171247Sthompsachar lacpbuf[120];	/* LACP peer '[(a,a,a),(p,p,p)]' */
34171247Sthompsa
35168793Sthompsastatic void
36168793Sthompsasetlaggport(const char *val, int d, int s, const struct afswtch *afp)
37168793Sthompsa{
38168793Sthompsa	struct lagg_reqport rp;
39168793Sthompsa
40168793Sthompsa	bzero(&rp, sizeof(rp));
41168793Sthompsa	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
42168793Sthompsa	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
43168793Sthompsa
44236178Srea	/* Don't choke if the port is already in this lagg. */
45236178Srea	if (ioctl(s, SIOCSLAGGPORT, &rp) && errno != EEXIST)
46168793Sthompsa		err(1, "SIOCSLAGGPORT");
47168793Sthompsa}
48168793Sthompsa
49168793Sthompsastatic void
50168793Sthompsaunsetlaggport(const char *val, int d, int s, const struct afswtch *afp)
51168793Sthompsa{
52168793Sthompsa	struct lagg_reqport rp;
53168793Sthompsa
54168793Sthompsa	bzero(&rp, sizeof(rp));
55168793Sthompsa	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
56168793Sthompsa	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
57168793Sthompsa
58168793Sthompsa	if (ioctl(s, SIOCSLAGGDELPORT, &rp))
59168793Sthompsa		err(1, "SIOCSLAGGDELPORT");
60168793Sthompsa}
61168793Sthompsa
62168793Sthompsastatic void
63168793Sthompsasetlaggproto(const char *val, int d, int s, const struct afswtch *afp)
64168793Sthompsa{
65170603Sthompsa	struct lagg_protos lpr[] = LAGG_PROTOS;
66168793Sthompsa	struct lagg_reqall ra;
67168793Sthompsa	int i;
68168793Sthompsa
69168793Sthompsa	bzero(&ra, sizeof(ra));
70168793Sthompsa	ra.ra_proto = LAGG_PROTO_MAX;
71168793Sthompsa
72287723Shrs	for (i = 0; i < nitems(lpr); i++) {
73170603Sthompsa		if (strcmp(val, lpr[i].lpr_name) == 0) {
74170603Sthompsa			ra.ra_proto = lpr[i].lpr_proto;
75168793Sthompsa			break;
76168793Sthompsa		}
77168793Sthompsa	}
78168793Sthompsa	if (ra.ra_proto == LAGG_PROTO_MAX)
79168793Sthompsa		errx(1, "Invalid aggregation protocol: %s", val);
80168793Sthompsa
81168793Sthompsa	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
82168793Sthompsa	if (ioctl(s, SIOCSLAGG, &ra) != 0)
83168793Sthompsa		err(1, "SIOCSLAGG");
84168793Sthompsa}
85168793Sthompsa
86232629Sthompsastatic void
87287723Shrssetlaggflowidshift(const char *val, int d, int s, const struct afswtch *afp)
88287723Shrs{
89287723Shrs	struct lagg_reqopts ro;
90287723Shrs
91287723Shrs	bzero(&ro, sizeof(ro));
92287723Shrs	ro.ro_opts = LAGG_OPT_FLOWIDSHIFT;
93287723Shrs	strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
94287723Shrs	ro.ro_flowid_shift = (int)strtol(val, NULL, 10);
95287723Shrs	if (ro.ro_flowid_shift & ~LAGG_OPT_FLOWIDSHIFT_MASK)
96287723Shrs		errx(1, "Invalid flowid_shift option: %s", val);
97287723Shrs
98287723Shrs	if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0)
99287723Shrs		err(1, "SIOCSLAGGOPTS");
100287723Shrs}
101287723Shrs
102287723Shrsstatic void
103287723Shrssetlaggsetopt(const char *val, int d, int s, const struct afswtch *afp)
104287723Shrs{
105287723Shrs	struct lagg_reqopts ro;
106287723Shrs
107287723Shrs	bzero(&ro, sizeof(ro));
108287723Shrs	ro.ro_opts = d;
109287723Shrs	switch (ro.ro_opts) {
110287723Shrs	case LAGG_OPT_USE_FLOWID:
111287723Shrs	case -LAGG_OPT_USE_FLOWID:
112287723Shrs	case LAGG_OPT_LACP_STRICT:
113287723Shrs	case -LAGG_OPT_LACP_STRICT:
114287723Shrs	case LAGG_OPT_LACP_TXTEST:
115287723Shrs	case -LAGG_OPT_LACP_TXTEST:
116287723Shrs	case LAGG_OPT_LACP_RXTEST:
117287723Shrs	case -LAGG_OPT_LACP_RXTEST:
118287723Shrs		break;
119287723Shrs	default:
120287723Shrs		err(1, "Invalid lagg option");
121287723Shrs	}
122287723Shrs	strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
123287723Shrs
124287723Shrs	if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0)
125287723Shrs		err(1, "SIOCSLAGGOPTS");
126287723Shrs}
127287723Shrs
128287723Shrsstatic void
129232629Sthompsasetlagghash(const char *val, int d, int s, const struct afswtch *afp)
130232629Sthompsa{
131232629Sthompsa	struct lagg_reqflags rf;
132232629Sthompsa	char *str, *tmp, *tok;
133232629Sthompsa
134232629Sthompsa
135232629Sthompsa	rf.rf_flags = 0;
136232629Sthompsa	str = tmp = strdup(val);
137232629Sthompsa	while ((tok = strsep(&tmp, ",")) != NULL) {
138232629Sthompsa		if (strcmp(tok, "l2") == 0)
139232629Sthompsa			rf.rf_flags |= LAGG_F_HASHL2;
140232629Sthompsa		else if (strcmp(tok, "l3") == 0)
141232629Sthompsa			rf.rf_flags |= LAGG_F_HASHL3;
142232629Sthompsa		else if (strcmp(tok, "l4") == 0)
143232629Sthompsa			rf.rf_flags |= LAGG_F_HASHL4;
144249897Sglebius		else
145232629Sthompsa			errx(1, "Invalid lagghash option: %s", tok);
146232629Sthompsa	}
147232629Sthompsa	free(str);
148232629Sthompsa	if (rf.rf_flags == 0)
149232629Sthompsa		errx(1, "No lagghash options supplied");
150232629Sthompsa
151232629Sthompsa	strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
152232629Sthompsa	if (ioctl(s, SIOCSLAGGHASH, &rf))
153232629Sthompsa		err(1, "SIOCSLAGGHASH");
154232629Sthompsa}
155232629Sthompsa
156171247Sthompsastatic char *
157171247Sthompsalacp_format_mac(const uint8_t *mac, char *buf, size_t buflen)
158171247Sthompsa{
159171247Sthompsa	snprintf(buf, buflen, "%02X-%02X-%02X-%02X-%02X-%02X",
160171247Sthompsa	    (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3],
161171247Sthompsa	    (int)mac[4], (int)mac[5]);
162171247Sthompsa
163171247Sthompsa	return (buf);
164171247Sthompsa}
165171247Sthompsa
166171247Sthompsastatic char *
167171247Sthompsalacp_format_peer(struct lacp_opreq *req, const char *sep)
168171247Sthompsa{
169171247Sthompsa	char macbuf1[20];
170171247Sthompsa	char macbuf2[20];
171171247Sthompsa
172171247Sthompsa	snprintf(lacpbuf, sizeof(lacpbuf),
173171247Sthompsa	    "[(%04X,%s,%04X,%04X,%04X),%s(%04X,%s,%04X,%04X,%04X)]",
174171247Sthompsa	    req->actor_prio,
175171247Sthompsa	    lacp_format_mac(req->actor_mac, macbuf1, sizeof(macbuf1)),
176171247Sthompsa	    req->actor_key, req->actor_portprio, req->actor_portno, sep,
177171247Sthompsa	    req->partner_prio,
178171247Sthompsa	    lacp_format_mac(req->partner_mac, macbuf2, sizeof(macbuf2)),
179171247Sthompsa	    req->partner_key, req->partner_portprio, req->partner_portno);
180171247Sthompsa
181171247Sthompsa	return(lacpbuf);
182171247Sthompsa}
183171247Sthompsa
184168793Sthompsastatic void
185168793Sthompsalagg_status(int s)
186168793Sthompsa{
187170603Sthompsa	struct lagg_protos lpr[] = LAGG_PROTOS;
188168793Sthompsa	struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS];
189168793Sthompsa	struct lagg_reqall ra;
190287723Shrs	struct lagg_reqopts ro;
191232629Sthompsa	struct lagg_reqflags rf;
192171247Sthompsa	struct lacp_opreq *lp;
193168793Sthompsa	const char *proto = "<unknown>";
194168793Sthompsa	int i, isport = 0;
195168793Sthompsa
196168793Sthompsa	bzero(&rp, sizeof(rp));
197168793Sthompsa	bzero(&ra, sizeof(ra));
198287723Shrs	bzero(&ro, sizeof(ro));
199168793Sthompsa
200168793Sthompsa	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
201168793Sthompsa	strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname));
202168793Sthompsa
203168793Sthompsa	if (ioctl(s, SIOCGLAGGPORT, &rp) == 0)
204168793Sthompsa		isport = 1;
205168793Sthompsa
206168793Sthompsa	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
207168793Sthompsa	ra.ra_size = sizeof(rpbuf);
208168793Sthompsa	ra.ra_port = rpbuf;
209168793Sthompsa
210287723Shrs	strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
211287723Shrs	ioctl(s, SIOCGLAGGOPTS, &ro);
212287723Shrs
213232629Sthompsa	strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
214232629Sthompsa	if (ioctl(s, SIOCGLAGGFLAGS, &rf) != 0)
215232629Sthompsa		rf.rf_flags = 0;
216232629Sthompsa
217168793Sthompsa	if (ioctl(s, SIOCGLAGG, &ra) == 0) {
218171247Sthompsa		lp = (struct lacp_opreq *)&ra.ra_lacpreq;
219171247Sthompsa
220287723Shrs		for (i = 0; i < nitems(lpr); i++) {
221170603Sthompsa			if (ra.ra_proto == lpr[i].lpr_proto) {
222170603Sthompsa				proto = lpr[i].lpr_name;
223168793Sthompsa				break;
224168793Sthompsa			}
225168793Sthompsa		}
226168793Sthompsa
227171247Sthompsa		printf("\tlaggproto %s", proto);
228232629Sthompsa		if (rf.rf_flags & LAGG_F_HASHMASK) {
229232629Sthompsa			const char *sep = "";
230232629Sthompsa
231232629Sthompsa			printf(" lagghash ");
232232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL2) {
233232629Sthompsa				printf("%sl2", sep);
234232629Sthompsa				sep = ",";
235232629Sthompsa			}
236232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL3) {
237232629Sthompsa				printf("%sl3", sep);
238232629Sthompsa				sep = ",";
239232629Sthompsa			}
240232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL4) {
241232629Sthompsa				printf("%sl4", sep);
242232629Sthompsa				sep = ",";
243232629Sthompsa			}
244232629Sthompsa		}
245168793Sthompsa		if (isport)
246168793Sthompsa			printf(" laggdev %s", rp.rp_ifname);
247168793Sthompsa		putchar('\n');
248287723Shrs		if (verbose) {
249287723Shrs			printf("\tlagg options:\n");
250287723Shrs			printb("\t\tflags", ro.ro_opts, LAGG_OPT_BITS);
251287723Shrs			putchar('\n');
252287723Shrs			printf("\t\tflowid_shift: %d\n", ro.ro_flowid_shift);
253287723Shrs			printf("\tlagg statistics:\n");
254287723Shrs			printf("\t\tactive ports: %d\n", ro.ro_active);
255287723Shrs			printf("\t\tflapping: %u\n", ro.ro_flapping);
256287723Shrs			if (ra.ra_proto == LAGG_PROTO_LACP) {
257287723Shrs				printf("\tlag id: %s\n",
258287723Shrs				    lacp_format_peer(lp, "\n\t\t "));
259287723Shrs			}
260287723Shrs		}
261168793Sthompsa
262168793Sthompsa		for (i = 0; i < ra.ra_ports; i++) {
263171247Sthompsa			lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq;
264171247Sthompsa			printf("\tlaggport: %s ", rpbuf[i].rp_portname);
265171247Sthompsa			printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS);
266171247Sthompsa			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
267287723Shrs				printb(" state", lp->actor_state,
268287723Shrs				    LACP_STATE_BITS);
269168793Sthompsa			putchar('\n');
270171247Sthompsa			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
271171247Sthompsa				printf("\t\t%s\n",
272171247Sthompsa				    lacp_format_peer(lp, "\n\t\t "));
273168793Sthompsa		}
274168793Sthompsa
275168793Sthompsa		if (0 /* XXX */) {
276168793Sthompsa			printf("\tsupported aggregation protocols:\n");
277170603Sthompsa			for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++)
278170603Sthompsa				printf("\t\tlaggproto %s\n", lpr[i].lpr_name);
279168793Sthompsa		}
280191693Sthompsa	}
281168793Sthompsa}
282168793Sthompsa
283168793Sthompsastatic struct cmd lagg_cmds[] = {
284168793Sthompsa	DEF_CMD_ARG("laggport",		setlaggport),
285168793Sthompsa	DEF_CMD_ARG("-laggport",	unsetlaggport),
286168793Sthompsa	DEF_CMD_ARG("laggproto",	setlaggproto),
287232629Sthompsa	DEF_CMD_ARG("lagghash",		setlagghash),
288287723Shrs	DEF_CMD("use_flowid",	LAGG_OPT_USE_FLOWID,	setlaggsetopt),
289287723Shrs	DEF_CMD("-use_flowid",	-LAGG_OPT_USE_FLOWID,	setlaggsetopt),
290287723Shrs	DEF_CMD("lacp_strict",	LAGG_OPT_LACP_STRICT,	setlaggsetopt),
291287723Shrs	DEF_CMD("-lacp_strict",	-LAGG_OPT_LACP_STRICT,	setlaggsetopt),
292287723Shrs	DEF_CMD("lacp_txtest",	LAGG_OPT_LACP_TXTEST,	setlaggsetopt),
293287723Shrs	DEF_CMD("-lacp_txtest",	-LAGG_OPT_LACP_TXTEST,	setlaggsetopt),
294287723Shrs	DEF_CMD("lacp_rxtest",	LAGG_OPT_LACP_RXTEST,	setlaggsetopt),
295287723Shrs	DEF_CMD("-lacp_rxtest",	-LAGG_OPT_LACP_RXTEST,	setlaggsetopt),
296287723Shrs	DEF_CMD_ARG("flowid_shift",	setlaggflowidshift),
297168793Sthompsa};
298168793Sthompsastatic struct afswtch af_lagg = {
299168793Sthompsa	.af_name	= "af_lagg",
300168793Sthompsa	.af_af		= AF_UNSPEC,
301168793Sthompsa	.af_other_status = lagg_status,
302168793Sthompsa};
303168793Sthompsa
304168793Sthompsastatic __constructor void
305168793Sthompsalagg_ctor(void)
306168793Sthompsa{
307168793Sthompsa#define	N(a)	(sizeof(a) / sizeof(a[0]))
308168793Sthompsa	int i;
309168793Sthompsa
310168793Sthompsa	for (i = 0; i < N(lagg_cmds);  i++)
311168793Sthompsa		cmd_register(&lagg_cmds[i]);
312168793Sthompsa	af_register(&af_lagg);
313168793Sthompsa#undef N
314168793Sthompsa}
315