[ovs-dev] 回复: [PATCH v1] ofproto-dpif-xlate: Using output netdev's ip as tunnel arp/nd request ip

miterv at outlook.com miterv at outlook.com
Fri Jun 25 05:49:25 UTC 2021


If VXLAN tunnel's source ip and the output_bridge netdev's ip are not on
the same subnet, tnl_send_arp_request() will use tunnel's source ip as
arp/nd sender not the output netdev's ip. This lead to address resolution
(i.e., IPv4 ARP and IPv6 ND) scaling issues. OVS unable to get gateway
address information.

For example, OVS vxlan tunnel source ip is 2.2.2.2. The output_bridge
netdev's ip is 1.1.1.1. The ToR gateway ip is 1.1.1.2. After we sending
packets into this tunnel, tnl_send_arp_request() will send arp/nd request
which sender ip is 2.2.2.2 not the 1.1.1.1. That is arp/nd gateway learning
failed, no packets will be encapped in vxlan tunnel.

This patch fix it using the output_bridge netdev's ip as arp/nd request ip.

Signed-off-by: Lin Huang <linhuang at ruijie.com.cn>
---
 lib/ovs-router.c             |  2 +-
 ofproto/ofproto-dpif-xlate.c | 31 ++++++++++++++++++++++++++-----
 2 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/lib/ovs-router.c b/lib/ovs-router.c
index 09b81c6e5..3f9a72153 100644
--- a/lib/ovs-router.c
+++ b/lib/ovs-router.c
@@ -132,7 +132,7 @@ ovs_router_lookup(uint32_t mark, const struct in6_addr *ip6_dst,

         ovs_strlcpy(output_bridge, p->output_bridge, IFNAMSIZ);
         *gw = p->gw;
-        if (src && !ipv6_addr_is_set(src)) {
+        if (src) {
             *src = p->src_addr;
         }
         return true;
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index a6f4ea334..36253379d 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -3603,9 +3603,10 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport,
     struct netdev_tnl_build_header_params tnl_params;
     struct ovs_action_push_tnl tnl_push_data;
     struct xport *out_dev = NULL;
-    ovs_be32 s_ip = 0, d_ip = 0;
+    ovs_be32 s_ip = 0, d_ip = 0, o_ip = 0;
     struct in6_addr s_ip6 = in6addr_any;
     struct in6_addr d_ip6 = in6addr_any;
+    struct in6_addr o_ip6 = in6addr_any;
     struct eth_addr smac;
     struct eth_addr dmac;
     int err;
@@ -3627,7 +3628,14 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport,
         in6_addr_set_mapped_ipv4(&s_ip6, flow->tunnel.ip_src);
     }

-    err = tnl_route_lookup_flow(ctx, flow, &d_ip6, &s_ip6, &out_dev);
+    if (!ipv6_addr_is_set(&s_ip6)) {
+        err = tnl_route_lookup_flow(ctx, flow, &d_ip6, &s_ip6, &out_dev);
+    } else {
+        /* o_ip6/o_ip means the output_bridge netdev's ip. */
+        o_ip6 = s_ip6;
+        err = tnl_route_lookup_flow(ctx, flow, &d_ip6, &o_ip6, &out_dev);
+    }
+
     if (err) {
         xlate_report(ctx, OFT_WARN, "native tunnel routing failed");
         return err;
@@ -3648,6 +3656,7 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport,
     d_ip = in6_addr_get_mapped_ipv4(&d_ip6);
     if (d_ip) {
         s_ip = in6_addr_get_mapped_ipv4(&s_ip6);
+        o_ip = in6_addr_get_mapped_ipv4(&o_ip6);
     }

     err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac);
@@ -3656,10 +3665,22 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport,
                      "neighbor cache miss for %s on bridge %s, "
                      "sending %s request",
                      buf_dip6, out_dev->xbridge->name, d_ip ? "ARP" : "ND");
-        if (d_ip) {
-            tnl_send_arp_request(ctx, out_dev, smac, s_ip, d_ip);
+        if (!ipv6_addr_is_set(&o_ip6) || ipv6_addr_equals(&o_ip6, &s_ip6)) {
+            if (d_ip) {
+                tnl_send_arp_request(ctx, out_dev, smac, s_ip, d_ip);
+            } else {
+                tnl_send_nd_request(ctx, out_dev, smac, &s_ip6, &d_ip6);
+            }
         } else {
-            tnl_send_nd_request(ctx, out_dev, smac, &s_ip6, &d_ip6);
+            /*
+             * s_ip and d_ip is not on the same subnet, we need to using
+             * output_bridge netdev's ip as the arp sender or nd sender.
+             */
+            if (o_ip) {
+                tnl_send_arp_request(ctx, out_dev, smac, o_ip, d_ip);
+            } else {
+                tnl_send_nd_request(ctx, out_dev, smac, &o_ip6, &d_ip6);
+            }
         }
         return err;
     }
