root/drivers/net/netdevsim/fib.c

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

DEFINITIONS

This source file includes following definitions.
  1. nsim_fib_get_val
  2. nsim_fib_set_max
  3. nsim_fib_rule_account
  4. nsim_fib_rule_event
  5. nsim_fib_account
  6. nsim_fib_event
  7. nsim_fib_event_nb
  8. nsim_fib_dump_inconsistent
  9. nsim_fib_netns_init
  10. nsim_fib_exit
  11. nsim_fib_init

   1 /*
   2  * Copyright (c) 2018 Cumulus Networks. All rights reserved.
   3  * Copyright (c) 2018 David Ahern <dsa@cumulusnetworks.com>
   4  *
   5  * This software is licensed under the GNU General License Version 2,
   6  * June 1991 as shown in the file COPYING in the top-level directory of this
   7  * source tree.
   8  *
   9  * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
  10  * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  11  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  12  * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
  13  * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
  14  * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  15  */
  16 
  17 #include <net/fib_notifier.h>
  18 #include <net/ip_fib.h>
  19 #include <net/ip6_fib.h>
  20 #include <net/fib_rules.h>
  21 #include <net/netns/generic.h>
  22 
  23 #include "netdevsim.h"
  24 
  25 struct nsim_fib_entry {
  26         u64 max;
  27         u64 num;
  28 };
  29 
  30 struct nsim_per_fib_data {
  31         struct nsim_fib_entry fib;
  32         struct nsim_fib_entry rules;
  33 };
  34 
  35 struct nsim_fib_data {
  36         struct nsim_per_fib_data ipv4;
  37         struct nsim_per_fib_data ipv6;
  38 };
  39 
  40 static unsigned int nsim_fib_net_id;
  41 
  42 u64 nsim_fib_get_val(struct net *net, enum nsim_resource_id res_id, bool max)
  43 {
  44         struct nsim_fib_data *fib_data = net_generic(net, nsim_fib_net_id);
  45         struct nsim_fib_entry *entry;
  46 
  47         switch (res_id) {
  48         case NSIM_RESOURCE_IPV4_FIB:
  49                 entry = &fib_data->ipv4.fib;
  50                 break;
  51         case NSIM_RESOURCE_IPV4_FIB_RULES:
  52                 entry = &fib_data->ipv4.rules;
  53                 break;
  54         case NSIM_RESOURCE_IPV6_FIB:
  55                 entry = &fib_data->ipv6.fib;
  56                 break;
  57         case NSIM_RESOURCE_IPV6_FIB_RULES:
  58                 entry = &fib_data->ipv6.rules;
  59                 break;
  60         default:
  61                 return 0;
  62         }
  63 
  64         return max ? entry->max : entry->num;
  65 }
  66 
  67 int nsim_fib_set_max(struct net *net, enum nsim_resource_id res_id, u64 val,
  68                      struct netlink_ext_ack *extack)
  69 {
  70         struct nsim_fib_data *fib_data = net_generic(net, nsim_fib_net_id);
  71         struct nsim_fib_entry *entry;
  72         int err = 0;
  73 
  74         switch (res_id) {
  75         case NSIM_RESOURCE_IPV4_FIB:
  76                 entry = &fib_data->ipv4.fib;
  77                 break;
  78         case NSIM_RESOURCE_IPV4_FIB_RULES:
  79                 entry = &fib_data->ipv4.rules;
  80                 break;
  81         case NSIM_RESOURCE_IPV6_FIB:
  82                 entry = &fib_data->ipv6.fib;
  83                 break;
  84         case NSIM_RESOURCE_IPV6_FIB_RULES:
  85                 entry = &fib_data->ipv6.rules;
  86                 break;
  87         default:
  88                 return 0;
  89         }
  90 
  91         /* not allowing a new max to be less than curren occupancy
  92          * --> no means of evicting entries
  93          */
  94         if (val < entry->num) {
  95                 NL_SET_ERR_MSG_MOD(extack, "New size is less than current occupancy");
  96                 err = -EINVAL;
  97         } else {
  98                 entry->max = val;
  99         }
 100 
 101         return err;
 102 }
 103 
 104 static int nsim_fib_rule_account(struct nsim_fib_entry *entry, bool add,
 105                                  struct netlink_ext_ack *extack)
 106 {
 107         int err = 0;
 108 
 109         if (add) {
 110                 if (entry->num < entry->max) {
 111                         entry->num++;
 112                 } else {
 113                         err = -ENOSPC;
 114                         NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported fib rule entries");
 115                 }
 116         } else {
 117                 entry->num--;
 118         }
 119 
 120         return err;
 121 }
 122 
 123 static int nsim_fib_rule_event(struct fib_notifier_info *info, bool add)
 124 {
 125         struct nsim_fib_data *data = net_generic(info->net, nsim_fib_net_id);
 126         struct netlink_ext_ack *extack = info->extack;
 127         int err = 0;
 128 
 129         switch (info->family) {
 130         case AF_INET:
 131                 err = nsim_fib_rule_account(&data->ipv4.rules, add, extack);
 132                 break;
 133         case AF_INET6:
 134                 err = nsim_fib_rule_account(&data->ipv6.rules, add, extack);
 135                 break;
 136         }
 137 
 138         return err;
 139 }
 140 
 141 static int nsim_fib_account(struct nsim_fib_entry *entry, bool add,
 142                             struct netlink_ext_ack *extack)
 143 {
 144         int err = 0;
 145 
 146         if (add) {
 147                 if (entry->num < entry->max) {
 148                         entry->num++;
 149                 } else {
 150                         err = -ENOSPC;
 151                         NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported fib entries");
 152                 }
 153         } else {
 154                 entry->num--;
 155         }
 156 
 157         return err;
 158 }
 159 
 160 static int nsim_fib_event(struct fib_notifier_info *info, bool add)
 161 {
 162         struct nsim_fib_data *data = net_generic(info->net, nsim_fib_net_id);
 163         struct netlink_ext_ack *extack = info->extack;
 164         int err = 0;
 165 
 166         switch (info->family) {
 167         case AF_INET:
 168                 err = nsim_fib_account(&data->ipv4.fib, add, extack);
 169                 break;
 170         case AF_INET6:
 171                 err = nsim_fib_account(&data->ipv6.fib, add, extack);
 172                 break;
 173         }
 174 
 175         return err;
 176 }
 177 
 178 static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event,
 179                              void *ptr)
 180 {
 181         struct fib_notifier_info *info = ptr;
 182         int err = 0;
 183 
 184         switch (event) {
 185         case FIB_EVENT_RULE_ADD: /* fall through */
 186         case FIB_EVENT_RULE_DEL:
 187                 err = nsim_fib_rule_event(info, event == FIB_EVENT_RULE_ADD);
 188                 break;
 189 
 190         case FIB_EVENT_ENTRY_ADD:  /* fall through */
 191         case FIB_EVENT_ENTRY_DEL:
 192                 err = nsim_fib_event(info, event == FIB_EVENT_ENTRY_ADD);
 193                 break;
 194         }
 195 
 196         return notifier_from_errno(err);
 197 }
 198 
 199 /* inconsistent dump, trying again */
 200 static void nsim_fib_dump_inconsistent(struct notifier_block *nb)
 201 {
 202         struct nsim_fib_data *data;
 203         struct net *net;
 204 
 205         rcu_read_lock();
 206         for_each_net_rcu(net) {
 207                 data = net_generic(net, nsim_fib_net_id);
 208 
 209                 data->ipv4.fib.num = 0ULL;
 210                 data->ipv4.rules.num = 0ULL;
 211 
 212                 data->ipv6.fib.num = 0ULL;
 213                 data->ipv6.rules.num = 0ULL;
 214         }
 215         rcu_read_unlock();
 216 }
 217 
 218 static struct notifier_block nsim_fib_nb = {
 219         .notifier_call = nsim_fib_event_nb,
 220 };
 221 
 222 /* Initialize per network namespace state */
 223 static int __net_init nsim_fib_netns_init(struct net *net)
 224 {
 225         struct nsim_fib_data *data = net_generic(net, nsim_fib_net_id);
 226 
 227         data->ipv4.fib.max = (u64)-1;
 228         data->ipv4.rules.max = (u64)-1;
 229 
 230         data->ipv6.fib.max = (u64)-1;
 231         data->ipv6.rules.max = (u64)-1;
 232 
 233         return 0;
 234 }
 235 
 236 static struct pernet_operations nsim_fib_net_ops = {
 237         .init = nsim_fib_netns_init,
 238         .id   = &nsim_fib_net_id,
 239         .size = sizeof(struct nsim_fib_data),
 240 };
 241 
 242 void nsim_fib_exit(void)
 243 {
 244         unregister_fib_notifier(&nsim_fib_nb);
 245         unregister_pernet_subsys(&nsim_fib_net_ops);
 246 }
 247 
 248 int nsim_fib_init(void)
 249 {
 250         int err;
 251 
 252         err = register_pernet_subsys(&nsim_fib_net_ops);
 253         if (err < 0) {
 254                 pr_err("Failed to register pernet subsystem\n");
 255                 goto err_out;
 256         }
 257 
 258         err = register_fib_notifier(&nsim_fib_nb, nsim_fib_dump_inconsistent);
 259         if (err < 0) {
 260                 pr_err("Failed to register fib notifier\n");
 261                 unregister_pernet_subsys(&nsim_fib_net_ops);
 262                 goto err_out;
 263         }
 264 
 265 err_out:
 266         return err;
 267 }

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