Skip to content

Commit 5e5d6fe

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. 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 e37b1e9 commit 5e5d6fe

File tree

6 files changed

+72
-12
lines changed

6 files changed

+72
-12
lines changed

include/net/ip6_fib.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,24 @@ void fib6_rules_cleanup(void);
415415
bool fib6_rule_default(const struct fib_rule *rule);
416416
int fib6_rules_dump(struct net *net, struct notifier_block *nb);
417417
unsigned int fib6_rules_seq_read(struct net *net);
418+
419+
static inline bool fib6_rules_early_flow_dissect(struct net *net,
420+
struct sk_buff *skb,
421+
struct flowi6 *fl6,
422+
struct flow_keys *flkeys)
423+
{
424+
unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
425+
426+
if (!net->ipv6.fib6_rules_require_fldissect)
427+
return false;
428+
429+
skb_flow_dissect_flow_keys(skb, flkeys, flag);
430+
fl6->fl6_sport = flkeys->ports.src;
431+
fl6->fl6_dport = flkeys->ports.dst;
432+
fl6->flowi6_proto = flkeys->basic.ip_proto;
433+
434+
return true;
435+
}
418436
#else
419437
static inline int fib6_rules_init(void)
420438
{
@@ -436,5 +454,12 @@ static inline unsigned int fib6_rules_seq_read(struct net *net)
436454
{
437455
return 0;
438456
}
457+
static inline bool fib6_rules_early_flow_dissect(struct net *net,
458+
struct sk_buff *skb,
459+
struct flowi6 *fl6,
460+
struct flow_keys *flkeys)
461+
{
462+
return false;
463+
}
439464
#endif
440465
#endif

include/net/ip6_route.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ static inline int ip6_route_get_saddr(struct net *net, struct rt6_info *rt,
127127

128128
struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
129129
const struct in6_addr *saddr, int oif, int flags);
130-
u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb);
130+
u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb,
131+
struct flow_keys *hkeys);
131132

132133
struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct flowi6 *fl6);
133134

@@ -266,4 +267,5 @@ static inline bool rt6_duplicate_nexthop(struct rt6_info *a, struct rt6_info *b)
266267
ipv6_addr_equal(&a->rt6i_gateway, &b->rt6i_gateway) &&
267268
!lwtunnel_cmp_encap(a->dst.lwtstate, b->dst.lwtstate);
268269
}
270+
269271
#endif

include/net/netns/ipv6.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ struct netns_ipv6 {
7171
unsigned int ip6_rt_gc_expire;
7272
unsigned long ip6_rt_last_gc;
7373
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
74-
bool fib6_has_custom_rules;
74+
unsigned int fib6_rules_require_fldissect;
75+
bool fib6_has_custom_rules;
7576
struct rt6_info *ip6_prohibit_entry;
7677
struct rt6_info *ip6_blk_hole_entry;
7778
struct fib6_table *fib6_local_tbl;

net/ipv6/fib6_rules.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,12 +269,26 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
269269
rule6->dst.plen = frh->dst_len;
270270
rule6->tclass = frh->tos;
271271

272+
if (fib_rule_requires_fldissect(rule))
273+
net->ipv6.fib6_rules_require_fldissect++;
274+
272275
net->ipv6.fib6_has_custom_rules = true;
273276
err = 0;
274277
errout:
275278
return err;
276279
}
277280

