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

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
...@@ -215,6 +215,18 @@ enum in6_addr_gen_mode { ...@@ -215,6 +215,18 @@ enum in6_addr_gen_mode {
IN6_ADDR_GEN_MODE_NONE, 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 { enum {
BRIDGE_MODE_UNSPEC, BRIDGE_MODE_UNSPEC,
BRIDGE_MODE_HAIRPIN, BRIDGE_MODE_HAIRPIN,
......
...@@ -252,12 +252,12 @@ static void del_nbp(struct net_bridge_port *p) ...@@ -252,12 +252,12 @@ static void del_nbp(struct net_bridge_port *p)
br_fdb_delete_by_port(br, p, 1); br_fdb_delete_by_port(br, p, 1);
nbp_update_port_count(br); nbp_update_port_count(br);
netdev_upper_dev_unlink(dev, br->dev);
dev->priv_flags &= ~IFF_BRIDGE_PORT; dev->priv_flags &= ~IFF_BRIDGE_PORT;
netdev_rx_handler_unregister(dev); netdev_rx_handler_unregister(dev);
netdev_upper_dev_unlink(dev, br->dev);
br_multicast_del_port(p); br_multicast_del_port(p);
kobject_uevent(&p->kobj, KOBJ_REMOVE); kobject_uevent(&p->kobj, KOBJ_REMOVE);
...@@ -476,16 +476,16 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) ...@@ -476,16 +476,16 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
if (err) if (err)
goto err3; goto err3;
err = netdev_master_upper_dev_link(dev, br->dev); err = netdev_rx_handler_register(dev, br_handle_frame, p);
if (err) if (err)
goto err4; 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) if (err)
goto err5; goto err5;
dev->priv_flags |= IFF_BRIDGE_PORT;
dev_disable_lro(dev); dev_disable_lro(dev);
list_add_rcu(&p->list, &br->port_list); list_add_rcu(&p->list, &br->port_list);
...@@ -520,7 +520,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) ...@@ -520,7 +520,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
return 0; return 0;
err5: err5:
netdev_upper_dev_unlink(dev, br->dev); dev->priv_flags &= ~IFF_BRIDGE_PORT;
netdev_rx_handler_unregister(dev);
err4: err4:
br_netpoll_disable(p); br_netpoll_disable(p);
err3: err3:
......
...@@ -276,7 +276,7 @@ static int br_afspec(struct net_bridge *br, ...@@ -276,7 +276,7 @@ static int br_afspec(struct net_bridge *br,
return err; 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_STATE] = { .type = NLA_U8 },
[IFLA_BRPORT_COST] = { .type = NLA_U32 }, [IFLA_BRPORT_COST] = { .type = NLA_U32 },
[IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 }, [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
...@@ -382,7 +382,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) ...@@ -382,7 +382,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
if (p && protinfo) { if (p && protinfo) {
if (protinfo->nla_type & NLA_F_NESTED) { if (protinfo->nla_type & NLA_F_NESTED) {
err = nla_parse_nested(tb, IFLA_BRPORT_MAX, err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
protinfo, ifla_brport_policy); protinfo, br_port_policy);
if (err) if (err)
return err; return err;
...@@ -461,6 +461,88 @@ static int br_dev_newlink(struct net *src_net, struct net_device *dev, ...@@ -461,6 +461,88 @@ static int br_dev_newlink(struct net *src_net, struct net_device *dev,
return register_netdevice(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) static size_t br_get_link_af_size(const struct net_device *dev)
{ {
struct net_port_vlans *pv; struct net_port_vlans *pv;
...@@ -488,9 +570,20 @@ struct rtnl_link_ops br_link_ops __read_mostly = { ...@@ -488,9 +570,20 @@ struct rtnl_link_ops br_link_ops __read_mostly = {
.kind = "bridge", .kind = "bridge",
.priv_size = sizeof(struct net_bridge), .priv_size = sizeof(struct net_bridge),
.setup = br_dev_setup, .setup = br_dev_setup,
.maxtype = IFLA_BRPORT_MAX,
.policy = br_policy,
.validate = br_validate, .validate = br_validate,
.newlink = br_dev_newlink, .newlink = br_dev_newlink,
.changelink = br_changelink,
.dellink = br_dev_delete, .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) int __init br_netlink_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment