diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/8021q/vlan_netlink.c | 8 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 9 | ||||
-rw-r--r-- | net/core/net_namespace.c | 1 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 5 | ||||
-rw-r--r-- | net/ipv4/fib_lookup.h | 1 | ||||
-rw-r--r-- | net/ipv4/fib_semantics.c | 18 | ||||
-rw-r--r-- | net/ipv4/fib_trie.c | 354 | ||||
-rw-r--r-- | net/ipv4/geneve.c | 5 | ||||
-rw-r--r-- | net/ipv4/udp_tunnel.c | 12 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 10 | ||||
-rw-r--r-- | net/ipv6/ip6_gre.c | 1 | ||||
-rw-r--r-- | net/ipv6/ip6_udp_tunnel.c | 12 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 8 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 2 | ||||
-rw-r--r-- | net/openvswitch/vport-vxlan.c | 6 | ||||
-rw-r--r-- | net/sched/Kconfig | 1 |
16 files changed, 246 insertions, 207 deletions
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 8ac8a5cc2143..c92b52f37d38 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -238,6 +238,13 @@ nla_put_failure: return -EMSGSIZE; } +static struct net *vlan_get_link_net(const struct net_device *dev) +{ + struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; + + return dev_net(real_dev); +} + struct rtnl_link_ops vlan_link_ops __read_mostly = { .kind = "vlan", .maxtype = IFLA_VLAN_MAX, @@ -250,6 +257,7 @@ struct rtnl_link_ops vlan_link_ops __read_mostly = { .dellink = unregister_vlan_dev, .get_size = vlan_get_size, .fill_info = vlan_fill_info, + .get_link_net = vlan_get_link_net, }; int __init vlan_netlink_init(void) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 528cf2790a5f..3875ea51f6fe 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -311,17 +311,14 @@ errout: int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, u32 filter_mask) { - int err = 0; struct net_bridge_port *port = br_port_get_rtnl(dev); if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN) && !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) - goto out; + return 0; - err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI, - filter_mask, dev); -out: - return err; + return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI, + filter_mask, dev); } static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p, diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 9d1a4cac83b6..b7bde551ef76 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -202,6 +202,7 @@ int peernet2id(struct net *net, struct net *peer) return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED; } +EXPORT_SYMBOL(peernet2id); struct net *get_net_ns_by_id(struct net *net, int id) { diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index a12eecc0f976..07447d1665e6 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2172,8 +2172,11 @@ replay: goto out; } - if (link_net) + if (link_net) { err = dev_change_net_namespace(dev, dest_net, ifname); + if (err < 0) + unregister_netdevice(dev); + } out: if (link_net) put_net(link_net); diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h index 1e4f6600b31d..825981b1049a 100644 --- a/net/ipv4/fib_lookup.h +++ b/net/ipv4/fib_lookup.h @@ -32,7 +32,6 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u32 tb_id, unsigned int); void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len, u32 tb_id, const struct nl_info *info, unsigned int nlm_flags); -struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio); static inline void fib_result_assign(struct fib_result *res, struct fib_info *fi) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 265cb72b7c1b..1e2090ea663e 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -411,24 +411,6 @@ errout: rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err); } -/* Return the first fib alias matching TOS with - * priority less than or equal to PRIO. - */ -struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio) -{ - if (fah) { - struct fib_alias *fa; - list_for_each_entry(fa, fah, fa_list) { - if (fa->fa_tos > tos) - continue; - if (fa->fa_info->fib_priority >= prio || - fa->fa_tos < tos) - return fa; - } - } - return NULL; -} - static int fib_detect_death(struct fib_info *fi, int order, struct fib_info **last_resort, int *last_idx, int dflt) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 281e5e00025f..3daf0224ff2e 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -83,7 +83,8 @@ #define MAX_STAT_DEPTH 32 -#define KEYLENGTH (8*sizeof(t_key)) +#define KEYLENGTH (8*sizeof(t_key)) +#define KEY_MAX ((t_key)~0) typedef unsigned int t_key; @@ -102,8 +103,8 @@ struct tnode { union { /* The fields in this struct are valid if bits > 0 (TNODE) */ struct { - unsigned int full_children; /* KEYLENGTH bits needed */ - unsigned int empty_children; /* KEYLENGTH bits needed */ + t_key empty_children; /* KEYLENGTH bits needed */ + t_key full_children; /* KEYLENGTH bits needed */ struct tnode __rcu *child[0]; }; /* This list pointer if valid if bits == 0 (LEAF) */ @@ -302,6 +303,16 @@ static struct tnode *tnode_alloc(size_t size) return vzalloc(size); } +static inline void empty_child_inc(struct tnode *n) +{ + ++n->empty_children ? : ++n->full_children; +} + +static inline void empty_child_dec(struct tnode *n) +{ + n->empty_children-- ? : n->full_children--; +} + static struct tnode *leaf_new(t_key key) { struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); @@ -335,7 +346,7 @@ static struct leaf_info *leaf_info_new(int plen) static struct tnode *tnode_new(t_key key, int pos, int bits) { - size_t sz = offsetof(struct tnode, child[1 << bits]); + size_t sz = offsetof(struct tnode, child[1ul << bits]); struct tnode *tn = tnode_alloc(sz); unsigned int shift = pos + bits; @@ -348,8 +359,10 @@ static struct tnode *tnode_new(t_key key, int pos, int bits) tn->pos = pos; tn->bits = bits; tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0; - tn->full_children = 0; - tn->empty_children = 1<<bits; + if (bits == KEYLENGTH) + tn->full_children = 1; + else + tn->empty_children = 1ul << bits; } pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode), @@ -375,11 +388,11 @@ static void put_child(struct tnode *tn, unsigned long i, struct tnode *n) BUG_ON(i >= tnode_child_length(tn)); - /* update emptyChildren */ + /* update emptyChildren, overflow into fullChildren */ if (n == NULL && chi != NULL) - tn->empty_children++; - else if (n != NULL && chi == NULL) - tn->empty_children--; + empty_child_inc(tn); + if (n != NULL && chi == NULL) + empty_child_dec(tn); /* update fullChildren */ wasfull = tnode_full(tn, chi); @@ -396,8 +409,30 @@ static void put_child(struct tnode *tn, unsigned long i, struct tnode *n) rcu_assign_pointer(tn->child[i], n); } -static void put_child_root(struct tnode *tp, struct trie *t, - t_key key, struct tnode *n) +static void update_children(struct tnode *tn) +{ + unsigned long i; + + /* update all of the child parent pointers */ + for (i = tnode_child_length(tn); i;) { + struct tnode *inode = tnode_get_child(tn, --i); + + if (!inode) + continue; + + /* Either update the children of a tnode that + * already belongs to us or update the child + * to point to ourselves. + */ + if (node_parent(inode) == tn) + update_children(inode); + else + node_set_parent(inode, tn); + } +} + +static inline void put_child_root(struct tnode *tp, struct trie *t, + t_key key, struct tnode *n) { if (tp) put_child(tp, get_index(key, tp), n); @@ -434,10 +469,35 @@ static void tnode_free(struct tnode *tn) } } +static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn) +{ + struct tnode *tp = node_parent(oldtnode); + unsigned long i; + + /* setup the parent pointer out of and back into this node */ + NODE_INIT_PARENT(tn, tp); + put_child_root(tp, t, tn->key, tn); + + /* update all of the child parent pointers */ + update_children(tn); + + /* all pointers should be clean so we are done */ + tnode_free(oldtnode); + + /* resize children now that oldtnode is freed */ + for (i = tnode_child_length(tn); i;) { + struct tnode *inode = tnode_get_child(tn, --i); + + /* resize child node */ + if (tnode_full(tn, inode)) + resize(t, inode); + } +} + static int inflate(struct trie *t, struct tnode *oldtnode) { - struct tnode *inode, *node0, *node1, *tn, *tp; - unsigned long i, j, k; + struct tnode *tn; + unsigned long i; t_key m; pr_debug("In inflate\n"); @@ -446,13 +506,18 @@ static int inflate(struct trie *t, struct tnode *oldtnode) if (!tn) return -ENOMEM; + /* prepare oldtnode to be freed */ + tnode_free_init(oldtnode); + /* Assemble all of the pointers in our cluster, in this case that * represents all of the pointers out of our allocated nodes that * point to existing tnodes and the links between our allocated * nodes. */ for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) { - inode = tnode_get_child(oldtnode, --i); + struct tnode *inode = tnode_get_child(oldtnode, --i); + struct tnode *node0, *node1; + unsigned long j, k; /* An empty child */ if (inode == NULL) @@ -464,6 +529,9 @@ static int inflate(struct trie *t, struct tnode *oldtnode) continue; } + /* drop the node in the old tnode free list */ + tnode_free_append(oldtnode, inode); + /* An internal node with two children */ if (inode->bits == 1) { put_child(tn, 2 * i + 1, tnode_get_child(inode, 1)); @@ -488,9 +556,9 @@ static int inflate(struct trie *t, struct tnode *oldtnode) node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1); if (!node1) goto nomem; - tnode_free_append(tn, node1); + node0 = tnode_new(inode->key, inode->pos, inode->bits - 1); - node0 = tnode_new(inode->key & ~m, inode->pos, inode->bits - 1); + tnode_free_append(tn, node1); if (!node0) goto nomem; tnode_free_append(tn, node0); @@ -512,53 +580,9 @@ static int inflate(struct trie *t, struct tnode *oldtnode) put_child(tn, 2 * i, node0); } - /* setup the parent pointer into and out of this node */ - tp = node_parent(oldtnode); - NODE_INIT_PARENT(tn, tp); - put_child_root(tp, t, tn->key, tn); - - /* prepare oldtnode to be freed */ - tnode_free_init(oldtnode); - - /* update all child nodes parent pointers to route to us */ - for (i = tnode_child_length(oldtnode); i;) { - inode = tnode_get_child(oldtnode, --i); - - /* A leaf or an internal node with skipped bits */ - if (!tnode_full(oldtnode, inode)) { - node_set_parent(inode, tn); - continue; - } - - /* drop the node in the old tnode free list */ - tnode_free_append(oldtnode, inode); - - /* fetch new nodes */ - node1 = tnode_get_child(tn, 2 * i + 1); - node0 = tnode_get_child(tn, 2 * i); - - /* bits == 1 then node0 and node1 represent inode's children */ - if (inode->bits == 1) { - node_set_parent(node1, tn); - node_set_parent(node0, tn); - continue; - } - - /* update parent pointers in child node's children */ - for (k = tnode_child_length(inode), j = k / 2; j;) { - node_set_parent(tnode_get_child(inode, --k), node1); - node_set_parent(tnode_get_child(inode, --j), node0); - node_set_parent(tnode_get_child(inode, --k), node1); - node_set_parent(tnode_get_child(inode, --j), node0); - } + /* setup the parent pointers into and out of this node */ + replace(t, oldtnode, tn); - /* resize child nodes */ - resize(t, node1); - resize(t, node0); - } - - /* we completed without error, prepare to free old node */ - tnode_free(oldtnode); return 0; nomem: /* all pointers should be clean so we are done */ @@ -568,7 +592,7 @@ nomem: static int halve(struct trie *t, struct tnode *oldtnode) { - struct tnode *tn, *tp, *inode, *node0, *node1; + struct tnode *tn; unsigned long i; pr_debug("In halve\n"); @@ -577,14 +601,18 @@ static int halve(struct trie *t, struct tnode *oldtnode) if (!tn) return -ENOMEM; + /* prepare oldtnode to be freed */ + tnode_free_init(oldtnode); + /* Assemble all of the pointers in our cluster, in this case that * represents all of the pointers out of our allocated nodes that * point to existing tnodes and the links between our allocated * nodes. */ for (i = tnode_child_length(oldtnode); i;) { - node1 = tnode_get_child(oldtnode, --i); - node0 = tnode_get_child(oldtnode, --i); + struct tnode *node1 = tnode_get_child(oldtnode, --i); + struct tnode *node0 = tnode_get_child(oldtnode, --i); + struct tnode *inode; /* At least one of the children is empty */ if (!node1 || !node0) { @@ -609,36 +637,28 @@ static int halve(struct trie *t, struct tnode *oldtnode) put_child(tn, i / 2, inode); } - /* setup the parent pointer out of and back into this node */ - tp = node_parent(oldtnode); - NODE_INIT_PARENT(tn, tp); - put_child_root(tp, t, tn->key, tn); - - /* prepare oldtnode to be freed */ - tnode_free_init(oldtnode); + /* setup the parent pointers into and out of this node */ + replace(t, oldtnode, tn); - /* update all of the child parent pointers */ - for (i = tnode_child_length(tn); i;) { - inode = tnode_get_child(tn, --i); - - /* only new tnodes will be considered "full" nodes */ - if (!tnode_full(tn, inode)) { - node_set_parent(inode, tn); - continue; - } + return 0; +} - /* Two nonempty children */ - node_set_parent(tnode_get_child(inode, 1), inode); - node_set_parent(tnode_get_child(inode, 0), inode); +static void collapse(struct trie *t, struct tnode *oldtnode) +{ + struct tnode *n, *tp; + unsigned long i; - /* resize child node */ - resize(t, inode); - } + /* scan the tnode looking for that one child that might still exist */ + for (n = NULL, i = tnode_child_length(oldtnode); !n && i;) + n = tnode_get_child(oldtnode, --i); - /* all pointers should be clean so we are done */ - tnode_free(oldtnode); + /* compress one level */ + tp = node_parent(oldtnode); + put_child_root(tp, t, oldtnode->key, n); + node_set_parent(n, tp); - return 0; + /* drop dead node */ + node_free(oldtnode); } static unsigned char update_suffix(struct tnode *tn) @@ -740,10 +760,12 @@ static bool should_inflate(const struct tnode *tp, const struct tnode *tn) /* Keep root node larger */ threshold *= tp ? inflate_threshold : inflate_threshold_root; - used += tn->full_children; used -= tn->empty_children; + used += tn->full_children; + + /* if bits == KEYLENGTH then pos = 0, and will fail below */ - return tn->pos && ((50 * used) >= threshold); + return (used > 1) && tn->pos && ((50 * used) >= threshold); } static bool should_halve(const struct tnode *tp, const struct tnode *tn) @@ -755,15 +777,31 @@ static bool should_halve(const struct tnode *tp, const struct tnode *tn) threshold *= tp ? halve_threshold : halve_threshold_root; used -= tn->empty_children; - return (tn->bits > 1) && ((100 * used) < threshold); + /* if bits == KEYLENGTH then used = 100% on wrap, and will fail below */ + + return (used > 1) && (tn->bits > 1) && ((100 * used) < threshold); +} + +static bool should_collapse(const struct tnode *tn) +{ + unsigned long used = tnode_child_length(tn); + + used -= tn->empty_children; + + /* account for bits == KEYLENGTH case */ + if ((tn->bits == KEYLENGTH) && tn->full_children) + used -= KEY_MAX; + + /* One child or none, time to drop us from the trie */ + return used < 2; } #define MAX_WORK 10 static void resize(struct trie *t, struct tnode *tn) { - struct tnode *tp = node_parent(tn), *n = NULL; + struct tnode *tp = node_parent(tn); struct tnode __rcu **cptr; - int max_work; + int max_work = MAX_WORK; pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n", tn, inflate_threshold, halve_threshold); @@ -775,19 +813,10 @@ static void resize(struct trie *t, struct tnode *tn) cptr = tp ? &tp->child[get_index(tn->key, tp)] : &t->trie; BUG_ON(tn != rtnl_dereference(*cptr)); - /* No children */ - if (tn->empty_children > (tnode_child_length(tn) - 1)) - goto no_children; - - /* One child */ - if (tn->empty_children == (tnode_child_length(tn) - 1)) - goto one_child; - /* Double as long as the resulting node has a number of * nonempty nodes that are above the threshold. */ - max_work = MAX_WORK; - while (should_inflate(tp, tn) && max_work--) { + while (should_inflate(tp, tn) && max_work) { if (inflate(t, tn)) { #ifdef CONFIG_IP_FIB_TRIE_STATS this_cpu_inc(t->stats->resize_node_skipped); @@ -795,6 +824,7 @@ static void resize(struct trie *t, struct tnode *tn) break; } + max_work--; tn = rtnl_dereference(*cptr); } @@ -805,8 +835,7 @@ static void resize(struct trie *t, struct tnode *tn) /* Halve as long as the number of empty children in this * node is above threshold. */ - max_work = MAX_WORK; - while (should_halve(tp, tn) && max_work--) { + while (should_halve(tp, tn) && max_work) { if (halve(t, tn)) { #ifdef CONFIG_IP_FIB_TRIE_STATS this_cpu_inc(t->stats->resize_node_skipped); @@ -814,23 +843,13 @@ static void resize(struct trie *t, struct tnode *tn) break; } + max_work--; tn = rtnl_dereference(*cptr); } /* Only one child remains */ - if (tn->empty_children == (tnode_child_length(tn) - 1)) { - unsigned long i; -one_child: - for (i = tnode_child_length(tn); !n && i;) - n = tnode_get_child(tn, --i); -no_children: - /* compress one level */ - put_child_root(tp, t, tn->key, n); - node_set_parent(n, tp); - - /* drop dead node */ - tnode_free_init(tn); - tnode_free(tn); + if (should_collapse(tn)) { + collapse(t, tn); return; } @@ -898,27 +917,20 @@ static void leaf_push_suffix(struct tnode *l) static void remove_leaf_info(struct tnode *l, struct leaf_info *old) { - struct hlist_node *prev; - - /* record the location of the pointer to this object */ - prev = rtnl_dereference(hlist_pprev_rcu(&old->hlist)); + /* record the location of the previous list_info entry */ + struct hlist_node **pprev = old->hlist.pprev; + struct leaf_info *li = hlist_entry(pprev, typeof(*li), hlist.next); /* remove the leaf info from the list */ hlist_del_rcu(&old->hlist); - /* if we emptied the list this leaf will be freed and we can sort - * out parent suffix lengths as a part of trie_rebalance - */ - if (hlist_empty(&l->list)) + /* only access li if it is pointing at the last valid hlist_node */ + if (hlist_empty(&l->list) || (*pprev)) return; - /* if we removed the tail then we need to update slen */ - if (!rcu_access_pointer(hlist_next_rcu(prev))) { - struct leaf_info *li = hlist_entry(prev, typeof(*li), hlist); - - l->slen = KEYLENGTH - li->plen; - leaf_pull_suffix(l); - } + /* update the trie with the latest suffix length */ + l->slen = KEYLENGTH - li->plen; + leaf_pull_suffix(l); } static void insert_leaf_info(struct tnode *l, struct leaf_info *new) @@ -942,7 +954,7 @@ static void insert_leaf_info(struct tnode *l, struct leaf_info *new) } /* if we added to the tail node then we need to update slen */ - if (!rcu_access_pointer(hlist_next_rcu(&new->hlist))) { + if (l->slen < (KEYLENGTH - new->plen)) { l->slen = KEYLENGTH - new->plen; leaf_push_suffix(l); } @@ -961,12 +973,12 @@ static struct tnode *fib_find_node(struct trie *t, u32 key) * prefix plus zeros for the bits in the cindex. The index * is the difference between the key and this value. From * this we can actually derive several pieces of data. - * if !(index >> bits) - * we know the value is cindex - * else + * if (index & (~0ul << bits)) * we have a mismatch in skip bits and failed + * else + * we know the value is cindex */ - if (index >> n->bits) + if (index & (~0ul << n->bits)) return NULL; /* we have found a leaf. Prefixes have already been compared */ @@ -979,6 +991,26 @@ static struct tnode *fib_find_node(struct trie *t, u32 key) return n; } +/* Return the first fib alias matching TOS with + * priority less than or equal to PRIO. + */ +static struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio) +{ + struct fib_alias *fa; + + if (!fah) + return NULL; + + list_for_each_entry(fa, fah, fa_list) { + if (fa->fa_tos > tos) + continue; + if (fa->fa_info->fib_priority >= prio || fa->fa_tos < tos) + return fa; + } + + return NULL; +} + static void trie_rebalance(struct trie *t, struct tnode *tn) { struct tnode *tp; @@ -1301,12 +1333,12 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, * prefix plus zeros for the "bits" in the prefix. The index * is the difference between the key and this value. From * this we can actually derive several pieces of data. - * if !(index >> bits) - * we know the value is child index - * else + * if (index & (~0ul << bits)) * we have a mismatch in skip bits and failed + * else + * we know the value is cindex */ - if (index >> n->bits) + if (index & (~0ul << n->bits)) break; /* we have found a leaf. Prefixes have already been compared */ @@ -1574,6 +1606,7 @@ static int trie_flush_leaf(struct tnode *l) struct hlist_head *lih = &l->list; struct hlist_node *tmp; struct leaf_info *li = NULL; + unsigned char plen = KEYLENGTH; hlist_for_each_entry_safe(li, tmp, lih, hlist) { found += trie_flush_list(&li->falh); @@ -1581,8 +1614,14 @@ static int trie_flush_leaf(struct tnode *l) if (list_empty(&li->falh)) { hlist_del_rcu(&li->hlist); free_leaf_info(li); + continue; } + + plen = li->plen; } + + l->slen = KEYLENGTH - plen; + return found; } @@ -1661,13 +1700,22 @@ int fib_table_flush(struct fib_table *tb) for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) { found += trie_flush_leaf(l); - if (ll && hlist_empty(&ll->list)) - trie_leaf_remove(t, ll); + if (ll) { + if (hlist_empty(&ll->list)) + trie_leaf_remove(t, ll); + else + leaf_pull_suffix(ll); + } + ll = l; } - if (ll && hlist_empty(&ll->list)) - trie_leaf_remove(t, ll); + if (ll) { + if (hlist_empty(&ll->list)) + trie_leaf_remove(t, ll); + else + leaf_pull_suffix(ll); + } pr_debug("trie_flush found=%d\n", found); return found; @@ -1935,16 +1983,10 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s) hlist_for_each_entry_rcu(li, &n->list, hlist) ++s->prefixes; } else { - unsigned long i; - s->tnodes++; if (n->bits < MAX_STAT_DEPTH) s->nodesizes[n->bits]++; - - for (i = tnode_child_length(n); i--;) { - if (!rcu_access_pointer(n->child[i])) - s->nullpointers++; - } + s->nullpointers += n->empty_children; } } rcu_read_unlock(); diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c index 9568594ca2f1..93e51199e44b 100644 --- a/net/ipv4/geneve.c +++ b/net/ipv4/geneve.c @@ -136,8 +136,9 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - return udp_tunnel_xmit_skb(gs->sock, rt, skb, src, dst, - tos, ttl, df, src_port, dst_port, xnet); + return udp_tunnel_xmit_skb(rt, skb, src, dst, + tos, ttl, df, src_port, dst_port, xnet, + gs->sock->sk->sk_no_check_tx); } EXPORT_SYMBOL_GPL(geneve_xmit_skb); diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c index 9996e63ed304..c83b35485056 100644 --- a/net/ipv4/udp_tunnel.c +++ b/net/ipv4/udp_tunnel.c @@ -75,10 +75,10 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock, } EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock); -int udp_tunnel_xmit_skb(struct socket *sock, struct rtable *rt, - struct sk_buff *skb, __be32 src, __be32 dst, - __u8 tos, __u8 ttl, __be16 df, __be16 src_port, - __be16 dst_port, bool xnet) +int udp_tunnel_xmit_skb(struct rtable *rt, struct sk_buff *skb, + __be32 src, __be32 dst, __u8 tos, __u8 ttl, + __be16 df, __be16 src_port, __be16 dst_port, + bool xnet, bool nocheck) { struct udphdr *uh; @@ -90,9 +90,9 @@ int udp_tunnel_xmit_skb(struct socket *sock, struct rtable *rt, uh->source = src_port; uh->len = htons(skb->len); - udp_set_csum(sock->sk->sk_no_check_tx, skb, src, dst, skb->len); + udp_set_csum(nocheck, skb, src, dst, skb->len); - return iptunnel_xmit(sock->sk, rt, skb, src, dst, IPPROTO_UDP, + return iptunnel_xmit(skb->sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet); } EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d6b4f5d08014..7dcc065e2160 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -201,6 +201,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { .disable_ipv6 = 0, .accept_dad = 1, .suppress_frag_ndisc = 1, + .accept_ra_mtu = 1, }; static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { @@ -238,6 +239,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .disable_ipv6 = 0, .accept_dad = 1, .suppress_frag_ndisc = 1, + .accept_ra_mtu = 1, }; /* Check if a valid qdisc is available */ @@ -4380,6 +4382,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; + array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu; } static inline size_t inet6_ifla6_size(void) @@ -5259,6 +5262,13 @@ static struct addrconf_sysctl_table .proc_handler = proc_dointvec, }, { + .procname = "accept_ra_mtu", + .data = &ipv6_devconf.accept_ra_mtu, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { /* sentinel */ } }, diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 9306a5ff9149..6dee2a8ca0a9 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -1676,6 +1676,7 @@ static struct rtnl_link_ops ip6gre_tap_ops __read_mostly = { .changelink = ip6gre_changelink, .get_size = ip6gre_get_size, .fill_info = ip6gre_fill_info, + .get_link_net = ip6_tnl_get_link_net, }; /* diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index 8db6c98fe218..32d9b268e7d8 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c @@ -62,14 +62,14 @@ error: } EXPORT_SYMBOL_GPL(udp_sock_create6); -int udp_tunnel6_xmit_skb(struct socket *sock, struct dst_entry *dst, - struct sk_buff *skb, struct net_device *dev, - struct in6_addr *saddr, struct in6_addr *daddr, - __u8 prio, __u8 ttl, __be16 src_port, __be16 dst_port) +int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, + struct net_device *dev, struct in6_addr *saddr, + struct in6_addr *daddr, + __u8 prio, __u8 ttl, __be16 src_port, + __be16 dst_port, bool nocheck) { struct udphdr *uh; struct ipv6hdr *ip6h; - struct sock *sk = sock->sk; __skb_push(skb, sizeof(*uh)); skb_reset_transport_header(skb); @@ -85,7 +85,7 @@ int udp_tunnel6_xmit_skb(struct socket *sock, struct dst_entry *dst, | IPSKB_REROUTED); skb_dst_set(skb, dst); - udp6_set_csum(udp_get_no_check6_tx(sk), skb, saddr, daddr, skb->len); + udp6_set_csum(nocheck, skb, saddr, daddr, skb->len); __skb_push(skb, sizeof(*ip6h)); skb_reset_network_header(skb); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 66980d8d98d1..8d766d9100cb 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -996,13 +996,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, lock_sock(sk); skb = np->pktoptions; if (skb) - atomic_inc(&skb->users); - release_sock(sk); - - if (skb) { ip6_datagram_recv_ctl(sk, &msg, skb); - kfree_skb(skb); - } else { + release_sock(sk); + if (!skb) { if (np->rxopt.bits.rxinfo) { struct in6_pktinfo src_info; src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 682866777d53..8a9d7c19e247 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1348,7 +1348,7 @@ skip_routeinfo: } } - if (ndopts.nd_opts_mtu) { + if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) { __be32 n; u32 mtu; diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 8a2d54cba9ba..3cc983bf444a 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -252,12 +252,10 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8); md.gbp = vxlan_ext_gbp(skb); - err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, - fl.saddr, tun_key->ipv4_dst, + err = vxlan_xmit_skb(rt, skb, fl.saddr, tun_key->ipv4_dst, tun_key->ipv4_tos, tun_key->ipv4_ttl, df, src_port, dst_port, - &md, - false); + &md, false, vxlan_port->exts); if (err < 0) ip_rt_put(rt); return err; diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 475e35e261ec..7a57f66e654a 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -713,6 +713,7 @@ config NET_ACT_BPF config NET_ACT_CONNMARK tristate "Netfilter Connection Mark Retriever" depends on NET_CLS_ACT && NETFILTER && IP_NF_IPTABLES + depends on NF_CONNTRACK_MARK ---help--- Say Y here to allow retrieving of conn mark |