1168793Sthompsa/*-
2168793Sthompsa */
3168793Sthompsa
4168793Sthompsa#ifndef lint
5168793Sthompsastatic const char rcsid[] =
6168793Sthompsa  "$FreeBSD: stable/10/sbin/ifconfig/iflagg.c 362368 2020-06-19 07:07:10Z rpokala $";
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:
118362368Srpokala	case LAGG_OPT_LACP_FAST_TIMO:
119362368Srpokala	case -LAGG_OPT_LACP_FAST_TIMO:
120287723Shrs		break;
121287723Shrs	default:
122287723Shrs		err(1, "Invalid lagg option");
123287723Shrs	}
124287723Shrs	strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
125287723Shrs
126287723Shrs	if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0)
127287723Shrs		err(1, "SIOCSLAGGOPTS");
128287723Shrs}
129287723Shrs
130287723Shrsstatic void
131232629Sthompsasetlagghash(const char *val, int d, int s, const struct afswtch *afp)
132232629Sthompsa{
133232629Sthompsa	struct lagg_reqflags rf;
134232629Sthompsa	char *str, *tmp, *tok;
135232629Sthompsa
136232629Sthompsa
137232629Sthompsa	rf.rf_flags = 0;
138232629Sthompsa	str = tmp = strdup(val);
139232629Sthompsa	while ((tok = strsep(&tmp, ",")) != NULL) {
140232629Sthompsa		if (strcmp(tok, "l2") == 0)
141232629Sthompsa			rf.rf_flags |= LAGG_F_HASHL2;
142232629Sthompsa		else if (strcmp(tok, "l3") == 0)
143232629Sthompsa			rf.rf_flags |= LAGG_F_HASHL3;
144232629Sthompsa		else if (strcmp(tok, "l4") == 0)
145232629Sthompsa			rf.rf_flags |= LAGG_F_HASHL4;
146249897Sglebius		else
147232629Sthompsa			errx(1, "Invalid lagghash option: %s", tok);
148232629Sthompsa	}
149232629Sthompsa	free(str);
150232629Sthompsa	if (rf.rf_flags == 0)
151232629Sthompsa		errx(1, "No lagghash options supplied");
152232629Sthompsa
153232629Sthompsa	strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
154232629Sthompsa	if (ioctl(s, SIOCSLAGGHASH, &rf))
155232629Sthompsa		err(1, "SIOCSLAGGHASH");
156232629Sthompsa}
157232629Sthompsa
158171247Sthompsastatic char *
159171247Sthompsalacp_format_mac(const uint8_t *mac, char *buf, size_t buflen)
160171247Sthompsa{
161171247Sthompsa	snprintf(buf, buflen, "%02X-%02X-%02X-%02X-%02X-%02X",
162171247Sthompsa	    (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3],
163171247Sthompsa	    (int)mac[4], (int)mac[5]);
164171247Sthompsa
165171247Sthompsa	return (buf);
166171247Sthompsa}
167171247Sthompsa
168171247Sthompsastatic char *
169171247Sthompsalacp_format_peer(struct lacp_opreq *req, const char *sep)
170171247Sthompsa{
171171247Sthompsa	char macbuf1[20];
172171247Sthompsa	char macbuf2[20];
173171247Sthompsa
174171247Sthompsa	snprintf(lacpbuf, sizeof(lacpbuf),
175171247Sthompsa	    "[(%04X,%s,%04X,%04X,%04X),%s(%04X,%s,%04X,%04X,%04X)]",
176171247Sthompsa	    req->actor_prio,
177171247Sthompsa	    lacp_format_mac(req->actor_mac, macbuf1, sizeof(macbuf1)),
178171247Sthompsa	    req->actor_key, req->actor_portprio, req->actor_portno, sep,
179171247Sthompsa	    req->partner_prio,
180171247Sthompsa	    lacp_format_mac(req->partner_mac, macbuf2, sizeof(macbuf2)),
181171247Sthompsa	    req->partner_key, req->partner_portprio, req->partner_portno);
182171247Sthompsa
183171247Sthompsa	return(lacpbuf);
184171247Sthompsa}
185171247Sthompsa
186168793Sthompsastatic void
187168793Sthompsalagg_status(int s)
188168793Sthompsa{
189170603Sthompsa	struct lagg_protos lpr[] = LAGG_PROTOS;
190319265Sasomers	struct lagg_reqport rpbuf[LAGG_MAX_PORTS];
191168793Sthompsa	struct lagg_reqall ra;
192287723Shrs	struct lagg_reqopts ro;
193232629Sthompsa	struct lagg_reqflags rf;
194171247Sthompsa	struct lacp_opreq *lp;
195168793Sthompsa	const char *proto = "<unknown>";
196319265Sasomers	int i;
197168793Sthompsa
198168793Sthompsa	bzero(&ra, sizeof(ra));
199287723Shrs	bzero(&ro, sizeof(ro));
200168793Sthompsa
201168793Sthompsa	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
202168793Sthompsa	ra.ra_size = sizeof(rpbuf);
203168793Sthompsa	ra.ra_port = rpbuf;
204168793Sthompsa
205287723Shrs	strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
206287723Shrs	ioctl(s, SIOCGLAGGOPTS, &ro);
207287723Shrs
208232629Sthompsa	strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
209232629Sthompsa	if (ioctl(s, SIOCGLAGGFLAGS, &rf) != 0)
210232629Sthompsa		rf.rf_flags = 0;
211232629Sthompsa
212168793Sthompsa	if (ioctl(s, SIOCGLAGG, &ra) == 0) {
213171247Sthompsa		lp = (struct lacp_opreq *)&ra.ra_lacpreq;
214171247Sthompsa
215287723Shrs		for (i = 0; i < nitems(lpr); i++) {
216170603Sthompsa			if (ra.ra_proto == lpr[i].lpr_proto) {
217170603Sthompsa				proto = lpr[i].lpr_name;
218168793Sthompsa				break;
219168793Sthompsa			}
220168793Sthompsa		}
221168793Sthompsa
222171247Sthompsa		printf("\tlaggproto %s", proto);
223232629Sthompsa		if (rf.rf_flags & LAGG_F_HASHMASK) {
224232629Sthompsa			const char *sep = "";
225232629Sthompsa
226232629Sthompsa			printf(" lagghash ");
227232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL2) {
228232629Sthompsa				printf("%sl2", sep);
229232629Sthompsa				sep = ",";
230232629Sthompsa			}
231232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL3) {
232232629Sthompsa				printf("%sl3", sep);
233232629Sthompsa				sep = ",";
234232629Sthompsa			}
235232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL4) {
236232629Sthompsa				printf("%sl4", sep);
237232629Sthompsa				sep = ",";
238232629Sthompsa			}
239232629Sthompsa		}
240168793Sthompsa		putchar('\n');
241287723Shrs		if (verbose) {
242287723Shrs			printf("\tlagg options:\n");
243287723Shrs			printb("\t\tflags", ro.ro_opts, LAGG_OPT_BITS);
244287723Shrs			putchar('\n');
245287723Shrs			printf("\t\tflowid_shift: %d\n", ro.ro_flowid_shift);
246287723Shrs			printf("\tlagg statistics:\n");
247287723Shrs			printf("\t\tactive ports: %d\n", ro.ro_active);
248287723Shrs			printf("\t\tflapping: %u\n", ro.ro_flapping);
249287723Shrs			if (ra.ra_proto == LAGG_PROTO_LACP) {
250287723Shrs				printf("\tlag id: %s\n",
251287723Shrs				    lacp_format_peer(lp, "\n\t\t "));
252287723Shrs			}
253287723Shrs		}
254168793Sthompsa
255168793Sthompsa		for (i = 0; i < ra.ra_ports; i++) {
256171247Sthompsa			lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq;
257171247Sthompsa			printf("\tlaggport: %s ", rpbuf[i].rp_portname);
258171247Sthompsa			printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS);
259171247Sthompsa			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
260287723Shrs				printb(" state", lp->actor_state,
261287723Shrs				    LACP_STATE_BITS);
262168793Sthompsa			putchar('\n');
263171247Sthompsa			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
264171247Sthompsa				printf("\t\t%s\n",
265171247Sthompsa				    lacp_format_peer(lp, "\n\t\t "));
266168793Sthompsa		}
267168793Sthompsa
268168793Sthompsa		if (0 /* XXX */) {
269168793Sthompsa			printf("\tsupported aggregation protocols:\n");
270170603Sthompsa			for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++)
271170603Sthompsa				printf("\t\tlaggproto %s\n", lpr[i].lpr_name);
272168793Sthompsa		}
273191693Sthompsa	}
274168793Sthompsa}
275168793Sthompsa
276168793Sthompsastatic struct cmd lagg_cmds[] = {
277168793Sthompsa	DEF_CMD_ARG("laggport",		setlaggport),
278168793Sthompsa	DEF_CMD_ARG("-laggport",	unsetlaggport),
279168793Sthompsa	DEF_CMD_ARG("laggproto",	setlaggproto),
280232629Sthompsa	DEF_CMD_ARG("lagghash",		setlagghash),
281287723Shrs	DEF_CMD("use_flowid",	LAGG_OPT_USE_FLOWID,	setlaggsetopt),
282287723Shrs	DEF_CMD("-use_flowid",	-LAGG_OPT_USE_FLOWID,	setlaggsetopt),
283287723Shrs	DEF_CMD("lacp_strict",	LAGG_OPT_LACP_STRICT,	setlaggsetopt),
284287723Shrs	DEF_CMD("-lacp_strict",	-LAGG_OPT_LACP_STRICT,	setlaggsetopt),
285287723Shrs	DEF_CMD("lacp_txtest",	LAGG_OPT_LACP_TXTEST,	setlaggsetopt),
286287723Shrs	DEF_CMD("-lacp_txtest",	-LAGG_OPT_LACP_TXTEST,	setlaggsetopt),
287287723Shrs	DEF_CMD("lacp_rxtest",	LAGG_OPT_LACP_RXTEST,	setlaggsetopt),
288287723Shrs	DEF_CMD("-lacp_rxtest",	-LAGG_OPT_LACP_RXTEST,	setlaggsetopt),
289362368Srpokala	DEF_CMD("lacp_fast_timeout",	LAGG_OPT_LACP_FAST_TIMO,	setlaggsetopt),
290362368Srpokala	DEF_CMD("-lacp_fast_timeout",	-LAGG_OPT_LACP_FAST_TIMO,	setlaggsetopt),
291287723Shrs	DEF_CMD_ARG("flowid_shift",	setlaggflowidshift),
292168793Sthompsa};
293168793Sthompsastatic struct afswtch af_lagg = {
294168793Sthompsa	.af_name	= "af_lagg",
295168793Sthompsa	.af_af		= AF_UNSPEC,
296168793Sthompsa	.af_other_status = lagg_status,
297168793Sthompsa};
298168793Sthompsa
299168793Sthompsastatic __constructor void
300168793Sthompsalagg_ctor(void)
301168793Sthompsa{
302168793Sthompsa	int i;
303168793Sthompsa
304289986Sngie	for (i = 0; i < nitems(lagg_cmds);  i++)
305168793Sthompsa		cmd_register(&lagg_cmds[i]);
306168793Sthompsa	af_register(&af_lagg);
307168793Sthompsa}
308