281+
static int fib6_rule_delete(struct fib_rule *rule)
282+
{
283+
struct net *net = rule->fr_net;
284+
285+
if (net->ipv6.fib6_rules_require_fldissect &&
286+
fib_rule_requires_fldissect(rule))
287+
net->ipv6.fib6_rules_require_fldissect--;
288+
289+
return 0;
290+
}
291+
278292
static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
279293
struct nlattr **tb)
280294
{
@@ -334,6 +348,7 @@ static const struct fib_rules_ops __net_initconst fib6_rules_ops_template = {
334348
.match = fib6_rule_match,
335349
.suppress = fib6_rule_suppress,
336350
.configure = fib6_rule_configure,
351+
.delete = fib6_rule_delete,
337352
.compare = fib6_rule_compare,
338353
.fill = fib6_rule_fill,
339354
.nlmsg_payload = fib6_rule_nlmsg_payload,
@@ -361,6 +376,7 @@ static int __net_init fib6_rules_net_init(struct net *net)
361376
goto out_fib6_rules_ops;
362377

363378
net->ipv6.fib6_rules_ops = ops;
379+
net->ipv6.fib6_rules_require_fldissect = 0;
364380
out:
365381
return err;
366382

net/ipv6/icmp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
522522
fl6.fl6_icmp_type = type;
523523
fl6.fl6_icmp_code = code;
524524
fl6.flowi6_uid = sock_net_uid(net, NULL);
525-
fl6.mp_hash = rt6_multipath_hash(&fl6, skb);
525+
fl6.mp_hash = rt6_multipath_hash(&fl6, skb, NULL);
526526
security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
527527

528528
sk = icmpv6_xmit_lock(net);

net/ipv6/route.c

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
460460
* case it will always be non-zero. Otherwise now is the time to do it.
461461
*/
462462
if (!fl6->mp_hash)
463-
fl6->mp_hash = rt6_multipath_hash(fl6, NULL);
463+
fl6->mp_hash = rt6_multipath_hash(fl6, NULL, NULL);
464464

465465
if (fl6->mp_hash <= atomic_read(&match->rt6i_nh_upper_bound))
466466
return match;
@@ -1786,10 +1786,12 @@ struct dst_entry *ip6_route_input_lookup(struct net *net,
17861786
EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
17871787

17881788
static void ip6_multipath_l3_keys(const struct sk_buff *skb,
1789-
struct flow_keys *keys)
1789+
struct flow_keys *keys,
1790+
struct flow_keys *flkeys)
17901791
{
17911792
const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
17921793
const struct ipv6hdr *key_iph = outer_iph;
1794+
struct flow_keys *_flkeys = flkeys;
17931795
const struct ipv6hdr *inner_iph;
17941796
const struct icmp6hdr *icmph;
17951797
struct ipv6hdr _inner_iph;
@@ -1811,22 +1813,31 @@ static void ip6_multipath_l3_keys(const struct sk_buff *skb,
18111813
goto out;
18121814

18131815
key_iph = inner_iph;
1816+
_flkeys = NULL;
18141817
out:
18151818
memset(keys, 0, sizeof(*keys));
18161819
keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1817-
keys->addrs.v6addrs.src = key_iph->saddr;
1818-
keys->addrs.v6addrs.dst = key_iph->daddr;
1819-
keys->tags.flow_label = ip6_flowinfo(key_iph);
1820-
keys->basic.ip_proto = key_iph->nexthdr;
1820+
if (_flkeys) {
1821+
keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src;
1822+
keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst;
1823+
keys->tags.flow_label = _flkeys->tags.flow_label;
1824+
keys->basic.ip_proto = _flkeys->basic.ip_proto;
1825+
} else {
1826+
keys->addrs.v6addrs.src = key_iph->saddr;
1827+
keys->addrs.v6addrs.dst = key_iph->daddr;
1828+
keys->tags.flow_label = ip6_flowinfo(key_iph);
1829+
keys->basic.ip_proto = key_iph->nexthdr;
1830+
}
18211831
}
18221832

18231833
/* if skb is set it will be used and fl6 can be NULL */
1824-
u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb)
1834+
u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb,
1835+
struct flow_keys *flkeys)
18251836
{
18261837
struct flow_keys hash_keys;
18271838

18281839
if (skb) {
1829-
ip6_multipath_l3_keys(skb, &hash_keys);
1840+
ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
18301841
return flow_hash_from_keys(&hash_keys) >> 1;
18311842
}
18321843

@@ -1847,12 +1858,17 @@ void ip6_route_input(struct sk_buff *skb)
18471858
.flowi6_mark = skb->mark,
18481859
.flowi6_proto = iph->nexthdr,
18491860
};
1861+
struct flow_keys *flkeys = NULL, _flkeys;
18501862

18511863
tun_info = skb_tunnel_info(skb);
18521864
if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
18531865
fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
1866+
1867+
if (fib6_rules_early_flow_dissect(net, skb, &fl6, &_flkeys))
1868+
flkeys = &_flkeys;
1869+
18541870
if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
1855-
fl6.mp_hash = rt6_multipath_hash(&fl6, skb);
1871+
fl6.mp_hash = rt6_multipath_hash(&fl6, skb, flkeys);
18561872
skb_dst_drop(skb);
18571873
skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
18581874
}

0 commit comments

Comments
 (0)