Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a25724b0 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'fib_rules-support-sport-dport-and-proto-match'



Roopa Prabhu says:

====================
fib_rules: support sport, dport and proto match

This series extends fib rule match support to include sport, dport
and ip proto match (to complete the 5-tuple match support).
Common use-cases of Policy based routing in the data center require
5-tuple match. The last 2 patches in the series add a call to flow dissect
in the fwd path if required by the installed fib rules (controlled by a flag).

v1:
  - Fix errors reported by kbuild and feedback on RFC
  - extend port match uapi to accomodate port ranges

v2:
  - address comments from Nikolay, David Ahern and Paolo (Thanks!)

Pending things I will submit separate patches for:
  - extack for fib rules
  - fib rules test (as requested by david ahern)
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 29274991 5e5d6fed
Loading
Loading
Loading
Loading
+35 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ struct fib_rule {
	u8			action;
	u8			l3mdev;
	u8                      proto;
	/* 1 byte hole, try to use */
	u8			ip_proto;
	u32			target;
	__be64			tun_id;
	struct fib_rule __rcu	*ctarget;
@@ -40,6 +40,8 @@ struct fib_rule {
	char			iifname[IFNAMSIZ];
	char			oifname[IFNAMSIZ];
	struct fib_kuid_range	uid_range;
	struct fib_rule_port_range	sport_range;
	struct fib_rule_port_range	dport_range;
	struct rcu_head		rcu;
};

@@ -144,6 +146,38 @@ static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla)
	return frh->table;
}

static inline bool fib_rule_port_range_set(const struct fib_rule_port_range *range)
{
	return range->start != 0 && range->end != 0;
}

static inline bool fib_rule_port_inrange(const struct fib_rule_port_range *a,
					 __be16 port)
{
	return ntohs(port) >= a->start &&
		ntohs(port) <= a->end;
}

static inline bool fib_rule_port_range_valid(const struct fib_rule_port_range *a)
{
	return a->start != 0 && a->end != 0 && a->end < 0xffff &&
		a->start <= a->end;
}

static inline bool fib_rule_port_range_compare(struct fib_rule_port_range *a,
					       struct fib_rule_port_range *b)
{
	return a->start == b->start &&
		a->end == b->end;
}

static inline bool fib_rule_requires_fldissect(struct fib_rule *rule)
{
	return rule->ip_proto ||
		fib_rule_port_range_set(&rule->sport_range) ||
		fib_rule_port_range_set(&rule->dport_range);
}

struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *,
					 struct net *);
void fib_rules_unregister(struct fib_rules_ops *);
+25 −0
Original line number Diff line number Diff line
@@ -415,6 +415,24 @@ void fib6_rules_cleanup(void);
bool fib6_rule_default(const struct fib_rule *rule);
int fib6_rules_dump(struct net *net, struct notifier_block *nb);
unsigned int fib6_rules_seq_read(struct net *net);

static inline bool fib6_rules_early_flow_dissect(struct net *net,
						 struct sk_buff *skb,
						 struct flowi6 *fl6,
						 struct flow_keys *flkeys)
{
	unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;

	if (!net->ipv6.fib6_rules_require_fldissect)
		return false;

	skb_flow_dissect_flow_keys(skb, flkeys, flag);
	fl6->fl6_sport = flkeys->ports.src;
	fl6->fl6_dport = flkeys->ports.dst;
	fl6->flowi6_proto = flkeys->basic.ip_proto;

	return true;
}
#else
static inline int               fib6_rules_init(void)
{
@@ -436,5 +454,12 @@ static inline unsigned int fib6_rules_seq_read(struct net *net)
{
	return 0;
}
static inline bool fib6_rules_early_flow_dissect(struct net *net,
						 struct sk_buff *skb,
						 struct flowi6 *fl6,
						 struct flow_keys *flkeys)
{
	return false;
}
#endif
#endif
+3 −1
Original line number Diff line number Diff line
@@ -127,7 +127,8 @@ static inline int ip6_route_get_saddr(struct net *net, struct rt6_info *rt,

struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
			    const struct in6_addr *saddr, int oif, int flags);
u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb);
u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb,
		       struct flow_keys *hkeys);

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

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

#endif
+26 −1
Original line number Diff line number Diff line
@@ -293,6 +293,13 @@ static inline unsigned int fib4_rules_seq_read(struct net *net)
	return 0;
}

static inline bool fib4_rules_early_flow_dissect(struct net *net,
						 struct sk_buff *skb,
						 struct flowi4 *fl4,
						 struct flow_keys *flkeys)
{
	return false;
}
#else /* CONFIG_IP_MULTIPLE_TABLES */
int __net_init fib4_rules_init(struct net *net);
void __net_exit fib4_rules_exit(struct net *net);
@@ -341,6 +348,24 @@ bool fib4_rule_default(const struct fib_rule *rule);
int fib4_rules_dump(struct net *net, struct notifier_block *nb);
unsigned int fib4_rules_seq_read(struct net *net);

static inline bool fib4_rules_early_flow_dissect(struct net *net,
						 struct sk_buff *skb,
						 struct flowi4 *fl4,
						 struct flow_keys *flkeys)
{
	unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;

	if (!net->ipv4.fib_rules_require_fldissect)
		return false;

	skb_flow_dissect_flow_keys(skb, flkeys, flag);
	fl4->fl4_sport = flkeys->ports.src;
	fl4->fl4_dport = flkeys->ports.dst;
	fl4->flowi4_proto = flkeys->basic.ip_proto;

	return true;
}

#endif /* CONFIG_IP_MULTIPLE_TABLES */

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

#ifdef CONFIG_IP_ROUTE_MULTIPATH
int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
		       const struct sk_buff *skb);
		       const struct sk_buff *skb, struct flow_keys *flkeys);
#endif
void fib_select_multipath(struct fib_result *res, int hash);
void fib_select_path(struct net *net, struct fib_result *res,
+1 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ struct netns_ipv4 {
#ifdef CONFIG_IP_MULTIPLE_TABLES
	struct fib_rules_ops	*rules_ops;
	bool			fib_has_custom_rules;
	unsigned int		fib_rules_require_fldissect;
	struct fib_table __rcu	*fib_main;
	struct fib_table __rcu	*fib_default;
#endif
Loading