Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b86f7f3 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bridge_rtnl_link'



Jiri Pirko says:

====================
bridge: implement rtnl_link options for getting and setting bridge options

So far, only sysfs is complete interface for getting and setting bridge
options. This patchset follows-up on the similar bonding code and
allows userspace to get/set bridge master/port options using Netlink
IFLA_INFO_DATA/IFLA_INFO_SLAVE_DATA attr.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 49a60158 13323516
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -215,6 +215,18 @@ enum in6_addr_gen_mode {
	IN6_ADDR_GEN_MODE_NONE,
};

/* Bridge section */

enum {
	IFLA_BR_UNSPEC,
	IFLA_BR_FORWARD_DELAY,
	IFLA_BR_HELLO_TIME,
	IFLA_BR_MAX_AGE,
	__IFLA_BR_MAX,
};

#define IFLA_BR_MAX	(__IFLA_BR_MAX - 1)

enum {
	BRIDGE_MODE_UNSPEC,
	BRIDGE_MODE_HAIRPIN,
+8 −7
Original line number Diff line number Diff line
@@ -252,12 +252,12 @@ static void del_nbp(struct net_bridge_port *p)
	br_fdb_delete_by_port(br, p, 1);
	nbp_update_port_count(br);

	netdev_upper_dev_unlink(dev, br->dev);

	dev->priv_flags &= ~IFF_BRIDGE_PORT;

	netdev_rx_handler_unregister(dev);

	netdev_upper_dev_unlink(dev, br->dev);

	br_multicast_del_port(p);

	kobject_uevent(&p->kobj, KOBJ_REMOVE);
@@ -476,16 +476,16 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
	if (err)
		goto err3;

	err = netdev_master_upper_dev_link(dev, br->dev);
	err = netdev_rx_handler_register(dev, br_handle_frame, p);
	if (err)
		goto err4;

	err = netdev_rx_handler_register(dev, br_handle_frame, p);
	dev->priv_flags |= IFF_BRIDGE_PORT;

	err = netdev_master_upper_dev_link(dev, br->dev);
	if (err)
		goto err5;

	dev->priv_flags |= IFF_BRIDGE_PORT;

	dev_disable_lro(dev);

	list_add_rcu(&p->list, &br->port_list);
@@ -520,7 +520,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
	return 0;

err5:
	netdev_upper_dev_unlink(dev, br->dev);
	dev->priv_flags &= ~IFF_BRIDGE_PORT;
	netdev_rx_handler_unregister(dev);
err4:
	br_netpoll_disable(p);
err3:
+101 −8
Original line number Diff line number Diff line
@@ -276,7 +276,7 @@ static int br_afspec(struct net_bridge *br,
	return err;
}

static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = {
	[IFLA_BRPORT_STATE]	= { .type = NLA_U8 },
	[IFLA_BRPORT_COST]	= { .type = NLA_U32 },
	[IFLA_BRPORT_PRIORITY]	= { .type = NLA_U16 },
@@ -382,7 +382,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
	if (p && protinfo) {
		if (protinfo->nla_type & NLA_F_NESTED) {
			err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
					       protinfo, ifla_brport_policy);
					       protinfo, br_port_policy);
			if (err)
				return err;

@@ -461,6 +461,88 @@ static int br_dev_newlink(struct net *src_net, struct net_device *dev,
	return register_netdevice(dev);
}

static int br_port_slave_changelink(struct net_device *brdev,
				    struct net_device *dev,
				    struct nlattr *tb[],
				    struct nlattr *data[])
{
	if (!data)
		return 0;
	return br_setport(br_port_get_rtnl(dev), data);
}

static int br_port_fill_slave_info(struct sk_buff *skb,
				   const struct net_device *brdev,
				   const struct net_device *dev)
{
	return br_port_fill_attrs(skb, br_port_get_rtnl(dev));
}

static size_t br_port_get_slave_size(const struct net_device *brdev,
				     const struct net_device *dev)
{
	return br_port_info_size();
}

static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = {
	[IFLA_BR_FORWARD_DELAY]	= { .type = NLA_U32 },
	[IFLA_BR_HELLO_TIME]	= { .type = NLA_U32 },
	[IFLA_BR_MAX_AGE]	= { .type = NLA_U32 },
};

static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
			 struct nlattr *data[])
{
	struct net_bridge *br = netdev_priv(brdev);
	int err;

	if (!data)
		return 0;

	if (data[IFLA_BR_FORWARD_DELAY]) {
		err = br_set_forward_delay(br, nla_get_u32(data[IFLA_BR_FORWARD_DELAY]));
		if (err)
			return err;
	}

	if (data[IFLA_BR_HELLO_TIME]) {
		err = br_set_hello_time(br, nla_get_u32(data[IFLA_BR_HELLO_TIME]));
		if (err)
			return err;
	}

	if (data[IFLA_BR_MAX_AGE]) {
		err = br_set_max_age(br, nla_get_u32(data[IFLA_BR_MAX_AGE]));
		if (err)
			return err;
	}

	return 0;
}

static size_t br_get_size(const struct net_device *brdev)
{
	return nla_total_size(sizeof(u32)) +	/* IFLA_BR_FORWARD_DELAY  */
	       nla_total_size(sizeof(u32)) +	/* IFLA_BR_HELLO_TIME */
	       nla_total_size(sizeof(u32)) +	/* IFLA_BR_MAX_AGE */
	       0;
}

static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev)
{
	struct net_bridge *br = netdev_priv(brdev);
	u32 forward_delay = jiffies_to_clock_t(br->forward_delay);
	u32 hello_time = jiffies_to_clock_t(br->hello_time);
	u32 age_time = jiffies_to_clock_t(br->max_age);

	if (nla_put_u32(skb, IFLA_BR_FORWARD_DELAY, forward_delay) ||
	    nla_put_u32(skb, IFLA_BR_HELLO_TIME, hello_time) ||
	    nla_put_u32(skb, IFLA_BR_MAX_AGE, age_time))
		return -EMSGSIZE;

	return 0;
}

static size_t br_get_link_af_size(const struct net_device *dev)
{
	struct net_port_vlans *pv;
@@ -488,9 +570,20 @@ struct rtnl_link_ops br_link_ops __read_mostly = {
	.kind			= "bridge",
	.priv_size		= sizeof(struct net_bridge),
	.setup			= br_dev_setup,
	.maxtype		= IFLA_BRPORT_MAX,
	.policy			= br_policy,
	.validate		= br_validate,
	.newlink		= br_dev_newlink,
	.changelink		= br_changelink,
	.dellink		= br_dev_delete,
	.get_size		= br_get_size,
	.fill_info		= br_fill_info,

	.slave_maxtype		= IFLA_BRPORT_MAX,
	.slave_policy		= br_port_policy,
	.slave_changelink	= br_port_slave_changelink,
	.get_slave_size		= br_port_get_slave_size,
	.fill_slave_info	= br_port_fill_slave_info,
};

int __init br_netlink_init(void)