aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorstephen hemminger <shemminger@vyatta.com>2012-11-13 02:53:05 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-14 20:20:44 -0500
commit25c71c75ac87508528db053b818944f3650dd7a6 (patch)
tree6415de59be04019fa15a3e7cb2c53d1ecc930c48 /net/bridge
parentc75ea260400aaea8100caa012a0b1958ca094840 (diff)
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>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_netlink.c165
1 files changed, 132 insertions, 33 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 14b065cbd214..0188a2f706c4 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -20,16 +20,39 @@
20#include "br_private.h" 20#include "br_private.h"
21#include "br_private_stp.h" 21#include "br_private_stp.h"
22 22
23static 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
23static inline size_t br_nlmsg_size(void) 32static inline size_t br_nlmsg_size(void)
24{ 33{
25 return NLMSG_ALIGN(sizeof(struct ifinfomsg)) 34 return NLMSG_ALIGN(sizeof(struct ifinfomsg))
26 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ 35 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
27 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ 36 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
28 + nla_total_size(4) /* IFLA_MASTER */ 37 + nla_total_size(4) /* IFLA_MASTER */
29 + nla_total_size(4) /* IFLA_MTU */ 38 + nla_total_size(4) /* IFLA_MTU */
30 + nla_total_size(4) /* IFLA_LINK */ 39 + nla_total_size(4) /* IFLA_LINK */
31 + nla_total_size(1) /* IFLA_OPERSTATE */ 40 + nla_total_size(1) /* IFLA_OPERSTATE */
32 + nla_total_size(1); /* IFLA_PROTINFO */ 41 + nla_total_size(br_port_info_size()); /* IFLA_PROTINFO */
42}
43
44static 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;
33} 56}
34 57
35/* 58/*
@@ -67,10 +90,18 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
67 (dev->addr_len && 90 (dev->addr_len &&
68 nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || 91 nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
69 (dev->ifindex != dev->iflink && 92 (dev->ifindex != dev->iflink &&
70 nla_put_u32(skb, IFLA_LINK, dev->iflink)) || 93 nla_put_u32(skb, IFLA_LINK, dev->iflink)))
71 (event == RTM_NEWLINK &&
72 nla_put_u8(skb, IFLA_PROTINFO, port->state)))
73 goto nla_put_failure; 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 return nlmsg_end(skb, nlh); 105 return nlmsg_end(skb, nlh);
75 106
76nla_put_failure: 107nla_put_failure:
@@ -126,47 +157,115 @@ out:
126 return err; 157 return err;
127} 158}
128 159
129/* 160static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
130 * Change state of port (ie from forwarding to blocking etc) 161 [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
131 * Used by spanning tree in user space. 162 [IFLA_BRPORT_COST] = { .type = NLA_U32 },
132 */ 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 */
168static 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 */
188static 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 */
201static 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. */
133int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) 228int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
134{ 229{
135 struct ifinfomsg *ifm; 230 struct ifinfomsg *ifm;
136 struct nlattr *protinfo; 231 struct nlattr *protinfo;
137 struct net_bridge_port *p; 232 struct net_bridge_port *p;
138 u8 new_state; 233 struct nlattr *tb[IFLA_BRPORT_MAX];
234 int err;
139 235
140 ifm = nlmsg_data(nlh); 236 ifm = nlmsg_data(nlh);
141 237
142 protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); 238 protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
143 if (!protinfo || nla_len(protinfo) < sizeof(u8)) 239 if (!protinfo)
144 return -EINVAL; 240 return 0;
145
146 new_state = nla_get_u8(protinfo);
147 if (new_state > BR_STATE_BLOCKING)
148 return -EINVAL;
149 241
150 p = br_port_get_rtnl(dev); 242 p = br_port_get_rtnl(dev);
151 if (!p) 243 if (!p)
152 return -EINVAL; 244 return -EINVAL;
153 245
154 /* if kernel STP is running, don't allow changes */ 246 if (protinfo->nla_type & NLA_F_NESTED) {
155 if (p->br->stp_enabled == BR_KERNEL_STP) 247 err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
156 return -EBUSY; 248 protinfo, ifla_brport_policy);
249 if (err)
250 return err;
157 251
158 if (!netif_running(dev) || 252 spin_lock_bh(&p->br->lock);
159 (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED)) 253 err = br_setport(p, tb);
160 return -ENETDOWN; 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; 260 spin_lock_bh(&p->br->lock);
163 br_log_state(p); 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); 265 if (err == 0)
166 br_port_state_selection(p->br); 266 br_ifinfo_notify(RTM_NEWLINK, p);
167 spin_unlock_bh(&p->br->lock);
168 267
169 return 0; 268 return err;
170} 269}
171 270
172static int br_validate(struct nlattr *tb[], struct nlattr *data[]) 271static int br_validate(struct nlattr *tb[], struct nlattr *data[])