Skip to content

Commit 753c104

Browse files
committed
Merge branch 'vrf-fib-rule-improve'
David Ahern says: ==================== net: vrf: Improve use of FIB rules Currently, VRFs require 1 oif and 1 iif rule per address family per VRF. As the number of VRF devices increases it brings scalability issues with the increasing rule list. All of the VRF rules have the same format with the exception of the specific table id to direct the lookup. Since the table id is available from the oif or iif in the loopup, the VRF rules can be consolidated to a single rule that pulls the table from the VRF device. This solution still allows a user to insert their own rules for VRFs, including rules with additional attributes. Accordingly, it is backwards compatible with existing setups and allows other policy routing as desired. Hopefully v5 is the charm; my e-waste can is getting full. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 6278e03 + 1aa6c4f commit 753c104

File tree

8 files changed

+214
-12
lines changed

8 files changed

+214
-12
lines changed

drivers/net/vrf.c

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,17 @@
3535
#include <net/route.h>
3636
#include <net/addrconf.h>
3737
#include <net/l3mdev.h>
38+
#include <net/fib_rules.h>
3839

3940
#define RT_FL_TOS(oldflp4) \
4041
((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))
4142

4243
#define DRV_NAME "vrf"
4344
#define DRV_VERSION "1.0"
4445

