diff mbox series

[ovs-dev,ovn,RFC,v3,23/29] Move destination lookup, unicast out of into a function

Message ID 20200716131927.3943-24-anton.ivanov@cambridgegreys.com
State RFC
Headers show
Series [ovs-dev,ovn,RFC,v3,01/29] Move out Table 0 operations to functions | expand

Commit Message

Anton Ivanov July 16, 2020, 1:19 p.m. UTC
From: Anton Ivanov <anton.ivanov@cambridgegreys.com>

Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com>
---
 northd/ovn-northd.c | 427 +++++++++++++++++++++++---------------------
 1 file changed, 227 insertions(+), 200 deletions(-)
diff mbox series

Patch

diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index e215bcd63..c49d72462 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -6972,6 +6972,230 @@  build_lswitch_flows_step_100_od(
     }
 }
 
+static void
+build_lswitch_flows_step_110_igmp(
+        struct ovn_igmp_group *igmp_group, struct hmap *lflows)
+{
+    /* Ingress table 19: Add IP multicast flows learnt from IGMP/MLD
+     * (priority 90). */
+ 
+    if (igmp_group->datapath) {
+
+        struct ds actions = DS_EMPTY_INITIALIZER;
+        struct ds match = DS_EMPTY_INITIALIZER;
+
+        struct mcast_switch_info *mcast_sw_info =
+            &igmp_group->datapath->mcast_info.sw;
+
+        if (IN6_IS_ADDR_V4MAPPED(&igmp_group->address)) {
+            /* RFC 4541, section 2.1.2, item 2: Skip groups in the 224.0.0.X
+             * range.
+             */
+            ovs_be32 group_address =
+                in6_addr_get_mapped_ipv4(&igmp_group->address);
+            if (ip_is_local_multicast(group_address)) {
+                ds_destroy(&actions);
+                ds_destroy(&match);
+                return;
+            }
+
+            if (mcast_sw_info->active_v4_flows >= mcast_sw_info->table_size) {
+                ds_destroy(&actions);
+                ds_destroy(&match);
+                return;
+            }
+            mcast_sw_info->active_v4_flows++;
+            ds_put_format(&match, "eth.mcast && ip4 && ip4.dst == %s ",
+                          igmp_group->mcgroup.name);
+        } else {
+            /* RFC 4291, section 2.7.1: Skip groups that correspond to all
+             * hosts.
+             */
+            if (ipv6_is_all_hosts(&igmp_group->address)) {
+                ds_destroy(&actions);
+                ds_destroy(&match);
+                return;
+            }
+            if (mcast_sw_info->active_v6_flows >= mcast_sw_info->table_size) {
+                ds_destroy(&actions);
+                ds_destroy(&match);
+                return;
+            }
+            mcast_sw_info->active_v6_flows++;
+            ds_put_format(&match, "eth.mcast && ip6 && ip6.dst == %s ",
+                          igmp_group->mcgroup.name);
+        }
+
+        /* Also flood traffic to all multicast routers with relay enabled. */
+        if (mcast_sw_info->flood_relay) {
+            ds_put_cstr(&actions,
+                        "clone { "
+                            "outport = \""MC_MROUTER_FLOOD "\"; "
+                            "output; "
+                        "};");
+        }
+        if (mcast_sw_info->flood_static) {
+            ds_put_cstr(&actions,
+                        "clone { "
+                            "outport =\""MC_STATIC"\"; "
+                            "output; "
+                        "};");
+        }
+        ds_put_format(&actions, "outport = \"%s\"; output; ",
+                      igmp_group->mcgroup.name);
+
+        ovn_lflow_add(lflows, igmp_group->datapath, S_SWITCH_IN_L2_LKUP, 90,
+                      ds_cstr(&match), ds_cstr(&actions));
+        ds_destroy(&actions);
+        ds_destroy(&match);
+    }
+}
+
+static void
+build_lswitch_flows_step_120_op(
+        struct ovn_port *op, struct hmap *lflows, struct hmap *mcgroups)
+{
+    /* Ingress table 19: Destination lookup, unicast handling (priority 50), */
+
+    if (!op->nbsp || lsp_is_external(op->nbsp)) {
+        return;
+    }
+
+    struct ds actions = DS_EMPTY_INITIALIZER;
+    struct ds match = DS_EMPTY_INITIALIZER;
+
+    /* For ports connected to logical routers add flows to bypass the
+     * broadcast flooding of ARP/ND requests in table 19. We direct the
+     * requests only to the router port that owns the IP address.
+     */
+    if (!strcmp(op->nbsp->type, "router")) {
+        build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lflows,
+                                          &op->nbsp->header_);
+    }
+
+    for (size_t i = 0; i < op->nbsp->n_addresses; i++) {
+        /* Addresses are owned by the logical port.
+         * Ethernet address followed by zero or more IPv4
+         * or IPv6 addresses (or both). */
+        struct eth_addr mac;
+        if (ovs_scan(op->nbsp->addresses[i],
+                    ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
+            ds_clear(&match);
+            ds_put_format(&match, "eth.dst == "ETH_ADDR_FMT,
+                          ETH_ADDR_ARGS(mac));
+
+            ds_clear(&actions);
+            ds_put_format(&actions, "outport = %s; output;", op->json_key);
+            ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_L2_LKUP,
+                                    50, ds_cstr(&match),
+                                    ds_cstr(&actions),
+                                    &op->nbsp->header_);
+        } else if (!strcmp(op->nbsp->addresses[i], "unknown")) {
+            if (lsp_is_enabled(op->nbsp)) {
+                ovn_multicast_add(mcgroups, &mc_unknown, op);
+                op->od->has_unknown = true;
+            }
+        } else if (is_dynamic_lsp_address(op->nbsp->addresses[i])) {
+            if (!op->nbsp->dynamic_addresses
+                || !ovs_scan(op->nbsp->dynamic_addresses,
+                        ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
+                continue;
+            }
+            ds_clear(&match);
+            ds_put_format(&match, "eth.dst == "ETH_ADDR_FMT,
+                          ETH_ADDR_ARGS(mac));
+
+            ds_clear(&actions);
+            ds_put_format(&actions, "outport = %s; output;", op->json_key);
+            ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_L2_LKUP,
+                                    50, ds_cstr(&match),
+                                    ds_cstr(&actions),
+                                    &op->nbsp->header_);
+        } else if (!strcmp(op->nbsp->addresses[i], "router")) {
+            if (!op->peer || !op->peer->nbrp
+                || !ovs_scan(op->peer->nbrp->mac,
+                        ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
+                continue;
+            }
+            ds_clear(&match);
+            ds_put_format(&match, "eth.dst == "ETH_ADDR_FMT,
+                          ETH_ADDR_ARGS(mac));
+            if (op->peer->od->l3dgw_port
+                && op->peer->od->l3redirect_port
+                && op->od->n_localnet_ports) {
+                bool add_chassis_resident_check = false;
+                if (op->peer == op->peer->od->l3dgw_port) {
+                    /* The peer of this port represents a distributed
+                     * gateway port. The destination lookup flow for the
+                     * router's distributed gateway port MAC address should
+                     * only be programmed on the "redirect-chassis". */
+                    add_chassis_resident_check = true;
+                } else {
+                    /* Check if the option 'reside-on-redirect-chassis'
+                     * is set to true on the peer port. If set to true
+                     * and if the logical switch has a localnet port, it
+                     * means the router pipeline for the packets from
+                     * this logical switch should be run on the chassis
+                     * hosting the gateway port.
+                     */
+                    add_chassis_resident_check = smap_get_bool(
+                        &op->peer->nbrp->options,
+                        "reside-on-redirect-chassis", false);
+                }
+
+                if (add_chassis_resident_check) {
+                    ds_put_format(&match, " && is_chassis_resident(%s)",
+                                  op->peer->od->l3redirect_port->json_key);
+                }
+            }
+
+            ds_clear(&actions);
+            ds_put_format(&actions, "outport = %s; output;", op->json_key);
+            ovn_lflow_add_with_hint(lflows, op->od,
+                                    S_SWITCH_IN_L2_LKUP, 50,
+                                    ds_cstr(&match), ds_cstr(&actions),
+                                    &op->nbsp->header_);
+
+            /* Add ethernet addresses specified in NAT rules on
+             * distributed logical routers. */
+            if (op->peer->od->l3dgw_port
+                && op->peer == op->peer->od->l3dgw_port) {
+                for (int j = 0; j < op->peer->od->nbr->n_nat; j++) {
+                    const struct nbrec_nat *nat
+                                              = op->peer->od->nbr->nat[j];
+                    if (!strcmp(nat->type, "dnat_and_snat")
+                        && nat->logical_port && nat->external_mac
+                        && eth_addr_from_string(nat->external_mac, &mac)) {
+
+                        ds_clear(&match);
+                        ds_put_format(&match, "eth.dst == "ETH_ADDR_FMT
+                                      " && is_chassis_resident(\"%s\")",
+                                      ETH_ADDR_ARGS(mac),
+                                      nat->logical_port);
+
+                        ds_clear(&actions);
+                        ds_put_format(&actions, "outport = %s; output;",
+                                      op->json_key);
+                        ovn_lflow_add_with_hint(lflows, op->od,
+                                                S_SWITCH_IN_L2_LKUP, 50,
+                                                ds_cstr(&match),
+                                                ds_cstr(&actions),
+                                                &op->nbsp->header_);
+                    }
+                }
+            }
+        } else {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+            VLOG_INFO_RL(&rl,
+                         "%s: invalid syntax '%s' in addresses column",
+                         op->nbsp->name, op->nbsp->addresses[i]);
+        }
+    }
+    ds_destroy(&actions);
+    ds_destroy(&match);
+}
+
 static void
 build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
                     struct hmap *port_groups, struct hmap *lflows,
