Skip to content

Commit 0ddcf43

Browse files
Alexander Duyckdavem330
Alexander Duyck
authored andcommitted
ipv4: FIB Local/MAIN table collapse
This patch is meant to collapse local and main into one by converting tb_data from an array to a pointer. Doing this allows us to point the local table into the main while maintaining the same variables in the table. As such the tb_data was converted from an array to a pointer, and a new array called data is added in order to still provide an object for tb_data to point to. In order to track the origin of the fib aliases a tb_id value was added in a hole that existed on 64b systems. Using this we can also reverse the merge in the event that custom FIB rules are enabled. With this patch I am seeing an improvement of 20ns to 30ns for routing lookups as long as custom rules are not enabled, with custom rules enabled we fall back to split tables and the original behavior. Signed-off-by: Alexander Duyck <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 169bf91 commit 0ddcf43

File tree

7 files changed

+250
-38
lines changed

7 files changed

+250
-38
lines changed

include/net/fib_rules.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ struct fib_rules_ops {
5858
struct sk_buff *,
5959
struct fib_rule_hdr *,
6060
struct nlattr **);
61-
void (*delete)(struct fib_rule *);
61+
int (*delete)(struct fib_rule *);
6262
int (*compare)(struct fib_rule *,
6363
struct fib_rule_hdr *,
6464
struct nlattr **);

include/net/ip_fib.h

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ struct fib_table {
186186
int tb_default;
187187
int tb_num_default;
188188
struct rcu_head rcu;
189-
unsigned long tb_data[0];
189+
unsigned long *tb_data;
190+
unsigned long __data[0];
190191
};
191192

192193
int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
@@ -196,11 +197,10 @@ int fib_table_delete(struct fib_table *, struct fib_config *);
196197
int fib_table_dump(struct fib_table *table, struct sk_buff *skb,
197198
struct netlink_callback *cb);
198199
int fib_table_flush(struct fib_table *table);
200+
struct fib_table *fib_trie_unmerge(struct fib_table *main_tb);
199201
void fib_table_flush_external(struct fib_table *table);
200202
void fib_free_table(struct fib_table *tb);
201203

202-
203-
204204
#ifndef CONFIG_IP_MULTIPLE_TABLES
205205

