From mboxrd@z Thu Jan 1 00:00:00 1970 From: Vlad Yasevich Subject: [PATCH 07/11] bridge: Add netlink interface to configure vlans on bridge ports Date: Wed, 12 Dec 2012 15:01:13 -0500 Message-ID: <1355342477-4971-8-git-send-email-vyasevic@redhat.com> References: <1355342477-4971-1-git-send-email-vyasevic@redhat.com> Cc: shemminger@vyatta.com, davem@davemloft.net, mst@redhat.com, john.r.fastabend@intel.com To: netdev@vger.kernel.org Return-path: Received: from mx1.redhat.com ([209.132.183.28]:38398 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755075Ab2LLUBe (ORCPT ); Wed, 12 Dec 2012 15:01:34 -0500 In-Reply-To: <1355342477-4971-1-git-send-email-vyasevic@redhat.com> Sender: netdev-owner@vger.kernel.org List-ID: Add a netlink interface to add and remove vlan configuration on bridge port. The interface uses the RTM_SETLINK message and encodes the vlan configuration inside the IFLA_AF_SPEC. It is possble to include multiple vlans to either add or remove in a single message. Signed-off-by: Vlad Yasevich --- include/uapi/linux/if_bridge.h | 17 ++++++++ net/bridge/br_if.c | 1 + net/bridge/br_netlink.c | 85 ++++++++++++++++++++++++++++++++------- 3 files changed, 87 insertions(+), 16 deletions(-) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index 52aa738..c65ce5f 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -108,11 +108,13 @@ struct __fdb_entry { * [IFLA_AF_SPEC] = { * [IFLA_BRIDGE_FLAGS] * [IFLA_BRIDGE_MODE] + * [IFLA_BRIDGE_VLAN_INFO] * } */ enum { IFLA_BRIDGE_FLAGS, IFLA_BRIDGE_MODE, + IFLA_BRIDGE_VLAN_INFO, __IFLA_BRIDGE_MAX, }; #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) @@ -171,4 +173,19 @@ struct br_mdb_entry { } addr; }; +/* Bridge VLAN info + * [IFLA_BRIDGE_VLAN_INFO] + */ +enum { + BR_VLAN_ADD, + BR_VLAN_DEL, +}; + +struct bridge_vlan_info { + u16 op_code; + u16 flags; + u16 vid; + u16 unused; +}; + #endif /* _UAPI_LINUX_IF_BRIDGE_H */ diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 30c778e..9a3451b 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "br_private.h" diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index dead9df..c7301a9 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "br_private.h" #include "br_private_stp.h" @@ -162,6 +163,47 @@ out: return err; } +const struct nla_policy ifla_br_policy[IFLA_MAX+1] = { + [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 }, + [IFLA_BRIDGE_MODE] = { .type = NLA_U16 }, + [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY, + .len = sizeof(struct bridge_vlan_info), }, +}; + +static int br_afspec(struct net_bridge_port *p, struct nlattr *af_spec) +{ + struct nlattr *tb[IFLA_BRIDGE_MAX+1]; + int err; + + if (nla_type(af_spec) != AF_BRIDGE) + return -EINVAL; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, af_spec, ifla_br_policy); + if (err) + return err; + + if (tb[IFLA_BRIDGE_VLAN_INFO]) { + struct bridge_vlan_info *vinfo; + + vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); + + if (vinfo->vid > VLAN_N_VID) + return -EINVAL; + + switch(vinfo->op_code) { + case BR_VLAN_ADD: + nbp_vlan_add(p, vinfo->vid); + break; + + case BR_VLAN_DEL: + nbp_vlan_delete(p, vinfo->vid); + break; + } + } + + return 0; +} + static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, [IFLA_BRPORT_COST] = { .type = NLA_U32 }, @@ -238,6 +280,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) { struct ifinfomsg *ifm; struct nlattr *protinfo; + struct nlattr *afspec; struct net_bridge_port *p; struct nlattr *tb[IFLA_BRPORT_MAX + 1]; int err; @@ -245,35 +288,45 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) ifm = nlmsg_data(nlh); protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); - if (!protinfo) + afspec = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_AF_SPEC); + if (!protinfo && !afspec) return 0; p = br_port_get_rtnl(dev); if (!p) return -EINVAL; - if (protinfo->nla_type & NLA_F_NESTED) { - err = nla_parse_nested(tb, IFLA_BRPORT_MAX, - protinfo, ifla_brport_policy); + if (protinfo) { + if (protinfo->nla_type & NLA_F_NESTED) { + err = nla_parse_nested(tb, IFLA_BRPORT_MAX, + protinfo, ifla_brport_policy); + if (err) + return err; + + spin_lock_bh(&p->br->lock); + err = br_setport(p, tb); + spin_unlock_bh(&p->br->lock); + } else { + /* Binary compatability with old RSTP */ + if (nla_len(protinfo) < sizeof(u8)) + return -EINVAL; + + spin_lock_bh(&p->br->lock); + err = br_set_port_state(p, nla_get_u8(protinfo)); + spin_unlock_bh(&p->br->lock); + } if (err) - return err; + goto out; + } - spin_lock_bh(&p->br->lock); - err = br_setport(p, tb); - spin_unlock_bh(&p->br->lock); - } else { - /* Binary compatability with old RSTP */ - if (nla_len(protinfo) < sizeof(u8)) - return -EINVAL; + if (afspec) + err = br_afspec(p, afspec); - spin_lock_bh(&p->br->lock); - err = br_set_port_state(p, nla_get_u8(protinfo)); - spin_unlock_bh(&p->br->lock); - } if (err == 0) br_ifinfo_notify(RTM_NEWLINK, p); +out: return err; } -- 1.7.7.6