root/net/core/fib_notifier.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. call_fib_notifier
  2. call_fib_notifiers
  3. fib_seq_sum
  4. fib_net_dump
  5. fib_dump_is_consistent
  6. register_fib_notifier
  7. unregister_fib_notifier
  8. __fib_notifier_ops_register
  9. fib_notifier_ops_register
  10. fib_notifier_ops_unregister
  11. fib_notifier_net_init
  12. fib_notifier_net_exit
  13. fib_notifier_init

   1 #include <linux/rtnetlink.h>
   2 #include <linux/notifier.h>
   3 #include <linux/rcupdate.h>
   4 #include <linux/kernel.h>
   5 #include <linux/module.h>
   6 #include <linux/init.h>
   7 #include <net/net_namespace.h>
   8 #include <net/netns/generic.h>
   9 #include <net/fib_notifier.h>
  10 
  11 static unsigned int fib_notifier_net_id;
  12 
  13 struct fib_notifier_net {
  14         struct list_head fib_notifier_ops;
  15 };
  16 
  17 static ATOMIC_NOTIFIER_HEAD(fib_chain);
  18 
  19 int call_fib_notifier(struct notifier_block *nb, struct net *net,
  20                       enum fib_event_type event_type,
  21                       struct fib_notifier_info *info)
  22 {
  23         int err;
  24 
  25         info->net = net;
  26         err = nb->notifier_call(nb, event_type, info);
  27         return notifier_to_errno(err);
  28 }
  29 EXPORT_SYMBOL(call_fib_notifier);
  30 
  31 int call_fib_notifiers(struct net *net, enum fib_event_type event_type,
  32                        struct fib_notifier_info *info)
  33 {
  34         int err;
  35 
  36         info->net = net;
  37         err = atomic_notifier_call_chain(&fib_chain, event_type, info);
  38         return notifier_to_errno(err);
  39 }
  40 EXPORT_SYMBOL(call_fib_notifiers);
  41 
  42 static unsigned int fib_seq_sum(void)
  43 {
  44         struct fib_notifier_net *fn_net;
  45         struct fib_notifier_ops *ops;
  46         unsigned int fib_seq = 0;
  47         struct net *net;
  48 
  49         rtnl_lock();
  50         down_read(&net_rwsem);
  51         for_each_net(net) {
  52                 fn_net = net_generic(net, fib_notifier_net_id);
  53                 rcu_read_lock();
  54                 list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) {
  55                         if (!try_module_get(ops->owner))
  56                                 continue;
  57                         fib_seq += ops->fib_seq_read(net);
  58                         module_put(ops->owner);
  59                 }
  60                 rcu_read_unlock();
  61         }
  62         up_read(&net_rwsem);
  63         rtnl_unlock();
  64 
  65         return fib_seq;
  66 }
  67 
  68 static int fib_net_dump(struct net *net, struct notifier_block *nb)
  69 {
  70         struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id);
  71         struct fib_notifier_ops *ops;
  72 
  73         list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) {
  74                 int err;
  75 
  76                 if (!try_module_get(ops->owner))
  77                         continue;
  78                 err = ops->fib_dump(net, nb);
  79                 module_put(ops->owner);
  80                 if (err)
  81                         return err;
  82         }
  83 
  84         return 0;
  85 }
  86 
  87 static bool fib_dump_is_consistent(struct notifier_block *nb,
  88                                    void (*cb)(struct notifier_block *nb),
  89                                    unsigned int fib_seq)
  90 {
  91         atomic_notifier_chain_register(&fib_chain, nb);
  92         if (fib_seq == fib_seq_sum())
  93                 return true;
  94         atomic_notifier_chain_unregister(&fib_chain, nb);
  95         if (cb)
  96                 cb(nb);
  97         return false;
  98 }
  99 
 100 #define FIB_DUMP_MAX_RETRIES 5
 101 int register_fib_notifier(struct notifier_block *nb,
 102                           void (*cb)(struct notifier_block *nb))
 103 {
 104         int retries = 0;
 105         int err;
 106 
 107         do {
 108                 unsigned int fib_seq = fib_seq_sum();
 109                 struct net *net;
 110 
 111                 rcu_read_lock();
 112                 for_each_net_rcu(net) {
 113                         err = fib_net_dump(net, nb);
 114                         if (err)
 115                                 goto err_fib_net_dump;
 116                 }
 117                 rcu_read_unlock();
 118 
 119                 if (fib_dump_is_consistent(nb, cb, fib_seq))
 120                         return 0;
 121         } while (++retries < FIB_DUMP_MAX_RETRIES);
 122 
 123         return -EBUSY;
 124 
 125 err_fib_net_dump:
 126         rcu_read_unlock();
 127         return err;
 128 }
 129 EXPORT_SYMBOL(register_fib_notifier);
 130 
 131 int unregister_fib_notifier(struct notifier_block *nb)
 132 {
 133         return atomic_notifier_chain_unregister(&fib_chain, nb);
 134 }
 135 EXPORT_SYMBOL(unregister_fib_notifier);
 136 
 137 static int __fib_notifier_ops_register(struct fib_notifier_ops *ops,
 138                                        struct net *net)
 139 {
 140         struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id);
 141         struct fib_notifier_ops *o;
 142 
 143         list_for_each_entry(o, &fn_net->fib_notifier_ops, list)
 144                 if (ops->family == o->family)
 145                         return -EEXIST;
 146         list_add_tail_rcu(&ops->list, &fn_net->fib_notifier_ops);
 147         return 0;
 148 }
 149 
 150 struct fib_notifier_ops *
 151 fib_notifier_ops_register(const struct fib_notifier_ops *tmpl, struct net *net)
 152 {
 153         struct fib_notifier_ops *ops;
 154         int err;
 155 
 156         ops = kmemdup(tmpl, sizeof(*ops), GFP_KERNEL);
 157         if (!ops)
 158                 return ERR_PTR(-ENOMEM);
 159 
 160         err = __fib_notifier_ops_register(ops, net);
 161         if (err)
 162                 goto err_register;
 163 
 164         return ops;
 165 
 166 err_register:
 167         kfree(ops);
 168         return ERR_PTR(err);
 169 }
 170 EXPORT_SYMBOL(fib_notifier_ops_register);
 171 
 172 void fib_notifier_ops_unregister(struct fib_notifier_ops *ops)
 173 {
 174         list_del_rcu(&ops->list);
 175         kfree_rcu(ops, rcu);
 176 }
 177 EXPORT_SYMBOL(fib_notifier_ops_unregister);
 178 
 179 static int __net_init fib_notifier_net_init(struct net *net)
 180 {
 181         struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id);
 182 
 183         INIT_LIST_HEAD(&fn_net->fib_notifier_ops);
 184         return 0;
 185 }
 186 
 187 static void __net_exit fib_notifier_net_exit(struct net *net)
 188 {
 189         struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id);
 190 
 191         WARN_ON_ONCE(!list_empty(&fn_net->fib_notifier_ops));
 192 }
 193 
 194 static struct pernet_operations fib_notifier_net_ops = {
 195         .init = fib_notifier_net_init,
 196         .exit = fib_notifier_net_exit,
 197         .id = &fib_notifier_net_id,
 198         .size = sizeof(struct fib_notifier_net),
 199 };
 200 
 201 static int __init fib_notifier_init(void)
 202 {
 203         return register_pernet_subsys(&fib_notifier_net_ops);
 204 }
 205 
 206 subsys_initcall(fib_notifier_init);

/* [<][>][^][v][top][bottom][index][help] */