net: check tunnel option type in tunnel flags

Check the tunnel option type stored in tunnel flags when creating options
for tunnels. Thereby ensuring we do not set geneve, vxlan or erspan tunnel
options on interfaces that are not associated with them.

Make sure all users of the infrastructure set correct flags, for the BPF
helper we have to set all bits to keep backward compatibility.

Signed-off-by: Pieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Pieter Jansen van Vuuren 2018-06-26 21:39:36 -07:00 коммит произвёл David S. Miller
Родитель 9d7298cd1d
Коммит 256c87c17c
7 изменённых файлов: 23 добавлений и 7 удалений

Просмотреть файл

@ -236,7 +236,8 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
} }
/* Update tunnel dst according to Geneve options. */ /* Update tunnel dst according to Geneve options. */
ip_tunnel_info_opts_set(&tun_dst->u.tun_info, ip_tunnel_info_opts_set(&tun_dst->u.tun_info,
gnvh->options, gnvh->opt_len * 4); gnvh->options, gnvh->opt_len * 4,
TUNNEL_GENEVE_OPT);
} else { } else {
/* Drop packets w/ critical options, /* Drop packets w/ critical options,
* since we don't support any... * since we don't support any...
@ -675,7 +676,8 @@ static void geneve_build_header(struct genevehdr *geneveh,
geneveh->proto_type = htons(ETH_P_TEB); geneveh->proto_type = htons(ETH_P_TEB);
geneveh->rsvd2 = 0; geneveh->rsvd2 = 0;
ip_tunnel_info_opts_get(geneveh->options, info); if (info->key.tun_flags & TUNNEL_GENEVE_OPT)
ip_tunnel_info_opts_get(geneveh->options, info);
} }
static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb, static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,

Просмотреть файл

@ -2122,7 +2122,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
vni = tunnel_id_to_key32(info->key.tun_id); vni = tunnel_id_to_key32(info->key.tun_id);
ifindex = 0; ifindex = 0;
dst_cache = &info->dst_cache; dst_cache = &info->dst_cache;
if (info->options_len) if (info->options_len &&
info->key.tun_flags & TUNNEL_VXLAN_OPT)
md = ip_tunnel_info_opts(info); md = ip_tunnel_info_opts(info);
ttl = info->key.ttl; ttl = info->key.ttl;
tos = info->key.tos; tos = info->key.tos;

Просмотреть файл

@ -466,10 +466,12 @@ static inline void ip_tunnel_info_opts_get(void *to,
} }
static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info, static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info,
const void *from, int len) const void *from, int len,
__be16 flags)
{ {
memcpy(ip_tunnel_info_opts(info), from, len); memcpy(ip_tunnel_info_opts(info), from, len);
info->options_len = len; info->options_len = len;
info->key.tun_flags |= flags;
} }
static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstate) static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstate)
@ -511,9 +513,11 @@ static inline void ip_tunnel_info_opts_get(void *to,
} }
static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info, static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info,
const void *from, int len) const void *from, int len,
__be16 flags)
{ {
info->options_len = 0; info->options_len = 0;
info->key.tun_flags |= flags;
} }
#endif /* CONFIG_INET */ #endif /* CONFIG_INET */

Просмотреть файл

@ -3582,7 +3582,7 @@ BPF_CALL_3(bpf_skb_set_tunnel_opt, struct sk_buff *, skb,
if (unlikely(size > IP_TUNNEL_OPTS_MAX)) if (unlikely(size > IP_TUNNEL_OPTS_MAX))
return -ENOMEM; return -ENOMEM;
ip_tunnel_info_opts_set(info, from, size); ip_tunnel_info_opts_set(info, from, size, TUNNEL_OPTIONS_PRESENT);
return 0; return 0;
} }

Просмотреть файл

@ -587,6 +587,8 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
goto err_free_skb; goto err_free_skb;
key = &tun_info->key; key = &tun_info->key;
if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT))
goto err_free_rt;
md = ip_tunnel_info_opts(tun_info); md = ip_tunnel_info_opts(tun_info);
if (!md) if (!md)
goto err_free_rt; goto err_free_rt;

Просмотреть файл

@ -990,6 +990,8 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
dsfield = key->tos; dsfield = key->tos;
if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT))
goto tx_err;
md = ip_tunnel_info_opts(tun_info); md = ip_tunnel_info_opts(tun_info);
if (!md) if (!md)
goto tx_err; goto tx_err;

Просмотреть файл

@ -2516,7 +2516,9 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
struct ovs_tunnel_info *ovs_tun; struct ovs_tunnel_info *ovs_tun;
struct nlattr *a; struct nlattr *a;
int err = 0, start, opts_type; int err = 0, start, opts_type;
__be16 dst_opt_type;
dst_opt_type = 0;
ovs_match_init(&match, &key, true, NULL); ovs_match_init(&match, &key, true, NULL);
opts_type = ip_tun_from_nlattr(nla_data(attr), &match, false, log); opts_type = ip_tun_from_nlattr(nla_data(attr), &match, false, log);
if (opts_type < 0) if (opts_type < 0)
@ -2528,10 +2530,13 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
err = validate_geneve_opts(&key); err = validate_geneve_opts(&key);
if (err < 0) if (err < 0)
return err; return err;
dst_opt_type = TUNNEL_GENEVE_OPT;
break; break;
case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS: case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
dst_opt_type = TUNNEL_VXLAN_OPT;
break; break;
case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS: case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS:
dst_opt_type = TUNNEL_ERSPAN_OPT;
break; break;
} }
} }
@ -2574,7 +2579,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
*/ */
ip_tunnel_info_opts_set(tun_info, ip_tunnel_info_opts_set(tun_info,
TUN_METADATA_OPTS(&key, key.tun_opts_len), TUN_METADATA_OPTS(&key, key.tun_opts_len),
key.tun_opts_len); key.tun_opts_len, dst_opt_type);
add_nested_action_end(*sfa, start); add_nested_action_end(*sfa, start);
return err; return err;