--
2.12.2




 
发件人: lin huang
发送时间: 2021-06-24 21:09
收件人: dev at openvswitch.org
主题: [PATCH] ofproto-dpif-xlate: Using output netdev's ip as tunnel arp/nd request ip
If VXLAN tunnel's source ip and the output_bridge netdev's ip are not on
the same subnet, tnl_send_arp_request() will use tunnel's source ip as
arp/nd sender not the output netdev's ip. This lead to address resolution
(i.e., IPv4 ARP and IPv6 ND) scaling issues. OVS unable to get gateway
address information.

For example, OVS vxlan tunnel source ip is 2.2.2.2. The output_bridge
netdev's ip is 1.1.1.1. The ToR gateway ip is 1.1.1.2. After we sending
packets into this tunnel, tnl_send_arp_request() will send arp/nd request
which sender ip is 2.2.2.2 not the 1.1.1.1. That is arp/nd gateway learning
failed, no packets will be encapped in vxlan tunnel.

This patch fix it using the output_bridge netdev's ip as arp/nd request ip.

Signed-off-by: Lin Huang <linhuang at ruijie.com.cn>
---
 lib/ovs-router.c             |  2 +-
 ofproto/ofproto-dpif-xlate.c | 31 ++++++++++++++++++++++++++-----
 2 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/lib/ovs-router.c b/lib/ovs-router.c
index 09b81c6e5..3f9a72153 100644
--- a/lib/ovs-router.c
+++ b/lib/ovs-router.c
@@ -132,7 +132,7 @@ ovs_router_lookup(uint32_t mark, const struct in6_addr *ip6_dst,
 
         ovs_strlcpy(output_bridge, p->output_bridge, IFNAMSIZ);
         *gw = p->gw;
-        if (src && !ipv6_addr_is_set(src)) {
+        if (src) {
             *src = p->src_addr;
         }
         return true;
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index a6f4ea334..4009fd0f9 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -3603,9 +3603,10 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport,
     struct netdev_tnl_build_header_params tnl_params;
     struct ovs_action_push_tnl tnl_push_data;
     struct xport *out_dev = NULL;
-    ovs_be32 s_ip = 0, d_ip = 0;
+    ovs_be32 s_ip = 0, d_ip = 0, o_ip = 0;
     struct in6_addr s_ip6 = in6addr_any;
     struct in6_addr d_ip6 = in6addr_any;
+    struct in6_addr o_ip6 = in6addr_any;
     struct eth_addr smac;
     struct eth_addr dmac;
     int err;
@@ -3627,7 +3628,14 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport,
         in6_addr_set_mapped_ipv4(&s_ip6, flow->tunnel.ip_src);
     }
 
-    err = tnl_route_lookup_flow(ctx, flow, &d_ip6, &s_ip6, &out_dev);
+    if (!ipv6_addr_is_set(&s_ip6)) {
+        err = tnl_route_lookup_flow(ctx, flow, &d_ip6, &s_ip6, &out_dev);
+    } else {
+        /* o_ip6/o_ip means the output_bridge netdev's ip. */
+        o_ip6 = s_ip6;
+        err = tnl_route_lookup_flow(ctx, flow, &d_ip6, &o_ip6, &out_dev);
+    }
+
     if (err) {
         xlate_report(ctx, OFT_WARN, "native tunnel routing failed");
         return err;
@@ -3648,6 +3656,7 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport,
     d_ip = in6_addr_get_mapped_ipv4(&d_ip6);
     if (d_ip) {
         s_ip = in6_addr_get_mapped_ipv4(&s_ip6);
+        o_ip = in6_addr_get_mapped_ipv4(&o_ip6);
     }
 
     err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac);
@@ -3656,10 +3665,22 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport,
                      "neighbor cache miss for %s on bridge %s, "
                      "sending %s request",
                      buf_dip6, out_dev->xbridge->name, d_ip ? "ARP" : "ND");
-        if (d_ip) {
-            tnl_send_arp_request(ctx, out_dev, smac, s_ip, d_ip);
+        if (!ipv6_addr_is_set(&o_ip6) || ipv6_addr_equals(&o_ip6, &s_ip6)) {
+            if (d_ip) {
+                tnl_send_arp_request(ctx, out_dev, smac, s_ip, d_ip);
+            } else {
+                tnl_send_nd_request(ctx, out_dev, smac, &s_ip6, &d_ip6);
+            }
         } else {
-            tnl_send_nd_request(ctx, out_dev, smac, &s_ip6, &d_ip6);
+            /*
+             * s_ip and d_ip is not on the same subnet, we need to using
+             * output_bridge netdev's ip as the arp sender or nd sender.
+             */
+            if (local_ip) {
+                tnl_send_arp_request(ctx, out_dev, smac, o_ip, d_ip);
+            } else {
+                tnl_send_nd_request(ctx, out_dev, smac, &o_ip6, &d_ip6);
+            }
         }
         return err;
     }
-- 
2.12.2


More information about the dev mailing list