[ovs-dev] vxlan: Make vxlan tunnel work in IP_TUNNEL_INFO_BRIDGE mode
diff mbox series

Message ID 1553923703-32629-1-git-send-email-wenxu@ucloud.cn
State New
Headers show
Series
  • [ovs-dev] vxlan: Make vxlan tunnel work in IP_TUNNEL_INFO_BRIDGE mode
Related show

Commit Message

wenxu March 30, 2019, 5:28 a.m. UTC
From: wenxu <wenxu@ucloud.cn>

There is currently no support for the multicast/broadcast aspects
of VXLAN in ovs. In the datapath flow the tun_dst must specific.
But in the IP_TUNNEL_INFO_BRIDGE mode the tun_dst can not be specific.
And the packet can forward through the fdb table of vxlan devcice. In
this mode the broadcast/multicast packet can be sent through the
following ways in ovs.

It adds an options allow_info_bridge for vxlan tunnel interface to
permit to enable this mode for this vxlan tunnel.

ovs-vsctl add-port br0 vxlan -- set in vxlan type=vxlan \
        options:key=1000 options:remote_ip=flow
ovs-vsctl set in vxlan options:allow_info_bridge=true
ovs-ofctl add-flow br0 in_port=LOCAL,dl_dst=ff:ff:ff:ff:ff:ff, \
        action=output:vxlan

bridge fdb append ff:ff:ff:ff:ff:ff dev vxlan_sys_4789 dst 172.168.0.1 \
        src_vni 1000 vni 1000 self
bridge fdb append ff:ff:ff:ff:ff:ff dev vxlan_sys_4789 dst 172.168.0.2 \
        src_vni 1000 vni 1000 self

Signed-off-by: wenxu <wenxu@ucloud.cn>
---
 datapath/linux/compat/include/linux/openvswitch.h |  1 +
 include/openvswitch/packets.h                     |  3 ++-
 lib/netdev-vport.c                                | 20 +++++++++++++++++++-
 lib/netdev.h                                      |  2 ++
 lib/odp-util.c                                    | 19 ++++++++++++++++---
 lib/packets.h                                     |  6 ++++++
 ofproto/ofproto-dpif-xlate.c                      |  3 ++-
 ofproto/tunnel.c                                  |  5 +++++
 vswitchd/vswitch.xml                              |  9 +++++++++
 9 files changed, 62 insertions(+), 6 deletions(-)

Patch
diff mbox series

diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index d5aa09d..3b23590 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -400,6 +400,7 @@  enum ovs_tunnel_key_attr {
 	OVS_TUNNEL_KEY_ATTR_IPV6_DST,		/* struct in6_addr dst IPv6 address. */
 	OVS_TUNNEL_KEY_ATTR_PAD,
 	OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS,	/* struct erspan_metadata */
+	OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE,	/* No argument.ipv4 info bridge mode */
 	__OVS_TUNNEL_KEY_ATTR_MAX
 };
 
diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h
index 925844e..bad5618 100644
--- a/include/openvswitch/packets.h
+++ b/include/openvswitch/packets.h
@@ -43,7 +43,8 @@  struct flow_tnl {
     uint32_t erspan_idx;
     uint8_t erspan_dir;
     uint8_t erspan_hwid;
-    uint8_t pad1[6];     /* Pad to 64 bits. */
+    uint8_t ipv4_info_bridge;
+    uint8_t pad1[5];     /* Pad to 64 bits. */
     struct tun_metadata metadata;
 };
 
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 808a43f..43ca503 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -553,6 +553,7 @@  set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp)
     bool needs_dst_port, has_csum, has_seq;
     uint16_t dst_proto = 0, src_proto = 0;
     struct netdev_tunnel_config tnl_cfg;
+    bool allow_info_bridge = false;
     struct smap_node *node;
     int err;
 
@@ -725,12 +726,25 @@  set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp)
                     goto out;
                 }
             }
+        } else if (!strcmp(node->key, "allow_info_bridge")) {
+            if (!strcmp(node->value, "true")) {
+                allow_info_bridge = true;
+            }
         } else {
             ds_put_format(&errors, "%s: unknown %s argument '%s'\n", name,
                           type, node->key);
         }
     }
 
+    if (allow_info_bridge) {
+        if (!strcmp(type, "vxlan") && tnl_cfg.ip_dst_flow) {
+            tnl_cfg.allow_info_bridge = true;
+        } else {
+            ds_put_format(&errors, "%s: only work for vxlan in remote_ip=flow"
+                              " mode\n", node->key);
+        }
+    }
+
     enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg);
     const char *full_type = (strcmp(type, "vxlan") ? type
                              : (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GPE)
@@ -962,9 +976,13 @@  get_tunnel_config(const struct netdev *dev, struct smap *args)
         }
     }
 
+    if (!strcmp("vxlan", type) && tnl_cfg.allow_info_bridge) {
+        smap_add(args, "allow_info_bridge", "true");
+    }
+
     return 0;
 }
