This patch is to add LWTUNNEL_IP_OPTS into lwtunnel_ip_t, by which users will be able to set options for ip_tunnel_info by "ip route encap" for erspan and vxlan's private metadata. Like one way to go in iproute is:
# ip route add 1.1.1.0/24 encap ip id 1 erspan ver 1 idx 123 \ dst 10.1.0.2 dev erspan1 # ip route show 1.1.1.0/24 encap ip id 1 src 0.0.0.0 dst 10.1.0.2 ttl 0 \ tos 0 erspan ver 1 idx 123 dev erspan1 scope link Signed-off-by: Xin Long <lucien....@gmail.com> --- include/uapi/linux/lwtunnel.h | 1 + net/ipv4/ip_tunnel_core.c | 30 ++++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h index de696ca..93f2c05 100644 --- a/include/uapi/linux/lwtunnel.h +++ b/include/uapi/linux/lwtunnel.h @@ -27,6 +27,7 @@ enum lwtunnel_ip_t { LWTUNNEL_IP_TOS, LWTUNNEL_IP_FLAGS, LWTUNNEL_IP_PAD, + LWTUNNEL_IP_OPTS, __LWTUNNEL_IP_MAX, }; diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 10f0848..d9b7188 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -218,6 +218,7 @@ static const struct nla_policy ip_tun_policy[LWTUNNEL_IP_MAX + 1] = { [LWTUNNEL_IP_TTL] = { .type = NLA_U8 }, [LWTUNNEL_IP_TOS] = { .type = NLA_U8 }, [LWTUNNEL_IP_FLAGS] = { .type = NLA_U16 }, + [LWTUNNEL_IP_OPTS] = { .type = NLA_BINARY }, }; static int ip_tun_build_state(struct nlattr *attr, @@ -228,14 +229,20 @@ static int ip_tun_build_state(struct nlattr *attr, struct ip_tunnel_info *tun_info; struct lwtunnel_state *new_state; struct nlattr *tb[LWTUNNEL_IP_MAX + 1]; - int err; + int err, opts_len = 0; + void *opts; err = nla_parse_nested_deprecated(tb, LWTUNNEL_IP_MAX, attr, ip_tun_policy, extack); if (err < 0) return err; - new_state = lwtunnel_state_alloc(sizeof(*tun_info)); + if (tb[LWTUNNEL_IP_OPTS]) { + opts = nla_data(tb[LWTUNNEL_IP_OPTS]); + opts_len = nla_len(tb[LWTUNNEL_IP_OPTS]); + } + + new_state = lwtunnel_state_alloc(sizeof(*tun_info) + opts_len); if (!new_state) return -ENOMEM; @@ -269,8 +276,10 @@ static int ip_tun_build_state(struct nlattr *attr, if (tb[LWTUNNEL_IP_FLAGS]) tun_info->key.tun_flags = nla_get_be16(tb[LWTUNNEL_IP_FLAGS]); + if (opts_len) + ip_tunnel_info_opts_set(tun_info, opts, opts_len, 0); + tun_info->mode = IP_TUNNEL_INFO_TX; - tun_info->options_len = 0; *ts = new_state; @@ -299,6 +308,10 @@ static int ip_tun_fill_encap_info(struct sk_buff *skb, nla_put_u8(skb, LWTUNNEL_IP_TTL, tun_info->key.ttl) || nla_put_be16(skb, LWTUNNEL_IP_FLAGS, tun_info->key.tun_flags)) return -ENOMEM; + if (tun_info->options_len && + nla_put(skb, LWTUNNEL_IP_OPTS, + tun_info->options_len, ip_tunnel_info_opts(tun_info))) + return -ENOMEM; return 0; } @@ -310,13 +323,18 @@ static int ip_tun_encap_nlsize(struct lwtunnel_state *lwtstate) + nla_total_size(4) /* LWTUNNEL_IP_SRC */ + nla_total_size(1) /* LWTUNNEL_IP_TOS */ + nla_total_size(1) /* LWTUNNEL_IP_TTL */ - + nla_total_size(2); /* LWTUNNEL_IP_FLAGS */ + + nla_total_size(2) /* LWTUNNEL_IP_FLAGS */ + + lwt_tun_info(lwtstate)->options_len; /* LWTUNNEL_IP_OPTS */ } static int ip_tun_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b) { - return memcmp(lwt_tun_info(a), lwt_tun_info(b), - sizeof(struct ip_tunnel_info)); + struct ip_tunnel_info *info_a = lwt_tun_info(a); + struct ip_tunnel_info *info_b = lwt_tun_info(b); + u8 opts_len; + + opts_len = min(info_a->options_len, info_b->options_len); + return memcmp(info_a, info_b, sizeof(*info_a) + opts_len); } static const struct lwtunnel_encap_ops ip_tun_lwt_ops = { -- 2.1.0