From 665f257e04d6534e2001e3db73c0922a2968b48b Mon Sep 17 00:00:00 2001 From: Murat Sezgin Date: Wed, 10 Feb 2016 15:38:12 -0800 Subject: [PATCH 145/500] net: ipv4/ipv6: Added route table update notify chain Registered modules are notified for the changes in the route table. NOTE: This patch is originally suggested by "Jozsef Kadlecsik" in the following email chain but never merged to any of the kernel versions. http://www.spinics.net/lists/netfilter-devel/msg24239.html Cc: Jozsef Kadlecsik Patch-mainline: netfilter-devel@vger.kernel.org Change-Id: I402710474be0978867dfbbbb8d1a7f8c8f3dab06 Signed-off-by: Murat Sezgin --- include/net/ip6_route.h | 3 +++ include/net/route.h | 3 +++ net/ipv4/fib_trie.c | 19 +++++++++++++++++++ net/ipv6/route.c | 22 +++++++++++++++++++++- 4 files changed, 46 insertions(+), 1 deletion(-) --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -215,6 +215,9 @@ void rt6_multipath_rebalance(struct fib6 void rt6_uncached_list_add(struct rt6_info *rt); void rt6_uncached_list_del(struct rt6_info *rt); +int rt6_register_notifier(struct notifier_block *nb); +int rt6_unregister_notifier(struct notifier_block *nb); + static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb) { const struct dst_entry *dst = skb_dst(skb); --- a/include/net/route.h +++ b/include/net/route.h @@ -237,6 +237,9 @@ struct rtable *rt_dst_alloc(struct net_d unsigned int flags, u16 type, bool noxfrm); struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt); +int ip_rt_register_notifier(struct notifier_block *nb); +int ip_rt_unregister_notifier(struct notifier_block *nb); + struct in_ifaddr; void fib_add_ifaddr(struct in_ifaddr *); void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *); --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1211,6 +1211,9 @@ static bool fib_valid_key_len(u32 key, u static void fib_remove_alias(struct trie *t, struct key_vector *tp, struct key_vector *l, struct fib_alias *old); +/* Define route change notification chain. */ +static BLOCKING_NOTIFIER_HEAD(iproute_chain); + /* Caller must hold RTNL. */ int fib_table_insert(struct net *net, struct fib_table *tb, struct fib_config *cfg, struct netlink_ext_ack *extack) @@ -1404,6 +1407,8 @@ int fib_table_insert(struct net *net, st rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id, &cfg->fc_nlinfo, nlflags); succeeded: + blocking_notifier_call_chain(&iproute_chain, + RTM_NEWROUTE, fi); return 0; out_remove_new_fa: @@ -1776,6 +1781,8 @@ int fib_table_delete(struct net *net, st if (fa_to_delete->fa_state & FA_S_ACCESSED) rt_cache_flush(cfg->fc_nlinfo.nl_net); + blocking_notifier_call_chain(&iproute_chain, + RTM_DELROUTE, fa_to_delete->fa_info); fib_release_info(fa_to_delete->fa_info); alias_free_mem_rcu(fa_to_delete); return 0; @@ -2408,6 +2415,18 @@ void __init fib_trie_init(void) 0, SLAB_PANIC | SLAB_ACCOUNT, NULL); } +int ip_rt_register_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&iproute_chain, nb); +} +EXPORT_SYMBOL(ip_rt_register_notifier); + +int ip_rt_unregister_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&iproute_chain, nb); +} +EXPORT_SYMBOL(ip_rt_unregister_notifier); + struct fib_table *fib_trie_table(u32 id, struct fib_table *alias) { struct fib_table *tb; --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -198,6 +198,9 @@ static void rt6_uncached_list_flush_dev( } } +/* Define route change notification chain. */ +ATOMIC_NOTIFIER_HEAD(ip6route_chain); + static inline const void *choose_neigh_daddr(const struct in6_addr *p, struct sk_buff *skb, const void *daddr) @@ -3873,6 +3876,9 @@ int ip6_route_add(struct fib6_config *cf return PTR_ERR(rt); err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack); + if (!err) + atomic_notifier_call_chain(&ip6route_chain, + RTM_NEWROUTE, rt); fib6_info_release(rt); return err; @@ -3893,7 +3899,9 @@ static int __ip6_del_rt(struct fib6_info spin_lock_bh(&table->tb6_lock); err = fib6_del(rt, info); spin_unlock_bh(&table->tb6_lock); - + if (!err) + atomic_notifier_call_chain(&ip6route_chain, + RTM_DELROUTE, rt); out: fib6_info_release(rt); return err; @@ -6372,6 +6380,18 @@ static int ip6_route_dev_notify(struct n return NOTIFY_OK; } +int rt6_register_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&ip6route_chain, nb); +} +EXPORT_SYMBOL(rt6_register_notifier); + +int rt6_unregister_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&ip6route_chain, nb); +} +EXPORT_SYMBOL(rt6_unregister_notifier); + /* * /proc */