Commit 25c71c75ac87508528db053b818944f3650dd7a6

Authored by stephen hemminger
Committed by David S. Miller
1 parent c75ea26040

bridge: bridge port parameters over netlink

Expose bridge port parameter over netlink. By switching to a nested
message, this can be used for other bridge parameters.

This changes IFLA_PROTINFO attribute from one byte to a full nested
set of attributes. This is safe for application interface because the
old message used IFLA_PROTINFO and new one uses
 IFLA_PROTINFO | NLA_F_NESTED.

The code adapts to old format requests, and therefore stays
compatible 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>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 2 changed files with 147 additions and 33 deletions Side-by-side Diff

include/uapi/linux/if_link.h
... ... @@ -205,6 +205,21 @@
205 205  
206 206 #define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
207 207  
  208 +enum {
  209 + BRIDGE_MODE_UNSPEC,
  210 + BRIDGE_MODE_HAIRPIN,
  211 +};
  212 +
  213 +enum {
  214 + IFLA_BRPORT_UNSPEC,
  215 + IFLA_BRPORT_STATE, /* Spanning tree state */
  216 + IFLA_BRPORT_PRIORITY, /* " priority */
  217 + IFLA_BRPORT_COST, /* " cost */
  218 + IFLA_BRPORT_MODE, /* mode (hairpin) */
  219 + __IFLA_BRPORT_MAX
  220 +};
  221 +#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
  222 +
208 223 struct ifla_cacheinfo {
209 224 __u32 max_reasm_len;
210 225 __u32 tstamp; /* ipv6InterfaceTable updated timestamp */
net/bridge/br_netlink.c
... ... @@ -20,18 +20,41 @@
20 20 #include "br_private.h"
21 21 #include "br_private_stp.h"
22 22  
  23 +static inline size_t br_port_info_size(void)
  24 +{
  25 + return nla_total_size(1) /* IFLA_BRPORT_STATE */
  26 + + nla_total_size(2) /* IFLA_BRPORT_PRIORITY */
  27 + + nla_total_size(4) /* IFLA_BRPORT_COST */
  28 + + nla_total_size(1) /* IFLA_BRPORT_MODE */
  29 + + 0;
  30 +}
  31 +
23 32 static inline size_t br_nlmsg_size(void)
24 33 {
25 34 return NLMSG_ALIGN(sizeof(struct ifinfomsg))
26   - + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
27   - + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
28   - + nla_total_size(4) /* IFLA_MASTER */
29   - + nla_total_size(4) /* IFLA_MTU */
30   - + nla_total_size(4) /* IFLA_LINK */
31   - + nla_total_size(1) /* IFLA_OPERSTATE */
32   - + nla_total_size(1); /* IFLA_PROTINFO */
  35 + + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
  36 + + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
  37 + + nla_total_size(4) /* IFLA_MASTER */
  38 + + nla_total_size(4) /* IFLA_MTU */
  39 + + nla_total_size(4) /* IFLA_LINK */
  40 + + nla_total_size(1) /* IFLA_OPERSTATE */
  41 + + nla_total_size(br_port_info_size()); /* IFLA_PROTINFO */
33 42 }
34 43  
  44 +static int br_port_fill_attrs(struct sk_buff *skb,
  45 + const struct net_bridge_port *p)
  46 +{
  47 + u8 mode = !!(p->flags & BR_HAIRPIN_MODE);
  48 +
  49 + if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) ||
  50 + nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) ||
  51 + nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) ||
  52 + nla_put_u8(skb, IFLA_BRPORT_MODE, mode))
  53 + return -EMSGSIZE;
  54 +
  55 + return 0;
  56 +}
  57 +
