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>
22 #include "netdevsim.h"
24 struct nsim_fib_entry
{
29 struct nsim_per_fib_data
{
30 struct nsim_fib_entry fib
;
31 struct nsim_fib_entry rules
;
34 struct nsim_fib_data
{
35 struct notifier_block fib_nb
;
36 struct nsim_per_fib_data ipv4
;
37 struct nsim_per_fib_data ipv6
;
40 u64
nsim_fib_get_val(struct nsim_fib_data
*fib_data
,
41 enum nsim_resource_id res_id
, bool max
)
43 struct nsim_fib_entry
*entry
;
46 case NSIM_RESOURCE_IPV4_FIB
:
47 entry
= &fib_data
->ipv4
.fib
;
49 case NSIM_RESOURCE_IPV4_FIB_RULES
:
50 entry
= &fib_data
->ipv4
.rules
;
52 case NSIM_RESOURCE_IPV6_FIB
:
53 entry
= &fib_data
->ipv6
.fib
;
55 case NSIM_RESOURCE_IPV6_FIB_RULES
:
56 entry
= &fib_data
->ipv6
.rules
;
62 return max
? entry
->max
: entry
->num
;
65 int nsim_fib_set_max(struct nsim_fib_data
*fib_data
,
66 enum nsim_resource_id res_id
, u64 val
,
67 struct netlink_ext_ack
*extack
)
69 struct nsim_fib_entry
*entry
;
73 case NSIM_RESOURCE_IPV4_FIB
:
74 entry
= &fib_data
->ipv4
.fib
;
76 case NSIM_RESOURCE_IPV4_FIB_RULES
:
77 entry
= &fib_data
->ipv4
.rules
;
79 case NSIM_RESOURCE_IPV6_FIB
:
80 entry
= &fib_data
->ipv6
.fib
;
82 case NSIM_RESOURCE_IPV6_FIB_RULES
:
83 entry
= &fib_data
->ipv6
.rules
;
89 /* not allowing a new max to be less than curren occupancy
90 * --> no means of evicting entries
92 if (val
< entry
->num
) {
93 NL_SET_ERR_MSG_MOD(extack
, "New size is less than current occupancy");
102 static int nsim_fib_rule_account(struct nsim_fib_entry
*entry
, bool add
,
103 struct netlink_ext_ack
*extack
)
108 if (entry
->num
< entry
->max
) {
112 NL_SET_ERR_MSG_MOD(extack
, "Exceeded number of supported fib rule entries");
121 static int nsim_fib_rule_event(struct nsim_fib_data
*data
,
122 struct fib_notifier_info
*info
, bool add
)
124 struct netlink_ext_ack
*extack
= info
->extack
;
127 switch (info
->family
) {
129 err
= nsim_fib_rule_account(&data
->ipv4
.rules
, add
, extack
);
132 err
= nsim_fib_rule_account(&data
->ipv6
.rules
, add
, extack
);
139 static int nsim_fib_account(struct nsim_fib_entry
*entry
, bool add
,
140 struct netlink_ext_ack
*extack
)
145 if (entry
->num
< entry
->max
) {
149 NL_SET_ERR_MSG_MOD(extack
, "Exceeded number of supported fib entries");
158 static int nsim_fib_event(struct nsim_fib_data
*data
,
159 struct fib_notifier_info
*info
, bool add
)
161 struct netlink_ext_ack
*extack
= info
->extack
;
164 switch (info
->family
) {
166 err
= nsim_fib_account(&data
->ipv4
.fib
, add
, extack
);
169 err
= nsim_fib_account(&data
->ipv6
.fib
, add
, extack
);
176 static int nsim_fib_event_nb(struct notifier_block
*nb
, unsigned long event
,
179 struct nsim_fib_data
*data
= container_of(nb
, struct nsim_fib_data
,
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(data
, info
,
188 event
== FIB_EVENT_RULE_ADD
);
191 case FIB_EVENT_ENTRY_ADD
: /* fall through */
192 case FIB_EVENT_ENTRY_DEL
:
193 err
= nsim_fib_event(data
, info
,
194 event
== FIB_EVENT_ENTRY_ADD
);
198 return notifier_from_errno(err
);
201 /* inconsistent dump, trying again */
202 static void nsim_fib_dump_inconsistent(struct notifier_block
*nb
)
204 struct nsim_fib_data
*data
= container_of(nb
, struct nsim_fib_data
,
207 data
->ipv4
.fib
.num
= 0ULL;
208 data
->ipv4
.rules
.num
= 0ULL;
209 data
->ipv6
.fib
.num
= 0ULL;
210 data
->ipv6
.rules
.num
= 0ULL;
213 struct nsim_fib_data
*nsim_fib_create(void)
215 struct nsim_fib_data
*data
;
218 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
220 return ERR_PTR(-ENOMEM
);
222 data
->ipv4
.fib
.max
= (u64
)-1;
223 data
->ipv4
.rules
.max
= (u64
)-1;
225 data
->ipv6
.fib
.max
= (u64
)-1;
226 data
->ipv6
.rules
.max
= (u64
)-1;
228 data
->fib_nb
.notifier_call
= nsim_fib_event_nb
;
229 err
= register_fib_notifier(&data
->fib_nb
, nsim_fib_dump_inconsistent
);
231 pr_err("Failed to register fib notifier\n");
242 void nsim_fib_destroy(struct nsim_fib_data
*data
)
244 unregister_fib_notifier(&data
->fib_nb
);