forked from mirrors/linux
		
	The fundamental premise of VRF and l3mdev core code is binding a socket
to a device (l3mdev or netdev with an L3 domain) to indicate L3 scope.
Legacy code resets flowi_oif to the l3mdev losing any original port
device binding. Ben (among others) has demonstrated use cases where the
original port device binding is important and needs to be retained.
This patch handles that by adding a new entry to the common flow struct
that can indicate the l3mdev index for later rule and table matching
avoiding the need to reset flowi_oif.
In addition to allowing more use cases that require port device binds,
this patch brings a few datapath simplications:
1. l3mdev_fib_rule_match is only called when walking fib rules and
   always after l3mdev_update_flow. That allows an optimization to bail
   early for non-VRF type uses cases when flowi_l3mdev is not set. Also,
   only that index needs to be checked for the FIB table id.
2. l3mdev_update_flow can be called with flowi_oif set to a l3mdev
   (e.g., VRF) device. By resetting flowi_oif only for this case the
   FLOWI_FLAG_SKIP_NH_OIF flag is not longer needed and can be removed,
   removing several checks in the datapath. The flowi_iif path can be
   simplified to only be called if the it is not loopback (loopback can
   not be assigned to an L3 domain) and the l3mdev index is not already
   set.
3. Avoid another device lookup in the output path when the fib lookup
   returns a reject failure.
Note: 2 functional tests for local traffic with reject fib rules are
updated to reflect the new direct failure at FIB lookup time for ping
rather than the failure on packet path. The current code fails like this:
    HINT: Fails since address on vrf device is out of device scope
    COMMAND: ip netns exec ns-A ping -c1 -w1 -I eth1 172.16.3.1
    ping: Warning: source address might be selected on device other than: eth1
    PING 172.16.3.1 (172.16.3.1) from 172.16.3.1 eth1: 56(84) bytes of data.
    --- 172.16.3.1 ping statistics ---
    1 packets transmitted, 0 received, 100% packet loss, time 0ms
where the test now directly fails:
    HINT: Fails since address on vrf device is out of device scope
    COMMAND: ip netns exec ns-A ping -c1 -w1 -I eth1 172.16.3.1
    ping: connect: No route to host
Signed-off-by: David Ahern <dsahern@kernel.org>
Tested-by: Ben Greear <greearb@candelatech.com>
Link: https://lore.kernel.org/r/20220314204551.16369-1-dsahern@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
		
	
			
		
			
				
	
	
		
			221 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* SPDX-License-Identifier: GPL-2.0 */
 | 
						|
/*
 | 
						|
 *
 | 
						|
 *	Generic internet FLOW.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef _NET_FLOW_H
 | 
						|
#define _NET_FLOW_H
 | 
						|
 | 
						|
#include <linux/socket.h>
 | 
						|
#include <linux/in6.h>
 | 
						|
#include <linux/atomic.h>
 | 
						|
#include <net/flow_dissector.h>
 | 
						|
#include <linux/uidgid.h>
 | 
						|
 | 
						|
/*
 | 
						|
 * ifindex generation is per-net namespace, and loopback is
 | 
						|
 * always the 1st device in ns (see net_dev_init), thus any
 | 
						|
 * loopback device should get ifindex 1
 | 
						|
 */
 | 
						|
 | 
						|
#define LOOPBACK_IFINDEX	1
 | 
						|
 | 
						|
struct flowi_tunnel {
 | 
						|
	__be64			tun_id;
 | 
						|
};
 | 
						|
 | 
						|
struct flowi_common {
 | 
						|
	int	flowic_oif;
 | 
						|
	int	flowic_iif;
 | 
						|
	int     flowic_l3mdev;
 | 
						|
	__u32	flowic_mark;
 | 
						|
	__u8	flowic_tos;
 | 
						|
	__u8	flowic_scope;
 | 
						|
	__u8	flowic_proto;
 | 
						|
	__u8	flowic_flags;
 | 
						|
#define FLOWI_FLAG_ANYSRC		0x01
 | 
						|
#define FLOWI_FLAG_KNOWN_NH		0x02
 | 
						|
	__u32	flowic_secid;
 | 
						|
	kuid_t  flowic_uid;
 | 
						|
	struct flowi_tunnel flowic_tun_key;
 | 
						|
	__u32		flowic_multipath_hash;
 | 
						|
};
 | 
						|
 | 
						|
