openvswitch: netlink attributes for IPv6 tunneling

Add netlink attributes for IPv6 tunnel addresses. This enables IPv6 support
for tunnels.

Signed-off-by: Jiri Benc <jbenc@redhat.com>
Acked-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jiri Benc 2015-10-05 13:09:47 +02:00 committed by David S. Miller
parent 00a93babd0
commit 6b26ba3a7d
2 changed files with 86 additions and 37 deletions

View File

@ -349,6 +349,8 @@ enum ovs_tunnel_key_attr {
OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */ OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */
OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */ OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */
OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS, /* Nested OVS_VXLAN_EXT_* */ OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS, /* Nested OVS_VXLAN_EXT_* */
OVS_TUNNEL_KEY_ATTR_IPV6_SRC, /* struct in6_addr src IPv6 address. */
OVS_TUNNEL_KEY_ATTR_IPV6_DST, /* struct in6_addr dst IPv6 address. */
__OVS_TUNNEL_KEY_ATTR_MAX __OVS_TUNNEL_KEY_ATTR_MAX
}; };

View File

@ -262,8 +262,8 @@ size_t ovs_tun_key_attr_size(void)
* updating this function. * updating this function.
*/ */
return nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */ return nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */
+ nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */ + nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV[46]_SRC */
+ nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */ + nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV[46]_DST */
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */ + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */ + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */ + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
@ -323,6 +323,8 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE }, [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE },
[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED, [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED,
.next = ovs_vxlan_ext_key_lens }, .next = ovs_vxlan_ext_key_lens },
[OVS_TUNNEL_KEY_ATTR_IPV6_SRC] = { .len = sizeof(struct in6_addr) },
[OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = sizeof(struct in6_addr) },
}; };
/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */
@ -542,14 +544,14 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr,
return 0; return 0;
} }
static int ipv4_tun_from_nlattr(const struct nlattr *attr, static int ip_tun_from_nlattr(const struct nlattr *attr,
struct sw_flow_match *match, bool is_mask, struct sw_flow_match *match, bool is_mask,
bool log) bool log)
{ {
struct nlattr *a; struct nlattr *a;
int rem; int rem;
bool ttl = false; bool ttl = false;
__be16 tun_flags = 0; __be16 tun_flags = 0, ipv4 = false, ipv6 = false;
int opts_type = 0; int opts_type = 0;
nla_for_each_nested(a, attr, rem) { nla_for_each_nested(a, attr, rem) {
@ -578,10 +580,22 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.src, SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.src,
nla_get_in_addr(a), is_mask); nla_get_in_addr(a), is_mask);
ipv4 = true;
break; break;
case OVS_TUNNEL_KEY_ATTR_IPV4_DST: case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.dst, SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.dst,
nla_get_in_addr(a), is_mask); nla_get_in_addr(a), is_mask);
ipv4 = true;
break;
case OVS_TUNNEL_KEY_ATTR_IPV6_SRC:
SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.dst,
nla_get_in6_addr(a), is_mask);
ipv6 = true;
break;
case OVS_TUNNEL_KEY_ATTR_IPV6_DST:
SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.dst,
nla_get_in6_addr(a), is_mask);
ipv6 = true;
break; break;
case OVS_TUNNEL_KEY_ATTR_TOS: case OVS_TUNNEL_KEY_ATTR_TOS:
SW_FLOW_KEY_PUT(match, tun_key.tos, SW_FLOW_KEY_PUT(match, tun_key.tos,
@ -636,7 +650,7 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
opts_type = type; opts_type = type;
break; break;
default: default:
OVS_NLERR(log, "Unknown IPv4 tunnel attribute %d", OVS_NLERR(log, "Unknown IP tunnel attribute %d",
type); type);
return -EINVAL; return -EINVAL;
} }
@ -646,22 +660,36 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
if (is_mask) if (is_mask)
SW_FLOW_KEY_MEMSET_FIELD(match, tun_proto, 0xff, true); SW_FLOW_KEY_MEMSET_FIELD(match, tun_proto, 0xff, true);
else else
SW_FLOW_KEY_PUT(match, tun_proto, AF_INET, false); SW_FLOW_KEY_PUT(match, tun_proto, ipv6 ? AF_INET6 : AF_INET,
false);
if (rem > 0) { if (rem > 0) {
OVS_NLERR(log, "IPv4 tunnel attribute has %d unknown bytes.", OVS_NLERR(log, "IP tunnel attribute has %d unknown bytes.",
rem); rem);
return -EINVAL; return -EINVAL;
} }
if (ipv4 && ipv6) {
OVS_NLERR(log, "Mixed IPv4 and IPv6 tunnel attributes");
return -EINVAL;
}
if (!is_mask) { if (!is_mask) {
if (!match->key->tun_key.u.ipv4.dst) { if (!ipv4 && !ipv6) {
OVS_NLERR(log, "IP tunnel dst address not specified");
return -EINVAL;
}
if (ipv4 && !match->key->tun_key.u.ipv4.dst) {
OVS_NLERR(log, "IPv4 tunnel dst address is zero"); OVS_NLERR(log, "IPv4 tunnel dst address is zero");
return -EINVAL; return -EINVAL;
} }
if (ipv6 && ipv6_addr_any(&match->key->tun_key.u.ipv6.dst)) {
OVS_NLERR(log, "IPv6 tunnel dst address is zero");
return -EINVAL;
}
if (!ttl) { if (!ttl) {
OVS_NLERR(log, "IPv4 tunnel TTL not specified."); OVS_NLERR(log, "IP tunnel TTL not specified.");
return -EINVAL; return -EINVAL;
} }
} }
@ -686,21 +714,36 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb,
return 0; return 0;
} }
static int __ipv4_tun_to_nlattr(struct sk_buff *skb, static int __ip_tun_to_nlattr(struct sk_buff *skb,
const struct ip_tunnel_key *output, const struct ip_tunnel_key *output,
const void *tun_opts, int swkey_tun_opts_len) const void *tun_opts, int swkey_tun_opts_len,
unsigned short tun_proto)
{ {
if (output->tun_flags & TUNNEL_KEY && if (output->tun_flags & TUNNEL_KEY &&
nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id)) nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id))
return -EMSGSIZE; return -EMSGSIZE;
if (output->u.ipv4.src && switch (tun_proto) {
nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, case AF_INET:
output->u.ipv4.src)) if (output->u.ipv4.src &&
return -EMSGSIZE; nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC,
if (output->u.ipv4.dst && output->u.ipv4.src))
nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, return -EMSGSIZE;
output->u.ipv4.dst)) if (output->u.ipv4.dst &&
return -EMSGSIZE; nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST,
output->u.ipv4.dst))
return -EMSGSIZE;
break;
case AF_INET6:
if (!ipv6_addr_any(&output->u.ipv6.src) &&
nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_SRC,
&output->u.ipv6.src))
return -EMSGSIZE;
if (!ipv6_addr_any(&output->u.ipv6.dst) &&
nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_DST,
&output->u.ipv6.dst))
return -EMSGSIZE;
break;
}
if (output->tos && if (output->tos &&
nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->tos)) nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->tos))
return -EMSGSIZE; return -EMSGSIZE;
@ -734,9 +777,10 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
return 0; return 0;
} }
static int ipv4_tun_to_nlattr(struct sk_buff *skb, static int ip_tun_to_nlattr(struct sk_buff *skb,
const struct ip_tunnel_key *output, const struct ip_tunnel_key *output,
const void *tun_opts, int swkey_tun_opts_len) const void *tun_opts, int swkey_tun_opts_len,
unsigned short tun_proto)
{ {
struct nlattr *nla; struct nlattr *nla;
int err; int err;
@ -745,7 +789,8 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb,
if (!nla) if (!nla)
return -EMSGSIZE; return -EMSGSIZE;
err = __ipv4_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len); err = __ip_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len,
tun_proto);
if (err) if (err)
return err; return err;
@ -757,9 +802,10 @@ int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb,
const struct ip_tunnel_info *egress_tun_info, const struct ip_tunnel_info *egress_tun_info,
const void *egress_tun_opts) const void *egress_tun_opts)
{ {
return __ipv4_tun_to_nlattr(skb, &egress_tun_info->key, return __ip_tun_to_nlattr(skb, &egress_tun_info->key,
egress_tun_opts, egress_tun_opts,
egress_tun_info->options_len); egress_tun_info->options_len,
ip_tunnel_info_af(egress_tun_info));
} }
static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
@ -810,8 +856,8 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
*attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK); *attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK);
} }
if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) { if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) {
if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match, if (ip_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
is_mask, log) < 0) is_mask, log) < 0)
return -EINVAL; return -EINVAL;
*attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL); *attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL);
} }
@ -1377,8 +1423,8 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT) if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT)
opts = TUN_METADATA_OPTS(output, swkey->tun_opts_len); opts = TUN_METADATA_OPTS(output, swkey->tun_opts_len);
if (ipv4_tun_to_nlattr(skb, &output->tun_key, opts, if (ip_tun_to_nlattr(skb, &output->tun_key, opts,
swkey->tun_opts_len)) swkey->tun_opts_len, swkey->tun_proto))
goto nla_put_failure; goto nla_put_failure;
} }
@ -1881,7 +1927,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
int err = 0, start, opts_type; int err = 0, start, opts_type;
ovs_match_init(&match, &key, NULL); ovs_match_init(&match, &key, NULL);
opts_type = ipv4_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)
return opts_type; return opts_type;
@ -2380,10 +2426,11 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
if (!start) if (!start)
return -EMSGSIZE; return -EMSGSIZE;
err = ipv4_tun_to_nlattr(skb, &tun_info->key, err = ip_tun_to_nlattr(skb, &tun_info->key,
tun_info->options_len ? tun_info->options_len ?
ip_tunnel_info_opts(tun_info) : NULL, ip_tunnel_info_opts(tun_info) : NULL,
tun_info->options_len); tun_info->options_len,
ip_tunnel_info_af(tun_info));
if (err) if (err)
return err; return err;
nla_nest_end(skb, start); nla_nest_end(skb, start);