datapath: Add support for VXLAN tunnels to Open vSwitch
[sliver-openvswitch.git] / lib / netdev-vport.c
index d2c2672..1863d82 100644 (file)
@@ -49,6 +49,9 @@
 
 VLOG_DEFINE_THIS_MODULE(netdev_vport);
 
+/* Default to the OTV port, per the VXLAN IETF draft. */
+#define VXLAN_DST_PORT 8472
+
 struct netdev_dev_vport {
     struct netdev_dev netdev_dev;
     struct ofpbuf *options;
@@ -162,9 +165,21 @@ netdev_vport_get_netdev_type(const struct dpif_linux_vport *vport)
         return (nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_IPSEC
                 ? "ipsec_gre" : "gre");
 
+    case OVS_VPORT_TYPE_GRE64:
+        if (tnl_port_config_from_nlattr(vport->options, vport->options_len,
+                                        a)) {
+            break;
+        }
+        return (nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_IPSEC
+                ? "ipsec_gre64" : "gre64");
+
     case OVS_VPORT_TYPE_CAPWAP:
         return "capwap";
 
+    case OVS_VPORT_TYPE_VXLAN:
+        return ("vxlan");
+
+    case OVS_VPORT_TYPE_FT_GRE:
     case __OVS_VPORT_TYPE_MAX:
         break;
     }
@@ -576,20 +591,27 @@ parse_tunnel_config(const char *name, const char *type,
 {
     bool is_gre = false;
     bool is_ipsec = false;
+    bool needs_dst_port = false;
+    bool found_dst_port = false;
     struct smap_node *node;
     bool ipsec_mech_set = false;
     ovs_be32 daddr = htonl(0);
     ovs_be32 saddr = htonl(0);
     uint32_t flags;
 
-    flags = TNL_F_DF_DEFAULT | TNL_F_PMTUD | TNL_F_HDR_CACHE;
-    if (!strcmp(type, "gre")) {
+    if (!strcmp(type, "capwap")) {
+        VLOG_WARN_ONCE("CAPWAP tunnel support is deprecated.");
+    }
+
+    flags = TNL_F_DF_DEFAULT;
+    if (!strcmp(type, "gre") || !strcmp(type, "gre64")) {
         is_gre = true;
-    } else if (!strcmp(type, "ipsec_gre")) {
+    } else if (!strcmp(type, "ipsec_gre") || !strcmp(type, "ipsec_gre64")) {
         is_gre = true;
         is_ipsec = true;
         flags |= TNL_F_IPSEC;
-        flags &= ~TNL_F_HDR_CACHE;
+    } else if (!strcmp(type, "vxlan")) {
+        needs_dst_port = true;
     }
 
     SMAP_FOR_EACH (node, args) {
@@ -614,8 +636,10 @@ parse_tunnel_config(const char *name, const char *type,
                 char *endptr;
                 int tos;
                 tos = strtol(node->value, &endptr, 0);
-                if (*endptr == '\0') {
+                if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
                     nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TOS, tos);
+                } else {
+                    VLOG_WARN("%s: invalid TOS %s", name, node->value);
                 }
             }
         } else if (!strcmp(node->key, "ttl")) {
@@ -624,6 +648,10 @@ parse_tunnel_config(const char *name, const char *type,
             } else {
                 nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TTL, atoi(node->value));
             }
+        } else if (!strcmp(node->key, "dst_port") && needs_dst_port) {
+            nl_msg_put_u16(options, OVS_TUNNEL_ATTR_DST_PORT,
+                           atoi(node->value));
+            found_dst_port = true;
         } else if (!strcmp(node->key, "csum") && is_gre) {
             if (!strcmp(node->value, "true")) {
                 flags |= TNL_F_CSUM;
@@ -637,12 +665,12 @@ parse_tunnel_config(const char *name, const char *type,
                 flags &= ~TNL_F_DF_DEFAULT;
             }
         } else if (!strcmp(node->key, "pmtud")) {
-            if (!strcmp(node->value, "false")) {
-                flags &= ~TNL_F_PMTUD;
-            }
-        } else if (!strcmp(node->key, "header_cache")) {
-            if (!strcmp(node->value, "false")) {
-                flags &= ~TNL_F_HDR_CACHE;
+            if (!strcmp(node->value, "true")) {
+                VLOG_WARN_ONCE("%s: The tunnel Path MTU discovery is "
+                               "deprecated and may be removed in February "
+                               "2013. Please email dev@openvswitch.org with "
+                               "concerns.", name);
+                flags |= TNL_F_PMTUD;
             }
         } else if (!strcmp(node->key, "peer_cert") && is_ipsec) {
             if (smap_get(args, "certificate")) {
@@ -680,9 +708,14 @@ parse_tunnel_config(const char *name, const char *type,
         }
     }
 
+    /* Add a default destination port for VXLAN if none specified. */
+    if (needs_dst_port && !found_dst_port) {
+        nl_msg_put_u16(options, OVS_TUNNEL_ATTR_DST_PORT, VXLAN_DST_PORT);
+    }
+
     if (is_ipsec) {
         static pid_t pid = 0;
-        if (pid == 0) {
+        if (pid <= 0) {
             char *file_name = xasprintf("%s/%s", ovs_rundir(),
                                         "ovs-monitor-ipsec.pid");
             pid = read_pidfile(file_name);
@@ -742,6 +775,7 @@ tnl_port_config_from_nlattr(const struct nlattr *options, size_t options_len,
         [OVS_TUNNEL_ATTR_OUT_KEY] = { .type = NL_A_BE64, .optional = true },
         [OVS_TUNNEL_ATTR_TOS] = { .type = NL_A_U8, .optional = true },
         [OVS_TUNNEL_ATTR_TTL] = { .type = NL_A_U8, .optional = true },
+        [OVS_TUNNEL_ATTR_DST_PORT] = { .type = NL_A_U16, .optional = true },
     };
     struct ofpbuf buf;
 
@@ -774,11 +808,6 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED,
         return error;
     }
 
-    flags = nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]);
-    if (!(flags & TNL_F_HDR_CACHE) == !(flags & TNL_F_IPSEC)) {
-        smap_add(args, "header_cache",
-                 flags & TNL_F_HDR_CACHE ? "true" : "false");
-    }
 
     daddr = nl_attr_get_be32(a[OVS_TUNNEL_ATTR_DST_IPV4]);
     smap_add_format(args, "remote_ip", IP_FMT, IP_ARGS(&daddr));
@@ -811,11 +840,12 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED,
         }
     }
 
+    flags = nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]);
     if (flags & TNL_F_TTL_INHERIT) {
-        smap_add(args, "tos", "inherit");
+        smap_add(args, "ttl", "inherit");
     } else if (a[OVS_TUNNEL_ATTR_TTL]) {
         int ttl = nl_attr_get_u8(a[OVS_TUNNEL_ATTR_TTL]);
-        smap_add_format(args, "tos", "%d", ttl);
+        smap_add_format(args, "ttl", "%d", ttl);
     }
 
     if (flags & TNL_F_TOS_INHERIT) {
@@ -825,6 +855,13 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED,
         smap_add_format(args, "tos", "0x%x", tos);
     }
 
