[ovs-dev] [PATCH] [RFC] ovn: Support ARP proxy in logical switches.

Han Zhou zhouhan at gmail.com
Thu Dec 15 19:03:20 UTC 2016


This patch support "arp_proxy" option for logical switch ports. If
a lsp with arp_proxy=true, all the arp request to known ipv4
addresses on the ls will be responded with the arp proxy lsp's MAC
address, except when the arp request come from the arp proxy lsp
itself.

TODO: update ovn-northd.xml, add test cases
Signed-off-by: Han Zhou <zhouhan at gmail.com>
---
 ovn/northd/ovn-northd.c | 119 ++++++++++++++++++++++++++++++++++++++++--------
 ovn/ovn-nb.xml          |  11 +++++
 2 files changed, 112 insertions(+), 18 deletions(-)

diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index c56ac79..f897658 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -380,6 +380,10 @@ struct ovn_datapath {
 
     bool has_unknown;
 
+    /* ARP proxy port: MAC of the lport will be used by arp
+     * responder for other lports in the same LS. */
+    struct ovn_port *arp_proxy_port;
+
     /* IPAM data. */
     struct hmap ipam;
 };
@@ -2012,6 +2016,15 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op,
 }
 
 static bool
+lsp_is_arp_proxy(const struct nbrec_logical_switch_port *lsp)
+{
+
+    bool is_arp_proxy = smap_get_bool(&lsp->options,
+                                      "arp_proxy", false);
+    return is_arp_proxy;
+}
+
+static bool
 lsp_is_enabled(const struct nbrec_logical_switch_port *lsp)
 {
     return !lsp->enabled || *lsp->enabled;
@@ -2852,6 +2865,32 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
         ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_IP, 0, "1", "next;");
     }
 
+    /* Check arp_proxy option for LS ports */
+    HMAP_FOR_EACH (op, key_node, ports) {
+        if (!op->nbsp) {
+            continue;
+        }
+
+        if (lsp_is_arp_proxy(op->nbsp)) {
+            if (op->n_lsp_addrs != 1) {
+                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+                VLOG_WARN_RL(&rl, "one and only one address expected for arp "
+                             "proxy port %s", op->json_key);
+                continue;
+            }
+            if (op->od->arp_proxy_port) {
+                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+                VLOG_WARN_RL(&rl,
+                             "ARP proxy lsp %s already existed on ls "UUID_FMT
+                             " but another lsp %s is seen",
+                             op->od->arp_proxy_port->json_key,
+                             UUID_ARGS(&op->od->key),
+                             op->json_key);
+                continue;
+            }
+            op->od->arp_proxy_port = op;
+        }
+    }
     /* Ingress table 10: ARP/ND responder, skip requests coming from localnet
      * and vtep ports. (priority 100); see ovn-northd.8.xml for the
      * rationale. */
@@ -2888,24 +2927,68 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
         for (size_t i = 0; i < op->n_lsp_addrs; i++) {
             for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) {
                 ds_clear(&match);
-                ds_put_format(&match, "arp.tpa == %s && arp.op == 1",
-                              op->lsp_addrs[i].ipv4_addrs[j].addr_s);
-                ds_clear(&actions);
-                ds_put_format(&actions,
-                    "eth.dst = eth.src; "
-                    "eth.src = %s; "
-                    "arp.op = 2; /* ARP reply */ "
-                    "arp.tha = arp.sha; "
-                    "arp.sha = %s; "
-                    "arp.tpa = arp.spa; "
-                    "arp.spa = %s; "
-                    "outport = inport; "
-                    "flags.loopback = 1; "
-                    "output;",
-                    op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s,
-                    op->lsp_addrs[i].ipv4_addrs[j].addr_s);
-                ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50,
-                              ds_cstr(&match), ds_cstr(&actions));
+                if (op->od->arp_proxy_port) {
+                    ds_put_format(&match, "arp.tpa == %s && arp.op == 1 && inport == %s",
+                                  op->lsp_addrs[i].ipv4_addrs[j].addr_s,
+                                  op->od->arp_proxy_port->json_key);
+                    ds_clear(&actions);
+                    ds_put_format(&actions,
+                        "eth.dst = eth.src; "
+                        "eth.src = %s; "
+                        "arp.op = 2; /* ARP reply */ "
+                        "arp.tha = arp.sha; "
+                        "arp.sha = %s; "
+                        "arp.tpa = arp.spa; "
+                        "arp.spa = %s; "
+                        "outport = inport; "
+                        "flags.loopback = 1; "
+                        "output;",
+                        op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s,
+                        op->lsp_addrs[i].ipv4_addrs[j].addr_s);
+                    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 60,
+                                  ds_cstr(&match), ds_cstr(&actions));
+
+                    ds_clear(&match);
+                    ds_put_format(&match, "arp.tpa == %s && arp.op == 1",
+                                  op->lsp_addrs[i].ipv4_addrs[j].addr_s);
+                    ds_clear(&actions);
+                    char *proxy_mac = op->od->arp_proxy_port->lsp_addrs[0].ea_s;
+                    ds_put_format(&actions,
+                        "eth.dst = eth.src; "
+                        "eth.src = %s; "
+                        "arp.op = 2; /* ARP reply */ "
+                        "arp.tha = arp.sha; "
+                        "arp.sha = %s; "
+                        "arp.tpa = arp.spa; "
+                        "arp.spa = %s; "
+                        "outport = inport; "
+                        "flags.loopback = 1; "
+                        "output;",
+                        proxy_mac, proxy_mac,
+                        op->lsp_addrs[i].ipv4_addrs[j].addr_s);
+                    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50,
+                                  ds_cstr(&match), ds_cstr(&actions));
+
+                } else {
+                    ds_put_format(&match, "arp.tpa == %s && arp.op == 1",
+                                  op->lsp_addrs[i].ipv4_addrs[j].addr_s);
+                    ds_clear(&actions);
+                    ds_put_format(&actions,
+                        "eth.dst = eth.src; "
+                        "eth.src = %s; "
+                        "arp.op = 2; /* ARP reply */ "
+                        "arp.tha = arp.sha; "
+                        "arp.sha = %s; "
+                        "arp.tpa = arp.spa; "
+                        "arp.spa = %s; "
+                        "outport = inport; "
+                        "flags.loopback = 1; "
+                        "output;",
+                        op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s,
+                        op->lsp_addrs[i].ipv4_addrs[j].addr_s);
+                    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50,
+                                  ds_cstr(&match), ds_cstr(&actions));
+                }
 
                 /* Do not reply to an ARP request from the port that owns the
                  * address (otherwise a DHCP client that ARPs to check for a
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index 3e40881..a58d800 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -219,6 +219,17 @@
         individually below.
       </column>
 
+      <group title="Options for all port types">
+        <p>
+          These options apply when <ref column="type"/> is not set.
+        </p>
+
+        <column name="options" key="arp_proxy">
+          If this option is set to true, the lport acts as ARP proxy for all the
+          other lports on the same logical switch. Default value is false.
+        </column>
+      </group>
+
       <group title="Options for router ports">
         <p>
           These options apply when <ref column="type"/> is <code>router</code>.
-- 
2.1.0



More information about the dev mailing list