iflagg.c revision 236178
1168793Sthompsa/*-
2168793Sthompsa */
3168793Sthompsa
4168793Sthompsa#ifndef lint
5168793Sthompsastatic const char rcsid[] =
6168793Sthompsa  "$FreeBSD: head/sbin/ifconfig/iflagg.c 236178 2012-05-28 12:13:04Z rea $";
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>
20168793Sthompsa#include <net/route.h>
21168793Sthompsa
22168793Sthompsa#include <ctype.h>
23168793Sthompsa#include <stdio.h>
24168793Sthompsa#include <string.h>
25168793Sthompsa#include <stdlib.h>
26168793Sthompsa#include <unistd.h>
27168793Sthompsa#include <err.h>
28168793Sthompsa#include <errno.h>
29168793Sthompsa
30168793Sthompsa#include "ifconfig.h"
31168793Sthompsa
32171247Sthompsachar lacpbuf[120];	/* LACP peer '[(a,a,a),(p,p,p)]' */
33171247Sthompsa
34168793Sthompsastatic void
35168793Sthompsasetlaggport(const char *val, int d, int s, const struct afswtch *afp)
36168793Sthompsa{
37168793Sthompsa	struct lagg_reqport rp;
38168793Sthompsa
39168793Sthompsa	bzero(&rp, sizeof(rp));
40168793Sthompsa	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
41168793Sthompsa	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
42168793Sthompsa
43236178Srea	/* Don't choke if the port is already in this lagg. */
44236178Srea	if (ioctl(s, SIOCSLAGGPORT, &rp) && errno != EEXIST)
45168793Sthompsa		err(1, "SIOCSLAGGPORT");
46168793Sthompsa}
47168793Sthompsa
48168793Sthompsastatic void
49168793Sthompsaunsetlaggport(const char *val, int d, int s, const struct afswtch *afp)
50168793Sthompsa{
51168793Sthompsa	struct lagg_reqport rp;
52168793Sthompsa
53168793Sthompsa	bzero(&rp, sizeof(rp));
54168793Sthompsa	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
55168793Sthompsa	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
56168793Sthompsa
57168793Sthompsa	if (ioctl(s, SIOCSLAGGDELPORT, &rp))
58168793Sthompsa		err(1, "SIOCSLAGGDELPORT");
59168793Sthompsa}
60168793Sthompsa
61168793Sthompsastatic void
62168793Sthompsasetlaggproto(const char *val, int d, int s, const struct afswtch *afp)
63168793Sthompsa{
64170603Sthompsa	struct lagg_protos lpr[] = LAGG_PROTOS;
65168793Sthompsa	struct lagg_reqall ra;
66168793Sthompsa	int i;
67168793Sthompsa
68168793Sthompsa	bzero(&ra, sizeof(ra));
69168793Sthompsa	ra.ra_proto = LAGG_PROTO_MAX;
70168793Sthompsa
71170603Sthompsa	for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
72170603Sthompsa		if (strcmp(val, lpr[i].lpr_name) == 0) {
73170603Sthompsa			ra.ra_proto = lpr[i].lpr_proto;
74168793Sthompsa			break;
75168793Sthompsa		}
76168793Sthompsa	}
77168793Sthompsa	if (ra.ra_proto == LAGG_PROTO_MAX)
78168793Sthompsa		errx(1, "Invalid aggregation protocol: %s", val);
79168793Sthompsa
80168793Sthompsa	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
81168793Sthompsa	if (ioctl(s, SIOCSLAGG, &ra) != 0)
82168793Sthompsa		err(1, "SIOCSLAGG");
83168793Sthompsa}
84168793Sthompsa
85232629Sthompsastatic void
86232629Sthompsasetlagghash(const char *val, int d, int s, const struct afswtch *afp)
87232629Sthompsa{
88232629Sthompsa	struct lagg_reqflags rf;
89232629Sthompsa	char *str, *tmp, *tok;
90232629Sthompsa
91232629Sthompsa
92232629Sthompsa	rf.rf_flags = 0;
93232629Sthompsa	str = tmp = strdup(val);
94232629Sthompsa	while ((tok = strsep(&tmp, ",")) != NULL) {
95232629Sthompsa		if (strcmp(tok, "l2") == 0)
96232629Sthompsa			rf.rf_flags |= LAGG_F_HASHL2;
97232629Sthompsa		else if (strcmp(tok, "l3") == 0)
98232629Sthompsa			rf.rf_flags |= LAGG_F_HASHL3;
99232629Sthompsa		else if (strcmp(tok, "l4") == 0)
100232629Sthompsa			rf.rf_flags |= LAGG_F_HASHL4;
101232629Sthompsa		else  {
102232629Sthompsa			free(str);
103232629Sthompsa			errx(1, "Invalid lagghash option: %s", tok);
104232629Sthompsa		}
105232629Sthompsa	}
106232629Sthompsa	free(str);
107232629Sthompsa	if (rf.rf_flags == 0)
108232629Sthompsa		errx(1, "No lagghash options supplied");
109232629Sthompsa
110232629Sthompsa	strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
111232629Sthompsa	if (ioctl(s, SIOCSLAGGHASH, &rf))
112232629Sthompsa		err(1, "SIOCSLAGGHASH");
113232629Sthompsa}
114232629Sthompsa
115171247Sthompsastatic char *
116171247Sthompsalacp_format_mac(const uint8_t *mac, char *buf, size_t buflen)
117171247Sthompsa{
118171247Sthompsa	snprintf(buf, buflen, "%02X-%02X-%02X-%02X-%02X-%02X",
119171247Sthompsa	    (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3],
120171247Sthompsa	    (int)mac[4], (int)mac[5]);
121171247Sthompsa
122171247Sthompsa	return (buf);
123171247Sthompsa}
124171247Sthompsa
125171247Sthompsastatic char *
126171247Sthompsalacp_format_peer(struct lacp_opreq *req, const char *sep)
127171247Sthompsa{
128171247Sthompsa	char macbuf1[20];
129171247Sthompsa	char macbuf2[20];
130171247Sthompsa
131171247Sthompsa	snprintf(lacpbuf, sizeof(lacpbuf),
132171247Sthompsa	    "[(%04X,%s,%04X,%04X,%04X),%s(%04X,%s,%04X,%04X,%04X)]",
133171247Sthompsa	    req->actor_prio,
134171247Sthompsa	    lacp_format_mac(req->actor_mac, macbuf1, sizeof(macbuf1)),
135171247Sthompsa	    req->actor_key, req->actor_portprio, req->actor_portno, sep,
136171247Sthompsa	    req->partner_prio,
137171247Sthompsa	    lacp_format_mac(req->partner_mac, macbuf2, sizeof(macbuf2)),
138171247Sthompsa	    req->partner_key, req->partner_portprio, req->partner_portno);
139171247Sthompsa
140171247Sthompsa	return(lacpbuf);
141171247Sthompsa}
142171247Sthompsa
143168793Sthompsastatic void
144168793Sthompsalagg_status(int s)
145168793Sthompsa{
146170603Sthompsa	struct lagg_protos lpr[] = LAGG_PROTOS;
147168793Sthompsa	struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS];
148168793Sthompsa	struct lagg_reqall ra;
149232629Sthompsa	struct lagg_reqflags rf;
150171247Sthompsa	struct lacp_opreq *lp;
151168793Sthompsa	const char *proto = "<unknown>";
152168793Sthompsa	int i, isport = 0;
153168793Sthompsa
154168793Sthompsa	bzero(&rp, sizeof(rp));
155168793Sthompsa	bzero(&ra, sizeof(ra));
156168793Sthompsa
157168793Sthompsa	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
158168793Sthompsa	strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname));
159168793Sthompsa
160168793Sthompsa	if (ioctl(s, SIOCGLAGGPORT, &rp) == 0)
161168793Sthompsa		isport = 1;
162168793Sthompsa
163168793Sthompsa	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
164168793Sthompsa	ra.ra_size = sizeof(rpbuf);
165168793Sthompsa	ra.ra_port = rpbuf;
166168793Sthompsa
167232629Sthompsa	strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
168232629Sthompsa	if (ioctl(s, SIOCGLAGGFLAGS, &rf) != 0)
169232629Sthompsa		rf.rf_flags = 0;
170232629Sthompsa
171168793Sthompsa	if (ioctl(s, SIOCGLAGG, &ra) == 0) {
172171247Sthompsa		lp = (struct lacp_opreq *)&ra.ra_lacpreq;
173171247Sthompsa
174170603Sthompsa		for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
175170603Sthompsa			if (ra.ra_proto == lpr[i].lpr_proto) {
176170603Sthompsa				proto = lpr[i].lpr_name;
177168793Sthompsa				break;
178168793Sthompsa			}
179168793Sthompsa		}
180168793Sthompsa
181171247Sthompsa		printf("\tlaggproto %s", proto);
182232629Sthompsa		if (rf.rf_flags & LAGG_F_HASHMASK) {
183232629Sthompsa			const char *sep = "";
184232629Sthompsa
185232629Sthompsa			printf(" lagghash ");
186232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL2) {
187232629Sthompsa				printf("%sl2", sep);
188232629Sthompsa				sep = ",";
189232629Sthompsa			}
190232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL3) {
191232629Sthompsa				printf("%sl3", sep);
192232629Sthompsa				sep = ",";
193232629Sthompsa			}
194232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL4) {
195232629Sthompsa				printf("%sl4", sep);
196232629Sthompsa				sep = ",";
197232629Sthompsa			}
198232629Sthompsa		}
199168793Sthompsa		if (isport)
200168793Sthompsa			printf(" laggdev %s", rp.rp_ifname);
201168793Sthompsa		putchar('\n');
202171247Sthompsa		if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
203171247Sthompsa			printf("\tlag id: %s\n",
204171247Sthompsa			    lacp_format_peer(lp, "\n\t\t "));
205168793Sthompsa
206168793Sthompsa		for (i = 0; i < ra.ra_ports; i++) {
207171247Sthompsa			lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq;
208171247Sthompsa			printf("\tlaggport: %s ", rpbuf[i].rp_portname);
209171247Sthompsa			printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS);
210171247Sthompsa			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
211171247Sthompsa				printf(" state=%X", lp->actor_state);
212168793Sthompsa			putchar('\n');
213171247Sthompsa			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
214171247Sthompsa				printf("\t\t%s\n",
215171247Sthompsa				    lacp_format_peer(lp, "\n\t\t "));
216168793Sthompsa		}
217168793Sthompsa
218168793Sthompsa		if (0 /* XXX */) {
219168793Sthompsa			printf("\tsupported aggregation protocols:\n");
220170603Sthompsa			for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++)
221170603Sthompsa				printf("\t\tlaggproto %s\n", lpr[i].lpr_name);
222168793Sthompsa		}
223191693Sthompsa	}
224168793Sthompsa}
225168793Sthompsa
226168793Sthompsastatic struct cmd lagg_cmds[] = {
227168793Sthompsa	DEF_CMD_ARG("laggport",		setlaggport),
228168793Sthompsa	DEF_CMD_ARG("-laggport",	unsetlaggport),
229168793Sthompsa	DEF_CMD_ARG("laggproto",	setlaggproto),
230232629Sthompsa	DEF_CMD_ARG("lagghash",		setlagghash),
231168793Sthompsa};
232168793Sthompsastatic struct afswtch af_lagg = {
233168793Sthompsa	.af_name	= "af_lagg",
234168793Sthompsa	.af_af		= AF_UNSPEC,
235168793Sthompsa	.af_other_status = lagg_status,
236168793Sthompsa};
237168793Sthompsa
238168793Sthompsastatic __constructor void
239168793Sthompsalagg_ctor(void)
240168793Sthompsa{
241168793Sthompsa#define	N(a)	(sizeof(a) / sizeof(a[0]))
242168793Sthompsa	int i;
243168793Sthompsa
244168793Sthompsa	for (i = 0; i < N(lagg_cmds);  i++)
245168793Sthompsa		cmd_register(&lagg_cmds[i]);
246168793Sthompsa	af_register(&af_lagg);
247168793Sthompsa#undef N
248168793Sthompsa}
249