+    if (a[OVS_TUNNEL_ATTR_DST_PORT]) {
+        uint16_t dst_port = nl_attr_get_u16(a[OVS_TUNNEL_ATTR_DST_PORT]);
+        if (dst_port != VXLAN_DST_PORT) {
+            smap_add_format(args, "dst_port", "%d", dst_port);
+        }
+    }
+
     if (flags & TNL_F_CSUM) {
         smap_add(args, "csum", "true");
     }
@@ -834,8 +871,8 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED,
     if (!(flags & TNL_F_DF_DEFAULT)) {
         smap_add(args, "df_default", "false");
     }
-    if (!(flags & TNL_F_PMTUD)) {
-        smap_add(args, "pmtud", "false");
+    if (flags & TNL_F_PMTUD) {
+        smap_add(args, "pmtud", "true");
     }
 
     return 0;
@@ -968,10 +1005,22 @@ netdev_vport_register(void)
           { "ipsec_gre", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
           parse_tunnel_config, unparse_tunnel_config },
 
+        { OVS_VPORT_TYPE_GRE64,
+          { "gre64", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
+          parse_tunnel_config, unparse_tunnel_config },
+
+        { OVS_VPORT_TYPE_GRE64,
+          { "ipsec_gre64", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
+          parse_tunnel_config, unparse_tunnel_config },
+
         { OVS_VPORT_TYPE_CAPWAP,
           { "capwap", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
           parse_tunnel_config, unparse_tunnel_config },
 
+        { OVS_VPORT_TYPE_VXLAN,
+          { "vxlan", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
+          parse_tunnel_config, unparse_tunnel_config },
+
         { OVS_VPORT_TYPE_PATCH,
           { "patch", VPORT_FUNCTIONS(NULL) },
           parse_patch_config, unparse_patch_config }