From patchwork Fri Nov 2 23:23:19 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Fastabend X-Patchwork-Id: 196776 X-Patchwork-Delegate: shemminger@vyatta.com Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id D45DB2C00D7 for ; Sat, 3 Nov 2012 10:40:53 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759860Ab2KBXkv (ORCPT ); Fri, 2 Nov 2012 19:40:51 -0400 Received: from mga11.intel.com ([192.55.52.93]:52107 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758613Ab2KBXku (ORCPT ); Fri, 2 Nov 2012 19:40:50 -0400 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 02 Nov 2012 16:40:49 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.80,702,1344236400"; d="scan'208";a="243627522" Received: from unknown (HELO [127.0.0.1]) ([10.23.152.206]) by fmsmga002.fm.intel.com with ESMTP; 02 Nov 2012 16:40:49 -0700 From: John Fastabend Subject: [RFC PATCH] iproute2: bridge: add veb/vepa toggle To: bhutchings@solarflare.com Cc: shemminger@vyatta.com, netdev@vger.kernel.org Date: Fri, 02 Nov 2012 16:23:19 -0700 Message-ID: <20121102232318.2788.66019.stgit@jf-dev1-dcblab> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add bridge commands to set veb, vepa modes to iproute2. [root@jf-dev1-dcblab iproute2]# ./bridge/bridge bridge show eth2: mode VEB bridge_flags: self eth3: mode VEPA bridge_flags: self eth10: mode VEB bridge_flags: self eth12: mode VEB bridge_flags: self [root@jf-dev1-dcblab iproute2]# ./bridge/bridge bridge er mode veb dev eth3 self bridge_mode_set eth3: type 19 family 7 mode VEB flags 0002 [root@jf-dev1-dcblab iproute2]# ./bridge/bridge bridge show eth2: mode VEB bridge_flags: self eth3: mode VEB bridge_flags: self eth10: mode VEB bridge_flags: self eth12: mode VEB bridge_flags: self Should add code to print the flags on error so the user can learn what failed. And maybe the cmd line syntax could be better. Signed-off-by: John Fastabend --- bridge/br_common.h | 1 bridge/bridge.c | 3 bridge/fdb.c | 320 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/if_link.h | 16 ++ 4 files changed, 339 insertions(+), 1 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/bridge/br_common.h b/bridge/br_common.h index 718ecb9..3e5dcab 100644 --- a/bridge/br_common.h +++ b/bridge/br_common.h @@ -5,6 +5,7 @@ extern int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); extern int do_fdb(int argc, char **argv); +extern int do_bridge(int argc, char **argv); extern int do_monitor(int argc, char **argv); extern int preferred_family; diff --git a/bridge/bridge.c b/bridge/bridge.c index e2c33b0..b5145c1 100644 --- a/bridge/bridge.c +++ b/bridge/bridge.c @@ -27,7 +27,7 @@ static void usage(void) { fprintf(stderr, "Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n" -"where OBJECT := { fdb | monitor }\n" +"where OBJECT := { fdb | monitor | bridge }\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails]\n" ); exit(-1); } @@ -43,6 +43,7 @@ static const struct cmd { int (*func)(int argc, char **argv); } cmds[] = { { "fdb", do_fdb }, + { "bridge", do_bridge }, { "monitor", do_monitor }, { "help", do_help }, { 0 } diff --git a/bridge/fdb.c b/bridge/fdb.c index 4ca4861..1017307 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -34,6 +34,13 @@ static void usage(void) exit(-1); } +static void bridge_usage(void) +{ + fprintf(stderr, "Usage: br bridge er mode {veb | vepa} dev DEV\n"); + fprintf(stderr, " br bridge {show} [ dev DEV] \n"); + exit(-1); +} + static const char *state_n2a(unsigned s) { static char buf[32]; @@ -269,3 +276,316 @@ int do_fdb(int argc, char **argv) fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv); exit(-1); } + +int print_bridge(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +{ + FILE *fp = arg; + struct ifinfomsg *ifm = NLMSG_DATA(n); + int len = n->nlmsg_len; + struct rtattr * tb[IFLA_MAX+1]; + + len -= NLMSG_LENGTH(sizeof(*ifm)); + if (len < 0) { + fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); + return -1; + } + + if (ifm->ifi_family != AF_BRIDGE) { + fprintf(stderr, "hmm: Not PF_BRIDGE is %i\n", ifm->ifi_family); + } + + if (filter_index && filter_index != ifm->ifi_index) + return 0; + + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len); + + if (!tb[IFLA_IFNAME]) { + fprintf(stderr, "%s: missing ifname using ifi_index %u name %s\n", + __func__, ifm->ifi_index, + ll_index_to_name(ifm->ifi_index)); + } + if (tb[IFLA_AF_SPEC]) { + struct rtattr *bridge[IFLA_BRIDGE_MAX+1]; + __u16 mode = 0, flags = 0; + + parse_rtattr_nested(bridge, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]); + if (bridge[IFLA_BRIDGE_MODE]) + mode =*(__u16*)RTA_DATA(bridge[IFLA_BRIDGE_MODE]); + if (bridge[IFLA_BRIDGE_FLAGS]) + flags =*(__u16*)RTA_DATA(bridge[IFLA_BRIDGE_FLAGS]); + + fprintf(stderr, "%s: mode %s bridge_flags: %s %s\n", + ll_index_to_name(ifm->ifi_index), + mode ? "VEPA" : "VEB", + flags & BRIDGE_FLAGS_SELF ? "self" : "", + flags & BRIDGE_FLAGS_MASTER ? "master" : ""); + } + + if (tb[IFLA_PROTINFO]) { + __u8 state = *(__u8*)RTA_DATA(tb[IFLA_PROTINFO]); + char *sstate; + + switch (state) { + case 0: + sstate = "DISABLED"; + break; + case 1: + sstate = "LISTENING"; + break; + case 2: + sstate = "LEARNING"; + break; + case 3: + sstate = "FORWARDING"; + break; + case 4: + sstate = "BLOCKING"; + break; + default: + sstate = "UNKNOWN"; + break; + } + + + fprintf(stderr, "%s: ifla_protinfo: %s\n", + __func__, sstate); + } + + fflush(fp); + return 0; +} + +static int bridge_show(int argc, char **argv) +{ + char *filter_dev = NULL; + + + while (argc > 0) { + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + if (filter_dev) + duparg("dev", *argv); + + filter_dev = *argv; + } + argc--; argv++; + } + + if (filter_dev) { + if ((filter_index = if_nametoindex(filter_dev)) == 0) { + fprintf(stderr, "Cannot find device \"%s\"\n", filter_dev); + return -1; + } + } + + if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) { + perror("Cannot send dump request"); + exit(1); + } + + if (rtnl_dump_filter(&rth, print_bridge, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); + exit(1); + } + + return 0; +} + +static int bridge_mode_set(int argc, char **argv) +{ + struct { + struct nlmsghdr n; + struct ifinfomsg ifm; + char buf[1024]; + } req; + char *d = NULL; + __u16 mode = -1, flags = 0; + int err; + struct rtattr *binfo; + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_SETLINK; + req.ifm.ifi_family = PF_BRIDGE; + + while (argc > 0) { + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + d = *argv; + } else if (matches(*argv, "mode") == 0) { + NEXT_ARG(); + if (matches(*argv, "veb") == 0) + mode = BRIDGE_MODE_VEB; + else if (matches(*argv, "vepa") == 0) + mode = BRIDGE_MODE_VEPA; + else + invarg("Invalid mode value\n", *argv); + + } else if (matches(*argv, "self") == 0 ) { + flags |= BRIDGE_FLAGS_SELF; + } else if (matches(*argv, "master") == 0 ) { + flags |= BRIDGE_FLAGS_MASTER; + } + argc--; argv++; + } + + if (!d) { + fprintf(stderr, "Device required.\n"); + exit(-1); + } + + req.ifm.ifi_index = ll_name_to_index(d); + if (req.ifm.ifi_index == 0) { + fprintf(stderr, "Cannot find device \"%s\"\n", d); + return -1; + } + + binfo = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); + err = addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags); + err = addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode); + if (err < 0) + fprintf(stderr, "addattr16 failes\n"); + addattr_nest_end(&req.n, binfo); + + printf("%s %s: type %i family %i mode %s flags %04x\n", __func__, d, + req.n.nlmsg_type, req.ifm.ifi_family, + mode ? "VEPA" : "VEB", flags); + + if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) + exit(2); + + return 0; +} + +static int bridge_state_set(int argc, char **argv) +{ + struct { + struct nlmsghdr n; + struct ifinfomsg ifm; + char buf[1024]; + } req; + struct { + struct nlmsghdr hdr; + struct nlmsgerr err; + struct nlmsghdr rhdr; + struct ifinfomsg ifm; + char buf[1024]; + } reply; + char *d = NULL; + __u8 state = -1; //BRIDGE_MODE_VEB; + __u16 mode = 0, flags = 0; //BRIDGE_MODE_VEB; + + memset(&req, 0, sizeof(req)); + memset(&reply, 0, sizeof(reply)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_ACK; + req.n.nlmsg_type = RTM_SETLINK; + req.ifm.ifi_family = PF_BRIDGE; + + while (argc > 0) { + printf("%s: arg proc: %s\n", __func__, *argv); + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + d = *argv; + } else if (matches(*argv, "state") == 0) { + NEXT_ARG(); + printf("%s: arg matched state: %s\n", __func__, *argv); + if (matches(*argv, "DISABLED") == 0) + state = 0; + else if (matches(*argv, "LISTENING") == 0) + state = 1; + else if (matches(*argv, "LEARNING") == 0) + state = 2; + else if (matches(*argv, "FORWARDING") == 0) + state = 3; + else if (matches(*argv, "BLOCKING") == 0) + state = 4; + else + invarg("Invalid state value\n", *argv); + + } else if (matches(*argv, "mode") == 0) { + NEXT_ARG(); + printf("%s: arg set mode %s\n", __func__, *argv); + if (matches(*argv, "veb") == 0) + mode = BRIDGE_MODE_VEB; + else if (matches(*argv, "vepa") == 0) + mode = BRIDGE_MODE_VEPA; + else + invarg("Invalid mode value\n", *argv); + + } else if (matches(*argv, "master") == 0) { + printf("%s: arg set master\n", __func__); + flags |= BRIDGE_FLAGS_MASTER; + } else if (matches(*argv, "self") == 0) { + printf("%s: arg set self\n", __func__); + flags |= BRIDGE_FLAGS_SELF; + } + + argc--; argv++; + } + + if (!d) { + fprintf(stderr, "Device required.\n"); + exit(-1); + } + + req.ifm.ifi_index = ll_name_to_index(d); + if (req.ifm.ifi_index == 0) { + fprintf(stderr, "Cannot find device \"%s\"\n", d); + return -1; + } + + if (state < 4) + addattr8(&req.n, sizeof(req.buf), IFLA_PROTINFO, state); + + printf("%s %s(%u): type %i family %i state 0x%2x\n", __func__, d, req.ifm.ifi_index, + req.n.nlmsg_type, req.ifm.ifi_family, state); + + if (mode < 3 || flags) { + struct rtattr *binfo; + int err = 0; + + binfo = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); + if (flags) + err = addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags); + if (mode < 3) + err = addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode); + if (err < 0) + fprintf(stderr, "addattr16 failes\n"); + addattr_nest_end(&req.n, binfo); + + printf("%s %s(%u): type %i family %i mode %s\n", __func__, d, req.ifm.ifi_index, + req.n.nlmsg_type, req.ifm.ifi_family, + mode ? "VEPA" : "VEB"); + } + + printf("%s: %s(%u): rtnl_talk length %u\n", __func__, d, req.ifm.ifi_index, req.n.nlmsg_len); + if (rtnl_talk(&rth, &req.n, 0, 0, &reply.hdr) < 0) { + printf("\nREPLY: error %i\n", reply.err.error); + print_bridge(NULL, &reply.err.msg, stderr); + exit(2); + } + + return 0; +} + +int do_bridge(int argc, char **argv) +{ + ll_init_map(&rth); + + if (argc > 0) { + if (matches(*argv, "er") == 0) + return bridge_mode_set(argc-1, argv+1); + else if (matches(*argv, "show") == 0) + return bridge_show(argc-1, argv+1); + else if (matches(*argv, "state") == 0) + return bridge_state_set(argc-1, argv+1); + else if (matches(*argv, "help") == 0) + bridge_usage(); + } + + exit(0); +} diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 012d95a..1a6c2f1 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -142,6 +142,7 @@ enum { #define IFLA_PROMISCUITY IFLA_PROMISCUITY IFLA_NUM_TX_QUEUES, IFLA_NUM_RX_QUEUES, + IFLA_BRIDGE, __IFLA_MAX }; @@ -375,6 +376,21 @@ enum { #define PORT_UUID_MAX 16 #define PORT_SELF_VF -1 +/* Bridge Flags */ +#define BRIDGE_FLAGS_MASTER 1 /* Bridge command to/from master */ +#define BRIDGE_FLAGS_SELF 2 /* Bridge command to/from lowerdev */ + +#define BRIDGE_MODE_VEB 0 /* Default loopback mode */ +#define BRIDGE_MODE_VEPA 1 /* 802.1Qbg defined VEPA mode */ + +/* Bridge management nested attributes */ +enum { + IFLA_BRIDGE_FLAGS, + IFLA_BRIDGE_MODE, + __IFLA_BRIDGE_MAX, +}; +#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) + enum { PORT_REQUEST_PREASSOCIATE = 0, PORT_REQUEST_PREASSOCIATE_RR,