2 * Copyright (c) 2018 Cumulus Networks. All rights reserved.
3 * Copyright (c) 2018 David Ahern <dsa@cumulusnetworks.com>
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
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.
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>
23 #include "netdevsim.h"
25 struct nsim_fib_entry
{
30 struct nsim_per_fib_data
{
31 struct nsim_fib_entry fib
;
32 struct nsim_fib_entry rules
;
35 struct nsim_fib_data
{
36 struct nsim_per_fib_data ipv4
;
37 struct nsim_per_fib_data ipv6
;
40 static unsigned int nsim_fib_net_id
;
42 u64
nsim_fib_get_val(struct net
*net
, enum nsim_resource_id res_id
, bool max
)
44 struct nsim_fib_data
*fib_data
= net_generic(net
, nsim_fib_net_id
);
45 struct nsim_fib_entry
*entry
;
48 case NSIM_RESOURCE_IPV4_FIB
:
49 entry
= &fib_data
->ipv4
.fib
;
51 case NSIM_RESOURCE_IPV4_FIB_RULES
:
52 entry
= &fib_data
->ipv4
.rules
;
54 case NSIM_RESOURCE_IPV6_FIB
:
55 entry
= &fib_data
->ipv6
.fib
;
57 case NSIM_RESOURCE_IPV6_FIB_RULES
:
58 entry
= &fib_data
->ipv6
.rules
;
64 return max
? entry
->max
: entry
->num
;
67 int nsim_fib_set_max(struct net
*net
, enum nsim_resource_id res_id
, u64 val
,
68 struct netlink_ext_ack
*extack
)
70 struct nsim_fib_data
*fib_data
= net_generic(net
, nsim_fib_net_id
);
71 struct nsim_fib_entry
*entry
;
75 case NSIM_RESOURCE_IPV4_FIB
:
76 entry
= &fib_data
->ipv4
.fib
;
78 case NSIM_RESOURCE_IPV4_FIB_RULES
:
79 entry
= &fib_data
->ipv4
.rules
;
81 case NSIM_RESOURCE_IPV6_FIB
:
82 entry
= &fib_data
->ipv6
.fib
;
84 case NSIM_RESOURCE_IPV6_FIB_RULES
:
85 entry
= &fib_data
->ipv6
.rules
;
91 /* not allowing a new max to be less than curren occupancy
92 * --> no means of evicting entries
94 if (val
< entry
->num
) {
95 NL_SET_ERR_MSG_MOD(extack
, "New size is less than current occupancy");
104 static int nsim_fib_rule_account(struct nsim_fib_entry
*entry
, bool add
,
105 struct netlink_ext_ack
*extack
)
110 if (entry
->num
< entry
->max
) {
114 NL_SET_ERR_MSG_MOD(extack
, "Exceeded number of supported fib rule entries");
123 static int nsim_fib_rule_event(struct fib_notifier_info
*info
, bool add
)
125 struct nsim_fib_data
*data
= net_generic(info
->net
, nsim_fib_net_id
);
126 struct netlink_ext_ack
*extack
= info
->extack
;
129 switch (info
->family
) {
131 err
= nsim_fib_rule_account(&data
->ipv4
.rules
, add
, extack
);
134 err
= nsim_fib_rule_account(&data
->ipv6
.rules
, add
, extack
);
141 static int nsim_fib_account(struct nsim_fib_entry
*entry
, bool add
,
142 struct netlink_ext_ack
*extack
)
147 if (entry
->num
< entry
->max
) {
151 NL_SET_ERR_MSG_MOD(extack
, "Exceeded number of supported fib entries");
160 static int nsim_fib_event(struct fib_notifier_info
*info
, bool add
)
162 struct nsim_fib_data
*data
= net_generic(info
->net
, nsim_fib_net_id
);
163 struct netlink_ext_ack
*extack
= info
->extack
;
166 switch (info
->family
) {
168 err
= nsim_fib_account(&data
->ipv4
.fib
, add
, extack
);
171 err
= nsim_fib_account(&data
->ipv6
.fib
, add
, extack
);
178 static int nsim_fib_event_nb(struct notifier_block
*nb
, unsigned long event
,
181 struct fib_notifier_info
*info
= ptr
;
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
);
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
);
196 return notifier_from_errno(err
);
199 /* inconsistent dump, trying again */
200 static void nsim_fib_dump_inconsistent(struct notifier_block
*nb
)
202 struct nsim_fib_data
*data
;
206 for_each_net_rcu(net
) {
207 data
= net_generic(net
, nsim_fib_net_id
);
209 data
->ipv4
.fib
.num
= 0ULL;
210 data
->ipv4
.rules
.num
= 0ULL;
212 data
->ipv6
.fib
.num
= 0ULL;
213 data
->ipv6
.rules
.num
= 0ULL;
218 static struct notifier_block nsim_fib_nb
= {
219 .notifier_call
= nsim_fib_event_nb
,
222 /* Initialize per network namespace state */
223 static int __net_init
nsim_fib_netns_init(struct net
*net
)
225 struct nsim_fib_data
*data
= net_generic(net
, nsim_fib_net_id
);
227 data
->ipv4
.fib
.max
= (u64
)-1;
228 data
->ipv4
.rules
.max
= (u64
)-1;
230 data
->ipv6
.fib
.max
= (u64
)-1;
231 data
->ipv6
.rules
.max
= (u64
)-1;
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
),
242 void nsim_fib_exit(void)
244 unregister_pernet_subsys(&nsim_fib_net_ops
);
245 unregister_fib_notifier(&nsim_fib_nb
);
248 int nsim_fib_init(void)
252 err
= register_pernet_subsys(&nsim_fib_net_ops
);
254 pr_err("Failed to register pernet subsystem\n");
258 err
= register_fib_notifier(&nsim_fib_nb
, nsim_fib_dump_inconsistent
);
260 pr_err("Failed to register fib notifier\n");