Commit e7030878 authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller

fib: Add fib rule match on tunnel id

This add the ability to select a routing table based on the tunnel
id which allows to maintain separate routing tables for each virtual
tunnel network.

ip rule add from all tunnel-id 100 lookup 100
ip rule add from all tunnel-id 200 lookup 200

A new static key controls the collection of metadata at tunnel level
upon demand.
Signed-off-by: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3093fbe7
...@@ -143,7 +143,8 @@ static struct workqueue_struct *vxlan_wq; ...@@ -143,7 +143,8 @@ static struct workqueue_struct *vxlan_wq;
static inline bool vxlan_collect_metadata(struct vxlan_sock *vs) static inline bool vxlan_collect_metadata(struct vxlan_sock *vs)
{ {
return vs->flags & VXLAN_F_COLLECT_METADATA; return vs->flags & VXLAN_F_COLLECT_METADATA ||
ip_tunnel_collect_metadata();
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
......
...@@ -19,6 +19,7 @@ struct fib_rule { ...@@ -19,6 +19,7 @@ struct fib_rule {
u8 action; u8 action;
/* 3 bytes hole, try to use */ /* 3 bytes hole, try to use */
u32 target; u32 target;
__be64 tun_id;
struct fib_rule __rcu *ctarget; struct fib_rule __rcu *ctarget;
struct net *fr_net; struct net *fr_net;
......
...@@ -303,6 +303,17 @@ static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstat ...@@ -303,6 +303,17 @@ static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstat
return (struct ip_tunnel_info *)lwtstate->data; return (struct ip_tunnel_info *)lwtstate->data;
} }
extern struct static_key ip_tunnel_metadata_cnt;
/* Returns > 0 if metadata should be collected */
static inline int ip_tunnel_collect_metadata(void)
{
return static_key_false(&ip_tunnel_metadata_cnt);
}
void ip_tunnel_need_metadata(void);
void ip_tunnel_unneed_metadata(void);
#endif /* CONFIG_INET */ #endif /* CONFIG_INET */
#endif /* __NET_IP_TUNNELS_H */ #endif /* __NET_IP_TUNNELS_H */
...@@ -43,7 +43,7 @@ enum { ...@@ -43,7 +43,7 @@ enum {
FRA_UNUSED5, FRA_UNUSED5,
FRA_FWMARK, /* mark */ FRA_FWMARK, /* mark */
FRA_FLOW, /* flow/class id */ FRA_FLOW, /* flow/class id */
FRA_UNUSED6, FRA_TUN_ID,
FRA_SUPPRESS_IFGROUP, FRA_SUPPRESS_IFGROUP,
FRA_SUPPRESS_PREFIXLEN, FRA_SUPPRESS_PREFIXLEN,
FRA_TABLE, /* Extended table id */ FRA_TABLE, /* Extended table id */
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/fib_rules.h> #include <net/fib_rules.h>
#include <net/ip_tunnels.h>
int fib_default_rule_add(struct fib_rules_ops *ops, int fib_default_rule_add(struct fib_rules_ops *ops,
u32 pref, u32 table, u32 flags) u32 pref, u32 table, u32 flags)
...@@ -186,6 +187,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, ...@@ -186,6 +187,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
if ((rule->mark ^ fl->flowi_mark) & rule->mark_mask) if ((rule->mark ^ fl->flowi_mark) & rule->mark_mask)
goto out; goto out;
if (rule->tun_id && (rule->tun_id != fl->flowi_tun_key.tun_id))
goto out;
ret = ops->match(rule, fl, flags); ret = ops->match(rule, fl, flags);
out: out:
return (rule->flags & FIB_RULE_INVERT) ? !ret : ret; return (rule->flags & FIB_RULE_INVERT) ? !ret : ret;
...@@ -330,6 +334,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh) ...@@ -330,6 +334,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
if (tb[FRA_FWMASK]) if (tb[FRA_FWMASK])
rule->mark_mask = nla_get_u32(tb[FRA_FWMASK]); rule->mark_mask = nla_get_u32(tb[FRA_FWMASK]);
if (tb[FRA_TUN_ID])
rule->tun_id = nla_get_be64(tb[FRA_TUN_ID]);
rule->action = frh->action; rule->action = frh->action;
rule->flags = frh->flags; rule->flags = frh->flags;
rule->table = frh_get_table(frh, tb); rule->table = frh_get_table(frh, tb);
...@@ -407,6 +414,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh) ...@@ -407,6 +414,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
if (unresolved) if (unresolved)
ops->unresolved_rules++; ops->unresolved_rules++;
if (rule->tun_id)
ip_tunnel_need_metadata();
notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).portid); notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).portid);
flush_route_cache(ops); flush_route_cache(ops);
rules_ops_put(ops); rules_ops_put(ops);
...@@ -473,6 +483,10 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh) ...@@ -473,6 +483,10 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
(rule->mark_mask != nla_get_u32(tb[FRA_FWMASK]))) (rule->mark_mask != nla_get_u32(tb[FRA_FWMASK])))
continue; continue;
if (tb[FRA_TUN_ID] &&
(rule->tun_id != nla_get_be64(tb[FRA_TUN_ID])))
continue;
if (!ops->compare(rule, frh, tb)) if (!ops->compare(rule, frh, tb))
continue; continue;
...@@ -487,6 +501,9 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh) ...@@ -487,6 +501,9 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
goto errout; goto errout;
} }
if (rule->tun_id)
ip_tunnel_unneed_metadata();
list_del_rcu(&rule->list); list_del_rcu(&rule->list);
if (rule->action == FR_ACT_GOTO) { if (rule->action == FR_ACT_GOTO) {
...@@ -535,7 +552,8 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, ...@@ -535,7 +552,8 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
+ nla_total_size(4) /* FRA_SUPPRESS_PREFIXLEN */ + nla_total_size(4) /* FRA_SUPPRESS_PREFIXLEN */
+ nla_total_size(4) /* FRA_SUPPRESS_IFGROUP */ + nla_total_size(4) /* FRA_SUPPRESS_IFGROUP */
+ nla_total_size(4) /* FRA_FWMARK */ + nla_total_size(4) /* FRA_FWMARK */
+ nla_total_size(4); /* FRA_FWMASK */ + nla_total_size(4) /* FRA_FWMASK */
+ nla_total_size(8); /* FRA_TUN_ID */
if (ops->nlmsg_payload) if (ops->nlmsg_payload)
payload += ops->nlmsg_payload(rule); payload += ops->nlmsg_payload(rule);
...@@ -591,7 +609,9 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, ...@@ -591,7 +609,9 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
((rule->mark_mask || rule->mark) && ((rule->mark_mask || rule->mark) &&
nla_put_u32(skb, FRA_FWMASK, rule->mark_mask)) || nla_put_u32(skb, FRA_FWMASK, rule->mark_mask)) ||
(rule->target && (rule->target &&
nla_put_u32(skb, FRA_GOTO, rule->target))) nla_put_u32(skb, FRA_GOTO, rule->target)) ||
(rule->tun_id &&
nla_put_be64(skb, FRA_TUN_ID, rule->tun_id)))
goto nla_put_failure; goto nla_put_failure;
if (rule->suppress_ifgroup != -1) { if (rule->suppress_ifgroup != -1) {
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/static_key.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/icmp.h> #include <net/icmp.h>
...@@ -304,3 +305,18 @@ static void __exit ip_tunnel_core_exit(void) ...@@ -304,3 +305,18 @@ static void __exit ip_tunnel_core_exit(void)
lwtunnel_encap_del_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); lwtunnel_encap_del_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP);
} }
module_exit(ip_tunnel_core_exit); module_exit(ip_tunnel_core_exit);
struct static_key ip_tunnel_metadata_cnt = STATIC_KEY_INIT_FALSE;
EXPORT_SYMBOL(ip_tunnel_metadata_cnt);
void ip_tunnel_need_metadata(void)
{
static_key_slow_inc(&ip_tunnel_metadata_cnt);
}
EXPORT_SYMBOL_GPL(ip_tunnel_need_metadata);
void ip_tunnel_unneed_metadata(void)
{
static_key_slow_dec(&ip_tunnel_metadata_cnt);
}
EXPORT_SYMBOL_GPL(ip_tunnel_unneed_metadata);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment