1168793Sthompsa/*-
2168793Sthompsa */
3168793Sthompsa
4168793Sthompsa#ifndef lint
5168793Sthompsastatic const char rcsid[] =
6168793Sthompsa  "$FreeBSD$";
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;
101249897Sglebius		else
102232629Sthompsa			errx(1, "Invalid lagghash option: %s", tok);
103232629Sthompsa	}
104232629Sthompsa	free(str);
105232629Sthompsa	if (rf.rf_flags == 0)
106232629Sthompsa		errx(1, "No lagghash options supplied");
107232629Sthompsa
108232629Sthompsa	strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
109232629Sthompsa	if (ioctl(s, SIOCSLAGGHASH, &rf))
110232629Sthompsa		err(1, "SIOCSLAGGHASH");
111232629Sthompsa}
112232629Sthompsa
113171247Sthompsastatic char *
114171247Sthompsalacp_format_mac(const uint8_t *mac, char *buf, size_t buflen)
115171247Sthompsa{
116171247Sthompsa	snprintf(buf, buflen, "%02X-%02X-%02X-%02X-%02X-%02X",
117171247Sthompsa	    (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3],
118171247Sthompsa	    (int)mac[4], (int)mac[5]);
119171247Sthompsa
120171247Sthompsa	return (buf);
121171247Sthompsa}
122171247Sthompsa
123171247Sthompsastatic char *
124171247Sthompsalacp_format_peer(struct lacp_opreq *req, const char *sep)
125171247Sthompsa{
126171247Sthompsa	char macbuf1[20];
127171247Sthompsa	char macbuf2[20];
128171247Sthompsa
129171247Sthompsa	snprintf(lacpbuf, sizeof(lacpbuf),
130171247Sthompsa	    "[(%04X,%s,%04X,%04X,%04X),%s(%04X,%s,%04X,%04X,%04X)]",
131171247Sthompsa	    req->actor_prio,
132171247Sthompsa	    lacp_format_mac(req->actor_mac, macbuf1, sizeof(macbuf1)),
133171247Sthompsa	    req->actor_key, req->actor_portprio, req->actor_portno, sep,
134171247Sthompsa	    req->partner_prio,
135171247Sthompsa	    lacp_format_mac(req->partner_mac, macbuf2, sizeof(macbuf2)),
136171247Sthompsa	    req->partner_key, req->partner_portprio, req->partner_portno);
137171247Sthompsa
138171247Sthompsa	return(lacpbuf);
139171247Sthompsa}
140171247Sthompsa
141168793Sthompsastatic void
142168793Sthompsalagg_status(int s)
143168793Sthompsa{
144170603Sthompsa	struct lagg_protos lpr[] = LAGG_PROTOS;
145168793Sthompsa	struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS];
146168793Sthompsa	struct lagg_reqall ra;
147232629Sthompsa	struct lagg_reqflags rf;
148171247Sthompsa	struct lacp_opreq *lp;
149168793Sthompsa	const char *proto = "<unknown>";
150168793Sthompsa	int i, isport = 0;
151168793Sthompsa
152168793Sthompsa	bzero(&rp, sizeof(rp));
153168793Sthompsa	bzero(&ra, sizeof(ra));
154168793Sthompsa
155168793Sthompsa	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
156168793Sthompsa	strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname));
157168793Sthompsa
158168793Sthompsa	if (ioctl(s, SIOCGLAGGPORT, &rp) == 0)
159168793Sthompsa		isport = 1;
160168793Sthompsa
161168793Sthompsa	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
162168793Sthompsa	ra.ra_size = sizeof(rpbuf);
163168793Sthompsa	ra.ra_port = rpbuf;
164168793Sthompsa
165232629Sthompsa	strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
166232629Sthompsa	if (ioctl(s, SIOCGLAGGFLAGS, &rf) != 0)
167232629Sthompsa		rf.rf_flags = 0;
168232629Sthompsa
169168793Sthompsa	if (ioctl(s, SIOCGLAGG, &ra) == 0) {
170171247Sthompsa		lp = (struct lacp_opreq *)&ra.ra_lacpreq;
171171247Sthompsa
172170603Sthompsa		for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
173170603Sthompsa			if (ra.ra_proto == lpr[i].lpr_proto) {
174170603Sthompsa				proto = lpr[i].lpr_name;
175168793Sthompsa				break;
176168793Sthompsa			}
177168793Sthompsa		}
178168793Sthompsa
179171247Sthompsa		printf("\tlaggproto %s", proto);
180232629Sthompsa		if (rf.rf_flags & LAGG_F_HASHMASK) {
181232629Sthompsa			const char *sep = "";
182232629Sthompsa
183232629Sthompsa			printf(" lagghash ");
184232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL2) {
185232629Sthompsa				printf("%sl2", sep);
186232629Sthompsa				sep = ",";
187232629Sthompsa			}
188232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL3) {
189232629Sthompsa				printf("%sl3", sep);
190232629Sthompsa				sep = ",";
191232629Sthompsa			}
192232629Sthompsa			if (rf.rf_flags & LAGG_F_HASHL4) {
193232629Sthompsa				printf("%sl4", sep);
194232629Sthompsa				sep = ",";
195232629Sthompsa			}
196232629Sthompsa		}
197168793Sthompsa		if (isport)
198168793Sthompsa			printf(" laggdev %s", rp.rp_ifname);
199168793Sthompsa		putchar('\n');
200171247Sthompsa		if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
201171247Sthompsa			printf("\tlag id: %s\n",
202171247Sthompsa			    lacp_format_peer(lp, "\n\t\t "));
203168793Sthompsa
204168793Sthompsa		for (i = 0; i < ra.ra_ports; i++) {
205171247Sthompsa			lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq;
206171247Sthompsa			printf("\tlaggport: %s ", rpbuf[i].rp_portname);
207171247Sthompsa			printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS);
208171247Sthompsa			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
209171247Sthompsa				printf(" state=%X", lp->actor_state);
210168793Sthompsa			putchar('\n');
211171247Sthompsa			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
212171247Sthompsa				printf("\t\t%s\n",
213171247Sthompsa				    lacp_format_peer(lp, "\n\t\t "));
214168793Sthompsa		}
215168793Sthompsa
216168793Sthompsa		if (0 /* XXX */) {
217168793Sthompsa			printf("\tsupported aggregation protocols:\n");
218170603Sthompsa			for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++)
219170603Sthompsa				printf("\t\tlaggproto %s\n", lpr[i].lpr_name);
220168793Sthompsa		}
221191693Sthompsa	}
222168793Sthompsa}
223168793Sthompsa
224168793Sthompsastatic struct cmd lagg_cmds[] = {
225168793Sthompsa	DEF_CMD_ARG("laggport",		setlaggport),
226168793Sthompsa	DEF_CMD_ARG("-laggport",	unsetlaggport),
227168793Sthompsa	DEF_CMD_ARG("laggproto",	setlaggproto),
228232629Sthompsa	DEF_CMD_ARG("lagghash",		setlagghash),
229168793Sthompsa};
230168793Sthompsastatic struct afswtch af_lagg = {
231168793Sthompsa	.af_name	= "af_lagg",
232168793Sthompsa	.af_af		= AF_UNSPEC,
233168793Sthompsa	.af_other_status = lagg_status,
234168793Sthompsa};
235168793Sthompsa
236168793Sthompsastatic __constructor void
237168793Sthompsalagg_ctor(void)
238168793Sthompsa{
239168793Sthompsa#define	N(a)	(sizeof(a) / sizeof(a[0]))
240168793Sthompsa	int i;
241168793Sthompsa
242168793Sthompsa	for (i = 0; i < N(lagg_cmds);  i++)
243168793Sthompsa		cmd_register(&lagg_cmds[i]);
244168793Sthompsa	af_register(&af_lagg);
245168793Sthompsa#undef N
246168793Sthompsa}
247