@@ -6988,6 +7212,7 @@  build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
     struct ovn_datapath *od;
     struct ovn_port *op;
     struct ovn_lb *lb;
+    struct ovn_igmp_group *igmp_group;
 
     HMAP_FOR_EACH (od, key_node, datapaths) {
         build_lswitch_flows_step_0_od(
@@ -7046,209 +7271,12 @@  build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
         build_lswitch_flows_step_100_od(od, lflows);
     }
 
-
-    /* Ingress table 19: Add IP multicast flows learnt from IGMP/MLD
-     * (priority 90). */
-    struct ovn_igmp_group *igmp_group;
-
     HMAP_FOR_EACH (igmp_group, hmap_node, igmp_groups) {
-        if (!igmp_group->datapath) {
-            continue;
-        }
-
-        ds_clear(&match);
-        ds_clear(&actions);
-
-        struct mcast_switch_info *mcast_sw_info =
-            &igmp_group->datapath->mcast_info.sw;
-
-        if (IN6_IS_ADDR_V4MAPPED(&igmp_group->address)) {
-            /* RFC 4541, section 2.1.2, item 2: Skip groups in the 224.0.0.X
-             * range.
-             */
-            ovs_be32 group_address =
-                in6_addr_get_mapped_ipv4(&igmp_group->address);
-            if (ip_is_local_multicast(group_address)) {
-                continue;
-            }
-
-            if (mcast_sw_info->active_v4_flows >= mcast_sw_info->table_size) {
-                continue;
-            }
-            mcast_sw_info->active_v4_flows++;
-            ds_put_format(&match, "eth.mcast && ip4 && ip4.dst == %s ",
-                          igmp_group->mcgroup.name);
-        } else {
-            /* RFC 4291, section 2.7.1: Skip groups that correspond to all
-             * hosts.
-             */
-            if (ipv6_is_all_hosts(&igmp_group->address)) {
-                continue;
-            }
-            if (mcast_sw_info->active_v6_flows >= mcast_sw_info->table_size) {
-                continue;
-            }
-            mcast_sw_info->active_v6_flows++;
-            ds_put_format(&match, "eth.mcast && ip6 && ip6.dst == %s ",
-                          igmp_group->mcgroup.name);
-        }
-
-        /* Also flood traffic to all multicast routers with relay enabled. */
-        if (mcast_sw_info->flood_relay) {
-            ds_put_cstr(&actions,
-                        "clone { "
-                            "outport = \""MC_MROUTER_FLOOD "\"; "
-                            "output; "
-                        "};");
-        }
-        if (mcast_sw_info->flood_static) {
-            ds_put_cstr(&actions,
-                        "clone { "
-                            "outport =\""MC_STATIC"\"; "
-                            "output; "
-                        "};");
-        }
-        ds_put_format(&actions, "outport = \"%s\"; output; ",
-                      igmp_group->mcgroup.name);
-
-        ovn_lflow_add(lflows, igmp_group->datapath, S_SWITCH_IN_L2_LKUP, 90,
-                      ds_cstr(&match), ds_cstr(&actions));
+        build_lswitch_flows_step_110_igmp(igmp_group, lflows);
     }
 
-    /* Ingress table 19: Destination lookup, unicast handling (priority 50), */
     HMAP_FOR_EACH (op, key_node, ports) {
-        if (!op->nbsp || lsp_is_external(op->nbsp)) {
-            continue;
-        }
-
-        /* For ports connected to logical routers add flows to bypass the
-         * broadcast flooding of ARP/ND requests in table 19. We direct the
-         * requests only to the router port that owns the IP address.
-         */
-        if (!strcmp(op->nbsp->type, "router")) {
-            build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lflows,
-                                              &op->nbsp->header_);
-        }
-
-        for (size_t i = 0; i < op->nbsp->n_addresses; i++) {
-            /* Addresses are owned by the logical port.
-             * Ethernet address followed by zero or more IPv4
-             * or IPv6 addresses (or both). */
-            struct eth_addr mac;
-            if (ovs_scan(op->nbsp->addresses[i],
-                        ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
-                ds_clear(&match);
-                ds_put_format(&match, "eth.dst == "ETH_ADDR_FMT,
-                              ETH_ADDR_ARGS(mac));
-
-                ds_clear(&actions);
-                ds_put_format(&actions, "outport = %s; output;", op->json_key);
-                ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_L2_LKUP,
-                                        50, ds_cstr(&match),
-                                        ds_cstr(&actions),
-                                        &op->nbsp->header_);
-            } else if (!strcmp(op->nbsp->addresses[i], "unknown")) {
-                if (lsp_is_enabled(op->nbsp)) {
-                    ovn_multicast_add(mcgroups, &mc_unknown, op);
-                    op->od->has_unknown = true;
-                }
-            } else if (is_dynamic_lsp_address(op->nbsp->addresses[i])) {
-                if (!op->nbsp->dynamic_addresses
-                    || !ovs_scan(op->nbsp->dynamic_addresses,
-                            ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
-                    continue;
-                }
-                ds_clear(&match);
-                ds_put_format(&match, "eth.dst == "ETH_ADDR_FMT,
-                              ETH_ADDR_ARGS(mac));
-
-                ds_clear(&actions);
-                ds_put_format(&actions, "outport = %s; output;", op->json_key);
-                ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_L2_LKUP,
-                                        50, ds_cstr(&match),
-                                        ds_cstr(&actions),
-                                        &op->nbsp->header_);
-            } else if (!strcmp(op->nbsp->addresses[i], "router")) {
-                if (!op->peer || !op->peer->nbrp
-                    || !ovs_scan(op->peer->nbrp->mac,
-                            ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
-                    continue;
-                }
-                ds_clear(&match);
-                ds_put_format(&match, "eth.dst == "ETH_ADDR_FMT,
-                              ETH_ADDR_ARGS(mac));
-                if (op->peer->od->l3dgw_port
-                    && op->peer->od->l3redirect_port
-                    && op->od->n_localnet_ports) {
-                    bool add_chassis_resident_check = false;
-                    if (op->peer == op->peer->od->l3dgw_port) {
-                        /* The peer of this port represents a distributed
-                         * gateway port. The destination lookup flow for the
-                         * router's distributed gateway port MAC address should
-                         * only be programmed on the "redirect-chassis". */
-                        add_chassis_resident_check = true;
-                    } else {
-                        /* Check if the option 'reside-on-redirect-chassis'
-                         * is set to true on the peer port. If set to true
-                         * and if the logical switch has a localnet port, it
-                         * means the router pipeline for the packets from
-                         * this logical switch should be run on the chassis
-                         * hosting the gateway port.
-                         */
-                        add_chassis_resident_check = smap_get_bool(
-                            &op->peer->nbrp->options,
-                            "reside-on-redirect-chassis", false);
-                    }
-
-                    if (add_chassis_resident_check) {
-                        ds_put_format(&match, " && is_chassis_resident(%s)",
-                                      op->peer->od->l3redirect_port->json_key);
-                    }
-                }
-
-                ds_clear(&actions);
-                ds_put_format(&actions, "outport = %s; output;", op->json_key);
-                ovn_lflow_add_with_hint(lflows, op->od,
-                                        S_SWITCH_IN_L2_LKUP, 50,
-                                        ds_cstr(&match), ds_cstr(&actions),
-                                        &op->nbsp->header_);
-
-                /* Add ethernet addresses specified in NAT rules on
-                 * distributed logical routers. */
-                if (op->peer->od->l3dgw_port
-                    && op->peer == op->peer->od->l3dgw_port) {
-                    for (int j = 0; j < op->peer->od->nbr->n_nat; j++) {
-                        const struct nbrec_nat *nat
-                                                  = op->peer->od->nbr->nat[j];
-                        if (!strcmp(nat->type, "dnat_and_snat")
-                            && nat->logical_port && nat->external_mac
-                            && eth_addr_from_string(nat->external_mac, &mac)) {
-
-                            ds_clear(&match);
-                            ds_put_format(&match, "eth.dst == "ETH_ADDR_FMT
-                                          " && is_chassis_resident(\"%s\")",
-                                          ETH_ADDR_ARGS(mac),
-                                          nat->logical_port);
-
-                            ds_clear(&actions);
-                            ds_put_format(&actions, "outport = %s; output;",
-                                          op->json_key);
-                            ovn_lflow_add_with_hint(lflows, op->od,
-                                                    S_SWITCH_IN_L2_LKUP, 50,
-                                                    ds_cstr(&match),
-                                                    ds_cstr(&actions),
-                                                    &op->nbsp->header_);
-                        }
-                    }
-                }
-            } else {
-                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-
-                VLOG_INFO_RL(&rl,
-                             "%s: invalid syntax '%s' in addresses column",
-                             op->nbsp->name, op->nbsp->addresses[i]);
-            }
-        }
+        build_lswitch_flows_step_120_op(op, lflows, mcgroups);
     }
 
     /* Ingress table 19: Destination lookup for unknown MACs (priority 0). */
@@ -7256,7 +7284,6 @@  build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
         if (!od->nbs) {
             continue;
         }
-
         if (od->has_unknown) {
             ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 0, "1",
                           "outport = \""MC_UNKNOWN"\"; output;");