Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'ipv6-next'

Hannes Frederic Sowa says:

====================
ipv6: cleanup after rt6_genid removal

Leftover patches after rt6_genid removal after 705f1c869d577c ("ipv6:
remove rt6i_genid").

Major two changes are:
* keep fib6_sernum per namespace to reduce number of flushes in case
system has high number of namespaces
* make fn_sernum updates cheaper

v2: Incorporated feedback from Cong Wang, thanks a lot!
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+91 -75
+15 -5
include/net/ip6_fib.h
··· 64 64 65 65 __u16 fn_bit; /* bit key */ 66 66 __u16 fn_flags; 67 - __u32 fn_sernum; 67 + int fn_sernum; 68 68 struct rt6_info *rr_ptr; 69 69 }; 70 70 ··· 202 202 dst_release(&rt->dst); 203 203 } 204 204 205 - struct fib6_walker_t { 205 + enum fib6_walk_state { 206 + #ifdef CONFIG_IPV6_SUBTREES 207 + FWS_S, 208 + #endif 209 + FWS_L, 210 + FWS_R, 211 + FWS_C, 212 + FWS_U 213 + }; 214 + 215 + struct fib6_walker { 206 216 struct list_head lh; 207 217 struct fib6_node *root, *node; 208 218 struct rt6_info *leaf; 209 - unsigned char state; 210 - unsigned char prune; 219 + enum fib6_walk_state state; 220 + bool prune; 211 221 unsigned int skip; 212 222 unsigned int count; 213 - int (*func)(struct fib6_walker_t *); 223 + int (*func)(struct fib6_walker *); 214 224 void *args; 215 225 }; 216 226
+1 -1
include/net/netns/ipv6.h
··· 76 76 #endif 77 77 #endif 78 78 atomic_t dev_addr_genid; 79 - atomic_t rt_genid; 79 + atomic_t fib6_sernum; 80 80 }; 81 81 82 82 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
+1 -1
net/ipv6/af_inet6.c
··· 766 766 net->ipv6.sysctl.icmpv6_time = 1*HZ; 767 767 net->ipv6.sysctl.flowlabel_consistency = 1; 768 768 net->ipv6.sysctl.auto_flowlabels = 0; 769 - atomic_set(&net->ipv6.rt_genid, 0); 769 + atomic_set(&net->ipv6.fib6_sernum, 1); 770 770 771 771 err = ipv6_init_mibs(net); 772 772 if (err)
+74 -68
net/ipv6/ip6_fib.c
··· 46 46 47 47 static struct kmem_cache *fib6_node_kmem __read_mostly; 48 48 49 - enum fib_walk_state_t { 50 - #ifdef CONFIG_IPV6_SUBTREES 51 - FWS_S, 52 - #endif 53 - FWS_L, 54 - FWS_R, 55 - FWS_C, 56 - FWS_U 57 - }; 58 - 59 - struct fib6_cleaner_t { 60 - struct fib6_walker_t w; 49 + struct fib6_cleaner { 50 + struct fib6_walker w; 61 51 struct net *net; 62 52 int (*func)(struct rt6_info *, void *arg); 53 + int sernum; 63 54 void *arg; 64 55 }; 65 56 ··· 65 74 static void fib6_prune_clones(struct net *net, struct fib6_node *fn); 66 75 static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn); 67 76 static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn); 68 - static int fib6_walk(struct fib6_walker_t *w); 69 - static int fib6_walk_continue(struct fib6_walker_t *w); 77 + static int fib6_walk(struct fib6_walker *w); 78 + static int fib6_walk_continue(struct fib6_walker *w); 70 79 71 80 /* 72 81 * A routing update causes an increase of the serial number on the ··· 75 84 * result of redirects, path MTU changes, etc. 76 85 */ 77 86 78 - static __u32 rt_sernum; 79 - 80 87 static void fib6_gc_timer_cb(unsigned long arg); 81 88 82 89 static LIST_HEAD(fib6_walkers); 83 90 #define FOR_WALKERS(w) list_for_each_entry(w, &fib6_walkers, lh) 84 91 85 - static inline void fib6_walker_link(struct fib6_walker_t *w) 92 + static void fib6_walker_link(struct fib6_walker *w) 86 93 { 87 94 write_lock_bh(&fib6_walker_lock); 88 95 list_add(&w->lh, &fib6_walkers); 89 96 write_unlock_bh(&fib6_walker_lock); 90 97 } 91 98 92 - static inline void fib6_walker_unlink(struct fib6_walker_t *w) 99 + static void fib6_walker_unlink(struct fib6_walker *w) 93 100 { 94 101 write_lock_bh(&fib6_walker_lock); 95 102 list_del(&w->lh); 96 103 write_unlock_bh(&fib6_walker_lock); 97 104 } 98 - static __inline__ u32 fib6_new_sernum(void) 105 + 106 + static int fib6_new_sernum(struct net *net) 99 107 { 100 - u32 n = ++rt_sernum; 101 - if ((__s32)n <= 0) 102 - rt_sernum = n = 1; 103 - return n; 108 + int new, old; 109 + 110 + do { 111 + old = atomic_read(&net->ipv6.fib6_sernum); 112 + new = old < INT_MAX ? old + 1 : 1; 113 + } while (atomic_cmpxchg(&net->ipv6.fib6_sernum, 114 + old, new) != old); 115 + return new; 104 116 } 117 + 118 + enum { 119 + FIB6_NO_SERNUM_CHANGE = 0, 120 + }; 105 121 106 122 /* 107 123 * Auxiliary address test functions for the radix tree. ··· 126 128 # define BITOP_BE32_SWIZZLE 0 127 129 #endif 128 130 129 - static __inline__ __be32 addr_bit_set(const void *token, int fn_bit) 131 + static __be32 addr_bit_set(const void *token, int fn_bit) 130 132 { 131 133 const __be32 *addr = token; 132 134 /* ··· 140 142 addr[fn_bit >> 5]; 141 143 } 142 144 143 - static __inline__ struct fib6_node *node_alloc(void) 145 + static struct fib6_node *node_alloc(void) 144 146 { 145 147 struct fib6_node *fn; 146 148 ··· 149 151 return fn; 150 152 } 151 153 152 - static __inline__ void node_free(struct fib6_node *fn) 154 + static void node_free(struct fib6_node *fn) 153 155 { 154 156 kmem_cache_free(fib6_node_kmem, fn); 155 157 } 156 158 157 - static __inline__ void rt6_release(struct rt6_info *rt) 159 + static void rt6_release(struct rt6_info *rt) 158 160 { 159 161 if (atomic_dec_and_test(&rt->rt6i_ref)) 160 162 dst_free(&rt->dst); ··· 265 267 266 268 #endif 267 269 268 - static int fib6_dump_node(struct fib6_walker_t *w) 270 + static int fib6_dump_node(struct fib6_walker *w) 269 271 { 270 272 int res; 271 273 struct rt6_info *rt; ··· 285 287 286 288 static void fib6_dump_end(struct netlink_callback *cb) 287 289 { 288 - struct fib6_walker_t *w = (void *)cb->args[2]; 290 + struct fib6_walker *w = (void *)cb->args[2]; 289 291 290 292 if (w) { 291 293 if (cb->args[4]) { ··· 308 310 static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, 309 311 struct netlink_callback *cb) 310 312 { 311 - struct fib6_walker_t *w; 313 + struct fib6_walker *w; 312 314 int res; 313 315 314 316 w = (void *)cb->args[2]; ··· 353 355 unsigned int h, s_h; 354 356 unsigned int e = 0, s_e; 355 357 struct rt6_rtnl_dump_arg arg; 356 - struct fib6_walker_t *w; 358 + struct fib6_walker *w; 357 359 struct fib6_table *tb; 358 360 struct hlist_head *head; 359 361 int res = 0; ··· 421 423 static struct fib6_node *fib6_add_1(struct fib6_node *root, 422 424 struct in6_addr *addr, int plen, 423 425 int offset, int allow_create, 424 - int replace_required) 426 + int replace_required, int sernum) 425 427 { 426 428 struct fib6_node *fn, *in, *ln; 427 429 struct fib6_node *pn = NULL; 428 430 struct rt6key *key; 429 431 int bit; 430 432 __be32 dir = 0; 431 - __u32 sernum = fib6_new_sernum(); 432 433 433 434 RT6_TRACE("fib6_add_1\n"); 434 435 ··· 624 627 return ln; 625 628 } 626 629 627 - static inline bool rt6_qualify_for_ecmp(struct rt6_info *rt) 630 + static bool rt6_qualify_for_ecmp(struct rt6_info *rt) 628 631 { 629 632 return (rt->rt6i_flags & (RTF_GATEWAY|RTF_ADDRCONF|RTF_DYNAMIC)) == 630 633 RTF_GATEWAY; ··· 817 820 return 0; 818 821 } 819 822 820 - static __inline__ void fib6_start_gc(struct net *net, struct rt6_info *rt) 823 + static void fib6_start_gc(struct net *net, struct rt6_info *rt) 821 824 { 822 825 if (!timer_pending(&net->ipv6.ip6_fib_timer) && 823 826 (rt->rt6i_flags & (RTF_EXPIRES | RTF_CACHE))) ··· 845 848 int err = -ENOMEM; 846 849 int allow_create = 1; 847 850 int replace_required = 0; 851 + int sernum = fib6_new_sernum(info->nl_net); 848 852 849 853 if (info->nlh) { 850 854 if (!(info->nlh->nlmsg_flags & NLM_F_CREATE)) ··· 858 860 859 861 fn = fib6_add_1(root, &rt->rt6i_dst.addr, rt->rt6i_dst.plen, 860 862 offsetof(struct rt6_info, rt6i_dst), allow_create, 861 - replace_required); 863 + replace_required, sernum); 862 864 if (IS_ERR(fn)) { 863 865 err = PTR_ERR(fn); 864 866 fn = NULL; ··· 892 894 sfn->leaf = info->nl_net->ipv6.ip6_null_entry; 893 895 atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref); 894 896 sfn->fn_flags = RTN_ROOT; 895 - sfn->fn_sernum = fib6_new_sernum(); 897 + sfn->fn_sernum = sernum; 896 898 897 899 /* Now add the first leaf node to new subtree */ 898 900 899 901 sn = fib6_add_1(sfn, &rt->rt6i_src.addr, 900 902 rt->rt6i_src.plen, 901 903 offsetof(struct rt6_info, rt6i_src), 902 - allow_create, replace_required); 904 + allow_create, replace_required, sernum); 903 905 904 906 if (IS_ERR(sn)) { 905 907 /* If it is failed, discard just allocated ··· 918 920 sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, 919 921 rt->rt6i_src.plen, 920 922 offsetof(struct rt6_info, rt6i_src), 921 - allow_create, replace_required); 923 + allow_create, replace_required, sernum); 922 924 923 925 if (IS_ERR(sn)) { 924 926 err = PTR_ERR(sn); ··· 1172 1174 int children; 1173 1175 int nstate; 1174 1176 struct fib6_node *child, *pn; 1175 - struct fib6_walker_t *w; 1177 + struct fib6_walker *w; 1176 1178 int iter = 0; 1177 1179 1178 1180 for (;;) { ··· 1274 1276 static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, 1275 1277 struct nl_info *info) 1276 1278 { 1277 - struct fib6_walker_t *w; 1279 + struct fib6_walker *w; 1278 1280 struct rt6_info *rt = *rtp; 1279 1281 struct net *net = info->nl_net; 1280 1282 ··· 1412 1414 * <0 -> walk is terminated by an error. 1413 1415 */ 1414 1416 1415 - static int fib6_walk_continue(struct fib6_walker_t *w) 1417 + static int fib6_walk_continue(struct fib6_walker *w) 1416 1418 { 1417 1419 struct fib6_node *fn, *pn; 1418 1420 ··· 1496 1498 } 1497 1499 } 1498 1500 1499 - static int fib6_walk(struct fib6_walker_t *w) 1501 + static int fib6_walk(struct fib6_walker *w) 1500 1502 { 1501 1503 int res; 1502 1504 ··· 1510 1512 return res; 1511 1513 } 1512 1514 1513 - static int fib6_clean_node(struct fib6_walker_t *w) 1515 + static int fib6_clean_node(struct fib6_walker *w) 1514 1516 { 1515 1517 int res; 1516 1518 struct rt6_info *rt; 1517 - struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w); 1519 + struct fib6_cleaner *c = container_of(w, struct fib6_cleaner, w); 1518 1520 struct nl_info info = { 1519 1521 .nl_net = c->net, 1520 1522 }; 1523 + 1524 + if (c->sernum != FIB6_NO_SERNUM_CHANGE && 1525 + w->node->fn_sernum != c->sernum) 1526 + w->node->fn_sernum = c->sernum; 1527 + 1528 + if (!c->func) { 1529 + WARN_ON_ONCE(c->sernum == FIB6_NO_SERNUM_CHANGE); 1530 + w->leaf = NULL; 1531 + return 0; 1532 + } 1521 1533 1522 1534 for (rt = w->leaf; rt; rt = rt->dst.rt6_next) { 1523 1535 res = c->func(rt, c->arg); ··· 1562 1554 1563 1555 static void fib6_clean_tree(struct net *net, struct fib6_node *root, 1564 1556 int (*func)(struct rt6_info *, void *arg), 1565 - int prune, void *arg) 1557 + bool prune, int sernum, void *arg) 1566 1558 { 1567 - struct fib6_cleaner_t c; 1559 + struct fib6_cleaner c; 1568 1560 1569 1561 c.w.root = root; 1570 1562 c.w.func = fib6_clean_node; ··· 1572 1564 c.w.count = 0; 1573 1565 c.w.skip = 0; 1574 1566 c.func = func; 1567 + c.sernum = sernum; 1575 1568 c.arg = arg; 1576 1569 c.net = net; 1577 1570 1578 1571 fib6_walk(&c.w); 1579 1572 } 1580 1573 1581 - void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), 1582 - void *arg) 1574 + static void __fib6_clean_all(struct net *net, 1575 + int (*func)(struct rt6_info *, void *), 1576 + int sernum, void *arg) 1583 1577 { 1584 1578 struct fib6_table *table; 1585 1579 struct hlist_head *head; ··· 1593 1583 hlist_for_each_entry_rcu(table, head, tb6_hlist) { 1594 1584 write_lock_bh(&table->tb6_lock); 1595 1585 fib6_clean_tree(net, &table->tb6_root, 1596 - func, 0, arg); 1586 + func, false, sernum, arg); 1597 1587 write_unlock_bh(&table->tb6_lock); 1598 1588 } 1599 1589 } 1600 1590 rcu_read_unlock(); 1591 + } 1592 + 1593 + void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *), 1594 + void *arg) 1595 + { 1596 + __fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg); 1601 1597 } 1602 1598 1603 1599 static int fib6_prune_clone(struct rt6_info *rt, void *arg) ··· 1618 1602 1619 1603 static void fib6_prune_clones(struct net *net, struct fib6_node *fn) 1620 1604 { 1621 - fib6_clean_tree(net, fn, fib6_prune_clone, 1, NULL); 1622 - } 1623 - 1624 - static int fib6_update_sernum(struct rt6_info *rt, void *arg) 1625 - { 1626 - __u32 sernum = *(__u32 *)arg; 1627 - 1628 - if (rt->rt6i_node && 1629 - rt->rt6i_node->fn_sernum != sernum) 1630 - rt->rt6i_node->fn_sernum = sernum; 1631 - 1632 - return 0; 1605 + fib6_clean_tree(net, fn, fib6_prune_clone, true, 1606 + FIB6_NO_SERNUM_CHANGE, NULL); 1633 1607 } 1634 1608 1635 1609 static void fib6_flush_trees(struct net *net) 1636 1610 { 1637 - __u32 new_sernum = fib6_new_sernum(); 1611 + int new_sernum = fib6_new_sernum(net); 1638 1612 1639 - fib6_clean_all(net, fib6_update_sernum, &new_sernum); 1613 + __fib6_clean_all(net, NULL, new_sernum, NULL); 1640 1614 } 1641 1615 1642 1616 /* ··· 1834 1828 1835 1829 struct ipv6_route_iter { 1836 1830 struct seq_net_private p; 1837 - struct fib6_walker_t w; 1831 + struct fib6_walker w; 1838 1832 loff_t skip; 1839 1833 struct fib6_table *tbl; 1840 - __u32 sernum; 1834 + int sernum; 1841 1835 }; 1842 1836 1843 1837 static int ipv6_route_seq_show(struct seq_file *seq, void *v) ··· 1865 1859 return 0; 1866 1860 } 1867 1861 1868 - static int ipv6_route_yield(struct fib6_walker_t *w) 1862 + static int ipv6_route_yield(struct fib6_walker *w) 1869 1863 { 1870 1864 struct ipv6_route_iter *iter = w->args; 1871 1865 ··· 1986 1980 1987 1981 static bool ipv6_route_iter_active(struct ipv6_route_iter *iter) 1988 1982 { 1989 - struct fib6_walker_t *w = &iter->w; 1983 + struct fib6_walker *w = &iter->w; 1990 1984 return w->node && !(w->state == FWS_U && w->node == w->root); 1991 1985 } 1992 1986