|
@@ -1,86 +1,66 @@
|
|
#include <linux/rtnetlink.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/notifier.h>
|
|
-#include <linux/rcupdate.h>
|
|
|
|
|
|
+#include <linux/socket.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kernel.h>
|
|
#include <net/net_namespace.h>
|
|
#include <net/net_namespace.h>
|
|
|
|
+#include <net/fib_notifier.h>
|
|
#include <net/netns/ipv4.h>
|
|
#include <net/netns/ipv4.h>
|
|
#include <net/ip_fib.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)
|
|
|
|
|
|
+int call_fib4_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);
|
|
|
|
|
|
+ info->family = AF_INET;
|
|
|
|
+ return call_fib_notifier(nb, net, event_type, info);
|
|
}
|
|
}
|
|
|
|
|
|
-int call_fib_notifiers(struct net *net, enum fib_event_type event_type,
|
|
|
|
- struct fib_notifier_info *info)
|
|
|
|
|
|
+int call_fib4_notifiers(struct net *net, enum fib_event_type event_type,
|
|
|
|
+ struct fib_notifier_info *info)
|
|
{
|
|
{
|
|
|
|
+ ASSERT_RTNL();
|
|
|
|
+
|
|
|
|
+ info->family = AF_INET;
|
|
net->ipv4.fib_seq++;
|
|
net->ipv4.fib_seq++;
|
|
- info->net = net;
|
|
|
|
- return atomic_notifier_call_chain(&fib_chain, event_type, info);
|
|
|
|
|
|
+ return call_fib_notifiers(net, event_type, info);
|
|
}
|
|
}
|
|
|
|
|
|
-static unsigned int fib_seq_sum(void)
|
|
|
|
|
|
+static unsigned int fib4_seq_read(struct net *net)
|
|
{
|
|
{
|
|
- unsigned int fib_seq = 0;
|
|
|
|
- struct net *net;
|
|
|
|
|
|
+ ASSERT_RTNL();
|
|
|
|
|
|
- rtnl_lock();
|
|
|
|
- for_each_net(net)
|
|
|
|
- fib_seq += net->ipv4.fib_seq;
|
|
|
|
- rtnl_unlock();
|
|
|
|
-
|
|
|
|
- return fib_seq;
|
|
|
|
|
|
+ return net->ipv4.fib_seq;
|
|
}
|
|
}
|
|
|
|
|
|
-static bool fib_dump_is_consistent(struct notifier_block *nb,
|
|
|
|
- void (*cb)(struct notifier_block *nb),
|
|
|
|
- unsigned int fib_seq)
|
|
|
|
|
|
+static int fib4_dump(struct net *net, struct notifier_block *nb)
|
|
{
|
|
{
|
|
- 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;
|
|
|
|
|
|
+ fib_rules_notify(net, nb);
|
|
|
|
+ fib_notify(net, nb);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-#define FIB_DUMP_MAX_RETRIES 5
|
|
|
|
-int register_fib_notifier(struct notifier_block *nb,
|
|
|
|
- void (*cb)(struct notifier_block *nb))
|
|
|
|
-{
|
|
|
|
- int retries = 0;
|
|
|
|
|
|
+static const struct fib_notifier_ops fib4_notifier_ops_template = {
|
|
|
|
+ .family = AF_INET,
|
|
|
|
+ .fib_seq_read = fib4_seq_read,
|
|
|
|
+ .fib_dump = fib4_dump,
|
|
|
|
+};
|
|
|
|
|
|
- do {
|
|
|
|
- unsigned int fib_seq = fib_seq_sum();
|
|
|
|
- struct net *net;
|
|
|
|
|
|
+int __net_init fib4_notifier_init(struct net *net)
|
|
|
|
+{
|
|
|
|
+ struct fib_notifier_ops *ops;
|
|
|
|
|
|
- /* 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();
|
|
|
|
|
|
+ net->ipv4.fib_seq = 0;
|
|
|
|
|
|
- if (fib_dump_is_consistent(nb, cb, fib_seq))
|
|
|
|
- return 0;
|
|
|
|
- } while (++retries < FIB_DUMP_MAX_RETRIES);
|
|
|
|
|
|
+ ops = fib_notifier_ops_register(&fib4_notifier_ops_template, net);
|
|
|
|
+ if (IS_ERR(ops))
|
|
|
|
+ return PTR_ERR(ops);
|
|
|
|
+ net->ipv4.notifier_ops = ops;
|
|
|
|
|
|
- return -EBUSY;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
-EXPORT_SYMBOL(register_fib_notifier);
|
|
|
|
|
|
|
|
-int unregister_fib_notifier(struct notifier_block *nb)
|
|
|
|
|
|
+void __net_exit fib4_notifier_exit(struct net *net)
|
|
{
|
|
{
|
|
- return atomic_notifier_chain_unregister(&fib_chain, nb);
|
|
|
|
|
|
+ fib_notifier_ops_unregister(net->ipv4.notifier_ops);
|
|
}
|
|
}
|
|
-EXPORT_SYMBOL(unregister_fib_notifier);
|
|
|