fib.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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. #include <net/fib_notifier.h>
  17. #include <net/ip_fib.h>
  18. #include <net/ip6_fib.h>
  19. #include <net/fib_rules.h>
  20. #include <net/netns/generic.h>
  21. #include "netdevsim.h"
  22. struct nsim_fib_entry {
  23. u64 max;
  24. u64 num;
  25. };
  26. struct nsim_per_fib_data {
  27. struct nsim_fib_entry fib;
  28. struct nsim_fib_entry rules;
  29. };
  30. struct nsim_fib_data {
  31. struct nsim_per_fib_data ipv4;
  32. struct nsim_per_fib_data ipv6;
  33. };
  34. static unsigned int nsim_fib_net_id;
  35. u64 nsim_fib_get_val(struct net *net, enum nsim_resource_id res_id, bool max)
  36. {
  37. struct nsim_fib_data *fib_data = net_generic(net, nsim_fib_net_id);
  38. struct nsim_fib_entry *entry;
  39. switch (res_id) {
  40. case NSIM_RESOURCE_IPV4_FIB:
  41. entry = &fib_data->ipv4.fib;
  42. break;
  43. case NSIM_RESOURCE_IPV4_FIB_RULES:
  44. entry = &fib_data->ipv4.rules;
  45. break;
  46. case NSIM_RESOURCE_IPV6_FIB:
  47. entry = &fib_data->ipv6.fib;
  48. break;
  49. case NSIM_RESOURCE_IPV6_FIB_RULES:
  50. entry = &fib_data->ipv6.rules;
  51. break;
  52. default:
  53. return 0;
  54. }
  55. return max ? entry->max : entry->num;
  56. }
  57. int nsim_fib_set_max(struct net *net, enum nsim_resource_id res_id, u64 val)
  58. {
  59. struct nsim_fib_data *fib_data = net_generic(net, nsim_fib_net_id);
  60. struct nsim_fib_entry *entry;
  61. int err = 0;
  62. switch (res_id) {
  63. case NSIM_RESOURCE_IPV4_FIB:
  64. entry = &fib_data->ipv4.fib;
  65. break;
  66. case NSIM_RESOURCE_IPV4_FIB_RULES:
  67. entry = &fib_data->ipv4.rules;
  68. break;
  69. case NSIM_RESOURCE_IPV6_FIB:
  70. entry = &fib_data->ipv6.fib;
  71. break;
  72. case NSIM_RESOURCE_IPV6_FIB_RULES:
  73. entry = &fib_data->ipv6.rules;
  74. break;
  75. default:
  76. return 0;
  77. }
  78. /* not allowing a new max to be less than curren occupancy
  79. * --> no means of evicting entries
  80. */
  81. if (val < entry->num)
  82. err = -EINVAL;
  83. else
  84. entry->max = val;
  85. return err;
  86. }
  87. static int nsim_fib_rule_account(struct nsim_fib_entry *entry, bool add,
  88. struct netlink_ext_ack *extack)
  89. {
  90. int err = 0;
  91. if (add) {
  92. if (entry->num < entry->max) {
  93. entry->num++;
  94. } else {
  95. err = -ENOSPC;
  96. NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported fib rule entries");
  97. }
  98. } else {
  99. entry->num--;
  100. }
  101. return err;
  102. }
  103. static int nsim_fib_rule_event(struct fib_notifier_info *info, bool add)
  104. {
  105. struct nsim_fib_data *data = net_generic(info->net, nsim_fib_net_id);
  106. struct netlink_ext_ack *extack = info->extack;
  107. int err = 0;
  108. switch (info->family) {
  109. case AF_INET:
  110. err = nsim_fib_rule_account(&data->ipv4.rules, add, extack);
  111. break;
  112. case AF_INET6:
  113. err = nsim_fib_rule_account(&data->ipv6.rules, add, extack);
  114. break;
  115. }
  116. return err;
  117. }
  118. static int nsim_fib_account(struct nsim_fib_entry *entry, bool add,
  119. struct netlink_ext_ack *extack)
  120. {
  121. int err = 0;
  122. if (add) {
  123. if (entry->num < entry->max) {
  124. entry->num++;
  125. } else {
  126. err = -ENOSPC;
  127. NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported fib entries");
  128. }
  129. } else {
  130. entry->num--;
  131. }
  132. return err;
  133. }
  134. static int nsim_fib_event(struct fib_notifier_info *info, bool add)
  135. {
  136. struct nsim_fib_data *data = net_generic(info->net, nsim_fib_net_id);
  137. struct netlink_ext_ack *extack = info->extack;
  138. int err = 0;
  139. switch (info->family) {
  140. case AF_INET:
  141. err = nsim_fib_account(&data->ipv4.fib, add, extack);
  142. break;
  143. case AF_INET6:
  144. err = nsim_fib_account(&data->ipv6.fib, add, extack);
  145. break;
  146. }
  147. return err;
  148. }
  149. static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event,
  150. void *ptr)
  151. {
  152. struct fib_notifier_info *info = ptr;
  153. int err = 0;
  154. switch (event) {
  155. case FIB_EVENT_RULE_ADD: /* fall through */
  156. case FIB_EVENT_RULE_DEL:
  157. err = nsim_fib_rule_event(info, event == FIB_EVENT_RULE_ADD);
  158. break;
  159. case FIB_EVENT_ENTRY_ADD: /* fall through */
  160. case FIB_EVENT_ENTRY_DEL:
  161. err = nsim_fib_event(info, event == FIB_EVENT_ENTRY_ADD);
  162. break;
  163. }
  164. return notifier_from_errno(err);
  165. }
  166. /* inconsistent dump, trying again */
  167. static void nsim_fib_dump_inconsistent(struct notifier_block *nb)
  168. {
  169. struct nsim_fib_data *data;
  170. struct net *net;
  171. rcu_read_lock();
  172. for_each_net_rcu(net) {
  173. data = net_generic(net, nsim_fib_net_id);
  174. data->ipv4.fib.num = 0ULL;
  175. data->ipv4.rules.num = 0ULL;
  176. data->ipv6.fib.num = 0ULL;
  177. data->ipv6.rules.num = 0ULL;
  178. }
  179. rcu_read_unlock();
  180. }
  181. static struct notifier_block nsim_fib_nb = {
  182. .notifier_call = nsim_fib_event_nb,
  183. };
  184. /* Initialize per network namespace state */
  185. static int __net_init nsim_fib_netns_init(struct net *net)
  186. {
  187. struct nsim_fib_data *data = net_generic(net, nsim_fib_net_id);
  188. data->ipv4.fib.max = (u64)-1;
  189. data->ipv4.rules.max = (u64)-1;
  190. data->ipv6.fib.max = (u64)-1;
  191. data->ipv6.rules.max = (u64)-1;
  192. return 0;
  193. }
  194. static struct pernet_operations nsim_fib_net_ops __net_initdata = {
  195. .init = nsim_fib_netns_init,
  196. .id = &nsim_fib_net_id,
  197. .size = sizeof(struct nsim_fib_data),
  198. };
  199. void nsim_fib_exit(void)
  200. {
  201. unregister_pernet_subsys(&nsim_fib_net_ops);
  202. unregister_fib_notifier(&nsim_fib_nb);
  203. }
  204. int nsim_fib_init(void)
  205. {
  206. int err;
  207. err = register_pernet_subsys(&nsim_fib_net_ops);
  208. if (err < 0) {
  209. pr_err("Failed to register pernet subsystem\n");
  210. goto err_out;
  211. }
  212. err = register_fib_notifier(&nsim_fib_nb, nsim_fib_dump_inconsistent);
  213. if (err < 0) {
  214. pr_err("Failed to register fib notifier\n");
  215. goto err_out;
  216. }
  217. err_out:
  218. return err;
  219. }