206206
#define TABLE_LOCAL_INDEX (RT_TABLE_LOCAL & (FIB_TABLE_HASHSZ - 1))
@@ -229,18 +229,13 @@ static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
229229
struct fib_result *res)
230230
{
231231
struct fib_table *tb;
232-
int err;
232+
int err = -ENETUNREACH;
233233

234234
rcu_read_lock();
235235

236-
for (err = 0; !err; err = -ENETUNREACH) {
237-
tb = fib_get_table(net, RT_TABLE_LOCAL);
238-
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
239-
break;
240-
tb = fib_get_table(net, RT_TABLE_MAIN);
241-
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
242-
break;
243-
}
236+
tb = fib_get_table(net, RT_TABLE_MAIN);
237+
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
238+
err = 0;
244239

245240
rcu_read_unlock();
246241

@@ -270,10 +265,6 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp,
270265
res->tclassid = 0;
271266

272267
for (err = 0; !err; err = -ENETUNREACH) {
273-
tb = rcu_dereference_rtnl(net->ipv4.fib_local);
274-
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
275-
break;
276-
277268
tb = rcu_dereference_rtnl(net->ipv4.fib_main);
278269
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
279270
break;
@@ -309,6 +300,7 @@ static inline int fib_num_tclassid_users(struct net *net)
309300
return 0;
310301
}
311302
#endif
303+
int fib_unmerge(struct net *net);
312304
void fib_flush_external(struct net *net);
313305

314306
/* Exported by fib_semantics.c */
@@ -320,7 +312,7 @@ void fib_select_multipath(struct fib_result *res);
320312

321313
/* Exported by fib_trie.c */
322314
void fib_trie_init(void);
323-
struct fib_table *fib_trie_table(u32 id);
315+
struct fib_table *fib_trie_table(u32 id, struct fib_table *alias);
324316

325317
static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
326318
{

net/core/fib_rules.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,12 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
492492
goto errout;
493493
}
494494

495+
if (ops->delete) {
496+
err = ops->delete(rule);
497+
if (err)
498+
goto errout;
499+
}
500+
495501
list_del_rcu(&rule->list);
496502

497503
if (rule->action == FR_ACT_GOTO) {
@@ -517,8 +523,6 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
517523

518524
notify_rule_change(RTM_DELRULE, rule, ops, nlh,
519525
NETLINK_CB(skb).portid);
520-
if (ops->delete)
521-
ops->delete(rule);
522526
fib_rule_put(rule);
523527
flush_route_cache(ops);
524528
rules_ops_put(ops);

net/ipv4/fib_frontend.c

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ static int __net_init fib4_rules_init(struct net *net)
5252
{
5353
struct fib_table *local_table, *main_table;
5454

55-
local_table = fib_trie_table(RT_TABLE_LOCAL);
56-
if (local_table == NULL)
57-
return -ENOMEM;
58-
59-
main_table = fib_trie_table(RT_TABLE_MAIN);
55+
main_table = fib_trie_table(RT_TABLE_MAIN, NULL);
6056
if (main_table == NULL)
6157
goto fail;
6258

59+
local_table = fib_trie_table(RT_TABLE_LOCAL, main_table);
60+
if (local_table == NULL)
61+
return -ENOMEM;
62+
6363
hlist_add_head_rcu(&local_table->tb_hlist,
6464
&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]);
6565
hlist_add_head_rcu(&main_table->tb_hlist,
@@ -74,7 +74,7 @@ static int __net_init fib4_rules_init(struct net *net)
7474

7575
struct fib_table *fib_new_table(struct net *net, u32 id)
7676
{
77-
struct fib_table *tb;
77+
struct fib_table *tb, *alias = NULL;
7878
unsigned int h;
7979

8080
if (id == 0)
@@ -83,7 +83,10 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
8383
if (tb)
8484
return tb;
8585

86-
tb = fib_trie_table(id);
86+
if (id == RT_TABLE_LOCAL)
87+
alias = fib_new_table(net, RT_TABLE_MAIN);
88+
89+
tb = fib_trie_table(id, alias);
8790
if (!tb)
8891
return NULL;
8992

@@ -126,6 +129,48 @@ struct fib_table *fib_get_table(struct net *net, u32 id)
126129
}
127130
#endif /* CONFIG_IP_MULTIPLE_TABLES */
128131

132+
static void fib_replace_table(struct net *net, struct fib_table *old,
133+
struct fib_table *new)
134+
{
135+
#ifdef CONFIG_IP_MULTIPLE_TABLES
136+
switch (new->tb_id) {
137+
case RT_TABLE_LOCAL:
138+
rcu_assign_pointer(net->ipv4.fib_local, new);
139+
break;
140+
case RT_TABLE_MAIN:
141+
rcu_assign_pointer(net->ipv4.fib_main, new);
142+
break;
143+
case RT_TABLE_DEFAULT:
144+
rcu_assign_pointer(net->ipv4.fib_default, new);
145+
break;
146+
default:
147+
break;
148+
}
149+
150+
#endif
151+
/* replace the old table in the hlist */
152+
hlist_replace_rcu(&old->tb_hlist, &new->tb_hlist);
153+
}
154+
155+
int fib_unmerge(struct net *net)
156+
{
157+
struct fib_table *old, *new;
158+
159+
old = fib_get_table(net, RT_TABLE_LOCAL);
160+
new = fib_trie_unmerge(old);
161+
162+
if (!new)
163+
return -ENOMEM;
164+
165+
/* replace merged table with clean table */
166+
if (new != old) {
167+
fib_replace_table(net, old, new);
168+
fib_free_table(old);
169+
}
170+
171+
return 0;
172+
}
173+
129174
static void fib_flush(struct net *net)
130175
{
131176
int flushed = 0;

net/ipv4/fib_lookup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct fib_alias {
1212
u8 fa_type;
1313
u8 fa_state;
1414
u8 fa_slen;
15+
u32 tb_id;
1516
struct rcu_head rcu;
1617
};
1718

net/ipv4/fib_rules.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
174174
if (frh->tos & ~IPTOS_TOS_MASK)
175175
goto errout;
176176

177+
/* split local/main if they are not already split */
178+
err = fib_unmerge(net);
179+
if (err)
180+
goto errout;
181+
177182
if (rule->table == RT_TABLE_UNSPEC) {
178183
if (rule->action == FR_ACT_TO_TBL) {
179184
struct fib_table *table;
@@ -216,17 +221,24 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
216221
return err;
217222
}
218223

219-
static void fib4_rule_delete(struct fib_rule *rule)
224+
static int fib4_rule_delete(struct fib_rule *rule)
220225
{
221226
struct net *net = rule->fr_net;
222-
#ifdef CONFIG_IP_ROUTE_CLASSID
223-
struct fib4_rule *rule4 = (struct fib4_rule *) rule;
227+
int err;
224228

225-
if (rule4->tclassid)
229+
/* split local/main if they are not already split */
230+
err = fib_unmerge(net);
231+
if (err)
232+
goto errout;
233+
234+
#ifdef CONFIG_IP_ROUTE_CLASSID
235+
if (((struct fib4_rule *)rule)->tclassid)
226236
net->ipv4.fib_num_tclassid_users--;
227237
#endif
228238
net->ipv4.fib_has_custom_rules = true;
229239
fib_flush_external(rule->fr_net);
240+
errout:
241+
return err;
230242
}
231243

232244
static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,

0 commit comments

Comments
 (0)