summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJan Scheurich <jan.scheurich@ericsson.com>2017-06-02 16:16:21 +0000
committerBen Pfaff <blp@ovn.org>2017-06-02 14:40:34 -0700
commit63171f047fe20ef62ce0c42c4b9da2114ddd4bff (patch)
treec6666b342ea6346e43436e0a182e909ebbba733b /lib
parentbeb75a40fdc295bfd6521b0068b4cd12f6de507c (diff)
downloadopenvswitch-63171f047fe20ef62ce0c42c4b9da2114ddd4bff.tar.gz
userspace: L3 tunnel support for GRE and LISP
Add a boolean "layer3" configuration option for tunnel vports. The layer3 option defaults to false for all ports except LISP. GRE ports accept both true and false for "layer3". A tunnel vport configured with layer3=true receives L3 packets. which are then converted to Ethernet packets by pushing a dummy Ethernet heder at the ingress of the OpenFlow pipeline. The Ethernet header of a packet is stripped before sending to a layer3 tunnel vport. Presently a single GRE vport cannot carry both L2 and L3 packets. But it is possible to create two GRE vports representing the same GRE tunel, one with layer3=false, the other with layer3=true. L2 packet from the tunnel are received on the first vport, L3 packets on the second. The controller must send packets to the layer3 GRE vport to tunnel them without their Ethernet header. Units tests have been added to check the L3 tunnel handling. LISP tunnels are not yet supported by the netdev userspace datapath. Signed-off-by: Simon Horman <simon.horman@netronome.com> Signed-off-by: Jiri Benc <jbenc@redhat.com> Signed-off-by: Yi Yang <yi.y.yang@intel.com> Signed-off-by: Jan Scheurich <jan.scheurich@ericsson.com> Co-authored-by: Zoltan Balogh <zoltan.balogh@ericsson.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/netdev-native-tnl.c28
-rw-r--r--lib/netdev-vport.c14
2 files changed, 35 insertions, 7 deletions
diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
index 2798324f5..0651322ec 100644
--- a/lib/netdev-native-tnl.c
+++ b/lib/netdev-native-tnl.c
@@ -154,6 +154,10 @@ netdev_tnl_push_ip_header(struct dp_packet *packet,
*ip_tot_size = dp_packet_size(packet) - sizeof (struct eth_header);
memcpy(eth, header, size);
+ /* The encapsulated packet has type Ethernet. Adjust dp_packet. */
+ packet->packet_type = htonl(PT_ETH);
+ dp_packet_reset_offsets(packet);
+ packet->l3_ofs = sizeof (struct eth_header);
if (netdev_tnl_is_header_ipv6(header)) {
ip6 = netdev_tnl_ipv6_hdr(eth);
@@ -345,6 +349,7 @@ parse_gre_header(struct dp_packet *packet,
ovs_16aligned_be32 *options;
int hlen;
unsigned int ulen;
+ uint16_t greh_protocol;
greh = netdev_tnl_ip_extract_tnl_md(packet, tnl, &ulen);
if (!greh) {
@@ -355,10 +360,6 @@ parse_gre_header(struct dp_packet *packet,
return -EINVAL;
}
- if (greh->protocol != htons(ETH_TYPE_TEB)) {
- return -EINVAL;
- }
-
hlen = ulen + gre_header_len(greh->flags);
if (hlen > dp_packet_size(packet)) {
return -EINVAL;
@@ -388,6 +389,17 @@ parse_gre_header(struct dp_packet *packet,
options++;
}
+ /* Set the new packet type depending on the GRE protocol field. */
+ greh_protocol = ntohs(greh->protocol);
+ if (greh_protocol == ETH_TYPE_TEB) {
+ packet->packet_type = htonl(PT_ETH);
+ } else if (greh_protocol >= ETH_TYPE_MIN) {
+ /* Allow all GRE protocol values above 0x5ff as Ethertypes. */
+ packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, greh_protocol);
+ } else {
+ return -EINVAL;
+ }
+
return hlen;
}
@@ -451,7 +463,11 @@ netdev_gre_build_header(const struct netdev *netdev,
greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE);
- greh->protocol = htons(ETH_TYPE_TEB);
+ if (tnl_cfg->is_layer3) {
+ greh->protocol = params->flow->dl_type;
+ } else {
+ greh->protocol = htons(ETH_TYPE_TEB);
+ }
greh->flags = 0;
options = (ovs_16aligned_be32 *) (greh + 1);
@@ -504,6 +520,7 @@ netdev_vxlan_pop_header(struct dp_packet *packet)
tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
tnl->flags |= FLOW_TNL_F_KEY;
+ packet->packet_type = htonl(PT_ETH);
dp_packet_reset_packet(packet, hlen + VXLAN_HLEN);
return packet;
@@ -583,6 +600,7 @@ netdev_geneve_pop_header(struct dp_packet *packet)
tnl->metadata.present.len = opts_len;
tnl->flags |= FLOW_TNL_F_UDPIF;
+ packet->packet_type = htonl(PT_ETH);
dp_packet_reset_packet(packet, hlen);
return packet;
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 84b9be365..ba6946102 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -410,7 +410,7 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp)
const char *name = netdev_get_name(dev_);
const char *type = netdev_get_type(dev_);
struct ds errors = DS_EMPTY_INITIALIZER;
- bool needs_dst_port, has_csum;
+ bool needs_dst_port, has_csum, optional_layer3;
uint16_t dst_proto = 0, src_proto = 0;
struct netdev_tunnel_config tnl_cfg;
struct smap_node *node;
@@ -418,6 +418,7 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp)
has_csum = strstr(type, "gre") || strstr(type, "geneve") ||
strstr(type, "stt") || strstr(type, "vxlan");
+ optional_layer3 = !strcmp(type, "gre");
memset(&tnl_cfg, 0, sizeof tnl_cfg);
/* Add a default destination port for tunnel ports if none specified. */
@@ -431,6 +432,7 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp)
if (!strcmp(type, "lisp")) {
tnl_cfg.dst_port = htons(LISP_DST_PORT);
+ tnl_cfg.is_layer3 = true;
}
if (!strcmp(type, "stt")) {
@@ -518,6 +520,10 @@ 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) {
+ if (!strcmp(node->value, "true")) {
+ tnl_cfg.is_layer3 = true;
+ }
} else {
ds_put_format(&errors, "%s: unknown %s argument '%s'\n",
name, type, node->key);
@@ -587,6 +593,7 @@ static int
get_tunnel_config(const struct netdev *dev, struct smap *args)
{
struct netdev_vport *netdev = netdev_vport_cast(dev);
+ const char *type = netdev_get_type(dev);
struct netdev_tunnel_config tnl_cfg;
ovs_mutex_lock(&netdev->mutex);
@@ -640,7 +647,6 @@ get_tunnel_config(const struct netdev *dev, struct smap *args)
if (tnl_cfg.dst_port) {
uint16_t dst_port = ntohs(tnl_cfg.dst_port);
- const char *type = netdev_get_type(dev);
if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) ||
(!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
@@ -654,6 +660,10 @@ get_tunnel_config(const struct netdev *dev, struct smap *args)
smap_add(args, "csum", "true");
}
+ if (tnl_cfg.is_layer3 && !strcmp("gre", type)) {
+ smap_add(args, "layer3", "true");
+ }
+
if (!tnl_cfg.dont_fragment) {
smap_add(args, "df_default", "false");
}