46+
#define FIB_RULE_PREF 1000 /* default preference for FIB rules */
47+
static bool add_fib_rules = true;
48+
4549
struct net_vrf {
4650
struct rtable __rcu *rth;
4751
struct rtable __rcu *rth_local;
@@ -897,6 +901,91 @@ static const struct ethtool_ops vrf_ethtool_ops = {
897901
.get_drvinfo = vrf_get_drvinfo,
898902
};
899903

904+
static inline size_t vrf_fib_rule_nl_size(void)
905+
{
906+
size_t sz;
907+
908+
sz = NLMSG_ALIGN(sizeof(struct fib_rule_hdr));
909+
sz += nla_total_size(sizeof(u8)); /* FRA_L3MDEV */
910+
sz += nla_total_size(sizeof(u32)); /* FRA_PRIORITY */
911+
912+
return sz;
913+
}
914+
915+
static int vrf_fib_rule(const struct net_device *dev, __u8 family, bool add_it)
916+
{
917+
struct fib_rule_hdr *frh;
918+
struct nlmsghdr *nlh;
919+
struct sk_buff *skb;
920+
int err;
921+
922+
skb = nlmsg_new(vrf_fib_rule_nl_size(), GFP_KERNEL);
923+
if (!skb)
924+
return -ENOMEM;
925+
926+
nlh = nlmsg_put(skb, 0, 0, 0, sizeof(*frh), 0);
927+
if (!nlh)
928+
goto nla_put_failure;
929+
930+
/* rule only needs to appear once */
931+
nlh->nlmsg_flags &= NLM_F_EXCL;
932+
933+
frh = nlmsg_data(nlh);
934+
memset(frh, 0, sizeof(*frh));
935+
frh->family = family;
936+
frh->action = FR_ACT_TO_TBL;
937+
938+
if (nla_put_u32(skb, FRA_L3MDEV, 1))
939+
goto nla_put_failure;
940+
941+
if (nla_put_u32(skb, FRA_PRIORITY, FIB_RULE_PREF))
942+
goto nla_put_failure;
943+
944+
nlmsg_end(skb, nlh);
945+
946+
/* fib_nl_{new,del}rule handling looks for net from skb->sk */
947+
skb->sk = dev_net(dev)->rtnl;
948+
if (add_it) {
949+
err = fib_nl_newrule(skb, nlh);
950+
if (err == -EEXIST)
951+
err = 0;
952+
} else {
953+
err = fib_nl_delrule(skb, nlh);
954+
if (err == -ENOENT)
955+
err = 0;
956+
}
957+
nlmsg_free(skb);
958+
959+
return err;
960+
961+
nla_put_failure:
962+
nlmsg_free(skb);
963+
964+
return -EMSGSIZE;
965+
}
966+
967+
static int vrf_add_fib_rules(const struct net_device *dev)
968+
{
969+
int err;
970+
971+
err = vrf_fib_rule(dev, AF_INET, true);
972+
if (err < 0)
973+
goto out_err;
974+
975+
err = vrf_fib_rule(dev, AF_INET6, true);
976+
if (err < 0)
977+
goto ipv6_err;
978+
979+
return 0;
980+
981+
ipv6_err:
982+
vrf_fib_rule(dev, AF_INET, false);
983+
984+
out_err:
985+
netdev_err(dev, "Failed to add FIB rules.\n");
986+
return err;
987+
}
988+
900989
static void vrf_setup(struct net_device *dev)
901990
{
902991
ether_setup(dev);
@@ -937,6 +1026,7 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev,
9371026
struct nlattr *tb[], struct nlattr *data[])
9381027
{
9391028
struct net_vrf *vrf = netdev_priv(dev);
1029+
int err;
9401030

9411031
if (!data || !data[IFLA_VRF_TABLE])
9421032
return -EINVAL;
@@ -945,7 +1035,21 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev,
9451035

9461036
dev->priv_flags |= IFF_L3MDEV_MASTER;
9471037

948-
return register_netdevice(dev);
1038+
err = register_netdevice(dev);
1039+
if (err)
1040+
goto out;
1041+
1042+
if (add_fib_rules) {
1043+
err = vrf_add_fib_rules(dev);
1044+
if (err) {
1045+
unregister_netdevice(dev);
1046+
goto out;
1047+
}
1048+
add_fib_rules = false;
1049+
}
1050+
1051+
out:
1052+
return err;
9491053
}
9501054

9511055
static size_t vrf_nl_getsize(const struct net_device *dev)

include/net/fib_rules.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ struct fib_rule {
1717
u32 flags;
1818
u32 table;
1919
u8 action;
20-
/* 3 bytes hole, try to use */
20+
u8 l3mdev;
21+
/* 2 bytes hole, try to use */
2122
u32 target;
2223
__be64 tun_id;
2324
struct fib_rule __rcu *ctarget;
@@ -36,6 +37,7 @@ struct fib_lookup_arg {
3637
void *lookup_ptr;
3738
void *result;
3839
struct fib_rule *rule;
40+
u32 table;
3941
int flags;
4042
#define FIB_LOOKUP_NOREF 1
4143
#define FIB_LOOKUP_IGNORE_LINKSTATE 2
@@ -89,7 +91,8 @@ struct fib_rules_ops {
8991
[FRA_TABLE] = { .type = NLA_U32 }, \
9092
[FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \
9193
[FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32 }, \
92-
[FRA_GOTO] = { .type = NLA_U32 }
94+
[FRA_GOTO] = { .type = NLA_U32 }, \
95+
[FRA_L3MDEV] = { .type = NLA_U8 }
9396

9497
static inline void fib_rule_get(struct fib_rule *rule)
9598
{
@@ -102,6 +105,20 @@ static inline void fib_rule_put(struct fib_rule *rule)
102105
kfree_rcu(rule, rcu);
103106
}
104107

108+
#ifdef CONFIG_NET_L3_MASTER_DEV
109+
static inline u32 fib_rule_get_table(struct fib_rule *rule,
110+
struct fib_lookup_arg *arg)
111+
{
112+
return rule->l3mdev ? arg->table : rule->table;
113+
}
114+
#else
115+
static inline u32 fib_rule_get_table(struct fib_rule *rule,
116+
struct fib_lookup_arg *arg)
117+
{
118+
return rule->table;
119+
}
120+
#endif
121+
105122
static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla)
106123
{
107124
if (nla[FRA_TABLE])
@@ -117,4 +134,7 @@ int fib_rules_lookup(struct fib_rules_ops *, struct flowi *, int flags,
117134
struct fib_lookup_arg *);
118135
int fib_default_rule_add(struct fib_rules_ops *, u32 pref, u32 table,
119136
u32 flags);
137+
138+
int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh);
139+
int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh);
120140
#endif

include/net/l3mdev.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#ifndef _NET_L3MDEV_H_
1212
#define _NET_L3MDEV_H_
1313

14+
#include <net/fib_rules.h>
15+
1416
/**
1517
* struct l3mdev_ops - l3mdev operations
1618
*
@@ -41,6 +43,9 @@ struct l3mdev_ops {
4143

4244
#ifdef CONFIG_NET_L3_MASTER_DEV
4345

46+
int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
47+
struct fib_lookup_arg *arg);
48+
4449
int l3mdev_master_ifindex_rcu(const struct net_device *dev);
4550
static inline int l3mdev_master_ifindex(struct net_device *dev)
4651
{
@@ -236,6 +241,13 @@ struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb)
236241
{
237242
return skb;
238243
}
244+
245+
static inline
246+
int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
247+
struct fib_lookup_arg *arg)
248+
{
249+
return 1;
250+
}
239251
#endif
240252

241253
#endif /* _NET_L3MDEV_H_ */

include/uapi/linux/fib_rules.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ enum {
5050
FRA_FWMASK, /* mask for netfilter mark */
5151
FRA_OIFNAME,
5252
FRA_PAD,
53+
FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
5354
__FRA_MAX
5455
};
5556

net/core/fib_rules.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ void fib_rules_unregister(struct fib_rules_ops *ops)
173173
EXPORT_SYMBOL_GPL(fib_rules_unregister);
174174

175175
static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
176-
struct flowi *fl, int flags)
176+
struct flowi *fl, int flags,
177+
struct fib_lookup_arg *arg)
177178
{
178179
int ret = 0;
179180

@@ -189,6 +190,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
189190
if (rule->tun_id && (rule->tun_id != fl->flowi_tun_key.tun_id))
190191
goto out;
191192

193+
if (rule->l3mdev && !l3mdev_fib_rule_match(rule->fr_net, fl, arg))
194+
goto out;
195+
192196
ret = ops->match(rule, fl, flags);
193197
out:
194198
return (rule->flags & FIB_RULE_INVERT) ? !ret : ret;
@@ -204,7 +208,7 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,
204208

205209
list_for_each_entry_rcu(rule, &ops->rules_list, list) {
206210
jumped:
207-
if (!fib_rule_match(rule, ops, fl, flags))
211+
if (!fib_rule_match(rule, ops, fl, flags, arg))
208212
continue;
209213

210214
if (rule->action == FR_ACT_GOTO) {
@@ -265,7 +269,7 @@ static int validate_rulemsg(struct fib_rule_hdr *frh, struct nlattr **tb,
265269
return err;
266270
}
267271

268-
static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
272+
int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh)
269273
{
270274
struct net *net = sock_net(skb->sk);
271275
struct fib_rule_hdr *frh = nlmsg_data(nlh);
@@ -336,6 +340,14 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
336340
if (tb[FRA_TUN_ID])
337341
rule->tun_id = nla_get_be64(tb[FRA_TUN_ID]);
338342

343+
if (tb[FRA_L3MDEV]) {
344+
#ifdef CONFIG_NET_L3_MASTER_DEV
345+
rule->l3mdev = nla_get_u8(tb[FRA_L3MDEV]);
346+
if (rule->l3mdev != 1)
347+
#endif
348+
goto errout_free;
349+
}
350+
339351
rule->action = frh->action;
340352
rule->flags = frh->flags;
341353
rule->table = frh_get_table(frh, tb);
@@ -371,6 +383,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
371383
} else if (rule->action == FR_ACT_GOTO)
372384
goto errout_free;
373385

386+
if (rule->l3mdev && rule->table)
387+
goto errout_free;
388+
374389
err = ops->configure(rule, skb, frh, tb);
375390
if (err < 0)
376391
goto errout_free;
@@ -424,8 +439,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
424439
rules_ops_put(ops);
425440
return err;
426441
}
442+
EXPORT_SYMBOL_GPL(fib_nl_newrule);
427443

428-
static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
444+
int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh)
429445
{
430446
struct net *net = sock_net(skb->sk);
431447
struct fib_rule_hdr *frh = nlmsg_data(nlh);
@@ -483,6 +499,10 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
483499
(rule->tun_id != nla_get_be64(tb[FRA_TUN_ID])))
484500
continue;
485501

502+
if (tb[FRA_L3MDEV] &&
503+
(rule->l3mdev != nla_get_u8(tb[FRA_L3MDEV])))
504+
continue;
505+
486506
if (!ops->compare(rule, frh, tb))
487507
continue;
488508

@@ -536,6 +556,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
536556
rules_ops_put(ops);
537557
return err;
538558
}
559+
EXPORT_SYMBOL_GPL(fib_nl_delrule);
539560

