Skip to content

Commit e37b1e9

Browse files
roopa-prabhudavem330
authored andcommitted
ipv6: route: dissect flow in input path if fib rules need it
Dissect flow in fwd path if fib rules require it. Controlled by a flag to avoid penatly for the common case. Flag is set when fib rules with sport, dport and proto match that require flow dissect are installed. Also passes the dissected hash keys to the multipath hash function when applicable to avoid dissecting the flow again. icmp packets will continue to use inner header for hash calculations (Thanks to Nikolay Aleksandrov for some review here). Signed-off-by: Roopa Prabhu <[email protected]> Acked-by: Paolo Abeni <[email protected]> Acked-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent bb0ad19 commit e37b1e9

File tree

5 files changed

+65
-16
lines changed

5 files changed

+65
-16
lines changed

include/net/ip_fib.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,13 @@ static inline unsigned int fib4_rules_seq_read(struct net *net)
293293
return 0;
294294
}
295295

296+
static inline bool fib4_rules_early_flow_dissect(struct net *net,
297+
struct sk_buff *skb,
298+
struct flowi4 *fl4,
299+
struct flow_keys *flkeys)
300+
{
301+
return false;
302+
}
296303
#else /* CONFIG_IP_MULTIPLE_TABLES */
297304
int __net_init fib4_rules_init(struct net *net);
298305
void __net_exit fib4_rules_exit(struct net *net);
@@ -341,6 +348,24 @@ bool fib4_rule_default(const struct fib_rule *rule);
341348
int fib4_rules_dump(struct net *net, struct notifier_block *nb);
342349
unsigned int fib4_rules_seq_read(struct net *net);
343350

351+
static inline bool fib4_rules_early_flow_dissect(struct net *net,
352+
struct sk_buff *skb,
353+
struct flowi4 *fl4,
354+
struct flow_keys *flkeys)
355+
{
356+
unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
357+
358+
if (!net->ipv4.fib_rules_require_fldissect)
359+
return false;
360+
361+
skb_flow_dissect_flow_keys(skb, flkeys, flag);
362+
fl4->fl4_sport = flkeys->ports.src;
363+
fl4->fl4_dport = flkeys->ports.dst;
364+
fl4->flowi4_proto = flkeys->basic.ip_proto;
365+
366+
return true;
367+
}
368+
344369
#endif /* CONFIG_IP_MULTIPLE_TABLES */
345370

346371
/* Exported by fib_frontend.c */
@@ -371,7 +396,7 @@ int fib_sync_up(struct net_device *dev, unsigned int nh_flags);
371396

372397
#ifdef CONFIG_IP_ROUTE_MULTIPATH
373398
int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
374-
const struct sk_buff *skb);
399+
const struct sk_buff *skb, struct flow_keys *flkeys);
375400
#endif
376401
void fib_select_multipath(struct fib_result *res, int hash);
377402
void fib_select_path(struct net *net, struct fib_result *res,

include/net/netns/ipv4.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct netns_ipv4 {
5252
#ifdef CONFIG_IP_MULTIPLE_TABLES
5353
struct fib_rules_ops *rules_ops;
5454
bool fib_has_custom_rules;
55+
unsigned int fib_rules_require_fldissect;
5556
struct fib_table __rcu *fib_main;
5657
struct fib_table __rcu *fib_default;
5758
#endif

net/ipv4/fib_rules.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
255255
}
256256
#endif
257257

258+
if (fib_rule_requires_fldissect(rule))
259+
net->ipv4.fib_rules_require_fldissect++;
260+
258261
rule4->src_len = frh->src_len;
259262
rule4->srcmask = inet_make_mask(rule4->src_len);
260263
rule4->dst_len = frh->dst_len;
@@ -283,6 +286,10 @@ static int fib4_rule_delete(struct fib_rule *rule)
283286
net->ipv4.fib_num_tclassid_users--;
284287
#endif
285288
net->ipv4.fib_has_custom_rules = true;
289+
290+
if (net->ipv4.fib_rules_require_fldissect &&
291+
fib_rule_requires_fldissect(rule))
292+
net->ipv4.fib_rules_require_fldissect--;
286293
errout:
287294
return err;
288295
}
@@ -400,6 +407,7 @@ int __net_init fib4_rules_init(struct net *net)
400407
goto fail;
401408
net->ipv4.rules_ops = ops;
402409
net->ipv4.fib_has_custom_rules = false;
410+
net->ipv4.fib_rules_require_fldissect = 0;
403411
return 0;
404412

405413
fail:

