[ovs-dev] [PATCH RFC v2] ovn-northd: add default_dhcpvx_options for Logical_Switch

Zongkai LI zealokii at gmail.com
Tue Aug 30 03:48:37 UTC 2016


This patch adds default_dhcpv4_options and default_dhcpv6_options columns for
Logical_Switch, which should help CMS not to calculate and set dhcpv4_options
and dhcpv6_options columns for lswitch ports on lswitchs one by one, when
most of lswitch ports on the same lswitch are using the DHCPv4_Options and
DHCPv6_Options. Default DHCP(v4 and v6) Options should benefit in case
scalling up and DB synchronization between CMS and OVN NB.

v1 -> v2
add ACL lflows support for lswitch ports using default_dhcpvx_options from
lswitch.

---
 ovn/northd/ovn-northd.c | 144 ++++++++++++++++++++++++++++++++++++------------
 ovn/ovn-nb.ovsschema    |  18 +++++-
 ovn/ovn-nb.xml          |  26 +++++++++
 tests/ovn.at            |   6 +-
 4 files changed, 152 insertions(+), 42 deletions(-)

diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 19f3fb1..8919165 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -1784,14 +1784,27 @@ static bool
 build_dhcpv4_action(struct ovn_port *op, ovs_be32 offer_ip,
                     struct ds *options_action, struct ds *response_action)
 {
+    char *cidr = NULL;
+    struct smap dhcpv4_options = SMAP_INITIALIZER(&dhcpv4_options);
     if (!op->nbsp->dhcpv4_options) {
-        /* CMS has disabled native DHCPv4 for this lport. */
-        return false;
+        if ((!op->nbsp->use_default_dhcpv4 || *op->nbsp->use_default_dhcpv4)
+            && op->od->nbs->default_dhcpv4_options) {
+            /* Use lswitch default DHCPv4 options for this lport. */
+            cidr = op->od->nbs->default_dhcpv4_options->cidr;
+            smap_clone(&dhcpv4_options,
+                       &op->od->nbs->default_dhcpv4_options->options);
+        } else {
+            /* CMS has disabled native DHCPv4 for this lport. */
+            smap_destroy(&dhcpv4_options);
+            return false;
+        }
+    } else {
+        cidr = op->nbsp->dhcpv4_options->cidr;
+        smap_clone(&dhcpv4_options, &op->nbsp->dhcpv4_options->options);
     }
 
     ovs_be32 host_ip, mask;
-    char *error = ip_parse_masked(op->nbsp->dhcpv4_options->cidr, &host_ip,
-                                  &mask);
+    char *error = ip_parse_masked(cidr, &host_ip, &mask);
     if (error || ((offer_ip ^ host_ip) & mask)) {
        /* Either
         *  - cidr defined is invalid or
@@ -1802,14 +1815,10 @@ build_dhcpv4_action(struct ovn_port *op, ovs_be32 offer_ip,
         return false;
     }
 
-    const char *server_ip = smap_get(
-        &op->nbsp->dhcpv4_options->options, "server_id");
-    const char *server_mac = smap_get(
-        &op->nbsp->dhcpv4_options->options, "server_mac");
-    const char *lease_time = smap_get(
-        &op->nbsp->dhcpv4_options->options, "lease_time");
-    const char *router = smap_get(
-            &op->nbsp->dhcpv4_options->options, "router");
+    const char *server_ip = smap_get(&dhcpv4_options, "server_id");
+    const char *server_mac = smap_get(&dhcpv4_options, "server_mac");
+    const char *lease_time = smap_get(&dhcpv4_options, "lease_time");
+    const char *router = smap_get(&dhcpv4_options, "router");
 
     if (!(server_ip && server_mac && lease_time && router)) {
         /* "server_id", "server_mac", "lease_time" and "router" should be
@@ -1820,8 +1829,8 @@ build_dhcpv4_action(struct ovn_port *op, ovs_be32 offer_ip,
         return false;
     }
 
-    struct smap dhcpv4_options = SMAP_INITIALIZER(&dhcpv4_options);
-    smap_clone(&dhcpv4_options, &op->nbsp->dhcpv4_options->options);
+    char server_mac_str[ETH_ADDR_STRLEN + 1];
+    strcpy(server_mac_str, server_mac);
 
     /* server_mac is not DHCPv4 option, delete it from the smap. */
     smap_remove(&dhcpv4_options, "server_mac");
@@ -1845,7 +1854,7 @@ build_dhcpv4_action(struct ovn_port *op, ovs_be32 offer_ip,
                   "ip4.dst = "IP_FMT"; ip4.src = %s; udp.src = 67; "
                   "udp.dst = 68; outport = inport; flags.loopback = 1; "
                   "output;",
-                  server_mac, IP_ARGS(offer_ip), server_ip);
+                  server_mac_str, IP_ARGS(offer_ip), server_ip);
 
     smap_destroy(&dhcpv4_options);
     return true;
@@ -1855,15 +1864,28 @@ static bool
 build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip,
                     struct ds *options_action, struct ds *response_action)
 {
+    char *cidr = NULL;
+    struct smap dhcpv6_options = SMAP_INITIALIZER(&dhcpv6_options);
     if (!op->nbsp->dhcpv6_options) {
-        /* CMS has disabled native DHCPv6 for this lport. */
-        return false;
+        if ((!op->nbsp->use_default_dhcpv6 || *op->nbsp->use_default_dhcpv6)
+            && op->od->nbs->default_dhcpv6_options) {
+            /* Use lswitch default DHCPv6 options for this lport. */
+            cidr = op->od->nbs->default_dhcpv6_options->cidr;
+            smap_clone(&dhcpv6_options,
+                       &op->od->nbs->default_dhcpv6_options->options);
+        } else {
+            /* CMS has disabled native DHCPv6 for this lport. */
+            smap_destroy(&dhcpv6_options);
+            return false;
+        }
+    } else {
+        cidr = op->nbsp->dhcpv6_options->cidr;
+        smap_clone(&dhcpv6_options, &op->nbsp->dhcpv6_options->options);
     }
 
     struct in6_addr host_ip, mask;
 
-    char *error = ipv6_parse_masked(op->nbsp->dhcpv6_options->cidr, &host_ip,
-                                        &mask);
+    char *error = ipv6_parse_masked(cidr, &host_ip, &mask);
     if (error) {
         free(error);
         return false;
@@ -1877,8 +1899,7 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip,
     }
 
     /* "server_id" should be the MAC address. */
-    const char *server_mac = smap_get(&op->nbsp->dhcpv6_options->options,
-                                      "server_id");
+    const char *server_mac = smap_get(&dhcpv6_options, "server_id");
     struct eth_addr ea;
     if (!server_mac || !eth_addr_from_string(server_mac, &ea)) {
         /* "server_id" should be present in the dhcpv6_options. */
@@ -1902,7 +1923,7 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip,
                   REGBIT_DHCP_OPTS_RESULT" = put_dhcpv6_opts(ia_addr = %s, ",
                   ia_addr);
     struct smap_node *node;
-    SMAP_FOR_EACH (node, &op->nbsp->dhcpv6_options->options) {
+    SMAP_FOR_EACH (node, &dhcpv6_options) {
         ds_put_format(options_action, "%s = %s, ", node->key, node->value);
     }
     ds_chomp(options_action, ' ');
@@ -2324,6 +2345,39 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows)
 
     /* Add 34000 priority flow to allow DHCP reply from ovn-controller to all
      * logical ports of the datapath if the CMS has configured DHCPv4 options*/
+    struct ds od_default_dhcpv4_match = DS_EMPTY_INITIALIZER;
+    if (od->nbs->default_dhcpv4_options) {
+        const char *server_id = smap_get(
+            &od->nbs->default_dhcpv4_options->options, "server_id");
+        const char *server_mac = smap_get(
+            &od->nbs->default_dhcpv4_options->options, "server_mac");
+        const char *lease_time = smap_get(
+            &od->nbs->default_dhcpv4_options->options, "lease_time");
+        const char *router = smap_get(
+            &od->nbs->default_dhcpv4_options->options, "router");
+        if (server_id && server_mac && lease_time && router) {
+            ds_put_format(&od_default_dhcpv4_match, "eth.src == %s "
+                          "&& ip4.src == %s && udp && udp.src == 67 "
+                          "&& udp.dst == 68",
+                          server_mac, server_id);
+        }
+    }
+    struct ds od_default_dhcpv6_match = DS_EMPTY_INITIALIZER;
+    if (od->nbs->default_dhcpv6_options) {
+        const char *server_mac = smap_get(
+            &od->nbs->default_dhcpv6_options->options, "server_id");
+        struct eth_addr ea;
+        if (server_mac && eth_addr_from_string(server_mac, &ea)) {
+            struct in6_addr lla;
+            in6_generate_lla(ea, &lla);
+            char server_ip[INET6_ADDRSTRLEN + 1];
+            ipv6_string_mapped(server_ip, &lla);
+            ds_put_format(&od_default_dhcpv6_match, "eth.src == %s "
+                          "&& ip6.src == %s && udp && udp.src == 547 "
+                          "&& udp.dst == 546",
+                          server_mac, server_ip);
+        }
+    }
     for (size_t i = 0; i < od->nbs->n_ports; i++) {
         if (od->nbs->ports[i]->dhcpv4_options) {
             const char *server_id = smap_get(
@@ -2346,6 +2400,18 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows)
                     lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match),
                     actions);
             }
