iflagg.c revision 287723
1230557Sjimharris/*- 2230557Sjimharris */ 3230557Sjimharris 4230557Sjimharris#ifndef lint 5230557Sjimharrisstatic const char rcsid[] = 6230557Sjimharris "$FreeBSD: stable/10/sbin/ifconfig/iflagg.c 287723 2015-09-12 20:36:39Z hrs $"; 7230557Sjimharris#endif /* not lint */ 8230557Sjimharris 9230557Sjimharris#include <sys/param.h> 10230557Sjimharris#include <sys/ioctl.h> 11230557Sjimharris#include <sys/socket.h> 12230557Sjimharris#include <sys/sockio.h> 13230557Sjimharris 14230557Sjimharris#include <stdlib.h> 15230557Sjimharris#include <unistd.h> 16230557Sjimharris 17230557Sjimharris#include <net/ethernet.h> 18230557Sjimharris#include <net/if.h> 19230557Sjimharris#include <net/if_lagg.h> 20230557Sjimharris#include <net/ieee8023ad_lacp.h> 21230557Sjimharris#include <net/route.h> 22230557Sjimharris 23230557Sjimharris#include <ctype.h> 24230557Sjimharris#include <stdio.h> 25230557Sjimharris#include <string.h> 26230557Sjimharris#include <stdlib.h> 27230557Sjimharris#include <unistd.h> 28230557Sjimharris#include <err.h> 29230557Sjimharris#include <errno.h> 30230557Sjimharris 31230557Sjimharris#include "ifconfig.h" 32230557Sjimharris 33230557Sjimharrischar lacpbuf[120]; /* LACP peer '[(a,a,a),(p,p,p)]' */ 34230557Sjimharris 35230557Sjimharrisstatic void 36230557Sjimharrissetlaggport(const char *val, int d, int s, const struct afswtch *afp) 37230557Sjimharris{ 38230557Sjimharris struct lagg_reqport rp; 39230557Sjimharris 40230557Sjimharris bzero(&rp, sizeof(rp)); 41230557Sjimharris strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname)); 42230557Sjimharris strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname)); 43230557Sjimharris 44230557Sjimharris /* Don't choke if the port is already in this lagg. */ 45230557Sjimharris if (ioctl(s, SIOCSLAGGPORT, &rp) && errno != EEXIST) 46230557Sjimharris err(1, "SIOCSLAGGPORT"); 47230557Sjimharris} 48230557Sjimharris 49230557Sjimharrisstatic void 50230557Sjimharrisunsetlaggport(const char *val, int d, int s, const struct afswtch *afp) 51230557Sjimharris{ 52230557Sjimharris struct lagg_reqport rp; 53230557Sjimharris 54230557Sjimharris bzero(&rp, sizeof(rp)); 55230557Sjimharris strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname)); 56230557Sjimharris strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname)); 57230557Sjimharris 58230557Sjimharris if (ioctl(s, SIOCSLAGGDELPORT, &rp)) 59230557Sjimharris err(1, "SIOCSLAGGDELPORT"); 60230557Sjimharris} 61230557Sjimharris 62230557Sjimharrisstatic void 63230557Sjimharrissetlaggproto(const char *val, int d, int s, const struct afswtch *afp) 64230557Sjimharris{ 65230557Sjimharris struct lagg_protos lpr[] = LAGG_PROTOS; 66230557Sjimharris struct lagg_reqall ra; 67230557Sjimharris int i; 68230557Sjimharris 69230557Sjimharris bzero(&ra, sizeof(ra)); 70230557Sjimharris ra.ra_proto = LAGG_PROTO_MAX; 71230557Sjimharris 72230557Sjimharris for (i = 0; i < nitems(lpr); i++) { 73230557Sjimharris if (strcmp(val, lpr[i].lpr_name) == 0) { 74230557Sjimharris ra.ra_proto = lpr[i].lpr_proto; 75230557Sjimharris break; 76230557Sjimharris } 77230557Sjimharris } 78230557Sjimharris if (ra.ra_proto == LAGG_PROTO_MAX) 79230557Sjimharris errx(1, "Invalid aggregation protocol: %s", val); 80230557Sjimharris 81230557Sjimharris strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname)); 82230557Sjimharris if (ioctl(s, SIOCSLAGG, &ra) != 0) 83230557Sjimharris err(1, "SIOCSLAGG"); 84230557Sjimharris} 85230557Sjimharris 86230557Sjimharrisstatic void 87230557Sjimharrissetlaggflowidshift(const char *val, int d, int s, const struct afswtch *afp) 88230557Sjimharris{ 89230557Sjimharris struct lagg_reqopts ro; 90230557Sjimharris 91230557Sjimharris bzero(&ro, sizeof(ro)); 92230557Sjimharris ro.ro_opts = LAGG_OPT_FLOWIDSHIFT; 93230557Sjimharris strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname)); 94230557Sjimharris ro.ro_flowid_shift = (int)strtol(val, NULL, 10); 95230557Sjimharris if (ro.ro_flowid_shift & ~LAGG_OPT_FLOWIDSHIFT_MASK) 96230557Sjimharris errx(1, "Invalid flowid_shift option: %s", val); 97230557Sjimharris 98230557Sjimharris if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0) 99230557Sjimharris err(1, "SIOCSLAGGOPTS"); 100230557Sjimharris} 101230557Sjimharris 102230557Sjimharrisstatic void 103230557Sjimharrissetlaggsetopt(const char *val, int d, int s, const struct afswtch *afp) 104230557Sjimharris{ 105230557Sjimharris struct lagg_reqopts ro; 106230557Sjimharris 107230557Sjimharris bzero(&ro, sizeof(ro)); 108230557Sjimharris ro.ro_opts = d; 109230557Sjimharris switch (ro.ro_opts) { 110230557Sjimharris case LAGG_OPT_USE_FLOWID: 111230557Sjimharris case -LAGG_OPT_USE_FLOWID: 112230557Sjimharris case LAGG_OPT_LACP_STRICT: 113230557Sjimharris case -LAGG_OPT_LACP_STRICT: 114230557Sjimharris case LAGG_OPT_LACP_TXTEST: 115230557Sjimharris case -LAGG_OPT_LACP_TXTEST: 116230557Sjimharris case LAGG_OPT_LACP_RXTEST: 117230557Sjimharris case -LAGG_OPT_LACP_RXTEST: 118230557Sjimharris break; 119230557Sjimharris default: 120230557Sjimharris err(1, "Invalid lagg option"); 121230557Sjimharris } 122230557Sjimharris strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname)); 123230557Sjimharris 124230557Sjimharris if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0) 125230557Sjimharris err(1, "SIOCSLAGGOPTS"); 126230557Sjimharris} 127230557Sjimharris 128230557Sjimharrisstatic void 129230557Sjimharrissetlagghash(const char *val, int d, int s, const struct afswtch *afp) 130230557Sjimharris{ 131230557Sjimharris struct lagg_reqflags rf; 132230557Sjimharris char *str, *tmp, *tok; 133230557Sjimharris 134230557Sjimharris 135230557Sjimharris rf.rf_flags = 0; 136230557Sjimharris str = tmp = strdup(val); 137230557Sjimharris while ((tok = strsep(&tmp, ",")) != NULL) { 138230557Sjimharris if (strcmp(tok, "l2") == 0) 139230557Sjimharris rf.rf_flags |= LAGG_F_HASHL2; 140230557Sjimharris else if (strcmp(tok, "l3") == 0) 141230557Sjimharris rf.rf_flags |= LAGG_F_HASHL3; 142230557Sjimharris else if (strcmp(tok, "l4") == 0) 143230557Sjimharris rf.rf_flags |= LAGG_F_HASHL4; 144230557Sjimharris else 145230557Sjimharris errx(1, "Invalid lagghash option: %s", tok); 146230557Sjimharris } 147230557Sjimharris free(str); 148230557Sjimharris if (rf.rf_flags == 0) 149230557Sjimharris errx(1, "No lagghash options supplied"); 150230557Sjimharris 151230557Sjimharris strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname)); 152230557Sjimharris if (ioctl(s, SIOCSLAGGHASH, &rf)) 153230557Sjimharris err(1, "SIOCSLAGGHASH"); 154230557Sjimharris} 155230557Sjimharris 156230557Sjimharrisstatic char * 157230557Sjimharrislacp_format_mac(const uint8_t *mac, char *buf, size_t buflen) 158230557Sjimharris{ 159230557Sjimharris snprintf(buf, buflen, "%02X-%02X-%02X-%02X-%02X-%02X", 160230557Sjimharris (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], 161230557Sjimharris (int)mac[4], (int)mac[5]); 162230557Sjimharris 163230557Sjimharris return (buf); 164230557Sjimharris} 165230557Sjimharris 166230557Sjimharrisstatic char * 167230557Sjimharrislacp_format_peer(struct lacp_opreq *req, const char *sep) 168230557Sjimharris{ 169230557Sjimharris char macbuf1[20]; 170230557Sjimharris char macbuf2[20]; 171230557Sjimharris 172230557Sjimharris snprintf(lacpbuf, sizeof(lacpbuf), 173230557Sjimharris "[(%04X,%s,%04X,%04X,%04X),%s(%04X,%s,%04X,%04X,%04X)]", 174230557Sjimharris req->actor_prio, 175230557Sjimharris lacp_format_mac(req->actor_mac, macbuf1, sizeof(macbuf1)), 176230557Sjimharris req->actor_key, req->actor_portprio, req->actor_portno, sep, 177230557Sjimharris req->partner_prio, 178230557Sjimharris lacp_format_mac(req->partner_mac, macbuf2, sizeof(macbuf2)), 179230557Sjimharris req->partner_key, req->partner_portprio, req->partner_portno); 180230557Sjimharris 181230557Sjimharris return(lacpbuf); 182230557Sjimharris} 183230557Sjimharris 184230557Sjimharrisstatic void 185230557Sjimharrislagg_status(int s) 186230557Sjimharris{ 187230557Sjimharris struct lagg_protos lpr[] = LAGG_PROTOS; 188230557Sjimharris struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS]; 189230557Sjimharris struct lagg_reqall ra; 190230557Sjimharris struct lagg_reqopts ro; 191230557Sjimharris struct lagg_reqflags rf; 192230557Sjimharris struct lacp_opreq *lp; 193230557Sjimharris const char *proto = "<unknown>"; 194230557Sjimharris int i, isport = 0; 195230557Sjimharris 196230557Sjimharris bzero(&rp, sizeof(rp)); 197230557Sjimharris bzero(&ra, sizeof(ra)); 198230557Sjimharris bzero(&ro, sizeof(ro)); 199230557Sjimharris 200230557Sjimharris strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname)); 201230557Sjimharris strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname)); 202230557Sjimharris 203230557Sjimharris if (ioctl(s, SIOCGLAGGPORT, &rp) == 0) 204230557Sjimharris isport = 1; 205230557Sjimharris 206230557Sjimharris strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname)); 207230557Sjimharris ra.ra_size = sizeof(rpbuf); 208230557Sjimharris ra.ra_port = rpbuf; 209230557Sjimharris 210230557Sjimharris strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname)); 211230557Sjimharris ioctl(s, SIOCGLAGGOPTS, &ro); 212230557Sjimharris 213230557Sjimharris strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname)); 214230557Sjimharris if (ioctl(s, SIOCGLAGGFLAGS, &rf) != 0) 215230557Sjimharris rf.rf_flags = 0; 216230557Sjimharris 217230557Sjimharris if (ioctl(s, SIOCGLAGG, &ra) == 0) { 218230557Sjimharris lp = (struct lacp_opreq *)&ra.ra_lacpreq; 219230557Sjimharris 220230557Sjimharris for (i = 0; i < nitems(lpr); i++) { 221230557Sjimharris if (ra.ra_proto == lpr[i].lpr_proto) { 222230557Sjimharris proto = lpr[i].lpr_name; 223230557Sjimharris break; 224230557Sjimharris } 225230557Sjimharris } 226230557Sjimharris 227230557Sjimharris printf("\tlaggproto %s", proto); 228230557Sjimharris if (rf.rf_flags & LAGG_F_HASHMASK) { 229230557Sjimharris const char *sep = ""; 230230557Sjimharris 231230557Sjimharris printf(" lagghash "); 232230557Sjimharris if (rf.rf_flags & LAGG_F_HASHL2) { 233230557Sjimharris printf("%sl2", sep); 234230557Sjimharris sep = ","; 235230557Sjimharris } 236230557Sjimharris if (rf.rf_flags & LAGG_F_HASHL3) { 237230557Sjimharris printf("%sl3", sep); 238230557Sjimharris sep = ","; 239230557Sjimharris } 240230557Sjimharris if (rf.rf_flags & LAGG_F_HASHL4) { 241230557Sjimharris printf("%sl4", sep); 242230557Sjimharris sep = ","; 243230557Sjimharris } 244230557Sjimharris } 245230557Sjimharris if (isport) 246230557Sjimharris printf(" laggdev %s", rp.rp_ifname); 247230557Sjimharris putchar('\n'); 248230557Sjimharris if (verbose) { 249230557Sjimharris printf("\tlagg options:\n"); 250230557Sjimharris printb("\t\tflags", ro.ro_opts, LAGG_OPT_BITS); 251230557Sjimharris putchar('\n'); 252230557Sjimharris printf("\t\tflowid_shift: %d\n", ro.ro_flowid_shift); 253230557Sjimharris printf("\tlagg statistics:\n"); 254230557Sjimharris printf("\t\tactive ports: %d\n", ro.ro_active); 255230557Sjimharris printf("\t\tflapping: %u\n", ro.ro_flapping); 256230557Sjimharris if (ra.ra_proto == LAGG_PROTO_LACP) { 257230557Sjimharris printf("\tlag id: %s\n", 258230557Sjimharris lacp_format_peer(lp, "\n\t\t ")); 259230557Sjimharris } 260230557Sjimharris } 261230557Sjimharris 262230557Sjimharris for (i = 0; i < ra.ra_ports; i++) { 263230557Sjimharris lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq; 264230557Sjimharris printf("\tlaggport: %s ", rpbuf[i].rp_portname); 265230557Sjimharris printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS); 266230557Sjimharris if (verbose && ra.ra_proto == LAGG_PROTO_LACP) 267230557Sjimharris printb(" state", lp->actor_state, 268230557Sjimharris LACP_STATE_BITS); 269230557Sjimharris putchar('\n'); 270230557Sjimharris if (verbose && ra.ra_proto == LAGG_PROTO_LACP) 271230557Sjimharris printf("\t\t%s\n", 272230557Sjimharris lacp_format_peer(lp, "\n\t\t ")); 273230557Sjimharris } 274230557Sjimharris 275230557Sjimharris if (0 /* XXX */) { 276230557Sjimharris printf("\tsupported aggregation protocols:\n"); 277230557Sjimharris for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) 278230557Sjimharris printf("\t\tlaggproto %s\n", lpr[i].lpr_name); 279230557Sjimharris } 280230557Sjimharris } 281230557Sjimharris} 282230557Sjimharris 283230557Sjimharrisstatic struct cmd lagg_cmds[] = { 284230557Sjimharris DEF_CMD_ARG("laggport", setlaggport), 285230557Sjimharris DEF_CMD_ARG("-laggport", unsetlaggport), 286230557Sjimharris DEF_CMD_ARG("laggproto", setlaggproto), 287230557Sjimharris DEF_CMD_ARG("lagghash", setlagghash), 288230557Sjimharris DEF_CMD("use_flowid", LAGG_OPT_USE_FLOWID, setlaggsetopt), 289230557Sjimharris DEF_CMD("-use_flowid", -LAGG_OPT_USE_FLOWID, setlaggsetopt), 290230557Sjimharris DEF_CMD("lacp_strict", LAGG_OPT_LACP_STRICT, setlaggsetopt), 291230557Sjimharris DEF_CMD("-lacp_strict", -LAGG_OPT_LACP_STRICT, setlaggsetopt), 292230557Sjimharris DEF_CMD("lacp_txtest", LAGG_OPT_LACP_TXTEST, setlaggsetopt), 293230557Sjimharris DEF_CMD("-lacp_txtest", -LAGG_OPT_LACP_TXTEST, setlaggsetopt), 294230557Sjimharris DEF_CMD("lacp_rxtest", LAGG_OPT_LACP_RXTEST, setlaggsetopt), 295230557Sjimharris DEF_CMD("-lacp_rxtest", -LAGG_OPT_LACP_RXTEST, setlaggsetopt), 296230557Sjimharris DEF_CMD_ARG("flowid_shift", setlaggflowidshift), 297230557Sjimharris}; 298230557Sjimharrisstatic struct afswtch af_lagg = { 299230557Sjimharris .af_name = "af_lagg", 300230557Sjimharris .af_af = AF_UNSPEC, 301230557Sjimharris .af_other_status = lagg_status, 302230557Sjimharris}; 303230557Sjimharris 304230557Sjimharrisstatic __constructor void 305230557Sjimharrislagg_ctor(void) 306230557Sjimharris{ 307230557Sjimharris#define N(a) (sizeof(a) / sizeof(a[0])) 308230557Sjimharris int i; 309230557Sjimharris 310230557Sjimharris for (i = 0; i < N(lagg_cmds); i++) 311230557Sjimharris cmd_register(&lagg_cmds[i]); 312230557Sjimharris af_register(&af_lagg); 313230557Sjimharris#undef N 314230557Sjimharris} 315230557Sjimharris