net/ipv4/fib_semantics.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1770,7 +1770,7 @@ void fib_select_path(struct net *net, struct fib_result *res,
17701770

17711771
#ifdef CONFIG_IP_ROUTE_MULTIPATH
17721772
if (res->fi->fib_nhs > 1) {
1773-
int h = fib_multipath_hash(res->fi, fl4, skb);
1773+
int h = fib_multipath_hash(res->fi, fl4, skb, NULL);
17741774

17751775
fib_select_multipath(res, h);
17761776
}

net/ipv4/route.c

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,7 +1783,7 @@ static void ip_multipath_l3_keys(const struct sk_buff *skb,
17831783

17841784
/* if skb is set it will be used and fl4 can be NULL */
17851785
int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
1786-
const struct sk_buff *skb)
1786+
const struct sk_buff *skb, struct flow_keys *flkeys)
17871787
{
17881788
struct net *net = fi->fib_net;
17891789
struct flow_keys hash_keys;
@@ -1810,14 +1810,23 @@ int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
18101810
if (skb->l4_hash)
18111811
return skb_get_hash_raw(skb) >> 1;
18121812
memset(&hash_keys, 0, sizeof(hash_keys));
1813-
skb_flow_dissect_flow_keys(skb, &keys, flag);
18141813

1815-
hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1816-
hash_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src;
1817-
hash_keys.addrs.v4addrs.dst = keys.addrs.v4addrs.dst;
1818-
hash_keys.ports.src = keys.ports.src;
1819-
hash_keys.ports.dst = keys.ports.dst;
1820-
hash_keys.basic.ip_proto = keys.basic.ip_proto;
1814+
if (flkeys) {
1815+
hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1816+
hash_keys.addrs.v4addrs.src = flkeys->addrs.v4addrs.src;
1817+
hash_keys.addrs.v4addrs.dst = flkeys->addrs.v4addrs.dst;
1818+
hash_keys.ports.src = flkeys->ports.src;
1819+
hash_keys.ports.dst = flkeys->ports.dst;
1820+
hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
1821+
} else {
1822+
skb_flow_dissect_flow_keys(skb, &keys, flag);
1823+
hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1824+
hash_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src;
1825+
hash_keys.addrs.v4addrs.dst = keys.addrs.v4addrs.dst;
1826+
hash_keys.ports.src = keys.ports.src;
1827+
hash_keys.ports.dst = keys.ports.dst;
1828+
hash_keys.basic.ip_proto = keys.basic.ip_proto;
1829+
}
18211830
} else {
18221831
memset(&hash_keys, 0, sizeof(hash_keys));
18231832
hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
@@ -1838,11 +1847,12 @@ int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
18381847
static int ip_mkroute_input(struct sk_buff *skb,
18391848
struct fib_result *res,
18401849
struct in_device *in_dev,
1841-
__be32 daddr, __be32 saddr, u32 tos)
1850+
__be32 daddr, __be32 saddr, u32 tos,
1851+
struct flow_keys *hkeys)
18421852
{
18431853
#ifdef CONFIG_IP_ROUTE_MULTIPATH
18441854
if (res->fi && res->fi->fib_nhs > 1) {
1845-
int h = fib_multipath_hash(res->fi, NULL, skb);
1855+
int h = fib_multipath_hash(res->fi, NULL, skb, hkeys);
18461856

18471857
fib_select_multipath(res, h);
18481858
}
@@ -1868,13 +1878,14 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
18681878
struct fib_result *res)
18691879
{
18701880
struct in_device *in_dev = __in_dev_get_rcu(dev);
1881+
struct flow_keys *flkeys = NULL, _flkeys;
1882+
struct net *net = dev_net(dev);
18711883
struct ip_tunnel_info *tun_info;
1872-
struct flowi4 fl4;
1884+
int err = -EINVAL;
18731885
unsigned int flags = 0;
18741886
u32 itag = 0;
18751887
struct rtable *rth;
1876-
int err = -EINVAL;
1877-
struct net *net = dev_net(dev);
1888+
struct flowi4 fl4;
18781889
bool do_cache;
18791890

18801891
/* IP on this device is disabled. */
@@ -1933,6 +1944,10 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
19331944
fl4.daddr = daddr;
19341945
fl4.saddr = saddr;
19351946
fl4.flowi4_uid = sock_net_uid(net, NULL);
1947+
1948+
if (fib4_rules_early_flow_dissect(net, skb, &fl4, &_flkeys))
1949+
flkeys = &_flkeys;
1950+
19361951
err = fib_lookup(net, &fl4, res, 0);
19371952
if (err != 0) {
19381953
if (!IN_DEV_FORWARD(in_dev))
@@ -1958,7 +1973,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
19581973
if (res->type != RTN_UNICAST)
19591974
goto martian_destination;
19601975

1961-
err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos);
1976+
err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys);
19621977
out: return err;
19631978

19641979
brd_input:

0 commit comments

Comments
 (0)