[ovs-dev] [PATCH v2] OVN: Fix learning of neighbors from ARP/ND packets.

Dumitru Ceara dceara at redhat.com
Fri Jul 26 06:32:37 UTC 2019


Add a restriction on the target protocol addresses to match the configured
subnets. All other ARP/ND packets are invalid in this context.

One exception is for ARP replies that are received for route next-hops
that are only reachable via a port but can't be directly resolved
through route lookups. Such support was introduced by commit:

6b785fd8fe29 ("ovn-util: Allow /32 IP addresses for router ports.")

Reported-at: https://bugzilla.redhat.com/1729846
Reported-by: Haidong Li <haili at redhat.com>
CC: Han Zhou <zhouhan at gmail.com>
CC: Guru Shetty <guru at ovn.org>
Fixes: b068454082f5 ("ovn-northd: Support learning neighbor from ARP request.")
Signed-off-by: Dumitru Ceara <dceara at redhat.com>
---

v2:
- Update commit message.
- Implement the fix also for ARP replies and IPv6 ND.
---
 ovn/northd/ovn-northd.c | 95 +++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 81 insertions(+), 14 deletions(-)

diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index eb6c47c..1e3ec68 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -5815,10 +5815,32 @@ build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od,
             if (is_ipv4) {
                 if (out_port->lrp_networks.n_ipv4_addrs) {
                     lrp_addr_s = out_port->lrp_networks.ipv4_addrs[0].addr_s;
+
+                    /* Explicitly allow ARP replies for the next-hop. */
+                    struct ds match;
+                    ds_init(&match);
+                    ds_put_format(&match, "inport == %s && arp.op == 2 && "
+                                  "arp.spa == %s", out_port->json_key,
+                                  route->nexthop);
+                    ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90,
+                                  ds_cstr(&match),
+                                  "put_arp(inport, arp.spa, arp.sha);");
+                    ds_destroy(&match);
                 }
             } else {
                 if (out_port->lrp_networks.n_ipv6_addrs) {
                     lrp_addr_s = out_port->lrp_networks.ipv6_addrs[0].addr_s;
+
+                    /* Explicitly allow NA for the next-hop. */
+                    struct ds match;
+                    ds_init(&match);
+                    ds_put_format(&match, "inport == %s && nd_na && "
+                                  "ip6.src == %s", out_port->json_key,
+                                  route->nexthop);
+                    ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90,
+                                  ds_cstr(&match),
+                                  "put_nd(inport, nd.target, nd.tll);");
+                    ds_destroy(&match);
                 }
             }
         }
@@ -6159,10 +6181,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                       "ip4.dst == 0.0.0.0/8",
                       "drop;");
 
-        /* ARP reply handling.  Use ARP replies to populate the logical
-         * router's ARP table. */
-        ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, "arp.op == 2",
-                      "put_arp(inport, arp.spa, arp.sha);");
 
         /* Drop Ethernet local broadcast.  By definition this traffic should
          * not be forwarded.*/
@@ -6175,16 +6193,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30,
                       ds_cstr(&match), "drop;");
 
-        /* ND advertisement handling.  Use advertisements to populate
-         * the logical router's ARP/ND table. */
-        ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, "nd_na",
-                      "put_nd(inport, nd.target, nd.tll);");
 
-        /* Lean from neighbor solicitations that were not directed at
-         * us.  (A priority-90 flow will respond to requests to us and
-         * learn the sender's mac address. */
-        ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 80, "nd_ns",
-                      "put_nd(inport, ip6.src, nd.sll);");
 
         /* Pass other traffic not already handled to the next table for
          * routing. */
@@ -6320,15 +6329,34 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                           ds_cstr(&match), ds_cstr(&actions));
         }
 
+        /* ARP reply handling. Use ARP replies to populate the logical
+         * router's ARP table. */
+        for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
+            ds_clear(&match);
+            ds_put_format(&match, "inport == %s && arp.spa == %s/%u && "
+                          "arp.tpa == %s/%u && arp.op == 2",
+                          op->json_key,
+                          op->lrp_networks.ipv4_addrs[i].network_s,
+                          op->lrp_networks.ipv4_addrs[i].plen,
+                          op->lrp_networks.ipv4_addrs[i].network_s,
+                          op->lrp_networks.ipv4_addrs[i].plen);
+            ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
+                          ds_cstr(&match),
+                          "put_arp(inport, arp.spa, arp.sha);");
+        }
+
         /* Learn from ARP requests that were not directed at us. A typical
          * use case is GARP request handling.  (A priority-90 flow will
          * respond to request to us and learn the sender's mac address.) */
         for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
             ds_clear(&match);
             ds_put_format(&match,
-                          "inport == %s && arp.spa == %s/%u && arp.op == 1",
+                          "inport == %s && arp.spa == %s/%u && "
+                          "arp.tpa == %s/%u && arp.op == 1",
                           op->json_key,
                           op->lrp_networks.ipv4_addrs[i].network_s,
+                          op->lrp_networks.ipv4_addrs[i].plen,
+                          op->lrp_networks.ipv4_addrs[i].network_s,
                           op->lrp_networks.ipv4_addrs[i].plen);
             if (op->od->l3dgw_port && op == op->od->l3dgw_port
                 && op->od->l3redirect_port) {
@@ -6669,6 +6697,45 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                           ds_cstr(&match), ds_cstr(&actions));
         }
 
+        /* NA reply handling. Use NA replies to populate the logical
+         * router's neighbor table. */
+        for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
+            ds_clear(&match);
+            ds_put_format(&match, "inport == %s && nd_na && "
+                          "nd.target == %s/%u && ip6.src == %s/%u",
+                          op->json_key,
+                          op->lrp_networks.ipv6_addrs[i].network_s,
+                          op->lrp_networks.ipv6_addrs[i].plen,
+                          op->lrp_networks.ipv6_addrs[i].network_s,
+                          op->lrp_networks.ipv6_addrs[i].plen);
+            ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
+                          ds_cstr(&match),
+                          "put_nd(inport, nd.target, nd.tll);");
+        }
+
+        /* Learn from ND requests that were not directed at us.
+         * (A priority-90 flow will respond to request to us and learn the
+         * sender's mac address.) */
+        for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
+            ds_clear(&match);
+            ds_put_format(&match,
+                          "inport == %s && nd_ns && ip6.src == %s/%u && "
+                          "ip6.dst == %s/%u",
+                          op->json_key,
+                          op->lrp_networks.ipv6_addrs[i].network_s,
+                          op->lrp_networks.ipv6_addrs[i].plen,
+                          op->lrp_networks.ipv6_addrs[i].network_s,
+                          op->lrp_networks.ipv6_addrs[i].plen);
+            if (op->od->l3dgw_port && op == op->od->l3dgw_port
+                && op->od->l3redirect_port) {
+                ds_put_format(&match, " && is_chassis_resident(%s)",
+                              op->od->l3redirect_port->json_key);
+            }
+            ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80,
+                          ds_cstr(&match),
+                          "put_nd(inport, ip6.src, nd.sll);");
+        }
+
         /* UDP/TCP port unreachable */
         if (!smap_get(&op->od->nbr->options, "chassis")
             && !op->od->l3dgw_port) {
-- 
1.8.3.1



More information about the dev mailing list