1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- #include <linux/rtnetlink.h>
- #include <linux/notifier.h>
- #include <linux/rcupdate.h>
- #include <linux/kernel.h>
- #include <net/net_namespace.h>
- #include <net/netns/ipv4.h>
- #include <net/ip_fib.h>
- static ATOMIC_NOTIFIER_HEAD(fib_chain);
- int call_fib_notifier(struct notifier_block *nb, struct net *net,
- enum fib_event_type event_type,
- struct fib_notifier_info *info)
- {
- info->net = net;
- return nb->notifier_call(nb, event_type, info);
- }
- int call_fib_notifiers(struct net *net, enum fib_event_type event_type,
- struct fib_notifier_info *info)
- {
- net->ipv4.fib_seq++;
- info->net = net;
- return atomic_notifier_call_chain(&fib_chain, event_type, info);
- }
- static unsigned int fib_seq_sum(void)
- {
- unsigned int fib_seq = 0;
- struct net *net;
- rtnl_lock();
- for_each_net(net)
- fib_seq += net->ipv4.fib_seq;
- rtnl_unlock();
- return fib_seq;
- }
- static bool fib_dump_is_consistent(struct notifier_block *nb,
- void (*cb)(struct notifier_block *nb),
- unsigned int fib_seq)
- {
- atomic_notifier_chain_register(&fib_chain, nb);
- if (fib_seq == fib_seq_sum())
- return true;
- atomic_notifier_chain_unregister(&fib_chain, nb);
- if (cb)
- cb(nb);
- return false;
- }
- #define FIB_DUMP_MAX_RETRIES 5
- int register_fib_notifier(struct notifier_block *nb,
- void (*cb)(struct notifier_block *nb))
- {
- int retries = 0;
- do {
- unsigned int fib_seq = fib_seq_sum();
- struct net *net;
- /* Mutex semantics guarantee that every change done to
- * FIB tries before we read the change sequence counter
- * is now visible to us.
- */
- rcu_read_lock();
- for_each_net_rcu(net) {
- fib_rules_notify(net, nb);
- fib_notify(net, nb);
- }
- rcu_read_unlock();
- if (fib_dump_is_consistent(nb, cb, fib_seq))
- return 0;
- } while (++retries < FIB_DUMP_MAX_RETRIES);
- return -EBUSY;
- }
- EXPORT_SYMBOL(register_fib_notifier);
- int unregister_fib_notifier(struct notifier_block *nb)
- {
- return atomic_notifier_chain_unregister(&fib_chain, nb);
- }
- EXPORT_SYMBOL(unregister_fib_notifier);
|