[ovs-dev] [PATCH ovn RFC v3 09/29] Move packet size rules to a separate function

Dumitru Ceara dceara at redhat.com
Thu Aug 13 12:20:58 UTC 2020


On 7/16/20 3:19 PM, anton.ivanov at cambridgegreys.com wrote:
> From: Anton Ivanov <anton.ivanov at cambridgegreys.com>
> 
> Signed-off-by: Anton Ivanov <anton.ivanov at cambridgegreys.com>
> ---
>  northd/ovn-northd.c | 752 +++++++++++++++++++++++---------------------
>  1 file changed, 397 insertions(+), 355 deletions(-)
> 
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index 7932ab9e3..0b4926a75 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -9941,93 +9941,25 @@ build_lrouter_flows_step_100_od(
>  }
>  
>  static void
> -build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
> -                    struct hmap *lflows, struct shash *meter_groups,
> -                    struct hmap *lbs)
> +build_lrouter_flows_step_110_od(
> +        struct ovn_datapath *od, struct hmap *lflows)
>  {
> -    /* This flow table structure is documented in ovn-northd(8), so please
> -     * update ovn-northd.8.xml if you change anything. */
> -
> -    struct ds match = DS_EMPTY_INITIALIZER;
> -    struct ds actions = DS_EMPTY_INITIALIZER;
> -
> -    struct ovn_datapath *od;
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        build_lrouter_flows_step_0_od(od, lflows);
> -    }
> -
> -    struct ovn_port *op;
> -    HMAP_FOR_EACH (op, key_node, ports) {
> -        build_lrouter_flows_step_0_op(op, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        build_lrouter_flows_step_10_od(od, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (op, key_node, ports) {
> -        build_lrouter_flows_step_10_op(op, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        build_lrouter_flows_step_20_od(od, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (op, key_node, ports) {
> -        build_lrouter_flows_step_20_op(op, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (op, key_node, ports) {
> -        build_lrouter_flows_step_30_op(op, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (op, key_node, ports) {
> -        build_lrouter_flows_step_40_op(op, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        build_lrouter_flows_step_50_od(od, lflows, lbs, meter_groups);
> -    }
> -
> -    HMAP_FOR_EACH (op, key_node, ports) {
> -        build_lrouter_flows_step_50_op(op, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        build_lrouter_flows_step_60_od(od, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (op, key_node, ports) {
> -        build_lrouter_flows_step_70_op(op, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        build_lrouter_flows_step_80_od(od, lflows, ports);
> -    }
> -
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        build_lrouter_flows_step_90_od(od, lflows);
> -    }
> -
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        build_lrouter_flows_step_100_od(od, lflows, ports);
> -    }
> -
> -
> -    /* XXX destination unreachable */
> -
>      /* Local router ingress table ARP_RESOLVE: ARP Resolution.
>       *
>       * Multicast packets already have the outport set so just advance to next
>       * table (priority 500). */
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        if (!od->nbr) {
> -            continue;
> -        }
> -
> +    if (od->nbr) {
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 500,
>                        "ip4.mcast || ip6.mcast", "next;");
>      }
> +}
> +
> +static void
> +build_lrouter_flows_step_120_op(
> +        struct ovn_port *op, struct hmap *lflows, struct hmap *ports)
> +{
> +    struct ds match = DS_EMPTY_INITIALIZER;
> +    struct ds actions = DS_EMPTY_INITIALIZER;
>  
>      /* Local router ingress table ARP_RESOLVE: ARP Resolution.
>       *
> @@ -10038,188 +9970,133 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
>       * REG_NEXT_HOP_IPV4/REG_NEXT_HOP_IPV6 into an output port in outport and
>       * an Ethernet address in eth.dst.
>       */
> -    HMAP_FOR_EACH (op, key_node, ports) {
> -        if (op->nbsp && !lsp_is_enabled(op->nbsp)) {
> -            continue;
> -        }
> -
> -        if (op->nbrp) {
> -            /* This is a logical router port. If next-hop IP address in
> -             * REG_NEXT_HOP_IPV4/REG_NEXT_HOP_IPV6 matches IP address of this
> -             * router port, then the packet is intended to eventually be sent
> -             * to this logical port. Set the destination mac address using
> -             * this port's mac address.
> -             *
> -             * The packet is still in peer's logical pipeline. So the match
> -             * should be on peer's outport. */
> -            if (op->peer && op->nbrp->peer) {
> -                if (op->lrp_networks.n_ipv4_addrs) {
> -                    ds_clear(&match);
> -                    ds_put_format(&match, "outport == %s && "
> -                                  REG_NEXT_HOP_IPV4 "== ",
> -                                  op->peer->json_key);
> -                    op_put_v4_networks(&match, op, false);
>  
> -                    ds_clear(&actions);
> -                    ds_put_format(&actions, "eth.dst = %s; next;",
> -                                  op->lrp_networks.ea_s);
> -                    ovn_lflow_add_with_hint(lflows, op->peer->od,
> -                                            S_ROUTER_IN_ARP_RESOLVE, 100,
> -                                            ds_cstr(&match), ds_cstr(&actions),
> -                                            &op->nbrp->header_);
> -                }
> +    if (op->nbsp && !lsp_is_enabled(op->nbsp)) {
> +            return;

Nit: indent.

Thanks,
Dumitru

> +    }
>  
> -                if (op->lrp_networks.n_ipv6_addrs) {
> -                    ds_clear(&match);
> -                    ds_put_format(&match, "outport == %s && "
> -                                  REG_NEXT_HOP_IPV6 " == ",
> -                                  op->peer->json_key);
> -                    op_put_v6_networks(&match, op);
> +    if (op->nbrp) {
> +        /* This is a logical router port. If next-hop IP address in
> +         * REG_NEXT_HOP_IPV4/REG_NEXT_HOP_IPV6 matches IP address of this
> +         * router port, then the packet is intended to eventually be sent
> +         * to this logical port. Set the destination mac address using
> +         * this port's mac address.
> +         *
> +         * The packet is still in peer's logical pipeline. So the match
> +         * should be on peer's outport. */
> +        if (op->peer && op->nbrp->peer) {
> +            if (op->lrp_networks.n_ipv4_addrs) {
> +                ds_clear(&match);
> +                ds_put_format(&match, "outport == %s && "
> +                              REG_NEXT_HOP_IPV4 "== ",
> +                              op->peer->json_key);
> +                op_put_v4_networks(&match, op, false);
>  
> -                    ds_clear(&actions);
> -                    ds_put_format(&actions, "eth.dst = %s; next;",
> -                                  op->lrp_networks.ea_s);
> -                    ovn_lflow_add_with_hint(lflows, op->peer->od,
> -                                            S_ROUTER_IN_ARP_RESOLVE, 100,
> -                                            ds_cstr(&match), ds_cstr(&actions),
> -                                            &op->nbrp->header_);
> -                }
> +                ds_clear(&actions);
> +                ds_put_format(&actions, "eth.dst = %s; next;",
> +                              op->lrp_networks.ea_s);
> +                ovn_lflow_add_with_hint(lflows, op->peer->od,
> +                                        S_ROUTER_IN_ARP_RESOLVE, 100,
> +                                        ds_cstr(&match), ds_cstr(&actions),
> +                                        &op->nbrp->header_);
>              }
>  
> -            if (!op->derived && op->od->l3redirect_port) {
> -                const char *redirect_type = smap_get(&op->nbrp->options,
> -                                                     "redirect-type");
> -                if (redirect_type && !strcasecmp(redirect_type, "bridged")) {
> -                    /* Packet is on a non gateway chassis and
> -                     * has an unresolved ARP on a network behind gateway
> -                     * chassis attached router port. Since, redirect type
> -                     * is "bridged", instead of calling "get_arp"
> -                     * on this node, we will redirect the packet to gateway
> -                     * chassis, by setting destination mac router port mac.*/
> -                    ds_clear(&match);
> -                    ds_put_format(&match, "outport == %s && "
> -                                  "!is_chassis_resident(%s)", op->json_key,
> -                                  op->od->l3redirect_port->json_key);
> -                    ds_clear(&actions);
> -                    ds_put_format(&actions, "eth.dst = %s; next;",
> -                                  op->lrp_networks.ea_s);
> +            if (op->lrp_networks.n_ipv6_addrs) {
> +                ds_clear(&match);
> +                ds_put_format(&match, "outport == %s && "
> +                              REG_NEXT_HOP_IPV6 " == ",
> +                              op->peer->json_key);
> +                op_put_v6_networks(&match, op);
>  
> -                    ovn_lflow_add_with_hint(lflows, op->od,
> -                                            S_ROUTER_IN_ARP_RESOLVE, 50,
> -                                            ds_cstr(&match), ds_cstr(&actions),
> -                                            &op->nbrp->header_);
> -                }
> +                ds_clear(&actions);
> +                ds_put_format(&actions, "eth.dst = %s; next;",
> +                              op->lrp_networks.ea_s);
> +                ovn_lflow_add_with_hint(lflows, op->peer->od,
> +                                        S_ROUTER_IN_ARP_RESOLVE, 100,
> +                                        ds_cstr(&match), ds_cstr(&actions),
> +                                        &op->nbrp->header_);
>              }
> -        } else if (op->od->n_router_ports && strcmp(op->nbsp->type, "router")
> -                   && strcmp(op->nbsp->type, "virtual")) {
> -            /* This is a logical switch port that backs a VM or a container.
> -             * Extract its addresses. For each of the address, go through all
> -             * the router ports attached to the switch (to which this port
> -             * connects) and if the address in question is reachable from the
> -             * router port, add an ARP/ND entry in that router's pipeline. */
> -
> -            for (size_t i = 0; i < op->n_lsp_addrs; i++) {
> -                const char *ea_s = op->lsp_addrs[i].ea_s;
> -                for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) {
> -                    const char *ip_s = op->lsp_addrs[i].ipv4_addrs[j].addr_s;
> -                    for (size_t k = 0; k < op->od->n_router_ports; k++) {
> -                        /* Get the Logical_Router_Port that the
> -                         * Logical_Switch_Port is connected to, as
> -                         * 'peer'. */
> -                        const char *peer_name = smap_get(
> -                            &op->od->router_ports[k]->nbsp->options,
> -                            "router-port");
> -                        if (!peer_name) {
> -                            continue;
> -                        }
> +        }
>  
> -                        struct ovn_port *peer = ovn_port_find(ports, peer_name);
> -                        if (!peer || !peer->nbrp) {
> -                            continue;
> -                        }
> +        if (!op->derived && op->od->l3redirect_port) {
> +            const char *redirect_type = smap_get(&op->nbrp->options,
> +                                                 "redirect-type");
> +            if (redirect_type && !strcasecmp(redirect_type, "bridged")) {
> +                /* Packet is on a non gateway chassis and
> +                 * has an unresolved ARP on a network behind gateway
> +                 * chassis attached router port. Since, redirect type
> +                 * is "bridged", instead of calling "get_arp"
> +                 * on this node, we will redirect the packet to gateway
> +                 * chassis, by setting destination mac router port mac.*/
> +                ds_clear(&match);
> +                ds_put_format(&match, "outport == %s && "
> +                              "!is_chassis_resident(%s)", op->json_key,
> +                              op->od->l3redirect_port->json_key);
> +                ds_clear(&actions);
> +                ds_put_format(&actions, "eth.dst = %s; next;",
> +                              op->lrp_networks.ea_s);
>  
> -                        if (!find_lrp_member_ip(peer, ip_s)) {
> -                            continue;
> -                        }
> +                ovn_lflow_add_with_hint(lflows, op->od,
> +                                        S_ROUTER_IN_ARP_RESOLVE, 50,
> +                                        ds_cstr(&match), ds_cstr(&actions),
> +                                        &op->nbrp->header_);
> +            }
> +        }
> +    } else if (op->od->n_router_ports && strcmp(op->nbsp->type, "router")
> +               && strcmp(op->nbsp->type, "virtual")) {
> +        /* This is a logical switch port that backs a VM or a container.
> +         * Extract its addresses. For each of the address, go through all
> +         * the router ports attached to the switch (to which this port
> +         * connects) and if the address in question is reachable from the
> +         * router port, add an ARP/ND entry in that router's pipeline. */
>  
> -                        ds_clear(&match);
> -                        ds_put_format(&match, "outport == %s && "
> -                                      REG_NEXT_HOP_IPV4 " == %s",
> -                                      peer->json_key, ip_s);
> -
> -                        ds_clear(&actions);
> -                        ds_put_format(&actions, "eth.dst = %s; next;", ea_s);
> -                        ovn_lflow_add_with_hint(lflows, peer->od,
> -                                                S_ROUTER_IN_ARP_RESOLVE, 100,
> -                                                ds_cstr(&match),
> -                                                ds_cstr(&actions),
> -                                                &op->nbsp->header_);
> +        for (size_t i = 0; i < op->n_lsp_addrs; i++) {
> +            const char *ea_s = op->lsp_addrs[i].ea_s;
> +            for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) {
> +                const char *ip_s = op->lsp_addrs[i].ipv4_addrs[j].addr_s;
> +                for (size_t k = 0; k < op->od->n_router_ports; k++) {
> +                    /* Get the Logical_Router_Port that the
> +                     * Logical_Switch_Port is connected to, as
> +                     * 'peer'. */
> +                    const char *peer_name = smap_get(
> +                        &op->od->router_ports[k]->nbsp->options,
> +                        "router-port");
> +                    if (!peer_name) {
> +                        continue;
>                      }
> -                }
>  
> -                for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) {
> -                    const char *ip_s = op->lsp_addrs[i].ipv6_addrs[j].addr_s;
> -                    for (size_t k = 0; k < op->od->n_router_ports; k++) {
> -                        /* Get the Logical_Router_Port that the
> -                         * Logical_Switch_Port is connected to, as
> -                         * 'peer'. */
> -                        const char *peer_name = smap_get(
> -                            &op->od->router_ports[k]->nbsp->options,
> -                            "router-port");
> -                        if (!peer_name) {
> -                            continue;
> -                        }
> +                    struct ovn_port *peer = ovn_port_find(ports, peer_name);
> +                    if (!peer || !peer->nbrp) {
> +                        continue;
> +                    }
>  
> -                        struct ovn_port *peer = ovn_port_find(ports, peer_name);
> -                        if (!peer || !peer->nbrp) {
> -                            continue;
> -                        }
> +                    if (!find_lrp_member_ip(peer, ip_s)) {
> +                        continue;
> +                    }
>  
> -                        if (!find_lrp_member_ip(peer, ip_s)) {
> -                            continue;
> -                        }
> +                    ds_clear(&match);
> +                    ds_put_format(&match, "outport == %s && "
> +                                  REG_NEXT_HOP_IPV4 " == %s",
> +                                  peer->json_key, ip_s);
>  
> -                        ds_clear(&match);
> -                        ds_put_format(&match, "outport == %s && "
> -                                      REG_NEXT_HOP_IPV6 " == %s",
> -                                      peer->json_key, ip_s);
> -
> -                        ds_clear(&actions);
> -                        ds_put_format(&actions, "eth.dst = %s; next;", ea_s);
> -                        ovn_lflow_add_with_hint(lflows, peer->od,
> -                                                S_ROUTER_IN_ARP_RESOLVE, 100,
> -                                                ds_cstr(&match),
> -                                                ds_cstr(&actions),
> -                                                &op->nbsp->header_);
> -                    }
> +                    ds_clear(&actions);
> +                    ds_put_format(&actions, "eth.dst = %s; next;", ea_s);
> +                    ovn_lflow_add_with_hint(lflows, peer->od,
> +                                            S_ROUTER_IN_ARP_RESOLVE, 100,
> +                                            ds_cstr(&match),
> +                                            ds_cstr(&actions),
> +                                            &op->nbsp->header_);
>                  }
>              }
> -        } else if (op->od->n_router_ports && strcmp(op->nbsp->type, "router")
> -                   && !strcmp(op->nbsp->type, "virtual")) {
> -            /* This is a virtual port. Add ARP replies for the virtual ip with
> -             * the mac of the present active virtual parent.
> -             * If the logical port doesn't have virtual parent set in
> -             * Port_Binding table, then add the flow to set eth.dst to
> -             * 00:00:00:00:00:00 and advance to next table so that ARP is
> -             * resolved by router pipeline using the arp{} action.
> -             * The MAC_Binding entry for the virtual ip might be invalid. */
> -            ovs_be32 ip;
> -
> -            const char *vip = smap_get(&op->nbsp->options,
> -                                       "virtual-ip");
> -            const char *virtual_parents = smap_get(&op->nbsp->options,
> -                                                   "virtual-parents");
> -            if (!vip || !virtual_parents ||
> -                !ip_parse(vip, &ip) || !op->sb) {
> -                continue;
> -            }
>  
> -            if (!op->sb->virtual_parent || !op->sb->virtual_parent[0] ||
> -                !op->sb->chassis) {
> -                /* The virtual port is not claimed yet. */
> -                for (size_t i = 0; i < op->od->n_router_ports; i++) {
> +            for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) {
> +                const char *ip_s = op->lsp_addrs[i].ipv6_addrs[j].addr_s;
> +                for (size_t k = 0; k < op->od->n_router_ports; k++) {
> +                    /* Get the Logical_Router_Port that the
> +                     * Logical_Switch_Port is connected to, as
> +                     * 'peer'. */
>                      const char *peer_name = smap_get(
> -                        &op->od->router_ports[i]->nbsp->options,
> +                        &op->od->router_ports[k]->nbsp->options,
>                          "router-port");
>                      if (!peer_name) {
>                          continue;
> @@ -10230,155 +10107,228 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
>                          continue;
>                      }
>  
> -                    if (find_lrp_member_ip(peer, vip)) {
> -                        ds_clear(&match);
> -                        ds_put_format(&match, "outport == %s && "
> -                                      REG_NEXT_HOP_IPV4 " == %s",
> -                                      peer->json_key, vip);
> -
> -                        ds_clear(&actions);
> -                        ds_put_format(&actions,
> -                                      "eth.dst = 00:00:00:00:00:00; next;");
> -                        ovn_lflow_add_with_hint(lflows, peer->od,
> -                                                S_ROUTER_IN_ARP_RESOLVE, 100,
> -                                                ds_cstr(&match),
> -                                                ds_cstr(&actions),
> -                                                &op->nbsp->header_);
> -                        break;
> +                    if (!find_lrp_member_ip(peer, ip_s)) {
> +                        continue;
>                      }
> -                }
> -            } else {
> -                struct ovn_port *vp =
> -                    ovn_port_find(ports, op->sb->virtual_parent);
> -                if (!vp || !vp->nbsp) {
> -                    continue;
> -                }
> -
> -                for (size_t i = 0; i < vp->n_lsp_addrs; i++) {
> -                    bool found_vip_network = false;
> -                    const char *ea_s = vp->lsp_addrs[i].ea_s;
> -                    for (size_t j = 0; j < vp->od->n_router_ports; j++) {
> -                        /* Get the Logical_Router_Port that the
> -                        * Logical_Switch_Port is connected to, as
> -                        * 'peer'. */
> -                        const char *peer_name = smap_get(
> -                            &vp->od->router_ports[j]->nbsp->options,
> -                            "router-port");
> -                        if (!peer_name) {
> -                            continue;
> -                        }
> -
> -                        struct ovn_port *peer =
> -                            ovn_port_find(ports, peer_name);
> -                        if (!peer || !peer->nbrp) {
> -                            continue;
> -                        }
> -
> -                        if (!find_lrp_member_ip(peer, vip)) {
> -                            continue;
> -                        }
>  
> -                        ds_clear(&match);
> -                        ds_put_format(&match, "outport == %s && "
> -                                      REG_NEXT_HOP_IPV4 " == %s",
> -                                      peer->json_key, vip);
> -
> -                        ds_clear(&actions);
> -                        ds_put_format(&actions, "eth.dst = %s; next;", ea_s);
> -                        ovn_lflow_add_with_hint(lflows, peer->od,
> -                                                S_ROUTER_IN_ARP_RESOLVE, 100,
> -                                                ds_cstr(&match),
> -                                                ds_cstr(&actions),
> -                                                &op->nbsp->header_);
> -                        found_vip_network = true;
> -                        break;
> -                    }
> +                    ds_clear(&match);
> +                    ds_put_format(&match, "outport == %s && "
> +                                  REG_NEXT_HOP_IPV6 " == %s",
> +                                  peer->json_key, ip_s);
>  
> -                    if (found_vip_network) {
> -                        break;
> -                    }
> +                    ds_clear(&actions);
> +                    ds_put_format(&actions, "eth.dst = %s; next;", ea_s);
> +                    ovn_lflow_add_with_hint(lflows, peer->od,
> +                                            S_ROUTER_IN_ARP_RESOLVE, 100,
> +                                            ds_cstr(&match),
> +                                            ds_cstr(&actions),
> +                                            &op->nbsp->header_);
>                  }
>              }
> -        } else if (!strcmp(op->nbsp->type, "router")) {
> -            /* This is a logical switch port that connects to a router. */
> -
> -            /* The peer of this switch port is the router port for which
> -             * we need to add logical flows such that it can resolve
> -             * ARP entries for all the other router ports connected to
> -             * the switch in question. */
> -
> -            const char *peer_name = smap_get(&op->nbsp->options,
> -                                             "router-port");
> -            if (!peer_name) {
> -                continue;
> -            }
> +        }
> +    } else if (op->od->n_router_ports && strcmp(op->nbsp->type, "router")
> +               && !strcmp(op->nbsp->type, "virtual")) {
> +        /* This is a virtual port. Add ARP replies for the virtual ip with
> +         * the mac of the present active virtual parent.
> +         * If the logical port doesn't have virtual parent set in
> +         * Port_Binding table, then add the flow to set eth.dst to
> +         * 00:00:00:00:00:00 and advance to next table so that ARP is
> +         * resolved by router pipeline using the arp{} action.
> +         * The MAC_Binding entry for the virtual ip might be invalid. */
> +        ovs_be32 ip;
>  
> -            struct ovn_port *peer = ovn_port_find(ports, peer_name);
> -            if (!peer || !peer->nbrp) {
> -                continue;
> -            }
> +        const char *vip = smap_get(&op->nbsp->options,
> +                                   "virtual-ip");
> +        const char *virtual_parents = smap_get(&op->nbsp->options,
> +                                               "virtual-parents");
> +        if (!vip || !virtual_parents ||
> +            !ip_parse(vip, &ip) || !op->sb) {
> +            ds_destroy(&match);
> +            ds_destroy(&actions);
> +            return;
> +        }
>  
> +        if (!op->sb->virtual_parent || !op->sb->virtual_parent[0] ||
> +            !op->sb->chassis) {
> +            /* The virtual port is not claimed yet. */
>              for (size_t i = 0; i < op->od->n_router_ports; i++) {
> -                const char *router_port_name = smap_get(
> -                                    &op->od->router_ports[i]->nbsp->options,
> -                                    "router-port");
> -                struct ovn_port *router_port = ovn_port_find(ports,
> -                                                             router_port_name);
> -                if (!router_port || !router_port->nbrp) {
> +                const char *peer_name = smap_get(
> +                    &op->od->router_ports[i]->nbsp->options,
> +                    "router-port");
> +                if (!peer_name) {
>                      continue;
>                  }
>  
> -                /* Skip the router port under consideration. */
> -                if (router_port == peer) {
> -                   continue;
> +                struct ovn_port *peer = ovn_port_find(ports, peer_name);
> +                if (!peer || !peer->nbrp) {
> +                    continue;
>                  }
>  
> -                if (router_port->lrp_networks.n_ipv4_addrs) {
> +                if (find_lrp_member_ip(peer, vip)) {
>                      ds_clear(&match);
>                      ds_put_format(&match, "outport == %s && "
> -                                  REG_NEXT_HOP_IPV4 " == ",
> -                                  peer->json_key);
> -                    op_put_v4_networks(&match, router_port, false);
> +                                  REG_NEXT_HOP_IPV4 " == %s",
> +                                  peer->json_key, vip);
>  
>                      ds_clear(&actions);
> -                    ds_put_format(&actions, "eth.dst = %s; next;",
> -                                              router_port->lrp_networks.ea_s);
> +                    ds_put_format(&actions,
> +                                  "eth.dst = 00:00:00:00:00:00; next;");
>                      ovn_lflow_add_with_hint(lflows, peer->od,
>                                              S_ROUTER_IN_ARP_RESOLVE, 100,
> -                                            ds_cstr(&match), ds_cstr(&actions),
> +                                            ds_cstr(&match),
> +                                            ds_cstr(&actions),
>                                              &op->nbsp->header_);
> +                    break;
>                  }
> +            }
> +        } else {
> +            struct ovn_port *vp =
> +                ovn_port_find(ports, op->sb->virtual_parent);
> +            if (!vp || !vp->nbsp) {
> +                ds_destroy(&match);
> +                ds_destroy(&actions);
> +                return;
> +            }
> +
> +            for (size_t i = 0; i < vp->n_lsp_addrs; i++) {
> +                bool found_vip_network = false;
> +                const char *ea_s = vp->lsp_addrs[i].ea_s;
> +                for (size_t j = 0; j < vp->od->n_router_ports; j++) {
> +                    /* Get the Logical_Router_Port that the
> +                    * Logical_Switch_Port is connected to, as
> +                    * 'peer'. */
> +                    const char *peer_name = smap_get(
> +                        &vp->od->router_ports[j]->nbsp->options,
> +                        "router-port");
> +                    if (!peer_name) {
> +                        continue;
> +                    }
> +
> +                    struct ovn_port *peer =
> +                        ovn_port_find(ports, peer_name);
> +                    if (!peer || !peer->nbrp) {
> +                        continue;
> +                    }
> +
> +                    if (!find_lrp_member_ip(peer, vip)) {
> +                        continue;
> +                    }
>  
> -                if (router_port->lrp_networks.n_ipv6_addrs) {
>                      ds_clear(&match);
>                      ds_put_format(&match, "outport == %s && "
> -                                  REG_NEXT_HOP_IPV6 " == ",
> -                                  peer->json_key);
> -                    op_put_v6_networks(&match, router_port);
> +                                  REG_NEXT_HOP_IPV4 " == %s",
> +                                  peer->json_key, vip);
>  
>                      ds_clear(&actions);
> -                    ds_put_format(&actions, "eth.dst = %s; next;",
> -                                  router_port->lrp_networks.ea_s);
> +                    ds_put_format(&actions, "eth.dst = %s; next;", ea_s);
>                      ovn_lflow_add_with_hint(lflows, peer->od,
>                                              S_ROUTER_IN_ARP_RESOLVE, 100,
> -                                            ds_cstr(&match), ds_cstr(&actions),
> +                                            ds_cstr(&match),
> +                                            ds_cstr(&actions),
>                                              &op->nbsp->header_);
> +                    found_vip_network = true;
> +                    break;
> +                }
> +
> +                if (found_vip_network) {
> +                    break;
>                  }
>              }
>          }
> -    }
> +    } else if (!strcmp(op->nbsp->type, "router")) {
> +        /* This is a logical switch port that connects to a router. */
>  
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        if (!od->nbr) {
> -            continue;
> +        /* The peer of this switch port is the router port for which
> +         * we need to add logical flows such that it can resolve
> +         * ARP entries for all the other router ports connected to
> +         * the switch in question. */
> +
> +        const char *peer_name = smap_get(&op->nbsp->options,
> +                                         "router-port");
> +        if (!peer_name) {
> +            ds_destroy(&match);
> +            ds_destroy(&actions);
> +            return;
> +        }
> +
> +        struct ovn_port *peer = ovn_port_find(ports, peer_name);
> +        if (!peer || !peer->nbrp) {
> +            ds_destroy(&match);
> +            ds_destroy(&actions);
> +            return;
> +        }
> +
> +        for (size_t i = 0; i < op->od->n_router_ports; i++) {
> +            const char *router_port_name = smap_get(
> +                                &op->od->router_ports[i]->nbsp->options,
> +                                "router-port");
> +            struct ovn_port *router_port = ovn_port_find(ports,
> +                                                         router_port_name);
> +            if (!router_port || !router_port->nbrp) {
> +                continue;
> +            }
> +
> +            /* Skip the router port under consideration. */
> +            if (router_port == peer) {
> +               continue;
> +            }
> +
> +            if (router_port->lrp_networks.n_ipv4_addrs) {
> +                ds_clear(&match);
> +                ds_put_format(&match, "outport == %s && "
> +                              REG_NEXT_HOP_IPV4 " == ",
> +                              peer->json_key);
> +                op_put_v4_networks(&match, router_port, false);
> +
> +                ds_clear(&actions);
> +                ds_put_format(&actions, "eth.dst = %s; next;",
> +                                          router_port->lrp_networks.ea_s);
> +                ovn_lflow_add_with_hint(lflows, peer->od,
> +                                        S_ROUTER_IN_ARP_RESOLVE, 100,
> +                                        ds_cstr(&match), ds_cstr(&actions),
> +                                        &op->nbsp->header_);
> +            }
> +
> +            if (router_port->lrp_networks.n_ipv6_addrs) {
> +                ds_clear(&match);
> +                ds_put_format(&match, "outport == %s && "
> +                              REG_NEXT_HOP_IPV6 " == ",
> +                              peer->json_key);
> +                op_put_v6_networks(&match, router_port);
> +
> +                ds_clear(&actions);
> +                ds_put_format(&actions, "eth.dst = %s; next;",
> +                              router_port->lrp_networks.ea_s);
> +                ovn_lflow_add_with_hint(lflows, peer->od,
> +                                        S_ROUTER_IN_ARP_RESOLVE, 100,
> +                                        ds_cstr(&match), ds_cstr(&actions),
> +                                        &op->nbsp->header_);
> +            }
>          }
> +    }
> +    ds_destroy(&match);
> +    ds_destroy(&actions);
> +}
>  
> +static void
> +build_lrouter_flows_step_130_od(
> +        struct ovn_datapath *od, struct hmap *lflows)
> +{
> +    if (od->nbr) {
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 0, "ip4",
>                        "get_arp(outport, " REG_NEXT_HOP_IPV4 "); next;");
>  
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 0, "ip6",
>                        "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;");
>      }
> +}
> +
> +static void
> +build_lrouter_flows_step_140_od(
> +        struct ovn_datapath *od, struct hmap *lflows, struct hmap *ports)
> +{
> +    struct ds match = DS_EMPTY_INITIALIZER;
> +    struct ds actions = DS_EMPTY_INITIALIZER;
>  
>      /* Local router ingress table CHK_PKT_LEN: Check packet length.
>       *
> @@ -10393,10 +10343,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
>       * generate ICMPv4 packet with type 3 (Destination Unreachable) and
>       * code 4 (Fragmentation needed).
>       * */
> -    HMAP_FOR_EACH (od, key_node, datapaths) {
> -        if (!od->nbr) {
> -            continue;
> -        }
> +
> +    if (od->nbr) {
>  
>          /* Packets are allowed by default. */
>          ovn_lflow_add(lflows, od, S_ROUTER_IN_CHK_PKT_LEN, 0, "1",
> @@ -10412,7 +10360,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
>              }
>              /* Add the flows only if gateway_mtu is configured. */
>              if (gw_mtu <= 0) {
> -                continue;
> +                ds_destroy(&match);
> +                ds_destroy(&actions);
> +                return;
>              }
>  
>              ds_clear(&match);
> @@ -10491,6 +10441,98 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
>              }
>          }
>      }
> +    ds_destroy(&match);
> +    ds_destroy(&actions);
> +}
> +
> +static void
> +build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
> +                    struct hmap *lflows, struct shash *meter_groups,
> +                    struct hmap *lbs)
> +{
> +    /* This flow table structure is documented in ovn-northd(8), so please
> +     * update ovn-northd.8.xml if you change anything. */
> +
> +    struct ds match = DS_EMPTY_INITIALIZER;
> +    struct ds actions = DS_EMPTY_INITIALIZER;
> +
> +    struct ovn_datapath *od;
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_0_od(od, lflows);
> +    }
> +
> +    struct ovn_port *op;
> +    HMAP_FOR_EACH (op, key_node, ports) {
> +        build_lrouter_flows_step_0_op(op, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_10_od(od, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (op, key_node, ports) {
> +        build_lrouter_flows_step_10_op(op, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_20_od(od, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (op, key_node, ports) {
> +        build_lrouter_flows_step_20_op(op, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (op, key_node, ports) {
> +        build_lrouter_flows_step_30_op(op, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (op, key_node, ports) {
> +        build_lrouter_flows_step_40_op(op, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_50_od(od, lflows, lbs, meter_groups);
> +    }
> +
> +    HMAP_FOR_EACH (op, key_node, ports) {
> +        build_lrouter_flows_step_50_op(op, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_60_od(od, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (op, key_node, ports) {
> +        build_lrouter_flows_step_70_op(op, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_80_od(od, lflows, ports);
> +    }
> +
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_90_od(od, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_100_od(od, lflows, ports);
> +    }
> +
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_110_od(od, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (op, key_node, ports) {
> +        build_lrouter_flows_step_120_op(op, lflows, ports);
> +    }
> +
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_130_od(od, lflows);
> +    }
> +
> +    HMAP_FOR_EACH (od, key_node, datapaths) {
> +        build_lrouter_flows_step_140_od(od, lflows, ports);
> +    }
>  
>      /* Logical router ingress table GW_REDIRECT: Gateway redirect.
>       *
> 




More information about the dev mailing list