This source file includes following definitions.
- nsim_fib_get_val
- nsim_fib_set_max
- nsim_fib_rule_account
- nsim_fib_rule_event
- nsim_fib_account
- nsim_fib_event
- nsim_fib_event_nb
- nsim_fib_dump_inconsistent
- nsim_fib_netns_init
- nsim_fib_exit
- nsim_fib_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
92
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:
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:
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
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
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 }