1 /*- 2 * $FreeBSD: head/sbin/ifconfig/iflagg.c 249897 2013-04-25 16:34:04Z glebius $ 3 */ 4 5 #include <sys/param.h> 6 #include <sys/ioctl.h> 7 #include <sys/socket.h> 8 #include <sys/sockio.h> 9 10 #include <stdlib.h> 11 #include <unistd.h> 12 13 #include <net/ethernet.h> 14 #include <net/if.h> 15 #include <net/lagg/if_lagg.h> 16 #include <net/route.h> 17 18 #include <ctype.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <stdlib.h> 22 #include <unistd.h> 23 #include <err.h> 24 #include <errno.h> 25 26 #include "ifconfig.h" 27 28 char lacpbuf[120]; /* LACP peer '[(a,a,a),(p,p,p)]' */ 29 30 static void 31 setlaggport(const char *val, int d, int s, const struct afswtch *afp) 32 { 33 struct lagg_reqport rp; 34 35 bzero(&rp, sizeof(rp)); 36 strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname)); 37 strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname)); 38 39 /* Don't choke if the port is already in this lagg. */ 40 if (ioctl(s, SIOCSLAGGPORT, &rp) && errno != EEXIST) 41 err(1, "SIOCSLAGGPORT"); 42 } 43 44 static void 45 unsetlaggport(const char *val, int d, int s, const struct afswtch *afp) 46 { 47 struct lagg_reqport rp; 48 49 bzero(&rp, sizeof(rp)); 50 strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname)); 51 strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname)); 52 53 if (ioctl(s, SIOCSLAGGDELPORT, &rp)) 54 err(1, "SIOCSLAGGDELPORT"); 55 } 56 57 static void 58 setlaggproto(const char *val, int d, int s, const struct afswtch *afp) 59 { 60 struct lagg_protos lpr[] = LAGG_PROTOS; 61 struct lagg_reqall ra; 62 int i; 63 64 bzero(&ra, sizeof(ra)); 65 ra.ra_proto = LAGG_PROTO_MAX; 66 67 for (i = 0; i < (NELEM(lpr)); i++) { 68 if (strcmp(val, lpr[i].lpr_name) == 0) { 69 ra.ra_proto = lpr[i].lpr_proto; 70 break; 71 } 72 } 73 if (ra.ra_proto == LAGG_PROTO_MAX) 74 errx(1, "Invalid aggregation protocol: %s", val); 75 76 strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname)); 77 if (ioctl(s, SIOCSLAGG, &ra) != 0) 78 err(1, "SIOCSLAGG"); 79 } 80 81 static void 82 setlagghash(const char *val, int d, int s, const struct afswtch *afp) 83 { 84 struct lagg_reqflags rf; 85 char *str, *tmp, *tok; 86 87 88 rf.rf_flags = 0; 89 str = tmp = strdup(val); 90 while ((tok = strsep(&tmp, ",")) != NULL) { 91 if (strcmp(tok, "l2") == 0) 92 rf.rf_flags |= LAGG_F_HASHL2; 93 else if (strcmp(tok, "l3") == 0) 94 rf.rf_flags |= LAGG_F_HASHL3; 95 else if (strcmp(tok, "l4") == 0) 96 rf.rf_flags |= LAGG_F_HASHL4; 97 else 98 errx(1, "Invalid lagghash option: %s", tok); 99 } 100 free(str); 101 if (rf.rf_flags == 0) 102 errx(1, "No lagghash options supplied"); 103 104 strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname)); 105 if (ioctl(s, SIOCSLAGGHASH, &rf)) 106 err(1, "SIOCSLAGGHASH"); 107 } 108 109 static char * 110 lacp_format_mac(const uint8_t *mac, char *buf, size_t buflen) 111 { 112 snprintf(buf, buflen, "%02X-%02X-%02X-%02X-%02X-%02X", 113 (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], 114 (int)mac[4], (int)mac[5]); 115 116 return (buf); 117 } 118 119 static char * 120 lacp_format_peer(struct lacp_opreq *req, const char *sep) 121 { 122 char macbuf1[20]; 123 char macbuf2[20]; 124 125 snprintf(lacpbuf, sizeof(lacpbuf), 126 "[(%04X,%s,%04X,%04X,%04X),%s(%04X,%s,%04X,%04X,%04X)]", 127 req->actor_prio, 128 lacp_format_mac(req->actor_mac, macbuf1, sizeof(macbuf1)), 129 req->actor_key, req->actor_portprio, req->actor_portno, sep, 130 req->partner_prio, 131 lacp_format_mac(req->partner_mac, macbuf2, sizeof(macbuf2)), 132 req->partner_key, req->partner_portprio, req->partner_portno); 133 134 return(lacpbuf); 135 } 136 137 static void 138 lagg_status(int s) 139 { 140 struct lagg_protos lpr[] = LAGG_PROTOS; 141 struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS]; 142 struct lagg_reqall ra; 143 struct lagg_reqflags rf; 144 struct lacp_opreq *lp; 145 const char *proto = "<unknown>"; 146 int i, isport = 0; 147 148 bzero(&rp, sizeof(rp)); 149 bzero(&ra, sizeof(ra)); 150 151 strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname)); 152 strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname)); 153 154 if (ioctl(s, SIOCGLAGGPORT, &rp) == 0) 155 isport = 1; 156 157 strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname)); 158 ra.ra_size = sizeof(rpbuf); 159 ra.ra_port = rpbuf; 160 161 strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname)); 162 if (ioctl(s, SIOCGLAGGFLAGS, &rf) != 0) 163 rf.rf_flags = 0; 164 165 if (ioctl(s, SIOCGLAGG, &ra) == 0) { 166 lp = (struct lacp_opreq *)&ra.ra_lacpreq; 167 168 for (i = 0; i < (NELEM(lpr)); i++) { 169 if (ra.ra_proto == lpr[i].lpr_proto) { 170 proto = lpr[i].lpr_name; 171 break; 172 } 173 } 174 175 printf("\tlaggproto %s", proto); 176 if (rf.rf_flags & LAGG_F_HASHMASK) { 177 const char *sep = ""; 178 179 printf(" lagghash "); 180 if (rf.rf_flags & LAGG_F_HASHL2) { 181 printf("%sl2", sep); 182 sep = ","; 183 } 184 if (rf.rf_flags & LAGG_F_HASHL3) { 185 printf("%sl3", sep); 186 sep = ","; 187 } 188 if (rf.rf_flags & LAGG_F_HASHL4) { 189 printf("%sl4", sep); 190 sep = ","; 191 } 192 } 193 if (isport) 194 printf(" laggdev %s", rp.rp_ifname); 195 putchar('\n'); 196 if (verbose && ra.ra_proto == LAGG_PROTO_LACP) 197 printf("\tlag id: %s\n", 198 lacp_format_peer(lp, "\n\t\t ")); 199 200 for (i = 0; i < ra.ra_ports; i++) { 201 lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq; 202 printf("\tlaggport: %s ", rpbuf[i].rp_portname); 203 printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS); 204 if (verbose && ra.ra_proto == LAGG_PROTO_LACP) 205 printf(" state=%X", lp->actor_state); 206 putchar('\n'); 207 if (verbose && ra.ra_proto == LAGG_PROTO_LACP) 208 printf("\t\t%s\n", 209 lacp_format_peer(lp, "\n\t\t ")); 210 } 211 212 if (0 /* XXX */) { 213 printf("\tsupported aggregation protocols:\n"); 214 for (i = 0; i < (NELEM(lpr)); i++) 215 printf("\t\tlaggproto %s\n", lpr[i].lpr_name); 216 } 217 } 218 } 219 220 static struct cmd lagg_cmds[] = { 221 DEF_CMD_ARG("laggport", setlaggport), 222 DEF_CMD_ARG("-laggport", unsetlaggport), 223 DEF_CMD_ARG("laggproto", setlaggproto), 224 DEF_CMD_ARG("lagghash", setlagghash), 225 }; 226 static struct afswtch af_lagg = { 227 .af_name = "af_lagg", 228 .af_af = AF_UNSPEC, 229 .af_other_status = lagg_status, 230 }; 231 232 static __constructor(101) void 233 lagg_ctor(void) 234 { 235 #define N(a) (sizeof(a) / sizeof(a[0])) 236 int i; 237 238 for (i = 0; i < N(lagg_cmds); i++) 239 cmd_register(&lagg_cmds[i]); 240 af_register(&af_lagg); 241 #undef N 242 } 243