35 58 /*
36 59 * Create one netlink message for one interface
37 60 * Contains port and master info as well as carrier and bridge state.
38 61  
... ... @@ -67,10 +90,18 @@
67 90 (dev->addr_len &&
68 91 nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
69 92 (dev->ifindex != dev->iflink &&
70   - nla_put_u32(skb, IFLA_LINK, dev->iflink)) ||
71   - (event == RTM_NEWLINK &&
72   - nla_put_u8(skb, IFLA_PROTINFO, port->state)))
  93 + nla_put_u32(skb, IFLA_LINK, dev->iflink)))
73 94 goto nla_put_failure;
  95 +
  96 + if (event == RTM_NEWLINK) {
  97 + struct nlattr *nest
  98 + = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
  99 +
  100 + if (nest == NULL || br_port_fill_attrs(skb, port) < 0)
  101 + goto nla_put_failure;
  102 + nla_nest_end(skb, nest);
  103 + }
  104 +
74 105 return nlmsg_end(skb, nlh);
75 106  
76 107 nla_put_failure:
77 108  
78 109  
79 110  
80 111  
81 112  
82 113  
83 114  
84 115  
... ... @@ -126,47 +157,115 @@
126 157 return err;
127 158 }
128 159  
129   -/*
130   - * Change state of port (ie from forwarding to blocking etc)
131   - * Used by spanning tree in user space.
132   - */
  160 +static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
  161 + [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
  162 + [IFLA_BRPORT_COST] = { .type = NLA_U32 },
  163 + [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
  164 + [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
  165 +};
  166 +
  167 +/* Change the state of the port and notify spanning tree */
  168 +static int br_set_port_state(struct net_bridge_port *p, u8 state)
  169 +{
  170 + if (state > BR_STATE_BLOCKING)
  171 + return -EINVAL;
  172 +
  173 + /* if kernel STP is running, don't allow changes */
  174 + if (p->br->stp_enabled == BR_KERNEL_STP)
  175 + return -EBUSY;
  176 +
  177 + if (!netif_running(p->dev) ||
  178 + (!netif_carrier_ok(p->dev) && state != BR_STATE_DISABLED))
  179 + return -ENETDOWN;
  180 +
  181 + p->state = state;
  182 + br_log_state(p);
  183 + br_port_state_selection(p->br);
  184 + return 0;
  185 +}
  186 +
  187 +/* Set/clear or port flags based on attribute */
  188 +static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[],
  189 + int attrtype, unsigned long mask)
  190 +{
  191 + if (tb[attrtype]) {
  192 + u8 flag = nla_get_u8(tb[attrtype]);
  193 + if (flag)
  194 + p->flags |= mask;
  195 + else
  196 + p->flags &= ~mask;
  197 + }
  198 +}
  199 +
  200 +/* Process bridge protocol info on port */
  201 +static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
  202 +{
  203 + int err;
  204 +
  205 + br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE);
  206 +
  207 + if (tb[IFLA_BRPORT_COST]) {
  208 + err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
  209 + if (err)
  210 + return err;
  211 + }
  212 +
  213 + if (tb[IFLA_BRPORT_PRIORITY]) {
  214 + err = br_stp_set_port_priority(p, nla_get_u16(tb[IFLA_BRPORT_PRIORITY]));
  215 + if (err)
  216 + return err;
  217 + }
  218 +
  219 + if (tb[IFLA_BRPORT_STATE]) {
  220 + err = br_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE]));
  221 + if (err)
  222 + return err;
  223 + }
  224 + return 0;
  225 +}
  226 +
  227 +/* Change state and parameters on port. */
133 228 int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
134 229 {
135 230 struct ifinfomsg *ifm;
136 231 struct nlattr *protinfo;
137 232 struct net_bridge_port *p;
138   - u8 new_state;
  233 + struct nlattr *tb[IFLA_BRPORT_MAX];
  234 + int err;
139 235  
140 236 ifm = nlmsg_data(nlh);
141 237  
142 238 protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
143   - if (!protinfo || nla_len(protinfo) < sizeof(u8))
144   - return -EINVAL;
  239 + if (!protinfo)
  240 + return 0;
145 241  
146   - new_state = nla_get_u8(protinfo);
147   - if (new_state > BR_STATE_BLOCKING)
148   - return -EINVAL;
149   -
150 242 p = br_port_get_rtnl(dev);
151 243 if (!p)
152 244 return -EINVAL;
153 245  
154   - /* if kernel STP is running, don't allow changes */
155   - if (p->br->stp_enabled == BR_KERNEL_STP)
156   - return -EBUSY;
  246 + if (protinfo->nla_type & NLA_F_NESTED) {
  247 + err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
  248 + protinfo, ifla_brport_policy);
  249 + if (err)
  250 + return err;
157 251  
158   - if (!netif_running(dev) ||
159   - (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED))
160   - return -ENETDOWN;
  252 + spin_lock_bh(&p->br->lock);
  253 + err = br_setport(p, tb);
  254 + spin_unlock_bh(&p->br->lock);
  255 + } else {
  256 + /* Binary compatability with old RSTP */
  257 + if (nla_len(protinfo) < sizeof(u8))
  258 + return -EINVAL;
161 259  
162   - p->state = new_state;
163   - br_log_state(p);
  260 + spin_lock_bh(&p->br->lock);
  261 + err = br_set_port_state(p, nla_get_u8(protinfo));
  262 + spin_unlock_bh(&p->br->lock);
  263 + }
164 264  
165   - spin_lock_bh(&p->br->lock);
166   - br_port_state_selection(p->br);
167   - spin_unlock_bh(&p->br->lock);
  265 + if (err == 0)
  266 + br_ifinfo_notify(RTM_NEWLINK, p);
168 267  
169   - return 0;
  268 + return err;
170 269 }
171 270  
172 271 static int br_validate(struct nlattr *tb[], struct nlattr *data[])