From: Stephen Hemminger <shemminger@vyatta.com>
To: davem@davemloft.net
Cc: netdev@vger.kernel.org
Subject: [PATCH net-next 1/8] bridge: bridge port parameters over netlink
Date: Mon, 29 Oct 2012 17:57:32 -0700 [thread overview]
Message-ID: <20121030005835.289407930@vyatta.com> (raw)
In-Reply-To: 20121030005731.843020405@vyatta.com
[-- Attachment #1: bridge-port-flags-netlink.patch --]
[-- Type: text/plain, Size: 8141 bytes --]
Expose bridge port parameters over netlink. By switching
from a single byet to a nested message, this can be used for
other bridge parameters.
Although, this changes IFLA_PROTINFO attribute from one byte to a full nested
set of attributes; it is safe for applications because the
old message used IFLA_PROTINFO and new one uses
IFLA_PROTINFO | NLA_F_NESTED.
The code still accepts to old format requests, and therefore stays
compatiable with user mode RSTP daemon. Since the type field
for nested and unnested attributes are different, and the old
code in libnetlink doesn't do the mask, it is also safe to use
with old versions of bridge monitor command.
Note: although mode is only a boolean, treating it as a
full byte since in the future someone will probably want to add more
values (like macvlan has).
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
include/uapi/linux/if_link.h | 10 ++
net/bridge/br_netlink.c | 145 ++++++++++++++++++++++++++++++++-----------
2 files changed, 119 insertions(+), 36 deletions(-)
--- a/include/uapi/linux/if_link.h 2012-10-29 15:59:40.289955276 -0700
+++ b/include/uapi/linux/if_link.h 2012-10-29 16:10:15.263578236 -0700
@@ -205,6 +205,21 @@ enum {
#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+enum {
+ BRIDGE_MODE_UNSPEC,
+ BRIDGE_MODE_HAIRPIN,
+};
+
+enum {
+ IFLA_BRPORT_UNSPEC,
+ IFLA_BRPORT_STATE, /* Spanning tree state */
+ IFLA_BRPORT_PRIORITY, /* " priority */
+ IFLA_BRPORT_COST, /* " cost */
+ IFLA_BRPORT_MODE, /* mode (hairpin) */
+ __IFLA_BRPORT_MAX
+};
+#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+
struct ifla_cacheinfo {
__u32 max_reasm_len;
__u32 tstamp; /* ipv6InterfaceTable updated timestamp */
--- a/net/bridge/br_netlink.c 2012-10-29 15:59:40.289955276 -0700
+++ b/net/bridge/br_netlink.c 2012-10-29 16:14:21.069109611 -0700
@@ -20,16 +20,39 @@
#include "br_private.h"
#include "br_private_stp.h"
+static inline size_t br_port_info_size(void)
+{
+ return nla_total_size(1) /* IFLA_BRPORT_STATE */
+ + nla_total_size(2) /* IFLA_BRPORT_PRIORITY */
+ + nla_total_size(4) /* IFLA_BRPORT_COST */
+ + nla_total_size(1) /* IFLA_BRPORT_MODE */
+ + 0;
+}
+
static inline size_t br_nlmsg_size(void)
{
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
- + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
- + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
- + nla_total_size(4) /* IFLA_MASTER */
- + nla_total_size(4) /* IFLA_MTU */
- + nla_total_size(4) /* IFLA_LINK */
- + nla_total_size(1) /* IFLA_OPERSTATE */
- + nla_total_size(1); /* IFLA_PROTINFO */
+ + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
+ + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
+ + nla_total_size(4) /* IFLA_MASTER */
+ + nla_total_size(4) /* IFLA_MTU */
+ + nla_total_size(4) /* IFLA_LINK */
+ + nla_total_size(1) /* IFLA_OPERSTATE */
+ + nla_total_size(br_port_info_size()); /* IFLA_PROTINFO */
+}
+
+static int br_port_fill_attrs(struct sk_buff *skb,
+ const struct net_bridge_port *p)
+{
+ u8 mode = !!(p->flags & BR_HAIRPIN_MODE);
+
+ if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) ||
+ nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) ||
+ nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) ||
+ nla_put_u8(skb, IFLA_BRPORT_MODE, mode))
+ return -EMSGSIZE;
+
+ return 0;
}
/*
@@ -67,10 +90,18 @@ static int br_fill_ifinfo(struct sk_buff
(dev->addr_len &&
nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
(dev->ifindex != dev->iflink &&
- nla_put_u32(skb, IFLA_LINK, dev->iflink)) ||
- (event == RTM_NEWLINK &&
- nla_put_u8(skb, IFLA_PROTINFO, port->state)))
+ nla_put_u32(skb, IFLA_LINK, dev->iflink)))
goto nla_put_failure;
+
+ if (event == RTM_NEWLINK) {
+ struct nlattr *nest
+ = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
+
+ if (nest == NULL || br_port_fill_attrs(skb, port) < 0)
+ goto nla_put_failure;
+ nla_nest_end(skb, nest);
+ }
+
return nlmsg_end(skb, nlh);
nla_put_failure:
@@ -140,60 +171,127 @@ skip:
return skb->len;
}
-/*
- * Change state of port (ie from forwarding to blocking etc)
+static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
+ [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
+ [IFLA_BRPORT_COST] = { .type = NLA_U16 },
+ [IFLA_BRPORT_PRIORITY] = { .type = NLA_U32 },
+ [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
+};
+
+/* Change state of port (ie from forwarding to blocking etc)
* Used by spanning tree in user space.
*/
-static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int br_rtm_set_port_state(struct net_bridge_port *p, u8 state)
+{
+ if (state > BR_STATE_BLOCKING)
+ return -EINVAL;
+
+ /* if kernel STP is running, don't allow changes */
+ if (p->br->stp_enabled == BR_KERNEL_STP)
+ return -EBUSY;
+
+ if (!netif_running(p->dev) ||
+ (!netif_carrier_ok(p->dev) && state != BR_STATE_DISABLED))
+ return -ENETDOWN;
+
+ p->state = state;
+ br_log_state(p);
+ br_port_state_selection(p->br);
+ return 0;
+}
+
+static void br_rtm_setflag(struct net_bridge_port *p, struct nlattr *tb[],
+ int attrtype, unsigned long mask)
+{
+ if (tb[attrtype]) {
+ u8 flag = nla_get_u8(tb[attrtype]);
+ if (flag)
+ p->flags |= mask;
+ else
+ p->flags &= ~mask;
+ }
+}
+
+/* Process bridge protocol info on port */
+static int br_rtm_protinfo(struct net_bridge_port *p, struct nlattr *tb[])
+{
+ int err;
+
+ br_rtm_setflag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE);
+
+ if (tb[IFLA_BRPORT_COST]) {
+ err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
+ if (err)
+ return err;
+ }
+
+ if (tb[IFLA_BRPORT_PRIORITY]) {
+ err = br_stp_set_port_priority(p, nla_get_u16(tb[IFLA_BRPORT_PRIORITY]));
+ if (err)
+ return err;
+ }
+
+ if (tb[IFLA_BRPORT_STATE]) {
+ err = br_rtm_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE]));
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+/* Change state and parameters on port. */
+static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct net *net = sock_net(skb->sk);
struct ifinfomsg *ifm;
- struct nlattr *protinfo;
+ struct nlattr *pinfo;
struct net_device *dev;
struct net_bridge_port *p;
- u8 new_state;
-
- if (nlmsg_len(nlh) < sizeof(*ifm))
- return -EINVAL;
+ struct nlattr *tb[IFLA_BRPORT_MAX];
+ int err;
ifm = nlmsg_data(nlh);
if (ifm->ifi_family != AF_BRIDGE)
return -EPFNOSUPPORT;
- protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
- if (!protinfo || nla_len(protinfo) < sizeof(u8))
- return -EINVAL;
-
- new_state = nla_get_u8(protinfo);
- if (new_state > BR_STATE_BLOCKING)
- return -EINVAL;
+ pinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
+ if (!pinfo)
+ return 0;
dev = __dev_get_by_index(net, ifm->ifi_index);
- if (!dev)
+ if (!dev) {
+ pr_debug("br_rtm_setlink: ifindex %u not found\n",
+ ifm->ifi_index);
return -ENODEV;
+ }
p = br_port_get_rtnl(dev);
- if (!p)
+ if (!p) {
+ pr_debug("br_rtm_setlink: device %s not a bridge port\n",
+ dev->name);
return -EINVAL;
+ }
- /* if kernel STP is running, don't allow changes */
- if (p->br->stp_enabled == BR_KERNEL_STP)
- return -EBUSY;
-
- if (!netif_running(dev) ||
- (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED))
- return -ENETDOWN;
-
- p->state = new_state;
- br_log_state(p);
-
- spin_lock_bh(&p->br->lock);
- br_port_state_selection(p->br);
- spin_unlock_bh(&p->br->lock);
+ if (pinfo->nla_type & NLA_F_NESTED) {
+ err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
+ pinfo, ifla_brport_policy);
+ if (err)
+ return err;
+
+ spin_lock_bh(&p->br->lock);
+ err = br_rtm_protinfo(p, tb);
+ spin_unlock_bh(&p->br->lock);
+ } else {
+ /* Binary compatability with old RSTP */
+ spin_lock_bh(&p->br->lock);
+ err = br_rtm_set_port_state(p, nla_get_u8(pinfo));
+ spin_unlock_bh(&p->br->lock);
+ }
- br_ifinfo_notify(RTM_NEWLINK, p);
+ if (err == 0)
+ br_ifinfo_notify(RTM_NEWLINK, p);
- return 0;
+ return err;
}
static int br_validate(struct nlattr *tb[], struct nlattr *data[])
next prev parent reply other threads:[~2012-10-30 1:06 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-10-30 0:57 [PATCH net-next 0/8] bridge: new security features Stephen Hemminger
2012-10-30 0:57 ` Stephen Hemminger [this message]
2012-10-30 18:48 ` [PATCH net-next 1/8] bridge: bridge port parameters over netlink Tommy S. Christensen
2012-10-30 21:00 ` Stephen Hemminger
2012-10-31 14:01 ` John Fastabend
2012-10-31 21:30 ` Stephen Hemminger
2012-11-01 1:33 ` John Fastabend
2012-10-30 0:57 ` [PATCH net-next 2/8] bridge: add template for bridge port flags Stephen Hemminger
2012-10-30 0:57 ` [PATCH net-next 3/8] bridge: implement BPDU blocking Stephen Hemminger
2012-10-31 2:38 ` Cong Wang
2012-10-31 20:57 ` Stephen Hemminger
2012-10-30 0:57 ` [PATCH net-next 4/8] bridge: add root port blocking Stephen Hemminger
2012-10-30 0:57 ` [PATCH net-next 5/8] bridge: add bpdu filter Stephen Hemminger
2012-10-30 0:57 ` [PATCH net-next 6/8] tun: implement byte queue limits Stephen Hemminger
2012-10-30 1:09 ` Stephen Hemminger
2012-10-30 0:57 ` [PATCH net-next 7/8] virtio: make some structures const Stephen Hemminger
2012-10-30 1:09 ` Stephen Hemminger
2012-10-30 0:57 ` [PATCH net-next 8/8] iproute2: handle new bridge PROTINFO format Stephen Hemminger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20121030005835.289407930@vyatta.com \
--to=shemminger@vyatta.com \
--cc=davem@davemloft.net \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.