union flowi_uli {
 | 
						|
	struct {
 | 
						|
		__be16	dport;
 | 
						|
		__be16	sport;
 | 
						|
	} ports;
 | 
						|
 | 
						|
	struct {
 | 
						|
		__u8	type;
 | 
						|
		__u8	code;
 | 
						|
	} icmpt;
 | 
						|
 | 
						|
	struct {
 | 
						|
		__le16	dport;
 | 
						|
		__le16	sport;
 | 
						|
	} dnports;
 | 
						|
 | 
						|
	__be32		gre_key;
 | 
						|
 | 
						|
	struct {
 | 
						|
		__u8	type;
 | 
						|
	} mht;
 | 
						|
};
 | 
						|
 | 
						|
struct flowi4 {
 | 
						|
	struct flowi_common	__fl_common;
 | 
						|
#define flowi4_oif		__fl_common.flowic_oif
 | 
						|
#define flowi4_iif		__fl_common.flowic_iif
 | 
						|
#define flowi4_l3mdev		__fl_common.flowic_l3mdev
 | 
						|
#define flowi4_mark		__fl_common.flowic_mark
 | 
						|
#define flowi4_tos		__fl_common.flowic_tos
 | 
						|
#define flowi4_scope		__fl_common.flowic_scope
 | 
						|
#define flowi4_proto		__fl_common.flowic_proto
 | 
						|
#define flowi4_flags		__fl_common.flowic_flags
 | 
						|
#define flowi4_secid		__fl_common.flowic_secid
 | 
						|
#define flowi4_tun_key		__fl_common.flowic_tun_key
 | 
						|
#define flowi4_uid		__fl_common.flowic_uid
 | 
						|
#define flowi4_multipath_hash	__fl_common.flowic_multipath_hash
 | 
						|
 | 
						|
	/* (saddr,daddr) must be grouped, same order as in IP header */
 | 
						|
	__be32			saddr;
 | 
						|
	__be32			daddr;
 | 
						|
 | 
						|
	union flowi_uli		uli;
 | 
						|
#define fl4_sport		uli.ports.sport
 | 
						|
#define fl4_dport		uli.ports.dport
 | 
						|
#define fl4_icmp_type		uli.icmpt.type
 | 
						|
#define fl4_icmp_code		uli.icmpt.code
 | 
						|
#define fl4_mh_type		uli.mht.type
 | 
						|
#define fl4_gre_key		uli.gre_key
 | 
						|
} __attribute__((__aligned__(BITS_PER_LONG/8)));
 | 
						|
 | 
						|
