Merge branch 'mpls-next'
Eric W. Biederman says: ==================== mpls: Minor fixes and cleanups This is a bunch of small changes that have come out of the discussions of the mpls code and the automated tests that people run against things. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
9b974499e4
|
@ -226,6 +226,7 @@ enum {
|
||||||
NEIGH_ND_TABLE = 1,
|
NEIGH_ND_TABLE = 1,
|
||||||
NEIGH_DN_TABLE = 2,
|
NEIGH_DN_TABLE = 2,
|
||||||
NEIGH_NR_TABLES,
|
NEIGH_NR_TABLES,
|
||||||
|
NEIGH_LINK_TABLE = NEIGH_NR_TABLES /* Pseudo table for neigh_xmit */
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int neigh_parms_family(struct neigh_parms *p)
|
static inline int neigh_parms_family(struct neigh_parms *p)
|
||||||
|
|
|
@ -2391,22 +2391,15 @@ void __neigh_for_each_release(struct neigh_table *tbl,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__neigh_for_each_release);
|
EXPORT_SYMBOL(__neigh_for_each_release);
|
||||||
|
|
||||||
int neigh_xmit(int family, struct net_device *dev,
|
int neigh_xmit(int index, struct net_device *dev,
|
||||||
const void *addr, struct sk_buff *skb)
|
const void *addr, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
int err;
|
int err = -EAFNOSUPPORT;
|
||||||
if (family == AF_PACKET) {
|
if (likely(index < NEIGH_NR_TABLES)) {
|
||||||
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
|
|
||||||
addr, NULL, skb->len);
|
|
||||||
if (err < 0)
|
|
||||||
goto out_kfree_skb;
|
|
||||||
err = dev_queue_xmit(skb);
|
|
||||||
} else {
|
|
||||||
struct neigh_table *tbl;
|
struct neigh_table *tbl;
|
||||||
struct neighbour *neigh;
|
struct neighbour *neigh;
|
||||||
|
|
||||||
err = -ENETDOWN;
|
tbl = neigh_tables[index];
|
||||||
tbl = neigh_find_table(family);
|
|
||||||
if (!tbl)
|
if (!tbl)
|
||||||
goto out;
|
goto out;
|
||||||
neigh = __neigh_lookup_noref(tbl, addr, dev);
|
neigh = __neigh_lookup_noref(tbl, addr, dev);
|
||||||
|
@ -2417,6 +2410,13 @@ int neigh_xmit(int family, struct net_device *dev,
|
||||||
goto out_kfree_skb;
|
goto out_kfree_skb;
|
||||||
err = neigh->output(neigh, skb);
|
err = neigh->output(neigh, skb);
|
||||||
}
|
}
|
||||||
|
else if (index == NEIGH_LINK_TABLE) {
|
||||||
|
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
|
||||||
|
addr, NULL, skb->len);
|
||||||
|
if (err < 0)
|
||||||
|
goto out_kfree_skb;
|
||||||
|
err = dev_queue_xmit(skb);
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
out_kfree_skb:
|
out_kfree_skb:
|
||||||
|
|
|
@ -24,13 +24,13 @@
|
||||||
#define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, sizeof(unsigned long)))
|
#define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, sizeof(unsigned long)))
|
||||||
|
|
||||||
struct mpls_route { /* next hop label forwarding entry */
|
struct mpls_route { /* next hop label forwarding entry */
|
||||||
struct net_device *rt_dev;
|
struct net_device __rcu *rt_dev;
|
||||||
struct rcu_head rt_rcu;
|
struct rcu_head rt_rcu;
|
||||||
u32 rt_label[MAX_NEW_LABELS];
|
u32 rt_label[MAX_NEW_LABELS];
|
||||||
u8 rt_protocol; /* routing protocol that set this entry */
|
u8 rt_protocol; /* routing protocol that set this entry */
|
||||||
u8 rt_labels:2,
|
u8 rt_labels;
|
||||||
rt_via_alen:6;
|
u8 rt_via_alen;
|
||||||
unsigned short rt_via_family;
|
u8 rt_via_table;
|
||||||
u8 rt_via[0];
|
u8 rt_via[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
/* Find the output device */
|
/* Find the output device */
|
||||||
out_dev = rt->rt_dev;
|
out_dev = rcu_dereference(rt->rt_dev);
|
||||||
if (!mpls_output_possible(out_dev))
|
if (!mpls_output_possible(out_dev))
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
|
||||||
skb_forward_csum(skb);
|
skb_forward_csum(skb);
|
||||||
|
|
||||||
/* Verify ttl is valid */
|
/* Verify ttl is valid */
|
||||||
if (dec.ttl <= 2)
|
if (dec.ttl <= 1)
|
||||||
goto drop;
|
goto drop;
|
||||||
dec.ttl -= 1;
|
dec.ttl -= 1;
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = neigh_xmit(rt->rt_via_family, out_dev, rt->rt_via, skb);
|
err = neigh_xmit(rt->rt_via_table, out_dev, rt->rt_via, skb);
|
||||||
if (err)
|
if (err)
|
||||||
net_dbg_ratelimited("%s: packet transmission failed: %d\n",
|
net_dbg_ratelimited("%s: packet transmission failed: %d\n",
|
||||||
__func__, err);
|
__func__, err);
|
||||||
|
@ -225,7 +225,7 @@ static const struct nla_policy rtm_mpls_policy[RTA_MAX+1] = {
|
||||||
struct mpls_route_config {
|
struct mpls_route_config {
|
||||||
u32 rc_protocol;
|
u32 rc_protocol;
|
||||||
u32 rc_ifindex;
|
u32 rc_ifindex;
|
||||||
u16 rc_via_family;
|
u16 rc_via_table;
|
||||||
u16 rc_via_alen;
|
u16 rc_via_alen;
|
||||||
u8 rc_via[MAX_VIA_ALEN];
|
u8 rc_via[MAX_VIA_ALEN];
|
||||||
u32 rc_label;
|
u32 rc_label;
|
||||||
|
@ -239,7 +239,7 @@ static struct mpls_route *mpls_rt_alloc(size_t alen)
|
||||||
{
|
{
|
||||||
struct mpls_route *rt;
|
struct mpls_route *rt;
|
||||||
|
|
||||||
rt = kzalloc(GFP_KERNEL, sizeof(*rt) + alen);
|
rt = kzalloc(sizeof(*rt) + alen, GFP_KERNEL);
|
||||||
if (rt)
|
if (rt)
|
||||||
rt->rt_via_alen = alen;
|
rt->rt_via_alen = alen;
|
||||||
return rt;
|
return rt;
|
||||||
|
@ -269,13 +269,15 @@ static void mpls_route_update(struct net *net, unsigned index,
|
||||||
struct net_device *dev, struct mpls_route *new,
|
struct net_device *dev, struct mpls_route *new,
|
||||||
const struct nl_info *info)
|
const struct nl_info *info)
|
||||||
{
|
{
|
||||||
|
struct mpls_route __rcu **platform_label;
|
||||||
struct mpls_route *rt, *old = NULL;
|
struct mpls_route *rt, *old = NULL;
|
||||||
|
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
|
||||||
rt = net->mpls.platform_label[index];
|
platform_label = rtnl_dereference(net->mpls.platform_label);
|
||||||
if (!dev || (rt && (rt->rt_dev == dev))) {
|
rt = rtnl_dereference(platform_label[index]);
|
||||||
rcu_assign_pointer(net->mpls.platform_label[index], new);
|
if (!dev || (rt && (rtnl_dereference(rt->rt_dev) == dev))) {
|
||||||
|
rcu_assign_pointer(platform_label[index], new);
|
||||||
old = rt;
|
old = rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,9 +289,14 @@ static void mpls_route_update(struct net *net, unsigned index,
|
||||||
|
|
||||||
static unsigned find_free_label(struct net *net)
|
static unsigned find_free_label(struct net *net)
|
||||||
{
|
{
|
||||||
|
struct mpls_route __rcu **platform_label;
|
||||||
|
size_t platform_labels;
|
||||||
unsigned index;
|
unsigned index;
|
||||||
for (index = 16; index < net->mpls.platform_labels; index++) {
|
|
||||||
if (!net->mpls.platform_label[index])
|
platform_label = rtnl_dereference(net->mpls.platform_label);
|
||||||
|
platform_labels = net->mpls.platform_labels;
|
||||||
|
for (index = 16; index < platform_labels; index++) {
|
||||||
|
if (!rtnl_dereference(platform_label[index]))
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
return LABEL_NOT_SPECIFIED;
|
return LABEL_NOT_SPECIFIED;
|
||||||
|
@ -297,6 +304,7 @@ static unsigned find_free_label(struct net *net)
|
||||||
|
|
||||||
static int mpls_route_add(struct mpls_route_config *cfg)
|
static int mpls_route_add(struct mpls_route_config *cfg)
|
||||||
{
|
{
|
||||||
|
struct mpls_route __rcu **platform_label;
|
||||||
struct net *net = cfg->rc_nlinfo.nl_net;
|
struct net *net = cfg->rc_nlinfo.nl_net;
|
||||||
struct net_device *dev = NULL;
|
struct net_device *dev = NULL;
|
||||||
struct mpls_route *rt, *old;
|
struct mpls_route *rt, *old;
|
||||||
|
@ -335,17 +343,18 @@ static int mpls_route_add(struct mpls_route_config *cfg)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if ((cfg->rc_via_family == AF_PACKET) &&
|
if ((cfg->rc_via_table == NEIGH_LINK_TABLE) &&
|
||||||
(dev->addr_len != cfg->rc_via_alen))
|
(dev->addr_len != cfg->rc_via_alen))
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
/* Append makes no sense with mpls */
|
/* Append makes no sense with mpls */
|
||||||
err = -EINVAL;
|
err = -EOPNOTSUPP;
|
||||||
if (cfg->rc_nlflags & NLM_F_APPEND)
|
if (cfg->rc_nlflags & NLM_F_APPEND)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
old = net->mpls.platform_label[index];
|
platform_label = rtnl_dereference(net->mpls.platform_label);
|
||||||
|
old = rtnl_dereference(platform_label[index]);
|
||||||
if ((cfg->rc_nlflags & NLM_F_EXCL) && old)
|
if ((cfg->rc_nlflags & NLM_F_EXCL) && old)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
|
@ -366,8 +375,8 @@ static int mpls_route_add(struct mpls_route_config *cfg)
|
||||||
for (i = 0; i < rt->rt_labels; i++)
|
for (i = 0; i < rt->rt_labels; i++)
|
||||||
rt->rt_label[i] = cfg->rc_output_label[i];
|
rt->rt_label[i] = cfg->rc_output_label[i];
|
||||||
rt->rt_protocol = cfg->rc_protocol;
|
rt->rt_protocol = cfg->rc_protocol;
|
||||||
rt->rt_dev = dev;
|
RCU_INIT_POINTER(rt->rt_dev, dev);
|
||||||
rt->rt_via_family = cfg->rc_via_family;
|
rt->rt_via_table = cfg->rc_via_table;
|
||||||
memcpy(rt->rt_via, cfg->rc_via, cfg->rc_via_alen);
|
memcpy(rt->rt_via, cfg->rc_via, cfg->rc_via_alen);
|
||||||
|
|
||||||
mpls_route_update(net, index, NULL, rt, &cfg->rc_nlinfo);
|
mpls_route_update(net, index, NULL, rt, &cfg->rc_nlinfo);
|
||||||
|
@ -406,14 +415,16 @@ errout:
|
||||||
|
|
||||||
static void mpls_ifdown(struct net_device *dev)
|
static void mpls_ifdown(struct net_device *dev)
|
||||||
{
|
{
|
||||||
|
struct mpls_route __rcu **platform_label;
|
||||||
struct net *net = dev_net(dev);
|
struct net *net = dev_net(dev);
|
||||||
unsigned index;
|
unsigned index;
|
||||||
|
|
||||||
|
platform_label = rtnl_dereference(net->mpls.platform_label);
|
||||||
for (index = 0; index < net->mpls.platform_labels; index++) {
|
for (index = 0; index < net->mpls.platform_labels; index++) {
|
||||||
struct mpls_route *rt = net->mpls.platform_label[index];
|
struct mpls_route *rt = rtnl_dereference(platform_label[index]);
|
||||||
if (!rt)
|
if (!rt)
|
||||||
continue;
|
continue;
|
||||||
if (rt->rt_dev != dev)
|
if (rtnl_dereference(rt->rt_dev) != dev)
|
||||||
continue;
|
continue;
|
||||||
rt->rt_dev = NULL;
|
rt->rt_dev = NULL;
|
||||||
}
|
}
|
||||||
|
@ -437,15 +448,22 @@ static struct notifier_block mpls_dev_notifier = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int nla_put_via(struct sk_buff *skb,
|
static int nla_put_via(struct sk_buff *skb,
|
||||||
u16 family, const void *addr, int alen)
|
u8 table, const void *addr, int alen)
|
||||||
{
|
{
|
||||||
|
static const int table_to_family[NEIGH_NR_TABLES + 1] = {
|
||||||
|
AF_INET, AF_INET6, AF_DECnet, AF_PACKET,
|
||||||
|
};
|
||||||
struct nlattr *nla;
|
struct nlattr *nla;
|
||||||
struct rtvia *via;
|
struct rtvia *via;
|
||||||
|
int family = AF_UNSPEC;
|
||||||
|
|
||||||
nla = nla_reserve(skb, RTA_VIA, alen + 2);
|
nla = nla_reserve(skb, RTA_VIA, alen + 2);
|
||||||
if (!nla)
|
if (!nla)
|
||||||
return -EMSGSIZE;
|
return -EMSGSIZE;
|
||||||
|
|
||||||
|
if (table <= NEIGH_NR_TABLES)
|
||||||
|
family = table_to_family[table];
|
||||||
|
|
||||||
via = nla_data(nla);
|
via = nla_data(nla);
|
||||||
via->rtvia_family = family;
|
via->rtvia_family = family;
|
||||||
memcpy(via->rtvia_addr, addr, alen);
|
memcpy(via->rtvia_addr, addr, alen);
|
||||||
|
@ -588,21 +606,23 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||||
struct rtvia *via = nla_data(nla);
|
struct rtvia *via = nla_data(nla);
|
||||||
if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr))
|
if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr))
|
||||||
goto errout;
|
goto errout;
|
||||||
cfg->rc_via_family = via->rtvia_family;
|
|
||||||
cfg->rc_via_alen = nla_len(nla) -
|
cfg->rc_via_alen = nla_len(nla) -
|
||||||
offsetof(struct rtvia, rtvia_addr);
|
offsetof(struct rtvia, rtvia_addr);
|
||||||
if (cfg->rc_via_alen > MAX_VIA_ALEN)
|
if (cfg->rc_via_alen > MAX_VIA_ALEN)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
/* Validate the address family */
|
/* Validate the address family */
|
||||||
switch(cfg->rc_via_family) {
|
switch(via->rtvia_family) {
|
||||||
case AF_PACKET:
|
case AF_PACKET:
|
||||||
|
cfg->rc_via_table = NEIGH_LINK_TABLE;
|
||||||
break;
|
break;
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
|
cfg->rc_via_table = NEIGH_ARP_TABLE;
|
||||||
if (cfg->rc_via_alen != 4)
|
if (cfg->rc_via_alen != 4)
|
||||||
goto errout;
|
goto errout;
|
||||||
break;
|
break;
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
|
cfg->rc_via_table = NEIGH_ND_TABLE;
|
||||||
if (cfg->rc_via_alen != 16)
|
if (cfg->rc_via_alen != 16)
|
||||||
goto errout;
|
goto errout;
|
||||||
break;
|
break;
|
||||||
|
@ -653,6 +673,7 @@ static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||||
static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
|
static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
|
||||||
u32 label, struct mpls_route *rt, int flags)
|
u32 label, struct mpls_route *rt, int flags)
|
||||||
{
|
{
|
||||||
|
struct net_device *dev;
|
||||||
struct nlmsghdr *nlh;
|
struct nlmsghdr *nlh;
|
||||||
struct rtmsg *rtm;
|
struct rtmsg *rtm;
|
||||||
|
|
||||||
|
@ -674,9 +695,10 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
|
||||||
if (rt->rt_labels &&
|
if (rt->rt_labels &&
|
||||||
nla_put_labels(skb, RTA_NEWDST, rt->rt_labels, rt->rt_label))
|
nla_put_labels(skb, RTA_NEWDST, rt->rt_labels, rt->rt_label))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
if (nla_put_via(skb, rt->rt_via_family, rt->rt_via, rt->rt_via_alen))
|
if (nla_put_via(skb, rt->rt_via_table, rt->rt_via, rt->rt_via_alen))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
if (rt->rt_dev && nla_put_u32(skb, RTA_OIF, rt->rt_dev->ifindex))
|
dev = rtnl_dereference(rt->rt_dev);
|
||||||
|
if (dev && nla_put_u32(skb, RTA_OIF, dev->ifindex))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
if (nla_put_labels(skb, RTA_DST, 1, &label))
|
if (nla_put_labels(skb, RTA_DST, 1, &label))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
@ -692,6 +714,8 @@ nla_put_failure:
|
||||||
static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
|
static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(skb->sk);
|
struct net *net = sock_net(skb->sk);
|
||||||
|
struct mpls_route __rcu **platform_label;
|
||||||
|
size_t platform_labels;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
|
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
@ -700,9 +724,11 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
if (index < 16)
|
if (index < 16)
|
||||||
index = 16;
|
index = 16;
|
||||||
|
|
||||||
for (; index < net->mpls.platform_labels; index++) {
|
platform_label = rtnl_dereference(net->mpls.platform_label);
|
||||||
|
platform_labels = net->mpls.platform_labels;
|
||||||
|
for (; index < platform_labels; index++) {
|
||||||
struct mpls_route *rt;
|
struct mpls_route *rt;
|
||||||
rt = net->mpls.platform_label[index];
|
rt = rtnl_dereference(platform_label[index]);
|
||||||
if (!rt)
|
if (!rt)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -780,9 +806,9 @@ static int resize_platform_label_table(struct net *net, size_t limit)
|
||||||
rt0 = mpls_rt_alloc(lo->addr_len);
|
rt0 = mpls_rt_alloc(lo->addr_len);
|
||||||
if (!rt0)
|
if (!rt0)
|
||||||
goto nort0;
|
goto nort0;
|
||||||
rt0->rt_dev = lo;
|
RCU_INIT_POINTER(rt0->rt_dev, lo);
|
||||||
rt0->rt_protocol = RTPROT_KERNEL;
|
rt0->rt_protocol = RTPROT_KERNEL;
|
||||||
rt0->rt_via_family = AF_PACKET;
|
rt0->rt_via_table = NEIGH_LINK_TABLE;
|
||||||
memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len);
|
memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len);
|
||||||
}
|
}
|
||||||
if (limit > LABEL_IPV6_EXPLICIT_NULL) {
|
if (limit > LABEL_IPV6_EXPLICIT_NULL) {
|
||||||
|
@ -790,15 +816,15 @@ static int resize_platform_label_table(struct net *net, size_t limit)
|
||||||
rt2 = mpls_rt_alloc(lo->addr_len);
|
rt2 = mpls_rt_alloc(lo->addr_len);
|
||||||
if (!rt2)
|
if (!rt2)
|
||||||
goto nort2;
|
goto nort2;
|
||||||
rt2->rt_dev = lo;
|
RCU_INIT_POINTER(rt2->rt_dev, lo);
|
||||||
rt2->rt_protocol = RTPROT_KERNEL;
|
rt2->rt_protocol = RTPROT_KERNEL;
|
||||||
rt2->rt_via_family = AF_PACKET;
|
rt2->rt_via_table = NEIGH_LINK_TABLE;
|
||||||
memcpy(rt2->rt_via, lo->dev_addr, lo->addr_len);
|
memcpy(rt2->rt_via, lo->dev_addr, lo->addr_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
/* Remember the original table */
|
/* Remember the original table */
|
||||||
old = net->mpls.platform_label;
|
old = rtnl_dereference(net->mpls.platform_label);
|
||||||
old_limit = net->mpls.platform_labels;
|
old_limit = net->mpls.platform_labels;
|
||||||
|
|
||||||
/* Free any labels beyond the new table */
|
/* Free any labels beyond the new table */
|
||||||
|
@ -815,19 +841,19 @@ static int resize_platform_label_table(struct net *net, size_t limit)
|
||||||
/* If needed set the predefined labels */
|
/* If needed set the predefined labels */
|
||||||
if ((old_limit <= LABEL_IPV6_EXPLICIT_NULL) &&
|
if ((old_limit <= LABEL_IPV6_EXPLICIT_NULL) &&
|
||||||
(limit > LABEL_IPV6_EXPLICIT_NULL)) {
|
(limit > LABEL_IPV6_EXPLICIT_NULL)) {
|
||||||
labels[LABEL_IPV6_EXPLICIT_NULL] = rt2;
|
RCU_INIT_POINTER(labels[LABEL_IPV6_EXPLICIT_NULL], rt2);
|
||||||
rt2 = NULL;
|
rt2 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((old_limit <= LABEL_IPV4_EXPLICIT_NULL) &&
|
if ((old_limit <= LABEL_IPV4_EXPLICIT_NULL) &&
|
||||||
(limit > LABEL_IPV4_EXPLICIT_NULL)) {
|
(limit > LABEL_IPV4_EXPLICIT_NULL)) {
|
||||||
labels[LABEL_IPV4_EXPLICIT_NULL] = rt0;
|
RCU_INIT_POINTER(labels[LABEL_IPV4_EXPLICIT_NULL], rt0);
|
||||||
rt0 = NULL;
|
rt0 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the global pointers */
|
/* Update the global pointers */
|
||||||
net->mpls.platform_labels = limit;
|
net->mpls.platform_labels = limit;
|
||||||
net->mpls.platform_label = labels;
|
rcu_assign_pointer(net->mpls.platform_label, labels);
|
||||||
|
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
||||||
|
@ -903,6 +929,8 @@ static int mpls_net_init(struct net *net)
|
||||||
|
|
||||||
static void mpls_net_exit(struct net *net)
|
static void mpls_net_exit(struct net *net)
|
||||||
{
|
{
|
||||||
|
struct mpls_route __rcu **platform_label;
|
||||||
|
size_t platform_labels;
|
||||||
struct ctl_table *table;
|
struct ctl_table *table;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
|
|
||||||
|
@ -910,8 +938,8 @@ static void mpls_net_exit(struct net *net)
|
||||||
unregister_net_sysctl_table(net->mpls.ctl);
|
unregister_net_sysctl_table(net->mpls.ctl);
|
||||||
kfree(table);
|
kfree(table);
|
||||||
|
|
||||||
/* An rcu grace period haselapsed since there was a device in
|
/* An rcu grace period has passed since there was a device in
|
||||||
* the network namespace (and thus the last in fqlight packet)
|
* the network namespace (and thus the last in flight packet)
|
||||||
* left this network namespace. This is because
|
* left this network namespace. This is because
|
||||||
* unregister_netdevice_many and netdev_run_todo has completed
|
* unregister_netdevice_many and netdev_run_todo has completed
|
||||||
* for each network device that was in this network namespace.
|
* for each network device that was in this network namespace.
|
||||||
|
@ -920,14 +948,16 @@ static void mpls_net_exit(struct net *net)
|
||||||
* freeing the platform_label table.
|
* freeing the platform_label table.
|
||||||
*/
|
*/
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
for (index = 0; index < net->mpls.platform_labels; index++) {
|
platform_label = rtnl_dereference(net->mpls.platform_label);
|
||||||
struct mpls_route *rt = net->mpls.platform_label[index];
|
platform_labels = net->mpls.platform_labels;
|
||||||
rcu_assign_pointer(net->mpls.platform_label[index], NULL);
|
for (index = 0; index < platform_labels; index++) {
|
||||||
|
struct mpls_route *rt = rtnl_dereference(platform_label[index]);
|
||||||
|
RCU_INIT_POINTER(platform_label[index], NULL);
|
||||||
mpls_rt_free(rt);
|
mpls_rt_free(rt);
|
||||||
}
|
}
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
||||||
kvfree(net->mpls.platform_label);
|
kvfree(platform_label);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pernet_operations mpls_net_ops = {
|
static struct pernet_operations mpls_net_ops = {
|
||||||
|
|
|
@ -6,6 +6,7 @@ config OPENVSWITCH
|
||||||
tristate "Open vSwitch"
|
tristate "Open vSwitch"
|
||||||
depends on INET
|
depends on INET
|
||||||
select LIBCRC32C
|
select LIBCRC32C
|
||||||
|
select MPLS
|
||||||
select NET_MPLS_GSO
|
select NET_MPLS_GSO
|
||||||
---help---
|
---help---
|
||||||
Open vSwitch is a multilayer Ethernet switch targeted at virtualized
|
Open vSwitch is a multilayer Ethernet switch targeted at virtualized
|
||||||
|
|
Loading…
Reference in New Issue