mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
userspace: add vxlan gpe support to vport
This patch is based on the "datapath: enable vxlangpe creation in compat mode" from Yi Yang. It introduces an extension option "gpe" to the vxlan port in the netdev-dpdk datapath. Description of vxlan gpe protocoll was added to header file lib/packets.h. In the vxlan specific methods the different packet are introduced and handled. Added VXLAN GPE tunnel push test. Signed-off-by: Yi Yang <yi.y.yang at intel.com> Signed-off-by: Georg Schmuecking <georg.schmuecking@ericsson.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
parent
63171f047f
commit
439f39cb9b
3
NEWS
3
NEWS
@ -51,7 +51,8 @@ Post-v2.7.0
|
||||
- Add --cleanup option to command 'ovs-appctl exit' (see ovs-vswitchd(8)).
|
||||
- L3 tunneling:
|
||||
* Add "layer3" options for tunnel ports that support non-Ethernet (L3)
|
||||
payload (GRE).
|
||||
payload (GRE, VXLAN-GPE).
|
||||
* New vxlan tunnel extension "gpe" to support VXLAN-GPE tunnels.
|
||||
* Transparently pop and push Ethernet headers at transmit/reception
|
||||
of packets to/from L3 tunnels.
|
||||
|
||||
|
@ -291,6 +291,7 @@ enum ovs_vport_attr {
|
||||
enum {
|
||||
OVS_VXLAN_EXT_UNSPEC,
|
||||
OVS_VXLAN_EXT_GBP, /* Flag or __u32 */
|
||||
OVS_VXLAN_EXT_GPE = 8, /* Flag or __u32 */
|
||||
__OVS_VXLAN_EXT_MAX,
|
||||
};
|
||||
|
||||
|
@ -30,4 +30,3 @@ openvswitchinclude_HEADERS = \
|
||||
include/openvswitch/version.h \
|
||||
include/openvswitch/vconn.h \
|
||||
include/openvswitch/vlog.h
|
||||
|
||||
|
@ -499,6 +499,8 @@ netdev_vxlan_pop_header(struct dp_packet *packet)
|
||||
struct flow_tnl *tnl = &md->tunnel;
|
||||
struct vxlanhdr *vxh;
|
||||
unsigned int hlen;
|
||||
ovs_be32 vx_flags;
|
||||
enum packet_type next_pt = PT_ETH;
|
||||
|
||||
pkt_metadata_init_tnl(md);
|
||||
if (VXLAN_HLEN > dp_packet_l4_size(packet)) {
|
||||
@ -510,18 +512,43 @@ netdev_vxlan_pop_header(struct dp_packet *packet)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
|
||||
vx_flags = get_16aligned_be32(&vxh->vx_flags);
|
||||
if (vx_flags & htonl(VXLAN_HF_GPE)) {
|
||||
vx_flags &= htonl(~VXLAN_GPE_USED_BITS);
|
||||
/* Drop the OAM packets */
|
||||
if (vxh->vx_gpe.flags & VXLAN_GPE_FLAGS_O) {
|
||||
goto err;
|
||||
}
|
||||
switch (vxh->vx_gpe.next_protocol) {
|
||||
case VXLAN_GPE_NP_IPV4:
|
||||
next_pt = PT_IPV4;
|
||||
break;
|
||||
case VXLAN_GPE_NP_IPV6:
|
||||
next_pt = PT_IPV6;
|
||||
break;
|
||||
case VXLAN_GPE_NP_ETHERNET:
|
||||
next_pt = PT_ETH;
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (vx_flags != htonl(VXLAN_FLAGS) ||
|
||||
(get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
|
||||
VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
|
||||
ntohl(get_16aligned_be32(&vxh->vx_flags)),
|
||||
ntohl(vx_flags),
|
||||
ntohl(get_16aligned_be32(&vxh->vx_vni)));
|
||||
goto err;
|
||||
}
|
||||
tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
|
||||
tnl->flags |= FLOW_TNL_F_KEY;
|
||||
|
||||
packet->packet_type = htonl(PT_ETH);
|
||||
packet->packet_type = htonl(next_pt);
|
||||
dp_packet_reset_packet(packet, hlen + VXLAN_HLEN);
|
||||
if (next_pt != PT_ETH) {
|
||||
packet->l3_ofs = 0;
|
||||
}
|
||||
|
||||
return packet;
|
||||
err:
|
||||
@ -544,8 +571,30 @@ netdev_vxlan_build_header(const struct netdev *netdev,
|
||||
|
||||
vxh = udp_build_header(tnl_cfg, data, params);
|
||||
|
||||
put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
|
||||
put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8));
|
||||
if (tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GPE)) {
|
||||
put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS | VXLAN_HF_GPE));
|
||||
put_16aligned_be32(&vxh->vx_vni,
|
||||
htonl(ntohll(params->flow->tunnel.tun_id) << 8));
|
||||
if (tnl_cfg->is_layer3) {
|
||||
switch (ntohs(params->flow->dl_type)) {
|
||||
case ETH_TYPE_IP:
|
||||
vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_IPV4;
|
||||
break;
|
||||
case ETH_TYPE_IPV6:
|
||||
vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_IPV6;
|
||||
break;
|
||||
case ETH_TYPE_TEB:
|
||||
vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET;
|
||||
}
|
||||
} else {
|
||||
put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
|
||||
put_16aligned_be32(&vxh->vx_vni,
|
||||
htonl(ntohll(params->flow->tunnel.tun_id) << 8));
|
||||
}
|
||||
|
||||
ovs_mutex_unlock(&dev->mutex);
|
||||
data->header_len += sizeof *vxh;
|
||||
|
@ -414,6 +414,7 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp)
|
||||
uint16_t dst_proto = 0, src_proto = 0;
|
||||
struct netdev_tunnel_config tnl_cfg;
|
||||
struct smap_node *node;
|
||||
bool is_layer3 = false;
|
||||
int err;
|
||||
|
||||
has_csum = strstr(type, "gre") || strstr(type, "geneve") ||
|
||||
@ -508,6 +509,9 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp)
|
||||
while (ext) {
|
||||
if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
|
||||
tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
|
||||
} else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) {
|
||||
tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
|
||||
optional_layer3 = true;
|
||||
} else {
|
||||
ds_put_format(&errors, "%s: unknown extension '%s'\n",
|
||||
name, ext);
|
||||
@ -520,16 +524,23 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp)
|
||||
} else if (!strcmp(node->key, "egress_pkt_mark")) {
|
||||
tnl_cfg.egress_pkt_mark = strtoul(node->value, NULL, 10);
|
||||
tnl_cfg.set_egress_pkt_mark = true;
|
||||
} else if (!strcmp(node->key, "layer3") && optional_layer3) {
|
||||
} else if (!strcmp(node->key, "layer3")) {
|
||||
if (!strcmp(node->value, "true")) {
|
||||
tnl_cfg.is_layer3 = true;
|
||||
is_layer3 = true;
|
||||
}
|
||||
} else {
|
||||
ds_put_format(&errors, "%s: unknown %s argument '%s'\n",
|
||||
name, type, node->key);
|
||||
ds_put_format(&errors, "%s: unknown %s argument '%s'\n", name,
|
||||
type, node->key);
|
||||
}
|
||||
}
|
||||
|
||||
if (optional_layer3 && is_layer3) {
|
||||
tnl_cfg.is_layer3 = is_layer3;
|
||||
} else if (!optional_layer3 && is_layer3) {
|
||||
ds_put_format(&errors, "%s: unknown %s argument '%s'\n",
|
||||
name, type, "layer3");
|
||||
}
|
||||
|
||||
if (!ipv6_addr_is_set(&tnl_cfg.ipv6_dst) && !tnl_cfg.ip_dst_flow) {
|
||||
ds_put_format(&errors,
|
||||
"%s: %s type requires valid 'remote_ip' argument\n",
|
||||
@ -660,7 +671,8 @@ get_tunnel_config(const struct netdev *dev, struct smap *args)
|
||||
smap_add(args, "csum", "true");
|
||||
}
|
||||
|
||||
if (tnl_cfg.is_layer3 && !strcmp("gre", type)) {
|
||||
if (tnl_cfg.is_layer3 && (!strcmp("gre", type) ||
|
||||
!strcmp("vxlan", type))) {
|
||||
smap_add(args, "layer3", "true");
|
||||
}
|
||||
|
||||
|
@ -1171,12 +1171,64 @@ struct gre_base_hdr {
|
||||
|
||||
/* VXLAN protocol header */
|
||||
struct vxlanhdr {
|
||||
ovs_16aligned_be32 vx_flags;
|
||||
union {
|
||||
ovs_16aligned_be32 vx_flags; /* VXLAN flags. */
|
||||
struct {
|
||||
uint8_t flags; /* VXLAN GPE flags. */
|
||||
uint8_t reserved[2]; /* 16 bits reserved. */
|
||||
uint8_t next_protocol; /* Next Protocol field for VXLAN GPE. */
|
||||
} vx_gpe;
|
||||
};
|
||||
ovs_16aligned_be32 vx_vni;
|
||||
};
|
||||
BUILD_ASSERT_DECL(sizeof(struct vxlanhdr) == 8);
|
||||
|
||||
#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
|
||||
|
||||
/*
|
||||
* VXLAN Generic Protocol Extension (VXLAN_F_GPE):
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* |R|R|Ver|I|P|R|O| Reserved |Next Protocol |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | VXLAN Network Identifier (VNI) | Reserved |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* Ver = Version. Indicates VXLAN GPE protocol version.
|
||||
*
|
||||
* P = Next Protocol Bit. The P bit is set to indicate that the
|
||||
* Next Protocol field is present.
|
||||
*
|
||||
* O = OAM Flag Bit. The O bit is set to indicate that the packet
|
||||
* is an OAM packet.
|
||||
*
|
||||
* Next Protocol = This 8 bit field indicates the protocol header
|
||||
* immediately following the VXLAN GPE header.
|
||||
*
|
||||
* https://tools.ietf.org/html/draft-ietf-nvo3-vxlan-gpe-01
|
||||
*/
|
||||
|
||||
/* Fields in struct vxlanhdr.vx_gpe.flags */
|
||||
#define VXLAN_GPE_FLAGS_VER 0x30 /* Version. */
|
||||
#define VLXAN_GPE_FLAGS_P 0x04 /* Next Protocol Bit. */
|
||||
#define VXLAN_GPE_FLAGS_O 0x01 /* OAM Bit. */
|
||||
|
||||
/* VXLAN-GPE header flags. */
|
||||
#define VXLAN_HF_VER ((1U <<29) | (1U <<28))
|
||||
#define VXLAN_HF_NP (1U <<26)
|
||||
#define VXLAN_HF_OAM (1U <<24)
|
||||
|
||||
#define VXLAN_GPE_USED_BITS (VXLAN_HF_VER | VXLAN_HF_NP | VXLAN_HF_OAM | \
|
||||
0xff)
|
||||
|
||||
/* VXLAN-GPE header Next Protocol. */
|
||||
#define VXLAN_GPE_NP_IPV4 0x01
|
||||
#define VXLAN_GPE_NP_IPV6 0x02
|
||||
#define VXLAN_GPE_NP_ETHERNET 0x03
|
||||
#define VXLAN_GPE_NP_NSH 0x04
|
||||
|
||||
#define VXLAN_F_GPE 0x4000
|
||||
#define VXLAN_HF_GPE 0x04000000
|
||||
|
||||
/* Input values for PACKET_TYPE macros have to be in host byte order.
|
||||
* The _BE postfix indicates result is in network byte order. Otherwise result
|
||||
* is in host byte order. */
|
||||
|
@ -16,6 +16,8 @@ AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \
|
||||
options:remote_ip=1.1.2.93 options:out_key=flow options:egress_pkt_mark=1234 ofport_request=6\
|
||||
-- add-port int-br t6 -- set Interface t6 type=gre \
|
||||
options:remote_ip=1.1.2.92 options:key=456 options:layer3=true ofport_request=7\
|
||||
-- add-port int-br t7 -- set Interface t7 type=vxlan \
|
||||
options:remote_ip=1.1.2.92 options:key=345 options:exts=gpe ofport_request=8\
|
||||
], [0])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show], [0], [dnl
|
||||
@ -31,6 +33,7 @@ dummy@ovs-dummy: hit:0 missed:0
|
||||
t4 5/6081: (geneve: key=123, remote_ip=flow)
|
||||
t5 6/6081: (geneve: egress_pkt_mark=1234, out_key=flow, remote_ip=1.1.2.93)
|
||||
t6 7/3: (gre: key=456, layer3=true, remote_ip=1.1.2.92)
|
||||
t7 8/4789: (vxlan: key=345, remote_ip=1.1.2.92)
|
||||
])
|
||||
|
||||
dnl First setup dummy interface IP address, then add the route
|
||||
@ -113,6 +116,13 @@ AT_CHECK([tail -1 stdout], [0],
|
||||
[Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100))
|
||||
])
|
||||
|
||||
dnl Check VXLAN GPE tunnel push
|
||||
AT_CHECK([ovs-ofctl add-flow int-br action=8])
|
||||
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
|
||||
AT_CHECK([tail -1 stdout], [0],
|
||||
[Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000003,vni=0x159)),out_port(100))
|
||||
])
|
||||
|
||||
dnl Check VXLAN tunnel push set tunnel id by flow and checksum
|
||||
AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"])
|
||||
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
|
||||
|
@ -2380,9 +2380,26 @@
|
||||
additional information.
|
||||
(<code>https://tools.ietf.org/html/draft-smith-vxlan-group-policy</code>)
|
||||
</li>
|
||||
<li>
|
||||
<code>gpe</code>: Support for Generic Protocol Encapsulation in
|
||||
accordance with IETF draft
|
||||
<code>https://tools.ietf.org/html/draft-ietf-nvo3-vxlan-gpe</code>.
|
||||
</li>
|
||||
</ul>
|
||||
</column>
|
||||
|
||||
<column name="options" key="layer3" type='{"type": "boolean"}'>
|
||||
<p>
|
||||
By default, or if set to false, the tunnel carries L2 packets (with
|
||||
an Ethernet header). If set to true, the tunnel carries L3 packets
|
||||
(without an Ethernet header present).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To set this option to true, the <code>gpe</code> extension must
|
||||
also be enabled in <ref column="options" key="exts"/>.
|
||||
</p>
|
||||
</column>
|
||||
</group>
|
||||
|
||||
<group title="Tunnel Options: gre only">
|
||||
|
Loading…
x
Reference in New Issue
Block a user