+        } else if (od_default_dhcpv4_match.length != 0
+                   && (!od->nbs->ports[i]->use_default_dhcpv4
+                       || *od->nbs->ports[i]->use_default_dhcpv4)) {
+            struct ds match = DS_EMPTY_INITIALIZER;
+            const char *actions =
+                has_stateful ? "ct_commit; next;" : "next;";
+            ds_put_format(&match, "outport == \"%s\" && %s",
+                          od->nbs->ports[i]->name,
+                          ds_cstr(&od_default_dhcpv4_match));
+            ovn_lflow_add(
+                lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match),
+                actions);
         }
 
         if (od->nbs->ports[i]->dhcpv6_options) {
@@ -2372,6 +2438,18 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows)
                     lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match),
                     actions);
             }
+        } else if (od_default_dhcpv6_match.length != 0
+                   && (!od->nbs->ports[i]->use_default_dhcpv6
+                       || *od->nbs->ports[i]->use_default_dhcpv6)) {
+            struct ds match = DS_EMPTY_INITIALIZER;
+            const char *actions =
+                has_stateful ? "ct_commit; next;" : "next;";
+            ds_put_format(&match, "outport == \"%s\" && %s",
+                          od->nbs->ports[i]->name,
+                          ds_cstr(&od_default_dhcpv6_match));
+            ovn_lflow_add(
+                lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match),
+                actions);
         }
     }
 }
