[ovs-dev] [PATCH 3/3] vxlan: Make vxlan tunnel work in IP_TUNNEL_INFO_BRIDGE mode

Greg Rose gvrose8192 at gmail.com
Thu Sep 17 17:14:14 UTC 2020


From: wenxu <wenxu at 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 at ucloud.cn>
Signed-off-by: Greg Rose <gvrose8192 at gmail.com>
---
 include/openvswitch/packets.h |  3 ++-
 lib/netdev-vport.c            | 18 ++++++++++++++++++
 lib/netdev.h                  |  2 ++
 lib/odp-util.c                | 21 ++++++++++++++++++---
 lib/packets.h                 |  6 ++++++
 ofproto/ofproto-dpif-xlate.c  |  3 ++-
 ofproto/tunnel.c              |  5 +++++
 vswitchd/vswitch.xml          |  9 +++++++++
 8 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h
index a65cb0d04..bf3774e84 100644
--- a/include/openvswitch/packets.h
+++ b/include/openvswitch/packets.h
@@ -43,9 +43,10 @@ struct flow_tnl {
     uint32_t erspan_idx;
     uint8_t erspan_dir;
     uint8_t erspan_hwid;
+    uint8_t ipv4_info_bridge;
     uint8_t gtpu_flags;
     uint8_t gtpu_msgtype;
-    uint8_t pad1[4];     /* Pad to 64 bits. */
+    uint8_t pad1[3];     /* Pad to 64 bits. */
     struct tun_metadata metadata;
 };
 
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 0252b61de..4cba7fe20 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -569,6 +569,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;
 
@@ -745,12 +746,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)
@@ -983,6 +997,10 @@ 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;
 }
 
diff --git a/lib/netdev.h b/lib/netdev.h
index fb5073056..715a8af84 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 5989381e9..b43c599d6 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -2668,6 +2668,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 },
     [OVS_TUNNEL_KEY_ATTR_GTPU_OPTS]   = { .len = ATTR_LEN_VARIABLE },
 };
 
@@ -3081,6 +3082,9 @@ odp_tun_key_from_attr__(const struct nlattr *attr, bool is_mask,
             tun->gtpu_msgtype = opts->msgtype;
             break;
         }
+        case OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE:
+            tun->ipv4_info_bridge = 1;
+            break;
 
         default:
             /* Allow this to show up as unexpected, if there are unknown
@@ -3128,6 +3132,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);
     }
@@ -3204,6 +3213,8 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
         nl_msg_put_unspec(a, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
                           &opts, sizeof(opts));
     }
+
+out:
     nl_msg_end_nested(a, tun_key_ofs);
 }
 
@@ -3973,6 +3984,9 @@ format_odp_tun_attr(const struct nlattr *attr, const struct nlattr *mask_attr,
             format_odp_tun_gtpu_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);
@@ -7687,9 +7701,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 395bc869e..9edf52113 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -58,6 +58,12 @@ flow_tnl_src_is_set(const struct flow_tnl *tnl)
     return tnl->ip_src || ipv6_addr_is_set(&tnl->ipv6_src);
 }
 
+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 e0ede2cab..fb26fb373 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -4172,7 +4172,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 3455ed233..18ec93655 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -488,6 +488,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 81c84927f..d9e8f4373 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -2944,6 +2944,15 @@
             </li>
           </ul>
         </column>
+
+        <column name="options" key="allow_info_bridge"
+                type='{"type": "boolean"}'>
+          Optional. Only in remote_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">
-- 
2.17.1



More information about the dev mailing list