summaryrefslogtreecommitdiff
path: root/lib/netdev-vport.c
diff options
context:
space:
mode:
authorJesse Gross <jesse@nicira.com>2015-06-22 14:23:37 -0700
committerJesse Gross <jesse@nicira.com>2015-06-26 14:18:07 -0700
commit5bb08b0ef605a9b164399bd74a194ae1b921c3ea (patch)
treedc63682400cab6eb2fd50cc563d88aeb12a60ee6 /lib/netdev-vport.c
parentdaab0ae6bb558411f24cee6a7bb32599a5f9e363 (diff)
downloadopenvswitch-5bb08b0ef605a9b164399bd74a194ae1b921c3ea.tar.gz
tunneling: Userspace datapath support for Geneve options.
Currently the userspace datapath only supports Geneve in a basic mode - without options - since the rest of userspace previously didn't support options either. This enables the userspace datapath to send and receive options as well. The receive path for extracting the tunnel options isn't entirely optimal because it does a lookup on the options on a per-packet basis, rather than per-flow like the kernel does. This is not as straightforward to do in the userspace datapath since there is no translation step between packet formats used in packet vs. flow lookup. This can be optimized in the future and in the meantime option support is still useful for testing and simulation. Signed-off-by: Jesse Gross <jesse@nicira.com> Acked-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'lib/netdev-vport.c')
-rw-r--r--lib/netdev-vport.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index ea9abf9e7..259d0ed4d 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -1199,6 +1199,7 @@ netdev_geneve_pop_header(struct dp_packet *packet)
struct flow_tnl *tnl = &md->tunnel;
struct genevehdr *gnh;
unsigned int hlen;
+ int err;
memset(md, 0, sizeof *md);
if (GENEVE_BASE_HLEN > dp_packet_size(packet)) {
@@ -1224,12 +1225,6 @@ netdev_geneve_pop_header(struct dp_packet *packet)
return EINVAL;
}
- if (gnh->opt_len && gnh->critical) {
- VLOG_WARN_RL(&err_rl, "unknown geneve critical options: %"PRIu8" bytes\n",
- gnh->opt_len * 4);
- return EINVAL;
- }
-
if (gnh->proto_type != htons(ETH_TYPE_TEB)) {
VLOG_WARN_RL(&err_rl, "unknown geneve encapsulated protocol: %#x\n",
ntohs(gnh->proto_type));
@@ -1240,6 +1235,13 @@ netdev_geneve_pop_header(struct dp_packet *packet)
tnl->tun_id = htonll(ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
tnl->flags |= FLOW_TNL_F_KEY;
+ err = tun_metadata_from_geneve_header(gnh->options, gnh->opt_len * 4,
+ &tnl->metadata);
+ if (err) {
+ VLOG_WARN_RL(&err_rl, "invalid geneve options");
+ return err;
+ }
+
dp_packet_reset_packet(packet, hlen);
return 0;
@@ -1253,6 +1255,8 @@ netdev_geneve_build_header(const struct netdev *netdev,
struct netdev_vport *dev = netdev_vport_cast(netdev);
struct netdev_tunnel_config *tnl_cfg;
struct genevehdr *gnh;
+ int opt_len;
+ bool crit_opt;
/* XXX: RCUfy tnl_cfg. */
ovs_mutex_lock(&dev->mutex);
@@ -1260,12 +1264,19 @@ netdev_geneve_build_header(const struct netdev *netdev,
gnh = udp_build_header(tnl_cfg, tnl_flow, data);
- gnh->oam = !!(tnl_flow->tunnel.flags & FLOW_TNL_F_OAM);
- gnh->proto_type = htons(ETH_TYPE_TEB);
put_16aligned_be32(&gnh->vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
ovs_mutex_unlock(&dev->mutex);
- data->header_len = GENEVE_BASE_HLEN;
+
+ opt_len = tun_metadata_to_geneve_header(&tnl_flow->tunnel.metadata,
+ gnh->options, &crit_opt);
+
+ gnh->opt_len = opt_len / 4;
+ gnh->oam = !!(tnl_flow->tunnel.flags & FLOW_TNL_F_OAM);
+ gnh->critical = crit_opt ? 1 : 0;
+ gnh->proto_type = htons(ETH_TYPE_TEB);
+
+ data->header_len = GENEVE_BASE_HLEN + opt_len;
data->tnl_type = OVS_VPORT_TYPE_GENEVE;
return 0;
}