@@ -2664,16 +2742,12 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
             continue;
         }
 
-        if (!op->nbsp->dhcpv4_options && !op->nbsp->dhcpv6_options) {
-            /* CMS has disabled both native DHCPv4 and DHCPv6 for this lport.
-             */
-            continue;
-        }
-
+        struct ds options_action = DS_EMPTY_INITIALIZER;
+        struct ds response_action = DS_EMPTY_INITIALIZER;
         for (size_t i = 0; i < op->n_lsp_addrs; i++) {
+            ds_clear(&options_action);
+            ds_clear(&response_action);
             for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) {
-                struct ds options_action = DS_EMPTY_INITIALIZER;
-                struct ds response_action = DS_EMPTY_INITIALIZER;
                 if (build_dhcpv4_action(
                         op, op->lsp_addrs[i].ipv4_addrs[j].addr,
                         &options_action, &response_action)) {
@@ -2694,15 +2768,13 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
                                   100, ds_cstr(&match),
                                   ds_cstr(&response_action));
                     ds_destroy(&match);
-                    ds_destroy(&options_action);
-                    ds_destroy(&response_action);
                     break;
                 }
             }
 
+            ds_clear(&options_action);
+            ds_clear(&response_action);
             for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) {
-                struct ds options_action = DS_EMPTY_INITIALIZER;
-                struct ds response_action = DS_EMPTY_INITIALIZER;
                 if (build_dhcpv6_action(
                         op, &op->lsp_addrs[i].ipv6_addrs[j].addr,
                         &options_action, &response_action)) {
@@ -2722,12 +2794,12 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
                     ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, 100,
                                   ds_cstr(&match), ds_cstr(&response_action));
                     ds_destroy(&match);
-                    ds_destroy(&options_action);
-                    ds_destroy(&response_action);
                     break;
                 }
             }
         }