static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
 | 
						|
				      __u32 mark, __u8 tos, __u8 scope,
 | 
						|
				      __u8 proto, __u8 flags,
 | 
						|
				      __be32 daddr, __be32 saddr,
 | 
						|
				      __be16 dport, __be16 sport,
 | 
						|
				      kuid_t uid)
 | 
						|
{
 | 
						|
	fl4->flowi4_oif = oif;
 | 
						|
	fl4->flowi4_iif = LOOPBACK_IFINDEX;
 | 
						|
	fl4->flowi4_l3mdev = 0;
 | 
						|
	fl4->flowi4_mark = mark;
 | 
						|
	fl4->flowi4_tos = tos;
 | 
						|
	fl4->flowi4_scope = scope;
 | 
						|
	fl4->flowi4_proto = proto;
 | 
						|
	fl4->flowi4_flags = flags;
 | 
						|
	fl4->flowi4_secid = 0;
 | 
						|
	fl4->flowi4_tun_key.tun_id = 0;
 | 
						|
	fl4->flowi4_uid = uid;
 | 
						|
	fl4->daddr = daddr;
 | 
						|
	fl4->saddr = saddr;
 | 
						|
	fl4->fl4_dport = dport;
 | 
						|
	fl4->fl4_sport = sport;
 | 
						|
	fl4->flowi4_multipath_hash = 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Reset some input parameters after previous lookup */
 | 
						|
static inline void flowi4_update_output(struct flowi4 *fl4, int oif, __u8 tos,
 | 
						|
					__be32 daddr, __be32 saddr)
 | 
						|
{
 | 
						|
	fl4->flowi4_oif = oif;
 | 
						|
	fl4->flowi4_tos = tos;
 | 
						|
	fl4->daddr = daddr;
 | 
						|
	fl4->saddr = saddr;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
struct flowi6 {
 | 
						|
	struct flowi_common	__fl_common;
 | 
						|
#define flowi6_oif		__fl_common.flowic_oif
 | 
						|
#define flowi6_iif		__fl_common.flowic_iif
 | 
						|
#define flowi6_l3mdev		__fl_common.flowic_l3mdev
 | 
						|
#define flowi6_mark		__fl_common.flowic_mark
 | 
						|
#define flowi6_scope		__fl_common.flowic_scope
 | 
						|
#define flowi6_proto		__fl_common.flowic_proto
 | 
						|
#define flowi6_flags		__fl_common.flowic_flags
 | 
						|
#define flowi6_secid		__fl_common.flowic_secid
 | 
						|
#define flowi6_tun_key		__fl_common.flowic_tun_key
 | 
						|
#define flowi6_uid		__fl_common.flowic_uid
 | 
						|
	struct in6_addr		daddr;
 | 
						|
	struct in6_addr		saddr;
 | 
						|
	/* Note: flowi6_tos is encoded in flowlabel, too. */
 | 
						|
	__be32			flowlabel;
 | 
						|
	union flowi_uli		uli;
 | 
						|
#define fl6_sport		uli.ports.sport
 | 
						|
#define fl6_dport		uli.ports.dport
 | 
						|
#define fl6_icmp_type		uli.icmpt.type
 | 
						|
#define fl6_icmp_code		uli.icmpt.code
 | 
						|
#define fl6_mh_type		uli.mht.type
 | 
						|
#define fl6_gre_key		uli.gre_key
 | 
						|
	__u32			mp_hash;
 | 
						|
} __attribute__((__aligned__(BITS_PER_LONG/8)));
 | 
						|
 | 
						|
struct flowidn {
 | 
						|
	struct flowi_common	__fl_common;
 | 
						|
#define flowidn_oif		__fl_common.flowic_oif
 | 
						|
#define flowidn_iif		__fl_common.flowic_iif
 | 
						|
#define flowidn_mark		__fl_common.flowic_mark
 | 
						|
#define flowidn_scope		__fl_common.flowic_scope
 | 
						|
#define flowidn_proto		__fl_common.flowic_proto
 | 
						|
#define flowidn_flags		__fl_common.flowic_flags
 | 
						|
	__le16			daddr;
 | 
						|
	__le16			saddr;
 | 
						|
	union flowi_uli		uli;
 | 
						|
#define fld_sport		uli.ports.sport
 | 
						|
#define fld_dport		uli.ports.dport
 | 
						|
} __attribute__((__aligned__(BITS_PER_LONG/8)));
 | 
						|
 | 
						|
struct flowi {
 | 
						|
	union {
 | 
						|
		struct flowi_common	__fl_common;
 | 
						|
		struct flowi4		ip4;
 | 
						|
		struct flowi6		ip6;
 | 
						|
		struct flowidn		dn;
 | 
						|
	} u;
 | 
						|
#define flowi_oif	u.__fl_common.flowic_oif
 | 
						|
#define flowi_iif	u.__fl_common.flowic_iif
 | 
						|
#define flowi_l3mdev	u.__fl_common.flowic_l3mdev
 | 
						|
#define flowi_mark	u.__fl_common.flowic_mark
 | 
						|
#define flowi_tos	u.__fl_common.flowic_tos
 | 
						|
#define flowi_scope	u.__fl_common.flowic_scope
 | 
						|
#define flowi_proto	u.__fl_common.flowic_proto
 | 
						|
#define flowi_flags	u.__fl_common.flowic_flags
 | 
						|
#define flowi_secid	u.__fl_common.flowic_secid
 | 
						|
#define flowi_tun_key	u.__fl_common.flowic_tun_key
 | 
						|
#define flowi_uid	u.__fl_common.flowic_uid
 | 
						|
} __attribute__((__aligned__(BITS_PER_LONG/8)));
 | 
						|
 | 
						|
static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4)
 | 
						|
{
 | 
						|
	return container_of(fl4, struct flowi, u.ip4);
 | 
						|
}
 | 
						|
 | 
						|
static inline struct flowi_common *flowi4_to_flowi_common(struct flowi4 *fl4)
 | 
						|
{
 | 
						|
	return &(fl4->__fl_common);
 | 
						|
}
 | 
						|
 | 
						|
static inline struct flowi *flowi6_to_flowi(struct flowi6 *fl6)
 | 
						|
{
 | 
						|
	return container_of(fl6, struct flowi, u.ip6);
 | 
						|
}
 | 
						|
 | 
						|
static inline struct flowi_common *flowi6_to_flowi_common(struct flowi6 *fl6)
 | 
						|
{
 | 
						|
	return &(fl6->__fl_common);
 | 
						|
}
 | 
						|
 | 
						|
static inline struct flowi *flowidn_to_flowi(struct flowidn *fldn)
 | 
						|
{
 | 
						|
	return container_of(fldn, struct flowi, u.dn);
 | 
						|
}
 | 
						|
 | 
						|
__u32 __get_hash_from_flowi6(const struct flowi6 *fl6, struct flow_keys *keys);
 | 
						|
 | 
						|
#endif
 |