br_netlink.c 7.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 *	Bridge netlink control interface
 *
 *	Authors:
 *	Stephen Hemminger		<shemminger@osdl.org>
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 */

#include <linux/kernel.h>
14
#include <linux/slab.h>
15
#include <linux/etherdevice.h>
16
#include <net/rtnetlink.h>
17
#include <net/net_namespace.h>
18
#include <net/sock.h>
19

20
#include "br_private.h"
21
#include "br_private_stp.h"
22

23 24 25 26 27 28
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 */
29
		+ nla_total_size(1)	/* IFLA_BRPORT_GUARD */
S
stephen hemminger 已提交
30
		+ nla_total_size(1)	/* IFLA_BRPORT_PROTECT */
31 32 33
		+ 0;
}

34 35 36
static inline size_t br_nlmsg_size(void)
{
	return NLMSG_ALIGN(sizeof(struct ifinfomsg))
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
		+ 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) ||
54
	    nla_put_u8(skb, IFLA_BRPORT_MODE, mode) ||
S
stephen hemminger 已提交
55
	    nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) ||
56 57
	    nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) ||
	    nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)))
58 59 60
		return -EMSGSIZE;

	return 0;
61 62
}

63 64 65 66 67 68 69 70 71
/*
 * Create one netlink message for one interface
 * Contains port and master info as well as carrier and bridge state.
 */
static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *port,
			  u32 pid, u32 seq, int event, unsigned int flags)
{
	const struct net_bridge *br = port->br;
	const struct net_device *dev = port->dev;
72
	struct ifinfomsg *hdr;
73 74 75
	struct nlmsghdr *nlh;
	u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;

76 77
	br_debug(br, "br_fill_info event %d port %s master %s\n",
		     event, dev->name, br->dev->name);
78

79 80
	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
	if (nlh == NULL)
81
		return -EMSGSIZE;
82

83 84 85 86 87 88 89
	hdr = nlmsg_data(nlh);
	hdr->ifi_family = AF_BRIDGE;
	hdr->__ifi_pad = 0;
	hdr->ifi_type = dev->type;
	hdr->ifi_index = dev->ifindex;
	hdr->ifi_flags = dev_get_flags(dev);
	hdr->ifi_change = 0;
90

D
David S. Miller 已提交
91 92 93 94 95 96 97
	if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
	    nla_put_u32(skb, IFLA_MASTER, br->dev->ifindex) ||
	    nla_put_u32(skb, IFLA_MTU, dev->mtu) ||
	    nla_put_u8(skb, IFLA_OPERSTATE, operstate) ||
	    (dev->addr_len &&
	     nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
	    (dev->ifindex != dev->iflink &&
98
	     nla_put_u32(skb, IFLA_LINK, dev->iflink)))
D
David S. Miller 已提交
99
		goto nla_put_failure;
100 101 102 103 104 105 106 107 108 109

	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);
	}

110
	return nlmsg_end(skb, nlh);
111

112
nla_put_failure:
113 114
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
115 116 117 118 119 120 121
}

/*
 * Notify listeners of a change in port information
 */
void br_ifinfo_notify(int event, struct net_bridge_port *port)
{
122
	struct net *net = dev_net(port->dev);
123
	struct sk_buff *skb;
124
	int err = -ENOBUFS;
125

126
	br_debug(port->br, "port %u(%s) event %d\n",
127
		 (unsigned int)port->port_no, port->dev->name, event);
128

129
	skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC);
130 131 132 133
	if (skb == NULL)
		goto errout;

	err = br_fill_ifinfo(skb, port, 0, 0, event, 0);
134 135 136 137 138 139
	if (err < 0) {
		/* -EMSGSIZE implies BUG in br_nlmsg_size() */
		WARN_ON(err == -EMSGSIZE);
		kfree_skb(skb);
		goto errout;
	}
140 141
	rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
	return;
142
errout:
S
Stephen Hemminger 已提交
143
	if (err < 0)
144
		rtnl_set_sk_err(net, RTNLGRP_LINK, err);
145 146 147 148 149
}

/*
 * Dump information about all ports, in response to GETLINK
 */
J
John Fastabend 已提交
150 151
int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
	       struct net_device *dev)
152
{
J
John Fastabend 已提交
153 154 155 156 157 158
	int err = 0;
	struct net_bridge_port *port = br_port_get_rcu(dev);

	/* not a bridge port */
	if (!port)
		goto out;
159

J
John Fastabend 已提交
160 161 162
	err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI);
out:
	return err;
163 164
}

165 166 167 168 169
static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
	[IFLA_BRPORT_STATE]	= { .type = NLA_U8 },
	[IFLA_BRPORT_COST]	= { .type = NLA_U32 },
	[IFLA_BRPORT_PRIORITY]	= { .type = NLA_U16 },
	[IFLA_BRPORT_MODE]	= { .type = NLA_U8 },
170
	[IFLA_BRPORT_GUARD]	= { .type = NLA_U8 },
S
stephen hemminger 已提交
171
	[IFLA_BRPORT_PROTECT]	= { .type = NLA_U8 },
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
};

/* Change the state of the port and notify spanning tree */
static int br_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;
}

/* Set/clear or port flags based on attribute */
static void br_set_port_flag(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_setport(struct net_bridge_port *p, struct nlattr *tb[])
{
	int err;

	br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE);
213
	br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD);
214
	br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, BR_MULTICAST_FAST_LEAVE);
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236

	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_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE]));
		if (err)
			return err;
	}
	return 0;
}

/* Change state and parameters on port. */
J
John Fastabend 已提交
237
int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
238
{
239 240
	struct ifinfomsg *ifm;
	struct nlattr *protinfo;
241
	struct net_bridge_port *p;
242
	struct nlattr *tb[IFLA_BRPORT_MAX + 1];
243
	int err;
244

245
	ifm = nlmsg_data(nlh);
246

247
	protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
248 249
	if (!protinfo)
		return 0;
250

251
	p = br_port_get_rtnl(dev);
252 253
	if (!p)
		return -EINVAL;
254

255 256 257 258 259
	if (protinfo->nla_type & NLA_F_NESTED) {
		err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
				       protinfo, ifla_brport_policy);
		if (err)
			return err;
260

261 262 263 264 265 266 267
		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;
268

269 270 271 272
		spin_lock_bh(&p->br->lock);
		err = br_set_port_state(p, nla_get_u8(protinfo));
		spin_unlock_bh(&p->br->lock);
	}
273

274 275
	if (err == 0)
		br_ifinfo_notify(RTM_NEWLINK, p);
276

277
	return err;
278 279
}

280 281 282 283 284 285 286 287 288 289 290 291
static int br_validate(struct nlattr *tb[], struct nlattr *data[])
{
	if (tb[IFLA_ADDRESS]) {
		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
			return -EINVAL;
		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
			return -EADDRNOTAVAIL;
	}

	return 0;
}

292
struct rtnl_link_ops br_link_ops __read_mostly = {
293 294 295 296
	.kind		= "bridge",
	.priv_size	= sizeof(struct net_bridge),
	.setup		= br_dev_setup,
	.validate	= br_validate,
297
	.dellink	= br_dev_delete,
298
};
299

300
int __init br_netlink_init(void)
301
{
J
John Fastabend 已提交
302
	return rtnl_link_register(&br_link_ops);
303 304 305 306
}

void __exit br_netlink_fini(void)
{
307
	rtnl_link_unregister(&br_link_ops);
308
	rtnl_unregister_all(PF_BRIDGE);
309
}