+        ds_destroy(&options_action);
+        ds_destroy(&response_action);
     }
 
     /* Ingress table 10 and 11: DHCP options and response, by default goto next.
diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema
index 456ae98..0591065 100644
--- a/ovn/ovn-nb.ovsschema
+++ b/ovn/ovn-nb.ovsschema
@@ -1,7 +1,7 @@
 {
     "name": "OVN_Northbound",
-    "version": "5.3.1",
-    "cksum": "1921908091 9353",
+    "version": "5.4.0",
+    "cksum": "2099971381 10299",
     "tables": {
         "NB_Global": {
             "columns": {
@@ -31,6 +31,16 @@
                                                   "refType": "strong"},
                                            "min": 0,
                                            "max": "unlimited"}},
+                "default_dhcpv4_options": {"type": {"key": {"type": "uuid",
+                                                    "refTable": "DHCP_Options",
+                                                    "refType": "weak"},
+                                           "min": 0,
+                                           "max": 1}},
+                "default_dhcpv6_options": {"type": {"key": {"type": "uuid",
+                                                    "refTable": "DHCP_Options",
+                                                    "refType": "weak"},
+                                            "min": 0,
+                                            "max": 1}},
                 "other_config": {
                     "type": {"key": "string", "value": "string",
                              "min": 0, "max": "unlimited"}},
@@ -74,6 +84,10 @@
                                             "refType": "weak"},
                                  "min": 0,
                                  "max": 1}},
+                "use_default_dhcpv4": {"type": {"key": "boolean",
+                                                "min": 0, "max": 1}},
+                "use_default_dhcpv6": {"type": {"key": "boolean",
+                                                "min": 0, "max": 1}},
                 "external_ids": {
                     "type": {"key": "string", "value": "string",
                              "min": 0, "max": "unlimited"}}},
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index 5719e74..37b4481 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -119,6 +119,18 @@
       Access control rules that apply to packets within the logical switch.
     </column>
 
+    <column name="default_dhcpv4_options">
+      This column defines the DHCPv4 Options would used by ports on switch.
+      Check column <ref column="use_default_dhcpv4"/> in table
+      <ref table="Logical_Switch_Port"/>.
+    </column>
+
+    <column name="default_dhcpv6_options">
+      This column defines the DHCPv6 Options would used by ports on switch.
+      Check column <ref column="use_default_dhcpv6"/> in table
+      <ref table="Logical_Switch_Port"/>.
+    </column>
+
     <group title="other_config">
       <p>
         Additional configuration options for the logical switch.
@@ -609,6 +621,20 @@
         Please see the <ref table="DHCP_Options"/> table.
       </column>
 
+      <column name="use_default_dhcpv4">
+        This column defines whether the port should use DHCPv4 Options owned by
+        lswitch. Only when column <ref column="dhcpv4_options"/> is unset or
+        empty, and this column is set to true, port will use DHCPv4 Options
+        owned by lswitch. Default to true.
+      </column>
+
+      <column name="use_default_dhcpv6">
+        This column defines whether the port should use DHCPv6 Options owned by
+        lswitch. Only when column <ref column="dhcpv6_options"/> is unset or
+        empty, and this column is set to true, port will use DHCPv6 Options
+        owned by lswitch. Default to true.
+      </column>
+
       <column name="external_ids">
         See <em>External IDs</em> at the beginning of this document.
       </column>
diff --git a/tests/ovn.at b/tests/ovn.at
index 2fa5d0b..9441d38 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -3502,8 +3502,7 @@ ovn-nbctl lsp-set-port-security ls2-lp2 "f0:00:00:00:00:04 30.0.0.7"
 ovn-nbctl -- --id=@d1 create DHCP_Options cidr=10.0.0.0/24 \
 options="\"server_id\"=\"10.0.0.1\" \"server_mac\"=\"ff:10:00:00:00:01\" \
 \"lease_time\"=\"3600\" \"router\"=\"10.0.0.1\"" \
--- add Logical_Switch_Port ls1-lp1 dhcpv4_options @d1 \
--- add Logical_Switch_Port ls1-lp2 dhcpv4_options @d1
+-- add Logical_Switch ls1 default_dhcpv4_options @d1
 
 ovn-nbctl -- --id=@d2 create DHCP_Options cidr=30.0.0.0/24 \
 options="\"server_id\"=\"30.0.0.1\" \"server_mac\"=\"ff:10:00:00:00:02\" \
@@ -3762,8 +3761,7 @@ ovn-nbctl lsp-set-port-security ls1-lp2 "f0:00:00:00:00:02 ae70::5"
 
 ovn-nbctl -- --id=@d1 create DHCP_Options cidr="ae70\:\:/64" \
 options="\"server_id\"=\"00:00:00:10:00:01\"" \
--- add Logical_Switch_Port ls1-lp1 dhcpv6_options @d1 \
--- add Logical_Switch_Port ls1-lp2 dhcpv6_options @d1
+-- add Logical_Switch ls1 default_dhcpv6_options @d1 \
 
 ovn-nbctl ls-add ls2
 ovn-nbctl lsp-add ls2 ls2-lp1 \
-- 
2.7.4




More information about the dev mailing list