540561
static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
541562
struct fib_rule *rule)
@@ -607,7 +628,9 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
607628
(rule->target &&
608629
nla_put_u32(skb, FRA_GOTO, rule->target)) ||
609630
(rule->tun_id &&
610-
nla_put_be64(skb, FRA_TUN_ID, rule->tun_id, FRA_PAD)))
631+
nla_put_be64(skb, FRA_TUN_ID, rule->tun_id, FRA_PAD)) ||
632+
(rule->l3mdev &&
633+
nla_put_u8(skb, FRA_L3MDEV, rule->l3mdev)))
611634
goto nla_put_failure;
612635

613636
if (rule->suppress_ifgroup != -1) {

net/ipv4/fib_rules.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
7676
{
7777
int err = -EAGAIN;
7878
struct fib_table *tbl;
79+
u32 tb_id;
7980

8081
switch (rule->action) {
8182
case FR_ACT_TO_TBL:
@@ -94,7 +95,8 @@ static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
9495

9596
rcu_read_lock();
9697

97-
tbl = fib_get_table(rule->fr_net, rule->table);
98+
tb_id = fib_rule_get_table(rule, arg);
99+
tbl = fib_get_table(rule->fr_net, tb_id);
98100
if (tbl)
99101
err = fib_table_lookup(tbl, &flp->u.ip4,
100102
(struct fib_result *)arg->result,
@@ -180,7 +182,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
180182
if (err)
181183
goto errout;
182184

183-
if (rule->table == RT_TABLE_UNSPEC) {
185+
if (rule->table == RT_TABLE_UNSPEC && !rule->l3mdev) {
184186
if (rule->action == FR_ACT_TO_TBL) {
185187
struct fib_table *table;
186188

net/ipv6/fib6_rules.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
6767
struct net *net = rule->fr_net;
6868
pol_lookup_t lookup = arg->lookup_ptr;
6969
int err = 0;
70+
u32 tb_id;
7071

7172
switch (rule->action) {
7273
case FR_ACT_TO_TBL:
@@ -86,7 +87,8 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
8687
goto discard_pkt;
8788
}
8889

89-
table = fib6_get_table(net, rule->table);
90+
tb_id = fib_rule_get_table(rule, arg);
91+
table = fib6_get_table(net, tb_id);
9092
if (!table) {
9193
err = -EAGAIN;
9294
goto out;
@@ -199,7 +201,7 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
199201
struct net *net = sock_net(skb->sk);
200202
struct fib6_rule *rule6 = (struct fib6_rule *) rule;
201203

202-
if (rule->action == FR_ACT_TO_TBL) {
204+
if (rule->action == FR_ACT_TO_TBL && !rule->l3mdev) {
203205
if (rule->table == RT6_TABLE_UNSPEC)
204206
goto errout;
205207

0 commit comments

Comments
 (0)