-
+
 /* Code specific to patch ports. */
 
 /* If 'netdev' is a patch port, returns the name of its peer as a malloc()'d
diff --git a/lib/netdev.h b/lib/netdev.h
index d94817f..1fcee9c 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -139,6 +139,8 @@  struct netdev_tunnel_config {
     bool erspan_idx_flow;
     bool erspan_dir_flow;
     bool erspan_hwid_flow;
+
+    bool allow_info_bridge;
 };
 
 void netdev_run(void);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index b6552c5..e3ad8ee 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -2480,6 +2480,7 @@  static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX +
     [OVS_TUNNEL_KEY_ATTR_IPV6_SRC]      = { .len = 16 },
     [OVS_TUNNEL_KEY_ATTR_IPV6_DST]      = { .len = 16 },
     [OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS]   = { .len = ATTR_LEN_VARIABLE },
+    [OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE]   = { .len = 0 },
 };
 
 const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = {
@@ -2871,6 +2872,8 @@  odp_tun_key_from_attr__(const struct nlattr *attr, bool is_mask,
             }
             break;
         }
+        case OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE:
+            tun->ipv4_info_bridge = 1;
 
         default:
             /* Allow this to show up as unexpected, if there are unknown
@@ -2918,6 +2921,11 @@  tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
     if (tun_key->tun_id || tun_key->flags & FLOW_TNL_F_KEY) {
         nl_msg_put_be64(a, OVS_TUNNEL_KEY_ATTR_ID, tun_key->tun_id);
     }
+    if (tnl_type && !strcmp(tnl_type, "vxlan") &&
+        tun_key->ipv4_info_bridge) {
+        nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE);
+        goto out;
+    }
     if (tun_key->ip_src) {
         nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, tun_key->ip_src);
     }
@@ -2985,6 +2993,7 @@  tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
                           &opts, sizeof(opts));
     }
 
+out:
     nl_msg_end_nested(a, tun_key_ofs);
 }
 
@@ -3733,6 +3742,9 @@  format_odp_tun_attr(const struct nlattr *attr, const struct nlattr *mask_attr,
             format_odp_tun_erspan_opt(a, ma, ds, verbose);
             ds_put_cstr(ds, "),");
             break;
+        case OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE:
+            ds_put_cstr(ds, "ipv4_info_bridge,");
+            break;
         case __OVS_TUNNEL_KEY_ATTR_MAX:
         default:
             format_unknown_key(ds, a, ma);
@@ -7351,9 +7363,10 @@  void
 commit_odp_tunnel_action(const struct flow *flow, struct flow *base,
                          struct ofpbuf *odp_actions, const char *tnl_type)
 {
-    /* A valid IPV4_TUNNEL must have non-zero ip_dst; a valid IPv6 tunnel
-     * must have non-zero ipv6_dst. */
-    if (flow_tnl_dst_is_set(&flow->tunnel)) {
+    /* A valid IPV4_TUNNEL must have non-zero ip_dst or ipv4 info bridge mode;
+     * a valid IPv6 tunnel must have non-zero ipv6_dst. */
+    if (flow_tnl_dst_is_set(&flow->tunnel) ||
+        flow_tnl_ipv4_info_bridge(&flow->tunnel)) {
         if (!memcmp(&base->tunnel, &flow->tunnel, sizeof base->tunnel)) {
             return;
         }
diff --git a/lib/packets.h b/lib/packets.h
index d293b35..9b86be2 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -51,6 +51,12 @@  flow_tnl_dst_is_set(const struct flow_tnl *tnl)
     return tnl->ip_dst || ipv6_addr_is_set(&tnl->ipv6_dst);
 }
 
+static inline bool
+flow_tnl_ipv4_info_bridge(const struct flow_tnl *tnl)
+{
+    return tnl->ipv4_info_bridge;
+}
+
 struct in6_addr flow_tnl_dst(const struct flow_tnl *tnl);
 struct in6_addr flow_tnl_src(const struct flow_tnl *tnl);
 
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index c4014d7..63eaaa1 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -4076,7 +4076,8 @@  compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
             goto out; /* restore flow_nw_tos */
         }
         dst = flow_tnl_dst(&flow->tunnel);
-        if (ipv6_addr_equals(&dst, &ctx->orig_tunnel_ipv6_dst)) {
+        if (!flow_tnl_ipv4_info_bridge(&flow->tunnel) &&
+            ipv6_addr_equals(&dst, &ctx->orig_tunnel_ipv6_dst)) {
             xlate_report(ctx, OFT_WARN, "Not tunneling to our own address");
             goto out; /* restore flow_nw_tos */
         }
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index 03f0ab7..86204d3 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -490,6 +490,11 @@  tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
         flow->tunnel.erspan_hwid = cfg->erspan_hwid;
     }
 
+    if (cfg->allow_info_bridge && !flow_tnl_dst_is_set(&flow->tunnel) &&
+        !flow->tunnel.gbp_flags && !flow->tunnel.gbp_id) {
+        flow->tunnel.ipv4_info_bridge = 1;
+    }
+
     if (pre_flow_str) {
         char *post_flow_str = flow_to_string(flow, NULL);
         char *tnl_str = tnl_port_to_string(tnl_port);
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 08001db..5c5728c 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -2848,6 +2848,15 @@ 
             </li>
           </ul>
         </column>
+
+        <column name="options" key="allow_info_bridge"
+                type='{"type": "boolean"}'>
+          Optional. Only in reomte_ip=flow mode can be enabled. If enabled,
+          the tunnel dst is not set in flow. It will ignore all other
+          parameters except VNI. It makes the packet forward through the fdb
+          of vxlan_sys_x device. Default is disable; set to <code>true</code>
+          to enable.
+        </column>
       </group>
 
       <group title="Tunnel Options: gre only">