From patchwork Tue Mar 21 06:02:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1759300 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PggyD3CWpz2476 for ; Tue, 21 Mar 2023 17:03:16 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id E307C40B69; Tue, 21 Mar 2023 06:03:13 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org E307C40B69 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id j-eG8MyXUSCK; Tue, 21 Mar 2023 06:03:05 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 9561D40AF0; Tue, 21 Mar 2023 06:03:03 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 9561D40AF0 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id B71EAC0092; Tue, 21 Mar 2023 06:03:00 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 79E01C0032 for ; Tue, 21 Mar 2023 06:02:58 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 5429D417D1 for ; Tue, 21 Mar 2023 06:02:58 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 5429D417D1 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3SzNcogM1qSI for ; Tue, 21 Mar 2023 06:02:55 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 25D13417D0 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by smtp4.osuosl.org (Postfix) with ESMTPS id 25D13417D0 for ; Tue, 21 Mar 2023 06:02:54 +0000 (UTC) Received: (Authenticated sender: hzhou@ovn.org) by mail.gandi.net (Postfix) with ESMTPSA id AF992E0004; Tue, 21 Mar 2023 06:02:51 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Mon, 20 Mar 2023 23:02:29 -0700 Message-Id: <20230321060235.2256118-2-hzhou@ovn.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230321060235.2256118-1-hzhou@ovn.org> References: <20230321060235.2256118-1-hzhou@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 1/7] northd.c: Refactor to reduce indentation. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Many functions are implemented with a big if block. This patch changes them to return as early as possible, to reduce indentations, which will also make code review easier for coming patches. Signed-off-by: Han Zhou --- northd/northd.c | 3149 ++++++++++++++++++++++++----------------------- ovs | 2 +- 2 files changed, 1591 insertions(+), 1560 deletions(-) diff --git a/northd/northd.c b/northd/northd.c index 5f0b436c20f2..1e49301dd5b4 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -5761,11 +5761,11 @@ static void build_lswitch_learn_fdb_od( struct ovn_datapath *od, struct hmap *lflows) { - - if (od->nbs) { - ovn_lflow_add(lflows, od, S_SWITCH_IN_LOOKUP_FDB, 0, "1", "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_IN_PUT_FDB, 0, "1", "next;"); + if (!od->nbs) { + return; } + ovn_lflow_add(lflows, od, S_SWITCH_IN_LOOKUP_FDB, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_PUT_FDB, 0, "1", "next;"); } /* Egress tables 8: Egress port security - IP (priority 0) @@ -5775,18 +5775,18 @@ static void build_lswitch_output_port_sec_od(struct ovn_datapath *od, struct hmap *lflows) { - if (od->nbs) { - ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 100, - "eth.mcast", REGBIT_PORT_SEC_DROP" = 0; next;"); - ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 0, "1", - REGBIT_PORT_SEC_DROP" = check_out_port_sec(); next;"); - - ovn_lflow_add(lflows, od, S_SWITCH_OUT_APPLY_PORT_SEC, 50, - REGBIT_PORT_SEC_DROP" == 1", debug_drop_action()); - ovn_lflow_add(lflows, od, S_SWITCH_OUT_APPLY_PORT_SEC, 0, - "1", "output;"); - + if (!od->nbs) { + return; } + ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 100, + "eth.mcast", REGBIT_PORT_SEC_DROP" = 0; next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 0, "1", + REGBIT_PORT_SEC_DROP" = check_out_port_sec(); next;"); + + ovn_lflow_add(lflows, od, S_SWITCH_OUT_APPLY_PORT_SEC, 50, + REGBIT_PORT_SEC_DROP" == 1", debug_drop_action()); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_APPLY_PORT_SEC, 0, + "1", "output;"); } static void @@ -7461,16 +7461,25 @@ build_lb_affinity_ls_flows(struct hmap *lflows, struct ovn_northd_lb *lb, } static void -build_lb_affinity_default_flows(struct ovn_datapath *od, struct hmap *lflows) +build_lswitch_lb_affinity_default_flows(struct ovn_datapath *od, + struct hmap *lflows) { - if (od->nbs) { - ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_CHECK, 0, "1", "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_LEARN, 0, "1", "next;"); + if (!od->nbs) { + return; } - if (od->nbr) { - ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_CHECK, 0, "1", "next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_LEARN, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_CHECK, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_LEARN, 0, "1", "next;"); +} + +static void +build_lrouter_lb_affinity_default_flows(struct ovn_datapath *od, + struct hmap *lflows) +{ + if (!od->nbr) { + return; } + ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_CHECK, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_LEARN, 0, "1", "next;"); } static void @@ -7697,66 +7706,67 @@ static void build_fwd_group_lflows(struct ovn_datapath *od, struct hmap *lflows) { - if (!(!od->nbs || !od->nbs->n_forwarding_groups)) { - struct ds match = DS_EMPTY_INITIALIZER; - struct ds actions = DS_EMPTY_INITIALIZER; - struct ds group_ports = DS_EMPTY_INITIALIZER; - - for (int i = 0; i < od->nbs->n_forwarding_groups; ++i) { - const struct nbrec_forwarding_group *fwd_group = NULL; - fwd_group = od->nbs->forwarding_groups[i]; - if (!fwd_group->n_child_port) { - continue; - } - - /* ARP responder for the forwarding group's virtual IP */ - ds_put_format(&match, "arp.tpa == %s && arp.op == 1", - fwd_group->vip); - 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;", - fwd_group->vmac, fwd_group->vmac, fwd_group->vip); + if (!od->nbs || !od->nbs->n_forwarding_groups) { + return; + } + struct ds match = DS_EMPTY_INITIALIZER; + struct ds actions = DS_EMPTY_INITIALIZER; + struct ds group_ports = DS_EMPTY_INITIALIZER; - ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 50, - ds_cstr(&match), ds_cstr(&actions), - &fwd_group->header_); + for (int i = 0; i < od->nbs->n_forwarding_groups; ++i) { + const struct nbrec_forwarding_group *fwd_group = NULL; + fwd_group = od->nbs->forwarding_groups[i]; + if (!fwd_group->n_child_port) { + continue; + } - /* L2 lookup for the forwarding group's virtual MAC */ - ds_clear(&match); - ds_put_format(&match, "eth.dst == %s", fwd_group->vmac); + /* ARP responder for the forwarding group's virtual IP */ + ds_put_format(&match, "arp.tpa == %s && arp.op == 1", + fwd_group->vip); + 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;", + fwd_group->vmac, fwd_group->vmac, fwd_group->vip); + + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 50, + ds_cstr(&match), ds_cstr(&actions), + &fwd_group->header_); - /* Create a comma separated string of child ports */ - ds_clear(&group_ports); - if (fwd_group->liveness) { - ds_put_cstr(&group_ports, "liveness=\"true\","); - } - ds_put_cstr(&group_ports, "childports="); - for (i = 0; i < (fwd_group->n_child_port - 1); ++i) { - ds_put_format(&group_ports, "\"%s\",", - fwd_group->child_port[i]); - } - ds_put_format(&group_ports, "\"%s\"", - fwd_group->child_port[fwd_group->n_child_port - 1]); + /* L2 lookup for the forwarding group's virtual MAC */ + ds_clear(&match); + ds_put_format(&match, "eth.dst == %s", fwd_group->vmac); - ds_clear(&actions); - ds_put_format(&actions, "fwd_group(%s);", ds_cstr(&group_ports)); - ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, 50, - ds_cstr(&match), ds_cstr(&actions), - &fwd_group->header_); + /* Create a comma separated string of child ports */ + ds_clear(&group_ports); + if (fwd_group->liveness) { + ds_put_cstr(&group_ports, "liveness=\"true\","); } + ds_put_cstr(&group_ports, "childports="); + for (i = 0; i < (fwd_group->n_child_port - 1); ++i) { + ds_put_format(&group_ports, "\"%s\",", + fwd_group->child_port[i]); + } + ds_put_format(&group_ports, "\"%s\"", + fwd_group->child_port[fwd_group->n_child_port - 1]); - ds_destroy(&match); - ds_destroy(&actions); - ds_destroy(&group_ports); + ds_clear(&actions); + ds_put_format(&actions, "fwd_group(%s);", ds_cstr(&group_ports)); + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, 50, + ds_cstr(&match), ds_cstr(&actions), + &fwd_group->header_); } + + ds_destroy(&match); + ds_destroy(&actions); + ds_destroy(&group_ports); } static void @@ -8377,19 +8387,20 @@ build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath *od, struct hmap *lflows, const struct shash *meter_groups) { - if (od->nbs) { - ls_get_acl_flags(od); - - build_pre_acls(od, port_groups, lflows); - build_pre_lb(od, meter_groups, lflows); - build_pre_stateful(od, features, lflows); - build_acl_hints(od, features, lflows); - build_acls(od, features, lflows, port_groups, meter_groups); - build_qos(od, lflows); - build_stateful(od, features, lflows); - build_lb_hairpin(od, lflows); - build_vtep_hairpin(od, lflows); + if (!od->nbs) { + return; } + ls_get_acl_flags(od); + + build_pre_acls(od, port_groups, lflows); + build_pre_lb(od, meter_groups, lflows); + build_pre_stateful(od, features, lflows); + build_acl_hints(od, features, lflows); + build_acls(od, features, lflows, port_groups, meter_groups); + build_qos(od, lflows); + build_stateful(od, features, lflows); + build_lb_hairpin(od, lflows); + build_vtep_hairpin(od, lflows); } /* Logical switch ingress table 0: Admission control framework (priority @@ -8398,26 +8409,27 @@ static void build_lswitch_lflows_admission_control(struct ovn_datapath *od, struct hmap *lflows) { - if (od->nbs) { - /* Logical VLANs not supported. */ - if (!is_vlan_transparent(od)) { - /* Block logical VLANs. */ - ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100, - "vlan.present", debug_drop_action()); - } - - /* Broadcast/multicast source address is invalid. */ + if (!od->nbs) { + return; + } + /* Logical VLANs not supported. */ + if (!is_vlan_transparent(od)) { + /* Block logical VLANs. */ ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100, - "eth.src[40]", debug_drop_action()); + "vlan.present", debug_drop_action()); + } - ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 50, "1", - REGBIT_PORT_SEC_DROP" = check_in_port_sec(); next;"); + /* Broadcast/multicast source address is invalid. */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100, + "eth.src[40]", debug_drop_action()); - ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 50, - REGBIT_PORT_SEC_DROP" == 1", debug_drop_action()); + ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 50, "1", + REGBIT_PORT_SEC_DROP" = check_in_port_sec(); next;"); - ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 0, "1", "next;"); - } + ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 50, + REGBIT_PORT_SEC_DROP" == 1", debug_drop_action()); + + ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 0, "1", "next;"); } /* Ingress table 19: ARP/ND responder, skip requests coming from localnet @@ -8428,14 +8440,15 @@ build_lswitch_arp_nd_responder_skip_local(struct ovn_port *op, struct hmap *lflows, struct ds *match) { - if (op->nbsp && lsp_is_localnet(op->nbsp)) { - ds_clear(match); - ds_put_format(match, "inport == %s", op->json_key); - ovn_lflow_add_with_lport_and_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, 100, - ds_cstr(match), "next;", op->key, - &op->nbsp->header_); + if (!op->nbsp || !lsp_is_localnet(op->nbsp)) { + return; } + ds_clear(match); + ds_put_format(match, "inport == %s", op->json_key); + ovn_lflow_add_with_lport_and_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 100, + ds_cstr(match), "next;", op->key, + &op->nbsp->header_); } /* Ingress table 19: ARP/ND responder, reply for known IPs. @@ -8448,239 +8461,125 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, struct ds *actions, struct ds *match) { - if (op->nbsp) { - if (!strcmp(op->nbsp->type, "virtual")) { - /* Handle - * - GARPs for virtual ip which belongs to a logical port - * of type 'virtual' and bind that port. - * - * - ARP reply from the virtual ip which belongs to a logical - * port of type 'virtual' and bind that port. - * - * - IPv6 Neighbor Solicitations requests that targets virtual - * ip which belongs to a logical port of type 'virtual' and - * bind that port. - * - * - IPv6 unsolicited Neighbor Advertisements that targets - * ip which belongs to a logical port of type 'virtual' - * and bind that port. - * */ - struct in6_addr ip; - - const char *virtual_ip = smap_get(&op->nbsp->options, - "virtual-ip"); - const char *virtual_parents = smap_get(&op->nbsp->options, - "virtual-parents"); - if (!virtual_ip || !virtual_parents) { - return; - } - - bool is_ipv4 = strchr(virtual_ip, '.') ? true : false; - if (is_ipv4) { - ovs_be32 ipv4; - if (!ip_parse(virtual_ip, &ipv4)) { - return; - } - } else { - if (!ipv6_parse(virtual_ip, &ip)) { - return; - } - } - - char *tokstr = xstrdup(virtual_parents); - char *save_ptr = NULL; - char *vparent; - for (vparent = strtok_r(tokstr, ",", &save_ptr); vparent != NULL; - vparent = strtok_r(NULL, ",", &save_ptr)) { - struct ovn_port *vp = ovn_port_find(ports, vparent); - if (!vp || vp->od != op->od) { - /* vparent name should be valid and it should belong - * to the same logical switch. */ - continue; - } - - if (is_ipv4) { - ds_clear(match); - ds_put_format(match, "inport == \"%s\" && " - "((arp.op == 1 && arp.spa == %s && " - "arp.tpa == %s) || (arp.op == 2 && " - "arp.spa == %s))", - vparent, virtual_ip, virtual_ip, - virtual_ip); - } else { - struct ipv6_netaddr na; - /* Find VIP multicast group */ - in6_addr_solicited_node(&na.sn_addr, &ip); - inet_ntop(AF_INET6, &na.sn_addr, na.sn_addr_s, - sizeof na.sn_addr_s); + if (!op->nbsp) { + return; + } + if (!strcmp(op->nbsp->type, "virtual")) { + /* Handle + * - GARPs for virtual ip which belongs to a logical port + * of type 'virtual' and bind that port. + * + * - ARP reply from the virtual ip which belongs to a logical + * port of type 'virtual' and bind that port. + * + * - IPv6 Neighbor Solicitations requests that targets virtual + * ip which belongs to a logical port of type 'virtual' and + * bind that port. + * + * - IPv6 unsolicited Neighbor Advertisements that targets + * ip which belongs to a logical port of type 'virtual' + * and bind that port. + * */ + struct in6_addr ip; - ds_clear(match); - ds_put_format(match, "inport == \"%s\" && " - "((nd_ns && ip6.dst == {%s, %s} && " - "nd.target == %s) ||" - "(nd_na && nd.target == %s))", - vparent, - virtual_ip, - na.sn_addr_s, - virtual_ip, - virtual_ip); - } + const char *virtual_ip = smap_get(&op->nbsp->options, + "virtual-ip"); + const char *virtual_parents = smap_get(&op->nbsp->options, + "virtual-parents"); + if (!virtual_ip || !virtual_parents) { + return; + } - ds_clear(actions); - ds_put_format(actions, - "bind_vport(%s, inport); " - "next;", - op->json_key); - ovn_lflow_add_with_lport_and_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, 100, - ds_cstr(match), - ds_cstr(actions), vparent, - &vp->nbsp->header_); + bool is_ipv4 = strchr(virtual_ip, '.') ? true : false; + if (is_ipv4) { + ovs_be32 ipv4; + if (!ip_parse(virtual_ip, &ipv4)) { + return; } - - free(tokstr); } else { - /* - * Add ARP/ND reply flows if either the - * - port is up and it doesn't have 'unknown' address defined or - * - port type is router or - * - port type is localport - */ - if (check_lsp_is_up && - !lsp_is_up(op->nbsp) && !lsp_is_router(op->nbsp) && - strcmp(op->nbsp->type, "localport")) { - return; - } - - if (lsp_is_external(op->nbsp) || op->has_unknown) { - return; + if (!ipv6_parse(virtual_ip, &ip)) { + return; } + } - if (is_vlan_transparent(op->od)) { - return; + char *tokstr = xstrdup(virtual_parents); + char *save_ptr = NULL; + char *vparent; + for (vparent = strtok_r(tokstr, ",", &save_ptr); vparent != NULL; + vparent = strtok_r(NULL, ",", &save_ptr)) { + struct ovn_port *vp = ovn_port_find(ports, vparent); + if (!vp || vp->od != op->od) { + /* vparent name should be valid and it should belong + * to the same logical switch. */ + continue; } - 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_with_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, 50, - ds_cstr(match), - ds_cstr(actions), - &op->nbsp->header_); - - /* Do not reply to an ARP request from the port that owns - * the address (otherwise a DHCP client that ARPs to check - * for a duplicate address will fail). Instead, forward - * it the usual way. - * - * (Another alternative would be to simply drop the packet. - * If everything is working as it is configured, then this - * would produce equivalent results, since no one should - * reply to the request. But ARPing for one's own IP - * address is intended to detect situations where the - * network is not working as configured, so dropping the - * request would frustrate that intent.) */ - ds_put_format(match, " && inport == %s", op->json_key); - ovn_lflow_add_with_lport_and_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, - 100, ds_cstr(match), - "next;", op->key, - &op->nbsp->header_); - } + if (is_ipv4) { + ds_clear(match); + ds_put_format(match, "inport == \"%s\" && " + "((arp.op == 1 && arp.spa == %s && " + "arp.tpa == %s) || (arp.op == 2 && " + "arp.spa == %s))", + vparent, virtual_ip, virtual_ip, + virtual_ip); + } else { + struct ipv6_netaddr na; + /* Find VIP multicast group */ + in6_addr_solicited_node(&na.sn_addr, &ip); + inet_ntop(AF_INET6, &na.sn_addr, na.sn_addr_s, + sizeof na.sn_addr_s); - /* For ND solicitations, we need to listen for both the - * unicast IPv6 address and its all-nodes multicast address, - * but always respond with the unicast IPv6 address. */ - for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) { - ds_clear(match); - ds_put_format(match, - "nd_ns && ip6.dst == {%s, %s} && nd.target == %s", - op->lsp_addrs[i].ipv6_addrs[j].addr_s, - op->lsp_addrs[i].ipv6_addrs[j].sn_addr_s, - op->lsp_addrs[i].ipv6_addrs[j].addr_s); + ds_clear(match); + ds_put_format(match, "inport == \"%s\" && " + "((nd_ns && ip6.dst == {%s, %s} && " + "nd.target == %s) ||" + "(nd_na && nd.target == %s))", + vparent, + virtual_ip, + na.sn_addr_s, + virtual_ip, + virtual_ip); + } - ds_clear(actions); - ds_put_format(actions, - "%s { " - "eth.src = %s; " - "ip6.src = %s; " - "nd.target = %s; " - "nd.tll = %s; " - "outport = inport; " - "flags.loopback = 1; " - "output; " - "};", - lsp_is_router(op->nbsp) ? "nd_na_router" : "nd_na", - op->lsp_addrs[i].ea_s, - op->lsp_addrs[i].ipv6_addrs[j].addr_s, - op->lsp_addrs[i].ipv6_addrs[j].addr_s, - op->lsp_addrs[i].ea_s); - ovn_lflow_add_with_hint__(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, 50, + ds_clear(actions); + ds_put_format(actions, + "bind_vport(%s, inport); " + "next;", + op->json_key); + ovn_lflow_add_with_lport_and_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 100, ds_cstr(match), - ds_cstr(actions), - NULL, - copp_meter_get(COPP_ND_NA, - op->od->nbs->copp, - meter_groups), - &op->nbsp->header_); - - /* Do not reply to a solicitation from the port that owns - * the address (otherwise DAD detection will fail). */ - ds_put_format(match, " && inport == %s", op->json_key); - ovn_lflow_add_with_lport_and_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, - 100, ds_cstr(match), - "next;", op->key, - &op->nbsp->header_); - } - } + ds_cstr(actions), vparent, + &vp->nbsp->header_); } - if (op->proxy_arp_addrs.n_ipv4_addrs || - op->proxy_arp_addrs.n_ipv6_addrs) { - /* Select the mac address to answer the proxy ARP/NDP */ - char *ea_s = NULL; - if (!eth_addr_is_zero(op->proxy_arp_addrs.ea)) { - ea_s = op->proxy_arp_addrs.ea_s; - } else if (op->peer) { - ea_s = op->peer->lrp_networks.ea_s; - } else { - return; - } - int i = 0; - /* Add IPv4 responses for ARP proxies. */ - if (op->proxy_arp_addrs.n_ipv4_addrs) { - /* Match rule on all proxy ARP IPs. */ - ds_clear(match); - ds_put_cstr(match, "arp.op == 1 && arp.tpa == {"); + free(tokstr); + } else { + /* + * Add ARP/ND reply flows if either the + * - port is up and it doesn't have 'unknown' address defined or + * - port type is router or + * - port type is localport + */ + if (check_lsp_is_up && + !lsp_is_up(op->nbsp) && !lsp_is_router(op->nbsp) && + strcmp(op->nbsp->type, "localport")) { + return; + } - for (i = 0; i < op->proxy_arp_addrs.n_ipv4_addrs; i++) { - ds_put_format(match, "%s/%u,", - op->proxy_arp_addrs.ipv4_addrs[i].addr_s, - op->proxy_arp_addrs.ipv4_addrs[i].plen); - } + if (lsp_is_external(op->nbsp) || op->has_unknown) { + return; + } - ds_chomp(match, ','); - ds_put_cstr(match, "}"); + if (is_vlan_transparent(op->od)) { + return; + } + 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; " @@ -8688,57 +8587,66 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, "arp.op = 2; /* ARP reply */ " "arp.tha = arp.sha; " "arp.sha = %s; " - "arp.tpa <-> arp.spa; " + "arp.tpa = arp.spa; " + "arp.spa = %s; " "outport = inport; " "flags.loopback = 1; " "output;", - ea_s, - ea_s); + op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s, + op->lsp_addrs[i].ipv4_addrs[j].addr_s); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 50, + ds_cstr(match), + ds_cstr(actions), + &op->nbsp->header_); - ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, - 50, ds_cstr(match), ds_cstr(actions), &op->nbsp->header_); + /* Do not reply to an ARP request from the port that owns + * the address (otherwise a DHCP client that ARPs to check + * for a duplicate address will fail). Instead, forward + * it the usual way. + * + * (Another alternative would be to simply drop the packet. + * If everything is working as it is configured, then this + * would produce equivalent results, since no one should + * reply to the request. But ARPing for one's own IP + * address is intended to detect situations where the + * network is not working as configured, so dropping the + * request would frustrate that intent.) */ + ds_put_format(match, " && inport == %s", op->json_key); + ovn_lflow_add_with_lport_and_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, + 100, ds_cstr(match), + "next;", op->key, + &op->nbsp->header_); } - /* Add IPv6 NDP responses. - * For ND solicitations, we need to listen for both the + /* For ND solicitations, we need to listen for both the * unicast IPv6 address and its all-nodes multicast address, * but always respond with the unicast IPv6 address. */ - if (op->proxy_arp_addrs.n_ipv6_addrs) { - struct ds ip6_dst_match = DS_EMPTY_INITIALIZER; - struct ds nd_target_match = DS_EMPTY_INITIALIZER; - for (size_t j = 0; j < op->proxy_arp_addrs.n_ipv6_addrs; j++) { - ds_put_format(&ip6_dst_match, "%s/%u, %s/%u, ", - op->proxy_arp_addrs.ipv6_addrs[j].addr_s, - op->proxy_arp_addrs.ipv6_addrs[j].plen, - op->proxy_arp_addrs.ipv6_addrs[j].sn_addr_s, - op->proxy_arp_addrs.ipv6_addrs[j].plen); - ds_put_format(&nd_target_match, "%s/%u, ", - op->proxy_arp_addrs.ipv6_addrs[j].addr_s, - op->proxy_arp_addrs.ipv6_addrs[j].plen); - } - ds_truncate(&ip6_dst_match, ip6_dst_match.length - 2); - ds_truncate(&nd_target_match, nd_target_match.length - 2); + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) { ds_clear(match); ds_put_format(match, - "nd_ns " - "&& ip6.dst == { %s } " - "&& nd.target == { %s }", - ds_cstr(&ip6_dst_match), - ds_cstr(&nd_target_match)); + "nd_ns && ip6.dst == {%s, %s} && nd.target == %s", + op->lsp_addrs[i].ipv6_addrs[j].addr_s, + op->lsp_addrs[i].ipv6_addrs[j].sn_addr_s, + op->lsp_addrs[i].ipv6_addrs[j].addr_s); + ds_clear(actions); ds_put_format(actions, "%s { " "eth.src = %s; " - "ip6.src = nd.target; " - "nd.target = nd.target; " + "ip6.src = %s; " + "nd.target = %s; " "nd.tll = %s; " "outport = inport; " "flags.loopback = 1; " "output; " "};", lsp_is_router(op->nbsp) ? "nd_na_router" : "nd_na", - ea_s, - ea_s); + op->lsp_addrs[i].ea_s, + op->lsp_addrs[i].ipv6_addrs[j].addr_s, + op->lsp_addrs[i].ipv6_addrs[j].addr_s, + op->lsp_addrs[i].ea_s); ovn_lflow_add_with_hint__(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50, ds_cstr(match), @@ -8748,9 +8656,115 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, op->od->nbs->copp, meter_groups), &op->nbsp->header_); - ds_destroy(&ip6_dst_match); - ds_destroy(&nd_target_match); + + /* Do not reply to a solicitation from the port that owns + * the address (otherwise DAD detection will fail). */ + ds_put_format(match, " && inport == %s", op->json_key); + ovn_lflow_add_with_lport_and_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, + 100, ds_cstr(match), + "next;", op->key, + &op->nbsp->header_); + } + } + } + if (op->proxy_arp_addrs.n_ipv4_addrs || + op->proxy_arp_addrs.n_ipv6_addrs) { + /* Select the mac address to answer the proxy ARP/NDP */ + char *ea_s = NULL; + if (!eth_addr_is_zero(op->proxy_arp_addrs.ea)) { + ea_s = op->proxy_arp_addrs.ea_s; + } else if (op->peer) { + ea_s = op->peer->lrp_networks.ea_s; + } else { + return; + } + + int i = 0; + /* Add IPv4 responses for ARP proxies. */ + if (op->proxy_arp_addrs.n_ipv4_addrs) { + /* Match rule on all proxy ARP IPs. */ + ds_clear(match); + ds_put_cstr(match, "arp.op == 1 && arp.tpa == {"); + + for (i = 0; i < op->proxy_arp_addrs.n_ipv4_addrs; i++) { + ds_put_format(match, "%s/%u,", + op->proxy_arp_addrs.ipv4_addrs[i].addr_s, + op->proxy_arp_addrs.ipv4_addrs[i].plen); + } + + ds_chomp(match, ','); + ds_put_cstr(match, "}"); + + 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; " + "outport = inport; " + "flags.loopback = 1; " + "output;", + ea_s, + ea_s); + + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, + 50, ds_cstr(match), ds_cstr(actions), &op->nbsp->header_); + } + + /* Add IPv6 NDP responses. + * For ND solicitations, we need to listen for both the + * unicast IPv6 address and its all-nodes multicast address, + * but always respond with the unicast IPv6 address. */ + if (op->proxy_arp_addrs.n_ipv6_addrs) { + struct ds ip6_dst_match = DS_EMPTY_INITIALIZER; + struct ds nd_target_match = DS_EMPTY_INITIALIZER; + for (size_t j = 0; j < op->proxy_arp_addrs.n_ipv6_addrs; j++) { + ds_put_format(&ip6_dst_match, "%s/%u, %s/%u, ", + op->proxy_arp_addrs.ipv6_addrs[j].addr_s, + op->proxy_arp_addrs.ipv6_addrs[j].plen, + op->proxy_arp_addrs.ipv6_addrs[j].sn_addr_s, + op->proxy_arp_addrs.ipv6_addrs[j].plen); + ds_put_format(&nd_target_match, "%s/%u, ", + op->proxy_arp_addrs.ipv6_addrs[j].addr_s, + op->proxy_arp_addrs.ipv6_addrs[j].plen); } + ds_truncate(&ip6_dst_match, ip6_dst_match.length - 2); + ds_truncate(&nd_target_match, nd_target_match.length - 2); + ds_clear(match); + ds_put_format(match, + "nd_ns " + "&& ip6.dst == { %s } " + "&& nd.target == { %s }", + ds_cstr(&ip6_dst_match), + ds_cstr(&nd_target_match)); + ds_clear(actions); + ds_put_format(actions, + "%s { " + "eth.src = %s; " + "ip6.src = nd.target; " + "nd.target = nd.target; " + "nd.tll = %s; " + "outport = inport; " + "flags.loopback = 1; " + "output; " + "};", + lsp_is_router(op->nbsp) ? "nd_na_router" : "nd_na", + ea_s, + ea_s); + ovn_lflow_add_with_hint__(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 50, + ds_cstr(match), + ds_cstr(actions), + NULL, + copp_meter_get(COPP_ND_NA, + op->od->nbs->copp, + meter_groups), + &op->nbsp->header_); + ds_destroy(&ip6_dst_match); + ds_destroy(&nd_target_match); } } } @@ -8842,47 +8856,48 @@ build_lswitch_dhcp_options_and_response(struct ovn_port *op, struct hmap *lflows, const struct shash *meter_groups) { - if (op->nbsp) { - if (!lsp_is_enabled(op->nbsp) || lsp_is_router(op->nbsp)) { - /* Don't add the DHCP flows if the port is not enabled or if the - * port is a router port. */ - return; - } + if (!op->nbsp) { + return; + } + if (!lsp_is_enabled(op->nbsp) || lsp_is_router(op->nbsp)) { + /* Don't add the DHCP flows if the port is not enabled or if the + * port is a router port. */ + return; + } - if (!op->nbsp->dhcpv4_options && !op->nbsp->dhcpv6_options) { - /* CMS has disabled both native DHCPv4 and DHCPv6 for this lport. - */ - return; - } + if (!op->nbsp->dhcpv4_options && !op->nbsp->dhcpv6_options) { + /* CMS has disabled both native DHCPv4 and DHCPv6 for this lport. + */ + return; + } - bool is_external = lsp_is_external(op->nbsp); - if (is_external && (!op->od->n_localnet_ports || - !op->nbsp->ha_chassis_group)) { - /* If it's an external port and there are no localnet ports - * and if it doesn't belong to an HA chassis group ignore it. */ - return; - } + bool is_external = lsp_is_external(op->nbsp); + if (is_external && (!op->od->n_localnet_ports || + !op->nbsp->ha_chassis_group)) { + /* If it's an external port and there are no localnet ports + * and if it doesn't belong to an HA chassis group ignore it. */ + return; + } - for (size_t i = 0; i < op->n_lsp_addrs; i++) { - if (is_external) { - for (size_t j = 0; j < op->od->n_localnet_ports; j++) { - build_dhcpv4_options_flows( - op, &op->lsp_addrs[i], - op->od->localnet_ports[j], is_external, - meter_groups, lflows); - build_dhcpv6_options_flows( - op, &op->lsp_addrs[i], - op->od->localnet_ports[j], is_external, - meter_groups, lflows); - } - } else { - build_dhcpv4_options_flows(op, &op->lsp_addrs[i], op, - is_external, meter_groups, - lflows); - build_dhcpv6_options_flows(op, &op->lsp_addrs[i], op, - is_external, meter_groups, - lflows); + for (size_t i = 0; i < op->n_lsp_addrs; i++) { + if (is_external) { + for (size_t j = 0; j < op->od->n_localnet_ports; j++) { + build_dhcpv4_options_flows( + op, &op->lsp_addrs[i], + op->od->localnet_ports[j], is_external, + meter_groups, lflows); + build_dhcpv6_options_flows( + op, &op->lsp_addrs[i], + op->od->localnet_ports[j], is_external, + meter_groups, lflows); } + } else { + build_dhcpv4_options_flows(op, &op->lsp_addrs[i], op, + is_external, meter_groups, + lflows); + build_dhcpv6_options_flows(op, &op->lsp_addrs[i], op, + is_external, meter_groups, + lflows); } } } @@ -8897,13 +8912,14 @@ static void build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od, struct hmap *lflows) { - if (od->nbs) { - ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_OPTIONS, 0, "1", "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_RESPONSE, 0, "1", "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 0, "1", "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 0, "1", "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_IN_EXTERNAL_PORT, 0, "1", "next;"); + if (!od->nbs) { + return; } + ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_OPTIONS, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_RESPONSE, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_EXTERNAL_PORT, 0, "1", "next;"); } /* Logical switch ingress table 22 and 23: DNS lookup and response @@ -8914,24 +8930,25 @@ build_lswitch_dns_lookup_and_response(struct ovn_datapath *od, struct hmap *lflows, const struct shash *meter_groups) { - if (od->nbs && ls_has_dns_records(od->nbs)) { - ovn_lflow_metered(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 100, - "udp.dst == 53", - REGBIT_DNS_LOOKUP_RESULT" = dns_lookup(); next;", - copp_meter_get(COPP_DNS, od->nbs->copp, - meter_groups)); - const char *dns_action = "eth.dst <-> eth.src; ip4.src <-> ip4.dst; " - "udp.dst = udp.src; udp.src = 53; outport = inport; " - "flags.loopback = 1; output;"; - const char *dns_match = "udp.dst == 53 && "REGBIT_DNS_LOOKUP_RESULT; - ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 100, - dns_match, dns_action); - dns_action = "eth.dst <-> eth.src; ip6.src <-> ip6.dst; " - "udp.dst = udp.src; udp.src = 53; outport = inport; " - "flags.loopback = 1; output;"; - ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 100, - dns_match, dns_action); + if (!od->nbs || !ls_has_dns_records(od->nbs)) { + return; } + ovn_lflow_metered(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 100, + "udp.dst == 53", + REGBIT_DNS_LOOKUP_RESULT" = dns_lookup(); next;", + copp_meter_get(COPP_DNS, od->nbs->copp, + meter_groups)); + const char *dns_action = "eth.dst <-> eth.src; ip4.src <-> ip4.dst; " + "udp.dst = udp.src; udp.src = 53; outport = inport; " + "flags.loopback = 1; output;"; + const char *dns_match = "udp.dst == 53 && "REGBIT_DNS_LOOKUP_RESULT; + ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 100, + dns_match, dns_action); + dns_action = "eth.dst <-> eth.src; ip6.src <-> ip6.dst; " + "udp.dst = udp.src; udp.src = 53; outport = inport; " + "flags.loopback = 1; output;"; + ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 100, + dns_match, dns_action); } /* Table 24: External port. Drop ARP request for router ips from @@ -8942,12 +8959,12 @@ static void build_lswitch_external_port(struct ovn_port *op, struct hmap *lflows) { - if (op->nbsp && lsp_is_external(op->nbsp)) { - - for (size_t i = 0; i < op->od->n_localnet_ports; i++) { - build_drop_arp_nd_flows_for_unbound_router_ports( - op, op->od->localnet_ports[i], lflows); - } + if (!op->nbsp || !lsp_is_external(op->nbsp)) { + return; + } + for (size_t i = 0; i < op->od->n_localnet_ports; i++) { + build_drop_arp_nd_flows_for_unbound_router_ports( + op, op->od->localnet_ports[i], lflows); } } @@ -8959,80 +8976,81 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, struct ds *actions, const struct shash *meter_groups) { - if (od->nbs) { + if (!od->nbs) { + return; + } - ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 110, - "eth.dst == $svc_monitor_mac", - "handle_svc_check(inport);"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 110, + "eth.dst == $svc_monitor_mac", + "handle_svc_check(inport);"); - struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw; + struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw; - if (mcast_sw_info->enabled) { - ds_clear(actions); - ds_put_cstr(actions, "igmp;"); - /* Punt IGMP traffic to controller. */ - ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100, - "igmp", ds_cstr(actions), - copp_meter_get(COPP_IGMP, od->nbs->copp, - meter_groups)); - - /* Punt MLD traffic to controller. */ - ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100, - "mldv1 || mldv2", ds_cstr(actions), - copp_meter_get(COPP_IGMP, od->nbs->copp, - meter_groups)); - - /* Flood all IP multicast traffic destined to 224.0.0.X to all - * ports - RFC 4541, section 2.1.2, item 2. - */ - ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 85, - "ip4.mcast && ip4.dst == 224.0.0.0/24", - "outport = \""MC_FLOOD_L2"\"; output;"); + if (mcast_sw_info->enabled) { + ds_clear(actions); + ds_put_cstr(actions, "igmp;"); + /* Punt IGMP traffic to controller. */ + ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100, + "igmp", ds_cstr(actions), + copp_meter_get(COPP_IGMP, od->nbs->copp, + meter_groups)); - /* Flood all IPv6 multicast traffic destined to reserved - * multicast IPs (RFC 4291, 2.7.1). - */ - ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 85, - "ip6.mcast_flood", - "outport = \""MC_FLOOD"\"; output;"); - - /* Forward uregistered IP multicast to routers with relay enabled - * and to any ports configured to flood IP multicast traffic. - * If configured to flood unregistered traffic this will be - * handled by the L2 multicast flow. - */ - if (!mcast_sw_info->flood_unregistered) { - ds_clear(actions); + /* Punt MLD traffic to controller. */ + ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100, + "mldv1 || mldv2", ds_cstr(actions), + copp_meter_get(COPP_IGMP, od->nbs->copp, + meter_groups)); - if (mcast_sw_info->flood_relay) { - ds_put_cstr(actions, - "clone { " - "outport = \""MC_MROUTER_FLOOD"\"; " - "output; " - "}; "); - } + /* Flood all IP multicast traffic destined to 224.0.0.X to all + * ports - RFC 4541, section 2.1.2, item 2. + */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 85, + "ip4.mcast && ip4.dst == 224.0.0.0/24", + "outport = \""MC_FLOOD_L2"\"; output;"); - if (mcast_sw_info->flood_static) { - ds_put_cstr(actions, "outport =\""MC_STATIC"\"; output;"); - } + /* Flood all IPv6 multicast traffic destined to reserved + * multicast IPs (RFC 4291, 2.7.1). + */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 85, + "ip6.mcast_flood", + "outport = \""MC_FLOOD"\"; output;"); - /* Explicitly drop the traffic if relay or static flooding - * is not configured. - */ - if (!mcast_sw_info->flood_relay && - !mcast_sw_info->flood_static) { - ds_put_cstr(actions, debug_drop_action()); - } + /* Forward uregistered IP multicast to routers with relay enabled + * and to any ports configured to flood IP multicast traffic. + * If configured to flood unregistered traffic this will be + * handled by the L2 multicast flow. + */ + if (!mcast_sw_info->flood_unregistered) { + ds_clear(actions); + + if (mcast_sw_info->flood_relay) { + ds_put_cstr(actions, + "clone { " + "outport = \""MC_MROUTER_FLOOD"\"; " + "output; " + "}; "); + } - ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80, - "ip4.mcast || ip6.mcast", - ds_cstr(actions)); + if (mcast_sw_info->flood_static) { + ds_put_cstr(actions, "outport =\""MC_STATIC"\"; output;"); } - } - ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 70, "eth.mcast", - "outport = \""MC_FLOOD"\"; output;"); + /* Explicitly drop the traffic if relay or static flooding + * is not configured. + */ + if (!mcast_sw_info->flood_relay && + !mcast_sw_info->flood_static) { + ds_put_cstr(actions, debug_drop_action()); + } + + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80, + "ip4.mcast || ip6.mcast", + ds_cstr(actions)); + } } + + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 70, "eth.mcast", + "outport = \""MC_FLOOD"\"; output;"); } @@ -9128,149 +9146,150 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op, struct ds *actions, struct ds *match) { - if (op->nbsp && (!lsp_is_external(op->nbsp))) { + if (!op->nbsp || lsp_is_external(op->nbsp)) { + return; + } - /* 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 (lsp_is_router(op->nbsp)) { - 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; - bool lsp_enabled = lsp_is_enabled(op->nbsp); - const char *action = lsp_enabled ? "outport = %s; output;" : - debug_drop_action(); - if (ovs_scan(op->nbsp->addresses[i], + /* 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 (lsp_is_router(op->nbsp)) { + 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; + bool lsp_enabled = lsp_is_enabled(op->nbsp); + const char *action = lsp_enabled ? "outport = %s; output;" : + debug_drop_action(); + 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, action, 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_enabled) { + ovs_mutex_lock(&mcgroup_mutex); + ovn_multicast_add(mcgroups, &mc_unknown, op); + ovs_mutex_unlock(&mcgroup_mutex); + 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))) { - ds_clear(match); - ds_put_format(match, "eth.dst == "ETH_ADDR_FMT, - ETH_ADDR_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, action, 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_enabled) { - ovs_mutex_lock(&mcgroup_mutex); - ovn_multicast_add(mcgroups, &mc_unknown, op); - ovs_mutex_unlock(&mcgroup_mutex); - 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, + ds_clear(actions); + ds_put_format(actions, action, 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_cstr(match, "eth.dst == "); + if (!eth_addr_is_zero(op->proxy_arp_addrs.ea)) { + ds_put_format(match, + "{ %s, "ETH_ADDR_FMT" }", + op->proxy_arp_addrs.ea_s, ETH_ADDR_ARGS(mac)); - - ds_clear(actions); - ds_put_format(actions, action, 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_cstr(match, "eth.dst == "); - if (!eth_addr_is_zero(op->proxy_arp_addrs.ea)) { - ds_put_format(match, - "{ %s, "ETH_ADDR_FMT" }", - op->proxy_arp_addrs.ea_s, - ETH_ADDR_ARGS(mac)); + } else { + ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(mac)); + } + if (op->peer->od->n_l3dgw_ports + && op->od->n_localnet_ports) { + bool add_chassis_resident_check = false; + const char *json_key; + if (is_l3dgw_port(op->peer)) { + /* 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 gateway chassis. */ + add_chassis_resident_check = true; + json_key = op->peer->cr_port->json_key; } else { - ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(mac)); + /* 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) && + op->peer->od->n_l3dgw_ports == 1; + json_key = + op->peer->od->l3dgw_ports[0]->cr_port->json_key; } - if (op->peer->od->n_l3dgw_ports - && op->od->n_localnet_ports) { - bool add_chassis_resident_check = false; - const char *json_key; - if (is_l3dgw_port(op->peer)) { - /* 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 gateway chassis. */ - add_chassis_resident_check = true; - json_key = op->peer->cr_port->json_key; - } 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) && - op->peer->od->n_l3dgw_ports == 1; - json_key = - op->peer->od->l3dgw_ports[0]->cr_port->json_key; - } - if (add_chassis_resident_check) { - ds_put_format(match, " && is_chassis_resident(%s)", - json_key); - } + if (add_chassis_resident_check) { + ds_put_format(match, " && is_chassis_resident(%s)", + json_key); } + } - ds_clear(actions); - ds_put_format(actions, action, 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 (is_l3dgw_port(op->peer)) { - 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, action, 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_); - } + ds_clear(actions); + ds_put_format(actions, action, 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 (is_l3dgw_port(op->peer)) { + 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, action, 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]); } + } 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]); } } } @@ -11587,15 +11606,16 @@ static void build_adm_ctrl_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows) { - if (od->nbr) { - /* Logical VLANs not supported. - * Broadcast/multicast source address is invalid. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100, - "vlan.present || eth.src[40]", debug_drop_action()); - - /* Default action for L2 security is to drop. */ - ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ADMISSION); + if (!od->nbr) { + return; } + /* Logical VLANs not supported. + * Broadcast/multicast source address is invalid. */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100, + "vlan.present || eth.src[40]", debug_drop_action()); + + /* Default action for L2 security is to drop. */ + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ADMISSION); } static int @@ -11688,50 +11708,52 @@ build_adm_ctrl_flows_for_lrouter_port( struct ovn_port *op, struct hmap *lflows, struct ds *match, struct ds *actions) { - if (op->nbrp) { - if (!lrport_is_enabled(op->nbrp)) { - /* Drop packets from disabled logical ports (since logical flow - * tables are default-drop). */ - return; - } + if (!op->nbrp) { + return; + } - if (is_cr_port(op)) { - /* No ingress packets should be received on a chassisredirect - * port. */ - return; - } + if (!lrport_is_enabled(op->nbrp)) { + /* Drop packets from disabled logical ports (since logical flow + * tables are default-drop). */ + return; + } - /* Store the ethernet address of the port receiving the packet. - * This will save us from having to match on inport further down in - * the pipeline. - */ - ds_clear(match); - ds_put_format(match, "eth.mcast && inport == %s", op->json_key); - build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_ADMISSION, 50, 55, - match, actions, &op->nbrp->header_, - REG_INPORT_ETH_ADDR " = %s; next;", - op->lrp_networks.ea_s); + if (is_cr_port(op)) { + /* No ingress packets should be received on a chassisredirect + * port. */ + return; + } - ds_clear(match); - ds_put_cstr(match, "eth.dst == "); - if (op->peer && !eth_addr_is_zero(op->peer->proxy_arp_addrs.ea)) { - ds_put_format(match, - "{ %s, %s }", - op->peer->proxy_arp_addrs.ea_s, - op->lrp_networks.ea_s); - } else { - ds_put_format(match, "%s", op->lrp_networks.ea_s); - } - ds_put_format(match, " && inport == %s", op->json_key); - if (consider_l3dgw_port_is_centralized(op)) { - ds_put_format(match, " && is_chassis_resident(%s)", - op->cr_port->json_key); - } - build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_ADMISSION, 50, 55, - match, actions, &op->nbrp->header_, - REG_INPORT_ETH_ADDR " = %s; next;", - op->lrp_networks.ea_s); + /* Store the ethernet address of the port receiving the packet. + * This will save us from having to match on inport further down in + * the pipeline. + */ + ds_clear(match); + ds_put_format(match, "eth.mcast && inport == %s", op->json_key); + build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_ADMISSION, 50, 55, + match, actions, &op->nbrp->header_, + REG_INPORT_ETH_ADDR " = %s; next;", + op->lrp_networks.ea_s); + + ds_clear(match); + ds_put_cstr(match, "eth.dst == "); + if (op->peer && !eth_addr_is_zero(op->peer->proxy_arp_addrs.ea)) { + ds_put_format(match, + "{ %s, %s }", + op->peer->proxy_arp_addrs.ea_s, + op->lrp_networks.ea_s); + } else { + ds_put_format(match, "%s", op->lrp_networks.ea_s); } + ds_put_format(match, " && inport == %s", op->json_key); + if (consider_l3dgw_port_is_centralized(op)) { + ds_put_format(match, " && is_chassis_resident(%s)", + op->cr_port->json_key); + } + build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_ADMISSION, 50, 55, + match, actions, &op->nbrp->header_, + REG_INPORT_ETH_ADDR " = %s; next;", + op->lrp_networks.ea_s); } @@ -11743,111 +11765,111 @@ build_neigh_learning_flows_for_lrouter( struct ds *match, struct ds *actions, const struct shash *meter_groups) { - if (od->nbr) { - - /* Learn MAC bindings from ARP/IPv6 ND. - * - * For ARP packets, table LOOKUP_NEIGHBOR does a lookup for the - * (arp.spa, arp.sha) in the mac binding table using the 'lookup_arp' - * action and stores the result in REGBIT_LOOKUP_NEIGHBOR_RESULT bit. - * If "always_learn_from_arp_request" is set to false, it will also - * lookup for the (arp.spa) in the mac binding table using the - * "lookup_arp_ip" action for ARP request packets, and stores the - * result in REGBIT_LOOKUP_NEIGHBOR_IP_RESULT bit; or set that bit - * to "1" directly for ARP response packets. - * - * For IPv6 ND NA packets, table LOOKUP_NEIGHBOR does a lookup - * for the (nd.target, nd.tll) in the mac binding table using the - * 'lookup_nd' action and stores the result in - * REGBIT_LOOKUP_NEIGHBOR_RESULT bit. If - * "always_learn_from_arp_request" is set to false, - * REGBIT_LOOKUP_NEIGHBOR_IP_RESULT bit is set. - * - * For IPv6 ND NS packets, table LOOKUP_NEIGHBOR does a lookup - * for the (ip6.src, nd.sll) in the mac binding table using the - * 'lookup_nd' action and stores the result in - * REGBIT_LOOKUP_NEIGHBOR_RESULT bit. If - * "always_learn_from_arp_request" is set to false, it will also lookup - * for the (ip6.src) in the mac binding table using the "lookup_nd_ip" - * action and stores the result in REGBIT_LOOKUP_NEIGHBOR_IP_RESULT - * bit. - * - * Table LEARN_NEIGHBOR learns the mac-binding using the action - * - 'put_arp/put_nd'. Learning mac-binding is skipped if - * REGBIT_LOOKUP_NEIGHBOR_RESULT bit is set or - * REGBIT_LOOKUP_NEIGHBOR_IP_RESULT is not set. - * - * */ - - /* Flows for LOOKUP_NEIGHBOR. */ - bool learn_from_arp_request = smap_get_bool(&od->nbr->options, - "always_learn_from_arp_request", true); - ds_clear(actions); - ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT - " = lookup_arp(inport, arp.spa, arp.sha); %snext;", - learn_from_arp_request ? "" : - REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; "); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, - "arp.op == 2", ds_cstr(actions)); - - ds_clear(actions); - ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT - " = lookup_nd(inport, nd.target, nd.tll); %snext;", - learn_from_arp_request ? "" : - REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; "); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_na", - ds_cstr(actions)); + if (!od->nbr) { + return; + } - ds_clear(actions); - ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT - " = lookup_nd(inport, ip6.src, nd.sll); %snext;", - learn_from_arp_request ? "" : - REGBIT_LOOKUP_NEIGHBOR_IP_RESULT - " = lookup_nd_ip(inport, ip6.src); "); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_ns", - ds_cstr(actions)); + /* Learn MAC bindings from ARP/IPv6 ND. + * + * For ARP packets, table LOOKUP_NEIGHBOR does a lookup for the + * (arp.spa, arp.sha) in the mac binding table using the 'lookup_arp' + * action and stores the result in REGBIT_LOOKUP_NEIGHBOR_RESULT bit. + * If "always_learn_from_arp_request" is set to false, it will also + * lookup for the (arp.spa) in the mac binding table using the + * "lookup_arp_ip" action for ARP request packets, and stores the + * result in REGBIT_LOOKUP_NEIGHBOR_IP_RESULT bit; or set that bit + * to "1" directly for ARP response packets. + * + * For IPv6 ND NA packets, table LOOKUP_NEIGHBOR does a lookup + * for the (nd.target, nd.tll) in the mac binding table using the + * 'lookup_nd' action and stores the result in + * REGBIT_LOOKUP_NEIGHBOR_RESULT bit. If + * "always_learn_from_arp_request" is set to false, + * REGBIT_LOOKUP_NEIGHBOR_IP_RESULT bit is set. + * + * For IPv6 ND NS packets, table LOOKUP_NEIGHBOR does a lookup + * for the (ip6.src, nd.sll) in the mac binding table using the + * 'lookup_nd' action and stores the result in + * REGBIT_LOOKUP_NEIGHBOR_RESULT bit. If + * "always_learn_from_arp_request" is set to false, it will also lookup + * for the (ip6.src) in the mac binding table using the "lookup_nd_ip" + * action and stores the result in REGBIT_LOOKUP_NEIGHBOR_IP_RESULT + * bit. + * + * Table LEARN_NEIGHBOR learns the mac-binding using the action + * - 'put_arp/put_nd'. Learning mac-binding is skipped if + * REGBIT_LOOKUP_NEIGHBOR_RESULT bit is set or + * REGBIT_LOOKUP_NEIGHBOR_IP_RESULT is not set. + * + * */ - /* For other packet types, we can skip neighbor learning. - * So set REGBIT_LOOKUP_NEIGHBOR_RESULT to 1. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 0, "1", - REGBIT_LOOKUP_NEIGHBOR_RESULT" = 1; next;"); + /* Flows for LOOKUP_NEIGHBOR. */ + bool learn_from_arp_request = smap_get_bool(&od->nbr->options, + "always_learn_from_arp_request", true); + ds_clear(actions); + ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT + " = lookup_arp(inport, arp.spa, arp.sha); %snext;", + learn_from_arp_request ? "" : + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; "); + ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, + "arp.op == 2", ds_cstr(actions)); - /* Flows for LEARN_NEIGHBOR. */ - /* Skip Neighbor learning if not required. */ - ds_clear(match); - ds_put_format(match, REGBIT_LOOKUP_NEIGHBOR_RESULT" == 1%s", - learn_from_arp_request ? "" : - " || "REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" == 0"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 100, - ds_cstr(match), "next;"); + ds_clear(actions); + ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT + " = lookup_nd(inport, nd.target, nd.tll); %snext;", + learn_from_arp_request ? "" : + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; "); + ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_na", + ds_cstr(actions)); - ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, - "arp", "put_arp(inport, arp.spa, arp.sha); next;", - copp_meter_get(COPP_ARP, od->nbr->copp, - meter_groups)); + ds_clear(actions); + ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT + " = lookup_nd(inport, ip6.src, nd.sll); %snext;", + learn_from_arp_request ? "" : + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT + " = lookup_nd_ip(inport, ip6.src); "); + ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_ns", + ds_cstr(actions)); + + /* For other packet types, we can skip neighbor learning. + * So set REGBIT_LOOKUP_NEIGHBOR_RESULT to 1. */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 0, "1", + REGBIT_LOOKUP_NEIGHBOR_RESULT" = 1; next;"); + + /* Flows for LEARN_NEIGHBOR. */ + /* Skip Neighbor learning if not required. */ + ds_clear(match); + ds_put_format(match, REGBIT_LOOKUP_NEIGHBOR_RESULT" == 1%s", + learn_from_arp_request ? "" : + " || "REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" == 0"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 100, + ds_cstr(match), "next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95, - "nd_ns && (ip6.src == 0 || nd.sll == 0)", "next;"); + ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, + "arp", "put_arp(inport, arp.spa, arp.sha); next;", + copp_meter_get(COPP_ARP, od->nbr->copp, + meter_groups)); - ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95, - "nd_na && nd.tll == 0", - "put_nd(inport, nd.target, eth.src); next;", - copp_meter_get(COPP_ND_NA, od->nbr->copp, - meter_groups)); + ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95, + "nd_ns && (ip6.src == 0 || nd.sll == 0)", "next;"); - ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, - "nd_na", "put_nd(inport, nd.target, nd.tll); next;", - copp_meter_get(COPP_ND_NA, od->nbr->copp, - meter_groups)); + ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95, + "nd_na && nd.tll == 0", + "put_nd(inport, nd.target, eth.src); next;", + copp_meter_get(COPP_ND_NA, od->nbr->copp, + meter_groups)); - ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, - "nd_ns", "put_nd(inport, ip6.src, nd.sll); next;", - copp_meter_get(COPP_ND_NS, od->nbr->copp, - meter_groups)); + ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, + "nd_na", "put_nd(inport, nd.target, nd.tll); next;", + copp_meter_get(COPP_ND_NA, od->nbr->copp, + meter_groups)); - ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR); - } + ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, + "nd_ns", "put_nd(inport, ip6.src, nd.sll); next;", + copp_meter_get(COPP_ND_NS, od->nbr->copp, + meter_groups)); + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR); } /* Logical router ingress Table 1: Neighbor lookup lflows @@ -11857,59 +11879,60 @@ build_neigh_learning_flows_for_lrouter_port( struct ovn_port *op, struct hmap *lflows, struct ds *match, struct ds *actions) { - if (op->nbrp) { + if (!op->nbrp) { + return; + } - bool learn_from_arp_request = smap_get_bool(&op->od->nbr->options, - "always_learn_from_arp_request", true); + bool learn_from_arp_request = smap_get_bool(&op->od->nbr->options, + "always_learn_from_arp_request", true); - /* Check if we need to learn mac-binding from ARP requests. */ - for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - if (!learn_from_arp_request) { - /* ARP request to this address should always get learned, - * so add a priority-110 flow to set - * REGBIT_LOOKUP_NEIGHBOR_IP_RESULT to 1. */ - ds_clear(match); - ds_put_format(match, - "inport == %s && arp.spa == %s/%u && " - "arp.tpa == %s && 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].addr_s); - if (is_l3dgw_port(op)) { - ds_put_format(match, " && is_chassis_resident(%s)", - op->cr_port->json_key); - } - const char *actions_s = REGBIT_LOOKUP_NEIGHBOR_RESULT - " = lookup_arp(inport, arp.spa, arp.sha); " - REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1;" - " next;"; - ovn_lflow_add_with_hint(lflows, op->od, - S_ROUTER_IN_LOOKUP_NEIGHBOR, 110, - ds_cstr(match), actions_s, - &op->nbrp->header_); - } + /* Check if we need to learn mac-binding from ARP requests. */ + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + if (!learn_from_arp_request) { + /* ARP request to this address should always get learned, + * so add a priority-110 flow to set + * REGBIT_LOOKUP_NEIGHBOR_IP_RESULT to 1. */ 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 && 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].plen, + op->lrp_networks.ipv4_addrs[i].addr_s); if (is_l3dgw_port(op)) { ds_put_format(match, " && is_chassis_resident(%s)", op->cr_port->json_key); } - ds_clear(actions); - ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT - " = lookup_arp(inport, arp.spa, arp.sha); %snext;", - learn_from_arp_request ? "" : - REGBIT_LOOKUP_NEIGHBOR_IP_RESULT - " = lookup_arp_ip(inport, arp.spa); "); + const char *actions_s = REGBIT_LOOKUP_NEIGHBOR_RESULT + " = lookup_arp(inport, arp.spa, arp.sha); " + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1;" + " next;"; ovn_lflow_add_with_hint(lflows, op->od, - S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, - ds_cstr(match), ds_cstr(actions), + S_ROUTER_IN_LOOKUP_NEIGHBOR, 110, + ds_cstr(match), actions_s, &op->nbrp->header_); } + ds_clear(match); + ds_put_format(match, + "inport == %s && arp.spa == %s/%u && arp.op == 1", + op->json_key, + op->lrp_networks.ipv4_addrs[i].network_s, + op->lrp_networks.ipv4_addrs[i].plen); + if (is_l3dgw_port(op)) { + ds_put_format(match, " && is_chassis_resident(%s)", + op->cr_port->json_key); + } + ds_clear(actions); + ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT + " = lookup_arp(inport, arp.spa, arp.sha); %snext;", + learn_from_arp_request ? "" : + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT + " = lookup_arp_ip(inport, arp.spa); "); + ovn_lflow_add_with_hint(lflows, op->od, + S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, + ds_cstr(match), ds_cstr(actions), + &op->nbrp->header_); } } @@ -12121,61 +12144,62 @@ build_static_route_flows_for_lrouter( struct hmap *lflows, const struct hmap *ports, const struct hmap *bfd_connections) { - if (od->nbr) { - ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP); - ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING); - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 150, - REG_ECMP_GROUP_ID" == 0", "next;"); - - struct hmap ecmp_groups = HMAP_INITIALIZER(&ecmp_groups); - struct hmap unique_routes = HMAP_INITIALIZER(&unique_routes); - struct ovs_list parsed_routes = OVS_LIST_INITIALIZER(&parsed_routes); - struct simap route_tables = SIMAP_INITIALIZER(&route_tables); - struct ecmp_groups_node *group; - - for (int i = 0; i < od->nbr->n_ports; i++) { - build_route_table_lflow(od, lflows, od->nbr->ports[i], - &route_tables); - } - - for (int i = 0; i < od->nbr->n_static_routes; i++) { - struct parsed_route *route = - parsed_routes_add(od, ports, &parsed_routes, &route_tables, - od->nbr->static_routes[i], bfd_connections); - if (!route) { - continue; - } - group = ecmp_groups_find(&ecmp_groups, route); - if (group) { - ecmp_groups_add_route(group, route); - } else { - const struct parsed_route *existed_route = - unique_routes_remove(&unique_routes, route); - if (existed_route) { - group = ecmp_groups_add(&ecmp_groups, existed_route); - if (group) { - ecmp_groups_add_route(group, route); - } - } else { - unique_routes_add(&unique_routes, route); + if (!od->nbr) { + return; + } + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP); + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 150, + REG_ECMP_GROUP_ID" == 0", "next;"); + + struct hmap ecmp_groups = HMAP_INITIALIZER(&ecmp_groups); + struct hmap unique_routes = HMAP_INITIALIZER(&unique_routes); + struct ovs_list parsed_routes = OVS_LIST_INITIALIZER(&parsed_routes); + struct simap route_tables = SIMAP_INITIALIZER(&route_tables); + struct ecmp_groups_node *group; + + for (int i = 0; i < od->nbr->n_ports; i++) { + build_route_table_lflow(od, lflows, od->nbr->ports[i], + &route_tables); + } + + for (int i = 0; i < od->nbr->n_static_routes; i++) { + struct parsed_route *route = + parsed_routes_add(od, ports, &parsed_routes, &route_tables, + od->nbr->static_routes[i], bfd_connections); + if (!route) { + continue; + } + group = ecmp_groups_find(&ecmp_groups, route); + if (group) { + ecmp_groups_add_route(group, route); + } else { + const struct parsed_route *existed_route = + unique_routes_remove(&unique_routes, route); + if (existed_route) { + group = ecmp_groups_add(&ecmp_groups, existed_route); + if (group) { + ecmp_groups_add_route(group, route); } + } else { + unique_routes_add(&unique_routes, route); } } - HMAP_FOR_EACH (group, hmap_node, &ecmp_groups) { - /* add a flow in IP_ROUTING, and one flow for each member in - * IP_ROUTING_ECMP. */ - build_ecmp_route_flow(lflows, od, features->ct_no_masked_label, - ports, group); - } - const struct unique_routes_node *ur; - HMAP_FOR_EACH (ur, hmap_node, &unique_routes) { - build_static_route_flow(lflows, od, ports, ur->route); - } - ecmp_groups_destroy(&ecmp_groups); - unique_routes_destroy(&unique_routes); - parsed_routes_destroy(&parsed_routes); - simap_destroy(&route_tables); } + HMAP_FOR_EACH (group, hmap_node, &ecmp_groups) { + /* add a flow in IP_ROUTING, and one flow for each member in + * IP_ROUTING_ECMP. */ + build_ecmp_route_flow(lflows, od, features->ct_no_masked_label, + ports, group); + } + const struct unique_routes_node *ur; + HMAP_FOR_EACH (ur, hmap_node, &unique_routes) { + build_static_route_flow(lflows, od, ports, ur->route); + } + ecmp_groups_destroy(&ecmp_groups); + unique_routes_destroy(&unique_routes); + parsed_routes_destroy(&parsed_routes); + simap_destroy(&route_tables); } /* IP Multicast lookup. Here we set the output port, adjust TTL and @@ -12186,91 +12210,92 @@ build_mcast_lookup_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows, struct ds *match, struct ds *actions) { - if (od->nbr) { + if (!od->nbr) { + return; + } - /* Drop IPv6 multicast traffic that shouldn't be forwarded, - * i.e., router solicitation and router advertisement. - */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550, - "nd_rs || nd_ra", debug_drop_action()); - if (!od->mcast_info.rtr.relay) { - return; - } + /* Drop IPv6 multicast traffic that shouldn't be forwarded, + * i.e., router solicitation and router advertisement. + */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550, + "nd_rs || nd_ra", debug_drop_action()); + if (!od->mcast_info.rtr.relay) { + return; + } - struct ovn_igmp_group *igmp_group; + struct ovn_igmp_group *igmp_group; - LIST_FOR_EACH (igmp_group, list_node, &od->mcast_info.groups) { - ds_clear(match); - ds_clear(actions); - if (IN6_IS_ADDR_V4MAPPED(&igmp_group->address)) { - ds_put_format(match, "ip4 && ip4.dst == %s ", - igmp_group->mcgroup.name); - } else { - ds_put_format(match, "ip6 && ip6.dst == %s ", - igmp_group->mcgroup.name); - } - if (od->mcast_info.rtr.flood_static) { - ds_put_cstr(actions, - "clone { " - "outport = \""MC_STATIC"\"; " - "ip.ttl--; " - "next; " - "};"); - } - ds_put_format(actions, "outport = \"%s\"; ip.ttl--; next;", - igmp_group->mcgroup.name); - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10500, - ds_cstr(match), ds_cstr(actions)); + LIST_FOR_EACH (igmp_group, list_node, &od->mcast_info.groups) { + ds_clear(match); + ds_clear(actions); + if (IN6_IS_ADDR_V4MAPPED(&igmp_group->address)) { + ds_put_format(match, "ip4 && ip4.dst == %s ", + igmp_group->mcgroup.name); + } else { + ds_put_format(match, "ip6 && ip6.dst == %s ", + igmp_group->mcgroup.name); } - - /* If needed, flood unregistered multicast on statically configured - * ports. Otherwise drop any multicast traffic. - */ if (od->mcast_info.rtr.flood_static) { - /* MLD and IGMP packets that need to be flooded statically - * should be flooded without decrementing TTL (it's always - * 1). To prevent packets looping for ever (to some extent), - * drop IGMP/MLD packets that are received from the router's - * own mac addresses. - */ - struct ovn_port *op; - LIST_FOR_EACH (op, dp_node, &od->port_list) { - ds_clear(match); - ds_put_format(match, "eth.src == %s && igmp", - op->lrp_networks.ea_s); - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550, - ds_cstr(match), debug_drop_action()); + ds_put_cstr(actions, + "clone { " + "outport = \""MC_STATIC"\"; " + "ip.ttl--; " + "next; " + "};"); + } + ds_put_format(actions, "outport = \"%s\"; ip.ttl--; next;", + igmp_group->mcgroup.name); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10500, + ds_cstr(match), ds_cstr(actions)); + } - ds_clear(match); - ds_put_format(match, "eth.src == %s && (mldv1 || mldv2)", - op->lrp_networks.ea_s); - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550, - ds_cstr(match), debug_drop_action()); - } + /* If needed, flood unregistered multicast on statically configured + * ports. Otherwise drop any multicast traffic. + */ + if (od->mcast_info.rtr.flood_static) { + /* MLD and IGMP packets that need to be flooded statically + * should be flooded without decrementing TTL (it's always + * 1). To prevent packets looping for ever (to some extent), + * drop IGMP/MLD packets that are received from the router's + * own mac addresses. + */ + struct ovn_port *op; + LIST_FOR_EACH (op, dp_node, &od->port_list) { + ds_clear(match); + ds_put_format(match, "eth.src == %s && igmp", + op->lrp_networks.ea_s); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550, + ds_cstr(match), debug_drop_action()); - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10460, - "igmp", - "clone { " - "outport = \""MC_STATIC"\"; " - "next; " - "};"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10460, - "mldv1 || mldv2", - "clone { " - "outport = \""MC_STATIC"\"; " - "next; " - "};"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10450, - "ip4.mcast || ip6.mcast", - "clone { " - "outport = \""MC_STATIC"\"; " - "ip.ttl--; " - "next; " - "};"); - } else { - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10450, - "ip4.mcast || ip6.mcast", debug_drop_action()); - } + ds_clear(match); + ds_put_format(match, "eth.src == %s && (mldv1 || mldv2)", + op->lrp_networks.ea_s); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550, + ds_cstr(match), debug_drop_action()); + } + + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10460, + "igmp", + "clone { " + "outport = \""MC_STATIC"\"; " + "next; " + "};"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10460, + "mldv1 || mldv2", + "clone { " + "outport = \""MC_STATIC"\"; " + "next; " + "};"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10450, + "ip4.mcast || ip6.mcast", + "clone { " + "outport = \""MC_STATIC"\"; " + "ip.ttl--; " + "next; " + "};"); + } else { + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10450, + "ip4.mcast || ip6.mcast", debug_drop_action()); } } @@ -12288,31 +12313,32 @@ build_ingress_policy_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows, const struct hmap *ports) { - if (od->nbr) { - /* This is a catch-all rule. It has the lowest priority (0) - * does a match-all("1") and pass-through (next) */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY, 0, "1", - REG_ECMP_GROUP_ID" = 0; next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY_ECMP, 150, - REG_ECMP_GROUP_ID" == 0", "next;"); - ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_POLICY_ECMP); - - /* Convert routing policies to flows. */ - uint16_t ecmp_group_id = 1; - for (int i = 0; i < od->nbr->n_policies; i++) { - const struct nbrec_logical_router_policy *rule - = od->nbr->policies[i]; - bool is_ecmp_reroute = - (!strcmp(rule->action, "reroute") && rule->n_nexthops > 1); - - if (is_ecmp_reroute) { - build_ecmp_routing_policy_flows(lflows, od, ports, rule, - ecmp_group_id); - ecmp_group_id++; - } else { - build_routing_policy_flow(lflows, od, ports, rule, - &rule->header_); - } + if (!od->nbr) { + return; + } + /* This is a catch-all rule. It has the lowest priority (0) + * does a match-all("1") and pass-through (next) */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY, 0, "1", + REG_ECMP_GROUP_ID" = 0; next;"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY_ECMP, 150, + REG_ECMP_GROUP_ID" == 0", "next;"); + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_POLICY_ECMP); + + /* Convert routing policies to flows. */ + uint16_t ecmp_group_id = 1; + for (int i = 0; i < od->nbr->n_policies; i++) { + const struct nbrec_logical_router_policy *rule + = od->nbr->policies[i]; + bool is_ecmp_reroute = + (!strcmp(rule->action, "reroute") && rule->n_nexthops > 1); + + if (is_ecmp_reroute) { + build_ecmp_routing_policy_flows(lflows, od, ports, rule, + ecmp_group_id); + ecmp_group_id++; + } else { + build_routing_policy_flow(lflows, od, ports, rule, + &rule->header_); } } } @@ -12322,20 +12348,21 @@ static void build_arp_resolve_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows) { - if (od->nbr) { - /* Multicast packets already have the outport set so just advance to - * next table (priority 500). */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 500, - "ip4.mcast || ip6.mcast", "next;"); + if (!od->nbr) { + return; + } + /* Multicast packets already have the outport set so just advance to + * next table (priority 500). */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 500, + "ip4.mcast || ip6.mcast", "next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip4", - "get_arp(outport, " REG_NEXT_HOP_IPV4 "); next;"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip4", + "get_arp(outport, " REG_NEXT_HOP_IPV4 "); next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip6", - "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip6", + "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;"); - ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ARP_RESOLVE); - } + ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ARP_RESOLVE); } static void @@ -12862,70 +12889,71 @@ build_arp_request_flows_for_lrouter( struct ds *match, struct ds *actions, const struct shash *meter_groups) { - if (od->nbr) { - for (int i = 0; i < od->nbr->n_static_routes; i++) { - const struct nbrec_logical_router_static_route *route; - - route = od->nbr->static_routes[i]; - struct in6_addr gw_ip6; - unsigned int plen; - char *error = ipv6_parse_cidr(route->nexthop, &gw_ip6, &plen); - if (error || plen != 128) { - free(error); - continue; - } + if (!od->nbr) { + return; + } + for (int i = 0; i < od->nbr->n_static_routes; i++) { + const struct nbrec_logical_router_static_route *route; - ds_clear(match); - ds_put_format(match, "eth.dst == 00:00:00:00:00:00 && " - "ip6 && " REG_NEXT_HOP_IPV6 " == %s", - route->nexthop); - struct in6_addr sn_addr; - struct eth_addr eth_dst; - in6_addr_solicited_node(&sn_addr, &gw_ip6); - ipv6_multicast_to_ethernet(ð_dst, &sn_addr); + route = od->nbr->static_routes[i]; + struct in6_addr gw_ip6; + unsigned int plen; + char *error = ipv6_parse_cidr(route->nexthop, &gw_ip6, &plen); + if (error || plen != 128) { + free(error); + continue; + } - char sn_addr_s[INET6_ADDRSTRLEN + 1]; - ipv6_string_mapped(sn_addr_s, &sn_addr); + ds_clear(match); + ds_put_format(match, "eth.dst == 00:00:00:00:00:00 && " + "ip6 && " REG_NEXT_HOP_IPV6 " == %s", + route->nexthop); + struct in6_addr sn_addr; + struct eth_addr eth_dst; + in6_addr_solicited_node(&sn_addr, &gw_ip6); + ipv6_multicast_to_ethernet(ð_dst, &sn_addr); - ds_clear(actions); - ds_put_format(actions, - "nd_ns { " - "eth.dst = "ETH_ADDR_FMT"; " - "ip6.dst = %s; " - "nd.target = %s; " - "output; " - "};", ETH_ADDR_ARGS(eth_dst), sn_addr_s, - route->nexthop); - - ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200, - ds_cstr(match), ds_cstr(actions), NULL, - copp_meter_get(COPP_ND_NS_RESOLVE, - od->nbr->copp, - meter_groups), - &route->header_); - } - - ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, - "eth.dst == 00:00:00:00:00:00 && ip4", - "arp { " - "eth.dst = ff:ff:ff:ff:ff:ff; " - "arp.spa = " REG_SRC_IPV4 "; " - "arp.tpa = " REG_NEXT_HOP_IPV4 "; " - "arp.op = 1; " /* ARP request */ - "output; " - "};", - copp_meter_get(COPP_ARP_RESOLVE, od->nbr->copp, - meter_groups)); - ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, - "eth.dst == 00:00:00:00:00:00 && ip6", - "nd_ns { " - "nd.target = " REG_NEXT_HOP_IPV6 "; " - "output; " - "};", - copp_meter_get(COPP_ND_NS_RESOLVE, od->nbr->copp, - meter_groups)); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "output;"); + char sn_addr_s[INET6_ADDRSTRLEN + 1]; + ipv6_string_mapped(sn_addr_s, &sn_addr); + + ds_clear(actions); + ds_put_format(actions, + "nd_ns { " + "eth.dst = "ETH_ADDR_FMT"; " + "ip6.dst = %s; " + "nd.target = %s; " + "output; " + "};", ETH_ADDR_ARGS(eth_dst), sn_addr_s, + route->nexthop); + + ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200, + ds_cstr(match), ds_cstr(actions), NULL, + copp_meter_get(COPP_ND_NS_RESOLVE, + od->nbr->copp, + meter_groups), + &route->header_); } + + ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, + "eth.dst == 00:00:00:00:00:00 && ip4", + "arp { " + "eth.dst = ff:ff:ff:ff:ff:ff; " + "arp.spa = " REG_SRC_IPV4 "; " + "arp.tpa = " REG_NEXT_HOP_IPV4 "; " + "arp.op = 1; " /* ARP request */ + "output; " + "};", + copp_meter_get(COPP_ARP_RESOLVE, od->nbr->copp, + meter_groups)); + ovn_lflow_metered(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, + "eth.dst == 00:00:00:00:00:00 && ip6", + "nd_ns { " + "nd.target = " REG_NEXT_HOP_IPV6 "; " + "output; " + "};", + copp_meter_get(COPP_ND_NS_RESOLVE, od->nbr->copp, + meter_groups)); + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "output;"); } /* Logical router egress table DELIVERY: Delivery (priority 100-110). @@ -12940,109 +12968,110 @@ build_egress_delivery_flows_for_lrouter_port( struct ovn_port *op, struct hmap *lflows, struct ds *match, struct ds *actions) { - if (op->nbrp) { - if (!lrport_is_enabled(op->nbrp)) { - /* Drop packets to disabled logical ports (since logical flow - * tables are default-drop). */ - return; - } - - if (is_cr_port(op)) { - /* No egress packets should be processed in the context of - * a chassisredirect port. The chassisredirect port should - * be replaced by the l3dgw port in the local output - * pipeline stage before egress processing. */ - return; - } + if (!op->nbrp) { + return; + } + if (!lrport_is_enabled(op->nbrp)) { + /* Drop packets to disabled logical ports (since logical flow + * tables are default-drop). */ + return; + } - /* If multicast relay is enabled then also adjust source mac for IP - * multicast traffic. - */ - if (op->od->mcast_info.rtr.relay) { - ds_clear(match); - ds_clear(actions); - ds_put_format(match, "(ip4.mcast || ip6.mcast) && outport == %s", - op->json_key); - ds_put_format(actions, "eth.src = %s; output;", - op->lrp_networks.ea_s); - ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 110, - ds_cstr(match), ds_cstr(actions)); - } + if (is_cr_port(op)) { + /* No egress packets should be processed in the context of + * a chassisredirect port. The chassisredirect port should + * be replaced by the l3dgw port in the local output + * pipeline stage before egress processing. */ + return; + } + /* If multicast relay is enabled then also adjust source mac for IP + * multicast traffic. + */ + if (op->od->mcast_info.rtr.relay) { ds_clear(match); - ds_put_format(match, "outport == %s", op->json_key); - ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 100, - ds_cstr(match), "output;"); - - ovn_lflow_add_default_drop(lflows, op->od, S_ROUTER_OUT_DELIVERY); + ds_clear(actions); + ds_put_format(match, "(ip4.mcast || ip6.mcast) && outport == %s", + op->json_key); + ds_put_format(actions, "eth.src = %s; output;", + op->lrp_networks.ea_s); + ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 110, + ds_cstr(match), ds_cstr(actions)); } + ds_clear(match); + ds_put_format(match, "outport == %s", op->json_key); + ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 100, + ds_cstr(match), "output;"); + + ovn_lflow_add_default_drop(lflows, op->od, S_ROUTER_OUT_DELIVERY); } static void build_misc_local_traffic_drop_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows) { - if (od->nbr) { - /* Allow IGMP and MLD packets (with TTL = 1) if the router is - * configured to flood them statically on some ports. - */ - if (od->mcast_info.rtr.flood_static) { - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 120, - "igmp && ip.ttl == 1", "next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 120, - "(mldv1 || mldv2) && ip.ttl == 1", "next;"); - } - - /* L3 admission control: drop multicast and broadcast source, localhost - * source or destination, and zero network source or destination - * (priority 100). */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 100, - "ip4.src_mcast ||" - "ip4.src == 255.255.255.255 || " - "ip4.src == 127.0.0.0/8 || " - "ip4.dst == 127.0.0.0/8 || " - "ip4.src == 0.0.0.0/8 || " - "ip4.dst == 0.0.0.0/8", - debug_drop_action()); - - /* Drop ARP packets (priority 85). ARP request packets for router's own - * IPs are handled with priority-90 flows. - * Drop IPv6 ND packets (priority 85). ND NA packets for router's own - * IPs are handled with priority-90 flows. - */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 85, - "arp || nd", debug_drop_action()); + if (!od->nbr) { + return; + } + /* Allow IGMP and MLD packets (with TTL = 1) if the router is + * configured to flood them statically on some ports. + */ + if (od->mcast_info.rtr.flood_static) { + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 120, + "igmp && ip.ttl == 1", "next;"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 120, + "(mldv1 || mldv2) && ip.ttl == 1", "next;"); + } + + /* L3 admission control: drop multicast and broadcast source, localhost + * source or destination, and zero network source or destination + * (priority 100). */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 100, + "ip4.src_mcast ||" + "ip4.src == 255.255.255.255 || " + "ip4.src == 127.0.0.0/8 || " + "ip4.dst == 127.0.0.0/8 || " + "ip4.src == 0.0.0.0/8 || " + "ip4.dst == 0.0.0.0/8", + debug_drop_action()); + + /* Drop ARP packets (priority 85). ARP request packets for router's own + * IPs are handled with priority-90 flows. + * Drop IPv6 ND packets (priority 85). ND NA packets for router's own + * IPs are handled with priority-90 flows. + */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 85, + "arp || nd", debug_drop_action()); - /* Allow IPv6 multicast traffic that's supposed to reach the - * router pipeline (e.g., router solicitations). - */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 84, "nd_rs || nd_ra", - "next;"); + /* Allow IPv6 multicast traffic that's supposed to reach the + * router pipeline (e.g., router solicitations). + */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 84, "nd_rs || nd_ra", + "next;"); - /* Drop other reserved multicast. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 83, - "ip6.mcast_rsvd", debug_drop_action()); + /* Drop other reserved multicast. */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 83, + "ip6.mcast_rsvd", debug_drop_action()); - /* Allow other multicast if relay enabled (priority 82). */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 82, - "ip4.mcast || ip6.mcast", - (od->mcast_info.rtr.relay ? "next;" : - debug_drop_action())); + /* Allow other multicast if relay enabled (priority 82). */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 82, + "ip4.mcast || ip6.mcast", + (od->mcast_info.rtr.relay ? "next;" : + debug_drop_action())); - /* Drop Ethernet local broadcast. By definition this traffic should - * not be forwarded.*/ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50, - "eth.bcast", debug_drop_action()); + /* Drop Ethernet local broadcast. By definition this traffic should + * not be forwarded.*/ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50, + "eth.bcast", debug_drop_action()); - /* TTL discard */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30, - "ip4 && ip.ttl == {0, 1}", debug_drop_action()); + /* TTL discard */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30, + "ip4 && ip.ttl == {0, 1}", debug_drop_action()); - /* Pass other traffic not already handled to the next table for - * routing. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 0, "1", "next;"); - } + /* Pass other traffic not already handled to the next table for + * routing. */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 0, "1", "next;"); } static void @@ -13050,18 +13079,18 @@ build_dhcpv6_reply_flows_for_lrouter_port( struct ovn_port *op, struct hmap *lflows, struct ds *match) { - if (op->nbrp && (!op->l3dgw_port)) { - for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { - ds_clear(match); - ds_put_format(match, "ip6.dst == %s && udp.src == 547 &&" - " udp.dst == 546", - op->lrp_networks.ipv6_addrs[i].addr_s); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, - ds_cstr(match), - "reg0 = 0; handle_dhcpv6_reply;"); - } + if (!op->nbrp || op->l3dgw_port) { + return; + } + for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + ds_clear(match); + ds_put_format(match, "ip6.dst == %s && udp.src == 547 &&" + " udp.dst == 546", + op->lrp_networks.ipv6_addrs[i].addr_s); + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, + ds_cstr(match), + "reg0 = 0; handle_dhcpv6_reply;"); } - } static void @@ -13070,165 +13099,165 @@ build_ipv6_input_flows_for_lrouter_port( struct ds *match, struct ds *actions, const struct shash *meter_groups) { - if (op->nbrp && !is_cr_port(op)) { - /* No ingress packets are accepted on a chassisredirect - * port, so no need to program flows for that port. */ - if (op->lrp_networks.n_ipv6_addrs) { - /* ICMPv6 echo reply. These flows reply to echo requests - * received for the router's IP address. */ - ds_clear(match); - ds_put_cstr(match, "ip6.dst == "); - op_put_v6_networks(match, op); - ds_put_cstr(match, " && icmp6.type == 128 && icmp6.code == 0"); - - const char *lrp_actions = - "ip6.dst <-> ip6.src; " - "ip.ttl = 255; " - "icmp6.type = 129; " - "flags.loopback = 1; " - "next; "; - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, - ds_cstr(match), lrp_actions, - &op->nbrp->header_); - } - - /* ND reply. These flows reply to ND solicitations for the - * router's own IP address. */ - for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { - ds_clear(match); - if (is_l3dgw_port(op)) { - /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s - * should only be sent from the gateway chassi, so that - * upstream MAC learning points to the gateway chassis. - * Also need to avoid generation of multiple ND replies - * from different chassis. */ - ds_put_format(match, "is_chassis_resident(%s)", - op->cr_port->json_key); - } + if (!op->nbrp || is_cr_port(op)) { + return; + } + /* No ingress packets are accepted on a chassisredirect + * port, so no need to program flows for that port. */ + if (op->lrp_networks.n_ipv6_addrs) { + /* ICMPv6 echo reply. These flows reply to echo requests + * received for the router's IP address. */ + ds_clear(match); + ds_put_cstr(match, "ip6.dst == "); + op_put_v6_networks(match, op); + ds_put_cstr(match, " && icmp6.type == 128 && icmp6.code == 0"); + + const char *lrp_actions = + "ip6.dst <-> ip6.src; " + "ip.ttl = 255; " + "icmp6.type = 129; " + "flags.loopback = 1; " + "next; "; + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(match), lrp_actions, + &op->nbrp->header_); + } - build_lrouter_nd_flow(op->od, op, "nd_na_router", - op->lrp_networks.ipv6_addrs[i].addr_s, - op->lrp_networks.ipv6_addrs[i].sn_addr_s, - REG_INPORT_ETH_ADDR, match, false, 90, - &op->nbrp->header_, lflows, meter_groups); + /* ND reply. These flows reply to ND solicitations for the + * router's own IP address. */ + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + ds_clear(match); + if (is_l3dgw_port(op)) { + /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s + * should only be sent from the gateway chassi, so that + * upstream MAC learning points to the gateway chassis. + * Also need to avoid generation of multiple ND replies + * from different chassis. */ + ds_put_format(match, "is_chassis_resident(%s)", + op->cr_port->json_key); } - /* UDP/TCP/SCTP port unreachable */ - if (!op->od->is_gw_router && !op->od->n_l3dgw_ports) { - for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { - ds_clear(match); - ds_put_format(match, - "ip6 && ip6.dst == %s && !ip.later_frag && tcp", - op->lrp_networks.ipv6_addrs[i].addr_s); - const char *action = "tcp_reset {" - "eth.dst <-> eth.src; " - "ip6.dst <-> ip6.src; " - "next; };"; - ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 80, ds_cstr(match), action, NULL, - copp_meter_get( - COPP_TCP_RESET, - op->od->nbr->copp, - meter_groups), - &op->nbrp->header_); - - ds_clear(match); - ds_put_format(match, - "ip6 && ip6.dst == %s && !ip.later_frag && sctp", - op->lrp_networks.ipv6_addrs[i].addr_s); - action = "sctp_abort {" - "eth.dst <-> eth.src; " - "ip6.dst <-> ip6.src; " - "next; };"; - ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 80, ds_cstr(match), action, NULL, - copp_meter_get( - COPP_TCP_RESET, - op->od->nbr->copp, - meter_groups), - &op->nbrp->header_); + build_lrouter_nd_flow(op->od, op, "nd_na_router", + op->lrp_networks.ipv6_addrs[i].addr_s, + op->lrp_networks.ipv6_addrs[i].sn_addr_s, + REG_INPORT_ETH_ADDR, match, false, 90, + &op->nbrp->header_, lflows, meter_groups); + } - ds_clear(match); - ds_put_format(match, - "ip6 && ip6.dst == %s && !ip.later_frag && udp", - op->lrp_networks.ipv6_addrs[i].addr_s); - action = "icmp6 {" - "eth.dst <-> eth.src; " - "ip6.dst <-> ip6.src; " - "ip.ttl = 255; " - "icmp6.type = 1; " - "icmp6.code = 4; " - "next; };"; - ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 80, ds_cstr(match), action, NULL, - copp_meter_get( - COPP_ICMP6_ERR, - op->od->nbr->copp, - meter_groups), - &op->nbrp->header_); + /* UDP/TCP/SCTP port unreachable */ + if (!op->od->is_gw_router && !op->od->n_l3dgw_ports) { + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + ds_clear(match); + ds_put_format(match, + "ip6 && ip6.dst == %s && !ip.later_frag && tcp", + op->lrp_networks.ipv6_addrs[i].addr_s); + const char *action = "tcp_reset {" + "eth.dst <-> eth.src; " + "ip6.dst <-> ip6.src; " + "next; };"; + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(match), action, NULL, + copp_meter_get( + COPP_TCP_RESET, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); - ds_clear(match); - ds_put_format(match, - "ip6 && ip6.dst == %s && !ip.later_frag", - op->lrp_networks.ipv6_addrs[i].addr_s); - action = "icmp6 {" - "eth.dst <-> eth.src; " - "ip6.dst <-> ip6.src; " - "ip.ttl = 255; " - "icmp6.type = 1; " - "icmp6.code = 3; " - "next; };"; - ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 70, ds_cstr(match), action, NULL, - copp_meter_get( - COPP_ICMP6_ERR, - op->od->nbr->copp, - meter_groups), - &op->nbrp->header_); - } - } + ds_clear(match); + ds_put_format(match, + "ip6 && ip6.dst == %s && !ip.later_frag && sctp", + op->lrp_networks.ipv6_addrs[i].addr_s); + action = "sctp_abort {" + "eth.dst <-> eth.src; " + "ip6.dst <-> ip6.src; " + "next; };"; + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(match), action, NULL, + copp_meter_get( + COPP_TCP_RESET, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); - /* ICMPv6 time exceeded */ - struct ds ip_ds = DS_EMPTY_INITIALIZER; - for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { - /* skip link-local address */ - if (in6_is_lla(&op->lrp_networks.ipv6_addrs[i].network)) { - continue; - } + ds_clear(match); + ds_put_format(match, + "ip6 && ip6.dst == %s && !ip.later_frag && udp", + op->lrp_networks.ipv6_addrs[i].addr_s); + action = "icmp6 {" + "eth.dst <-> eth.src; " + "ip6.dst <-> ip6.src; " + "ip.ttl = 255; " + "icmp6.type = 1; " + "icmp6.code = 4; " + "next; };"; + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(match), action, NULL, + copp_meter_get( + COPP_ICMP6_ERR, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); ds_clear(match); - ds_clear(actions); - ds_clear(&ip_ds); - if (is_l3dgw_port(op)) { - ds_put_cstr(&ip_ds, "ip6.dst <-> ip6.src"); - } else { - ds_put_format(&ip_ds, "ip6.dst = ip6.src; ip6.src = %s", - op->lrp_networks.ipv6_addrs[i].addr_s); - } ds_put_format(match, - "inport == %s && ip6 && " - "ip6.src == %s/%d && " - "ip.ttl == {0, 1} && !ip.later_frag", - op->json_key, - op->lrp_networks.ipv6_addrs[i].network_s, - op->lrp_networks.ipv6_addrs[i].plen); - ds_put_format(actions, - "icmp6 {" - "eth.dst <-> eth.src; " - "%s ; ip.ttl = 254; " - "icmp6.type = 3; /* Time exceeded */ " - "icmp6.code = 0; /* TTL exceeded in transit */ " - "outport = %s; flags.loopback = 1; output; };", - ds_cstr(&ip_ds), op->json_key); + "ip6 && ip6.dst == %s && !ip.later_frag", + op->lrp_networks.ipv6_addrs[i].addr_s); + action = "icmp6 {" + "eth.dst <-> eth.src; " + "ip6.dst <-> ip6.src; " + "ip.ttl = 255; " + "icmp6.type = 1; " + "icmp6.code = 3; " + "next; };"; ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 100, ds_cstr(match), ds_cstr(actions), NULL, - copp_meter_get(COPP_ICMP6_ERR, op->od->nbr->copp, - meter_groups), - &op->nbrp->header_); + 70, ds_cstr(match), action, NULL, + copp_meter_get( + COPP_ICMP6_ERR, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); } - ds_destroy(&ip_ds); } + /* ICMPv6 time exceeded */ + struct ds ip_ds = DS_EMPTY_INITIALIZER; + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + /* skip link-local address */ + if (in6_is_lla(&op->lrp_networks.ipv6_addrs[i].network)) { + continue; + } + + ds_clear(match); + ds_clear(actions); + ds_clear(&ip_ds); + if (is_l3dgw_port(op)) { + ds_put_cstr(&ip_ds, "ip6.dst <-> ip6.src"); + } else { + ds_put_format(&ip_ds, "ip6.dst = ip6.src; ip6.src = %s", + op->lrp_networks.ipv6_addrs[i].addr_s); + } + ds_put_format(match, + "inport == %s && ip6 && " + "ip6.src == %s/%d && " + "ip.ttl == {0, 1} && !ip.later_frag", + op->json_key, + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen); + ds_put_format(actions, + "icmp6 {" + "eth.dst <-> eth.src; " + "%s ; ip.ttl = 254; " + "icmp6.type = 3; /* Time exceeded */ " + "icmp6.code = 0; /* TTL exceeded in transit */ " + "outport = %s; flags.loopback = 1; output; };", + ds_cstr(&ip_ds), op->json_key); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 100, ds_cstr(match), ds_cstr(actions), NULL, + copp_meter_get(COPP_ICMP6_ERR, op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); + } + ds_destroy(&ip_ds); } static void @@ -13236,47 +13265,47 @@ build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od, struct hmap *lflows, const struct shash *meter_groups) { - if (od->nbr) { - - /* Priority-90-92 flows handle ARP requests and ND packets. Most are - * per logical port but DNAT addresses can be handled per datapath - * for non gateway router ports. - * - * Priority 91 and 92 flows are added for each gateway router - * port to handle the special cases. In case we get the packet - * on a regular port, just reply with the port's ETH address. - */ - for (int i = 0; i < od->nbr->n_nat; i++) { - struct ovn_nat *nat_entry = &od->nat_entries[i]; - - /* Skip entries we failed to parse. */ - if (!nat_entry_is_valid(nat_entry)) { - continue; - } + if (!od->nbr) { + return; + } + /* Priority-90-92 flows handle ARP requests and ND packets. Most are + * per logical port but DNAT addresses can be handled per datapath + * for non gateway router ports. + * + * Priority 91 and 92 flows are added for each gateway router + * port to handle the special cases. In case we get the packet + * on a regular port, just reply with the port's ETH address. + */ + for (int i = 0; i < od->nbr->n_nat; i++) { + struct ovn_nat *nat_entry = &od->nat_entries[i]; - /* Skip SNAT entries for now, we handle unique SNAT IPs separately - * below. - */ - if (!strcmp(nat_entry->nb->type, "snat")) { - continue; - } - build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups); + /* Skip entries we failed to parse. */ + if (!nat_entry_is_valid(nat_entry)) { + continue; } - /* Now handle SNAT entries too, one per unique SNAT IP. */ - struct shash_node *snat_snode; - SHASH_FOR_EACH (snat_snode, &od->snat_ips) { - struct ovn_snat_ip *snat_ip = snat_snode->data; + /* Skip SNAT entries for now, we handle unique SNAT IPs separately + * below. + */ + if (!strcmp(nat_entry->nb->type, "snat")) { + continue; + } + build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups); + } - if (ovs_list_is_empty(&snat_ip->snat_entries)) { - continue; - } + /* Now handle SNAT entries too, one per unique SNAT IP. */ + struct shash_node *snat_snode; + SHASH_FOR_EACH (snat_snode, &od->snat_ips) { + struct ovn_snat_ip *snat_ip = snat_snode->data; - struct ovn_nat *nat_entry = - CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries), - struct ovn_nat, ext_addr_list_node); - build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups); + if (ovs_list_is_empty(&snat_ip->snat_entries)) { + continue; } + + struct ovn_nat *nat_entry = + CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries), + struct ovn_nat, ext_addr_list_node); + build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups); } } @@ -13289,289 +13318,290 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, { /* No ingress packets are accepted on a chassisredirect * port, so no need to program flows for that port. */ - if (op->nbrp && !is_cr_port(op)) { - if (op->lrp_networks.n_ipv4_addrs) { - /* L3 admission control: drop packets that originate from an - * IPv4 address owned by the router or a broadcast address - * known to the router (priority 100). */ - ds_clear(match); - ds_put_cstr(match, "ip4.src == "); - op_put_v4_networks(match, op, true); - ds_put_cstr(match, " && "REGBIT_EGRESS_LOOPBACK" == 0"); - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, - ds_cstr(match), debug_drop_action(), - &op->nbrp->header_); + if (!op->nbrp || is_cr_port(op)) { + return; + } + if (op->lrp_networks.n_ipv4_addrs) { + /* L3 admission control: drop packets that originate from an + * IPv4 address owned by the router or a broadcast address + * known to the router (priority 100). */ + ds_clear(match); + ds_put_cstr(match, "ip4.src == "); + op_put_v4_networks(match, op, true); + ds_put_cstr(match, " && "REGBIT_EGRESS_LOOPBACK" == 0"); + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, + ds_cstr(match), debug_drop_action(), + &op->nbrp->header_); - /* ICMP echo reply. These flows reply to ICMP echo requests - * received for the router's IP address. Since packets only - * get here as part of the logical router datapath, the inport - * (i.e. the incoming locally attached net) does not matter. - * The ip.ttl also does not matter (RFC1812 section 4.2.2.9) */ - ds_clear(match); - ds_put_cstr(match, "ip4.dst == "); - op_put_v4_networks(match, op, false); - ds_put_cstr(match, " && icmp4.type == 8 && icmp4.code == 0"); - - const char * icmp_actions = "ip4.dst <-> ip4.src; " - "ip.ttl = 255; " - "icmp4.type = 0; " - "flags.loopback = 1; " - "next; "; - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, - ds_cstr(match), icmp_actions, - &op->nbrp->header_); - } + /* ICMP echo reply. These flows reply to ICMP echo requests + * received for the router's IP address. Since packets only + * get here as part of the logical router datapath, the inport + * (i.e. the incoming locally attached net) does not matter. + * The ip.ttl also does not matter (RFC1812 section 4.2.2.9) */ + ds_clear(match); + ds_put_cstr(match, "ip4.dst == "); + op_put_v4_networks(match, op, false); + ds_put_cstr(match, " && icmp4.type == 8 && icmp4.code == 0"); + + const char * icmp_actions = "ip4.dst <-> ip4.src; " + "ip.ttl = 255; " + "icmp4.type = 0; " + "flags.loopback = 1; " + "next; "; + ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(match), icmp_actions, + &op->nbrp->header_); + } - /* BFD msg handling */ - build_lrouter_bfd_flows(lflows, op, meter_groups); + /* BFD msg handling */ + build_lrouter_bfd_flows(lflows, op, meter_groups); - /* ICMP time exceeded */ - struct ds ip_ds = DS_EMPTY_INITIALIZER; - for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - ds_clear(match); - ds_clear(actions); - ds_clear(&ip_ds); + /* ICMP time exceeded */ + struct ds ip_ds = DS_EMPTY_INITIALIZER; + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + ds_clear(match); + ds_clear(actions); + ds_clear(&ip_ds); + if (is_l3dgw_port(op)) { + ds_put_cstr(&ip_ds, "ip4.dst <-> ip4.src"); + } else { + ds_put_format(&ip_ds, "ip4.dst = ip4.src; ip4.src = %s", + op->lrp_networks.ipv4_addrs[i].addr_s); + } + ds_put_format(match, + "inport == %s && ip4 && " + "ip.ttl == {0, 1} && !ip.later_frag", op->json_key); + ds_put_format(actions, + "icmp4 {" + "eth.dst <-> eth.src; " + "icmp4.type = 11; /* Time exceeded */ " + "icmp4.code = 0; /* TTL exceeded in transit */ " + "%s ; ip.ttl = 254; " + "outport = %s; flags.loopback = 1; output; };", + ds_cstr(&ip_ds), op->json_key); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 100, ds_cstr(match), ds_cstr(actions), NULL, + copp_meter_get(COPP_ICMP4_ERR, op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); + + } + ds_destroy(&ip_ds); + + /* ARP reply. These flows reply to ARP requests for the router's own + * IP address. */ + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + ds_clear(match); + ds_put_format(match, "arp.spa == %s/%u", + op->lrp_networks.ipv4_addrs[i].network_s, + op->lrp_networks.ipv4_addrs[i].plen); + + if (op->od->n_l3dgw_ports && op->peer + && op->peer->od->n_localnet_ports) { + bool add_chassis_resident_check = false; + const char *json_key; if (is_l3dgw_port(op)) { - ds_put_cstr(&ip_ds, "ip4.dst <-> ip4.src"); + /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s + * should only be sent from the gateway chassis, so that + * upstream MAC learning points to the gateway chassis. + * Also need to avoid generation of multiple ARP responses + * from different chassis. */ + add_chassis_resident_check = true; + json_key = op->cr_port->json_key; } else { - ds_put_format(&ip_ds, "ip4.dst = ip4.src; ip4.src = %s", - op->lrp_networks.ipv4_addrs[i].addr_s); + /* Check if the option 'reside-on-redirect-chassis' + * is set to true on the router port. If set to true + * and if peer's logical switch has a localnet port, it + * means the router pipeline for the packets from + * peer's logical switch is be run on the chassis + * hosting the gateway port and it should reply to the + * ARP requests for the router port IPs. + */ + add_chassis_resident_check = smap_get_bool( + &op->nbrp->options, + "reside-on-redirect-chassis", false) && + op->od->n_l3dgw_ports == 1; + json_key = op->od->l3dgw_ports[0]->cr_port->json_key; } - ds_put_format(match, - "inport == %s && ip4 && " - "ip.ttl == {0, 1} && !ip.later_frag", op->json_key); - ds_put_format(actions, - "icmp4 {" - "eth.dst <-> eth.src; " - "icmp4.type = 11; /* Time exceeded */ " - "icmp4.code = 0; /* TTL exceeded in transit */ " - "%s ; ip.ttl = 254; " - "outport = %s; flags.loopback = 1; output; };", - ds_cstr(&ip_ds), op->json_key); - ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 100, ds_cstr(match), ds_cstr(actions), NULL, - copp_meter_get(COPP_ICMP4_ERR, op->od->nbr->copp, - meter_groups), - &op->nbrp->header_); + if (add_chassis_resident_check) { + ds_put_format(match, " && is_chassis_resident(%s)", + json_key); + } } - ds_destroy(&ip_ds); - /* ARP reply. These flows reply to ARP requests for the router's own - * IP address. */ - for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - ds_clear(match); - ds_put_format(match, "arp.spa == %s/%u", - op->lrp_networks.ipv4_addrs[i].network_s, - op->lrp_networks.ipv4_addrs[i].plen); + build_lrouter_arp_flow(op->od, op, + op->lrp_networks.ipv4_addrs[i].addr_s, + REG_INPORT_ETH_ADDR, match, false, 90, + &op->nbrp->header_, lflows); + } - if (op->od->n_l3dgw_ports && op->peer - && op->peer->od->n_localnet_ports) { - bool add_chassis_resident_check = false; - const char *json_key; - if (is_l3dgw_port(op)) { - /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s - * should only be sent from the gateway chassis, so that - * upstream MAC learning points to the gateway chassis. - * Also need to avoid generation of multiple ARP responses - * from different chassis. */ - add_chassis_resident_check = true; - json_key = op->cr_port->json_key; - } else { - /* Check if the option 'reside-on-redirect-chassis' - * is set to true on the router port. If set to true - * and if peer's logical switch has a localnet port, it - * means the router pipeline for the packets from - * peer's logical switch is be run on the chassis - * hosting the gateway port and it should reply to the - * ARP requests for the router port IPs. - */ - add_chassis_resident_check = smap_get_bool( - &op->nbrp->options, - "reside-on-redirect-chassis", false) && - op->od->n_l3dgw_ports == 1; - json_key = op->od->l3dgw_ports[0]->cr_port->json_key; - } + if (sset_count(&op->od->lb_ips->ips_v4_reachable)) { + ds_clear(match); + if (is_l3dgw_port(op)) { + ds_put_format(match, "is_chassis_resident(%s)", + op->cr_port->json_key); + } - if (add_chassis_resident_check) { - ds_put_format(match, " && is_chassis_resident(%s)", - json_key); - } - } + /* Create a single ARP rule for all IPs that are used as VIPs. */ + char *lb_ips_v4_as = lr_lb_address_set_ref(op->od->tunnel_key, + AF_INET); + build_lrouter_arp_flow(op->od, op, lb_ips_v4_as, + REG_INPORT_ETH_ADDR, + match, false, 90, NULL, lflows); + free(lb_ips_v4_as); + } + + if (sset_count(&op->od->lb_ips->ips_v6_reachable)) { + ds_clear(match); - build_lrouter_arp_flow(op->od, op, - op->lrp_networks.ipv4_addrs[i].addr_s, - REG_INPORT_ETH_ADDR, match, false, 90, - &op->nbrp->header_, lflows); + if (is_l3dgw_port(op)) { + ds_put_format(match, "is_chassis_resident(%s)", + op->cr_port->json_key); } - if (sset_count(&op->od->lb_ips->ips_v4_reachable)) { - ds_clear(match); - if (is_l3dgw_port(op)) { - ds_put_format(match, "is_chassis_resident(%s)", - op->cr_port->json_key); - } + /* Create a single ND rule for all IPs that are used as VIPs. */ + char *lb_ips_v6_as = lr_lb_address_set_ref(op->od->tunnel_key, + AF_INET6); + build_lrouter_nd_flow(op->od, op, "nd_na", lb_ips_v6_as, NULL, + REG_INPORT_ETH_ADDR, match, false, 90, + NULL, lflows, meter_groups); + free(lb_ips_v6_as); + } - /* Create a single ARP rule for all IPs that are used as VIPs. */ - char *lb_ips_v4_as = lr_lb_address_set_ref(op->od->tunnel_key, - AF_INET); - build_lrouter_arp_flow(op->od, op, lb_ips_v4_as, - REG_INPORT_ETH_ADDR, - match, false, 90, NULL, lflows); - free(lb_ips_v4_as); - } + if (!op->od->is_gw_router && !op->od->n_l3dgw_ports) { + /* UDP/TCP/SCTP port unreachable. */ + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + ds_clear(match); + ds_put_format(match, + "ip4 && ip4.dst == %s && !ip.later_frag && udp", + op->lrp_networks.ipv4_addrs[i].addr_s); + const char *action = "icmp4 {" + "eth.dst <-> eth.src; " + "ip4.dst <-> ip4.src; " + "ip.ttl = 255; " + "icmp4.type = 3; " + "icmp4.code = 3; " + "next; };"; + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(match), action, NULL, + copp_meter_get( + COPP_ICMP4_ERR, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); - if (sset_count(&op->od->lb_ips->ips_v6_reachable)) { ds_clear(match); + ds_put_format(match, + "ip4 && ip4.dst == %s && !ip.later_frag && tcp", + op->lrp_networks.ipv4_addrs[i].addr_s); + action = "tcp_reset {" + "eth.dst <-> eth.src; " + "ip4.dst <-> ip4.src; " + "next; };"; + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(match), action, NULL, + copp_meter_get( + COPP_TCP_RESET, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); - if (is_l3dgw_port(op)) { - ds_put_format(match, "is_chassis_resident(%s)", - op->cr_port->json_key); - } + ds_clear(match); + ds_put_format(match, + "ip4 && ip4.dst == %s && !ip.later_frag && sctp", + op->lrp_networks.ipv4_addrs[i].addr_s); + action = "sctp_abort {" + "eth.dst <-> eth.src; " + "ip4.dst <-> ip4.src; " + "next; };"; + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(match), action, NULL, + copp_meter_get( + COPP_TCP_RESET, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); - /* Create a single ND rule for all IPs that are used as VIPs. */ - char *lb_ips_v6_as = lr_lb_address_set_ref(op->od->tunnel_key, - AF_INET6); - build_lrouter_nd_flow(op->od, op, "nd_na", lb_ips_v6_as, NULL, - REG_INPORT_ETH_ADDR, match, false, 90, - NULL, lflows, meter_groups); - free(lb_ips_v6_as); + ds_clear(match); + ds_put_format(match, + "ip4 && ip4.dst == %s && !ip.later_frag", + op->lrp_networks.ipv4_addrs[i].addr_s); + action = "icmp4 {" + "eth.dst <-> eth.src; " + "ip4.dst <-> ip4.src; " + "ip.ttl = 255; " + "icmp4.type = 3; " + "icmp4.code = 2; " + "next; };"; + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 70, ds_cstr(match), action, NULL, + copp_meter_get( + COPP_ICMP4_ERR, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); } + } - if (!op->od->is_gw_router && !op->od->n_l3dgw_ports) { - /* UDP/TCP/SCTP port unreachable. */ - for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - ds_clear(match); - ds_put_format(match, - "ip4 && ip4.dst == %s && !ip.later_frag && udp", - op->lrp_networks.ipv4_addrs[i].addr_s); - const char *action = "icmp4 {" - "eth.dst <-> eth.src; " - "ip4.dst <-> ip4.src; " - "ip.ttl = 255; " - "icmp4.type = 3; " - "icmp4.code = 3; " - "next; };"; - ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 80, ds_cstr(match), action, NULL, - copp_meter_get( - COPP_ICMP4_ERR, - op->od->nbr->copp, - meter_groups), - &op->nbrp->header_); - - ds_clear(match); - ds_put_format(match, - "ip4 && ip4.dst == %s && !ip.later_frag && tcp", - op->lrp_networks.ipv4_addrs[i].addr_s); - action = "tcp_reset {" - "eth.dst <-> eth.src; " - "ip4.dst <-> ip4.src; " - "next; };"; - ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 80, ds_cstr(match), action, NULL, - copp_meter_get( - COPP_TCP_RESET, - op->od->nbr->copp, - meter_groups), - &op->nbrp->header_); + /* Drop IP traffic destined to router owned IPs except if the IP is + * also a SNAT IP. Those are dropped later, in stage + * "lr_in_arp_resolve", if unSNAT was unsuccessful. + * + * If op->od->lb_force_snat_router_ip is true, it means the IP of the + * router port is also SNAT IP. + * + * Priority 60. + */ + if (!op->od->lb_force_snat_router_ip) { + build_lrouter_drop_own_dest(op, S_ROUTER_IN_IP_INPUT, 60, false, + lflows); + } + /* ARP / ND handling for external IP addresses. + * + * DNAT and SNAT IP addresses are external IP addresses that need ARP + * handling. + * + * These are already taken care globally, per router. The only + * exception is on the l3dgw_port where we might need to use a + * different ETH address. + */ + if (!is_l3dgw_port(op)) { + return; + } - ds_clear(match); - ds_put_format(match, - "ip4 && ip4.dst == %s && !ip.later_frag && sctp", - op->lrp_networks.ipv4_addrs[i].addr_s); - action = "sctp_abort {" - "eth.dst <-> eth.src; " - "ip4.dst <-> ip4.src; " - "next; };"; - ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 80, ds_cstr(match), action, NULL, - copp_meter_get( - COPP_TCP_RESET, - op->od->nbr->copp, - meter_groups), - &op->nbrp->header_); + for (size_t i = 0; i < op->od->nbr->n_nat; i++) { + struct ovn_nat *nat_entry = &op->od->nat_entries[i]; - ds_clear(match); - ds_put_format(match, - "ip4 && ip4.dst == %s && !ip.later_frag", - op->lrp_networks.ipv4_addrs[i].addr_s); - action = "icmp4 {" - "eth.dst <-> eth.src; " - "ip4.dst <-> ip4.src; " - "ip.ttl = 255; " - "icmp4.type = 3; " - "icmp4.code = 2; " - "next; };"; - ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 70, ds_cstr(match), action, NULL, - copp_meter_get( - COPP_ICMP4_ERR, - op->od->nbr->copp, - meter_groups), - &op->nbrp->header_); - } + /* Skip entries we failed to parse. */ + if (!nat_entry_is_valid(nat_entry)) { + continue; } - /* Drop IP traffic destined to router owned IPs except if the IP is - * also a SNAT IP. Those are dropped later, in stage - * "lr_in_arp_resolve", if unSNAT was unsuccessful. - * - * If op->od->lb_force_snat_router_ip is true, it means the IP of the - * router port is also SNAT IP. - * - * Priority 60. - */ - if (!op->od->lb_force_snat_router_ip) { - build_lrouter_drop_own_dest(op, S_ROUTER_IN_IP_INPUT, 60, false, - lflows); - } - /* ARP / ND handling for external IP addresses. - * - * DNAT and SNAT IP addresses are external IP addresses that need ARP - * handling. - * - * These are already taken care globally, per router. The only - * exception is on the l3dgw_port where we might need to use a - * different ETH address. + /* Skip SNAT entries for now, we handle unique SNAT IPs separately + * below. */ - if (!is_l3dgw_port(op)) { - return; + if (!strcmp(nat_entry->nb->type, "snat")) { + continue; } + build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows, + meter_groups); + } - for (size_t i = 0; i < op->od->nbr->n_nat; i++) { - struct ovn_nat *nat_entry = &op->od->nat_entries[i]; + /* Now handle SNAT entries too, one per unique SNAT IP. */ + struct shash_node *snat_snode; + SHASH_FOR_EACH (snat_snode, &op->od->snat_ips) { + struct ovn_snat_ip *snat_ip = snat_snode->data; - /* Skip entries we failed to parse. */ - if (!nat_entry_is_valid(nat_entry)) { - continue; - } - - /* Skip SNAT entries for now, we handle unique SNAT IPs separately - * below. - */ - if (!strcmp(nat_entry->nb->type, "snat")) { - continue; - } - build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows, - meter_groups); + if (ovs_list_is_empty(&snat_ip->snat_entries)) { + continue; } - /* Now handle SNAT entries too, one per unique SNAT IP. */ - struct shash_node *snat_snode; - SHASH_FOR_EACH (snat_snode, &op->od->snat_ips) { - struct ovn_snat_ip *snat_ip = snat_snode->data; - - if (ovs_list_is_empty(&snat_ip->snat_entries)) { - continue; - } - - struct ovn_nat *nat_entry = - CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries), - struct ovn_nat, ext_addr_list_node); - build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows, - meter_groups); - } + struct ovn_nat *nat_entry = + CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries), + struct ovn_nat, ext_addr_list_node); + build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows, + meter_groups); } } @@ -14562,6 +14592,7 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, build_lswitch_destination_lookup_bmcast(od, lsi->lflows, &lsi->actions, lsi->meter_groups); build_lswitch_output_port_sec_od(od, lsi->lflows); + build_lswitch_lb_affinity_default_flows(od, lsi->lflows); /* Build Logical Router Flows. */ build_adm_ctrl_flows_for_lrouter(od, lsi->lflows); @@ -14588,7 +14619,7 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, build_lrouter_nat_defrag_and_lb(od, lsi->lflows, lsi->ports, &lsi->match, &lsi->actions, lsi->meter_groups, lsi->features); - build_lb_affinity_default_flows(od, lsi->lflows); + build_lrouter_lb_affinity_default_flows(od, lsi->lflows); } /* Helper function to combine all lflow generation which is iterated by port. diff --git a/ovs b/ovs index b72a7f92573a..8986d4d55644 160000 --- a/ovs +++ b/ovs @@ -1 +1 @@ -Subproject commit b72a7f92573aa4e6205e57cb978532b4c04702e1 +Subproject commit 8986d4d5564401eeef3dea828b51fe8bae2cc8aa From patchwork Tue Mar 21 06:02:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1759299 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Pggy401bhz2476 for ; Tue, 21 Mar 2023 17:03:07 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id BBBD041840; Tue, 21 Mar 2023 06:03:04 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org BBBD041840 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id IGTeDDCbH_Xr; Tue, 21 Mar 2023 06:03:03 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id 2976941807; Tue, 21 Mar 2023 06:03:02 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 2976941807 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id D4A8FC008D; Tue, 21 Mar 2023 06:02:59 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 921EDC0032 for ; Tue, 21 Mar 2023 06:02:57 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 68349417E4 for ; Tue, 21 Mar 2023 06:02:57 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 68349417E4 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id a8HtT5hlw2oL for ; Tue, 21 Mar 2023 06:02:56 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 408FA417D1 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by smtp4.osuosl.org (Postfix) with ESMTPS id 408FA417D1 for ; Tue, 21 Mar 2023 06:02:56 +0000 (UTC) Received: (Authenticated sender: hzhou@ovn.org) by mail.gandi.net (Postfix) with ESMTPSA id BD73EE0007; Tue, 21 Mar 2023 06:02:53 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Mon, 20 Mar 2023 23:02:30 -0700 Message-Id: <20230321060235.2256118-3-hzhou@ovn.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230321060235.2256118-1-hzhou@ovn.org> References: <20230321060235.2256118-1-hzhou@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 2/7] northd.c: Simplify a code chunk by reusing existing ovn_port_get_peer. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" We already have a helper function for the logic, so reuse it. Signed-off-by: Han Zhou --- northd/northd.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/northd/northd.c b/northd/northd.c index 1e49301dd5b4..8f90e0ce4e04 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -12582,11 +12582,8 @@ build_arp_resolve_flows_for_lrouter_port( } 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); + struct ovn_port *router_port = + ovn_port_get_peer(ports, op->od->router_ports[i]); if (!router_port || !router_port->nbrp) { continue; } From patchwork Tue Mar 21 06:02:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1759301 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PggyK2Ct9z2476 for ; Tue, 21 Mar 2023 17:03:21 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id D58D761156; Tue, 21 Mar 2023 06:03:16 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org D58D761156 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VlYa1jENVzUF; Tue, 21 Mar 2023 06:03:09 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id 9A5AC610FF; Tue, 21 Mar 2023 06:03:06 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 9A5AC610FF Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 49B13C0077; Tue, 21 Mar 2023 06:03:06 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id B5320C0032 for ; Tue, 21 Mar 2023 06:03:02 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 8B2E840AFC for ; Tue, 21 Mar 2023 06:03:02 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 8B2E840AFC X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zc-_apTGTq9d for ; Tue, 21 Mar 2023 06:02:59 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 9CD44400E7 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by smtp2.osuosl.org (Postfix) with ESMTPS id 9CD44400E7 for ; Tue, 21 Mar 2023 06:02:58 +0000 (UTC) Received: (Authenticated sender: hzhou@ovn.org) by mail.gandi.net (Postfix) with ESMTPSA id 1A811E0008; Tue, 21 Mar 2023 06:02:54 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Mon, 20 Mar 2023 23:02:31 -0700 Message-Id: <20230321060235.2256118-4-hzhou@ovn.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230321060235.2256118-1-hzhou@ovn.org> References: <20230321060235.2256118-1-hzhou@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 3/7] northd: Split switch ports and router ports. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" The hmap 'ports' includes both logical switch ports and logical router ports. Although most of the code handles these two different types of port differently, we always have to iterate through the whole hmap, and skip one type of ports in the loop. More importantly, this hides dependency from the interfaces - it is not clear from the function prototypes what are the real input, switch ports or router ports, or both. With this patch, it splits the two types of ports in different hmap tables, and all the related functions are refactored, most of them only accept one of the types. This helps for future incremental processing implementation. As a byproduct, it improves the performance slightly. Note: This patch didn't change the ovn_port data structure, which is used by both switch ports and router ports. It may be a followup improvement in the future if necessary, e.g. to reduce memory footprint. Signed-off-by: Han Zhou --- northd/en-lflow.c | 5 +- northd/northd.c | 623 +++++++++++++++++++++++++++------------------- northd/northd.h | 6 +- 3 files changed, 368 insertions(+), 266 deletions(-) diff --git a/northd/en-lflow.c b/northd/en-lflow.c index fa0dfcbe03b2..9e7a2145e520 100644 --- a/northd/en-lflow.c +++ b/northd/en-lflow.c @@ -55,7 +55,8 @@ void en_lflow_run(struct engine_node *node, void *data OVS_UNUSED) "sbrec_mcast_group_by_name"); lflow_input.datapaths = &northd_data->datapaths; - lflow_input.ports = &northd_data->ports; + lflow_input.ls_ports = &northd_data->ls_ports; + lflow_input.lr_ports = &northd_data->lr_ports; lflow_input.port_groups = &northd_data->port_groups; lflow_input.meter_groups = &northd_data->meter_groups; lflow_input.lbs = &northd_data->lbs; @@ -67,7 +68,7 @@ void en_lflow_run(struct engine_node *node, void *data OVS_UNUSED) stopwatch_start(BUILD_LFLOWS_STOPWATCH_NAME, time_msec()); build_bfd_table(&lflow_input, eng_ctx->ovnsb_idl_txn, &northd_data->bfd_connections, - &northd_data->ports); + &northd_data->lr_ports); build_lflows(&lflow_input, eng_ctx->ovnsb_idl_txn); bfd_cleanup_connections(&lflow_input, &northd_data->bfd_connections); stopwatch_stop(BUILD_LFLOWS_STOPWATCH_NAME, time_msec()); diff --git a/northd/northd.c b/northd/northd.c index 8f90e0ce4e04..10b16e685adf 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -1801,7 +1801,7 @@ lrport_is_enabled(const struct nbrec_logical_router_port *lrport) } static struct ovn_port * -ovn_port_get_peer(const struct hmap *ports, struct ovn_port *op) +ovn_port_get_peer(const struct hmap *lr_ports, struct ovn_port *op) { if (!op->nbsp || !lsp_is_router(op->nbsp) || op->l3dgw_port) { return NULL; @@ -1816,7 +1816,7 @@ ovn_port_get_peer(const struct hmap *ports, struct ovn_port *op) return NULL; } - return ovn_port_find(ports, peer_name); + return ovn_port_find(lr_ports, peer_name); } static void @@ -2243,7 +2243,7 @@ update_dynamic_addresses(struct dynamic_address_update *update) } static void -build_ipam(struct hmap *datapaths, struct hmap *ports) +build_ipam(struct hmap *datapaths, struct hmap *ls_ports) { /* IPAM generally stands for IP address management. In non-virtualized * world, MAC addresses come with the hardware. But, with virtualized @@ -2275,7 +2275,7 @@ build_ipam(struct hmap *datapaths, struct hmap *ports) continue; } - struct ovn_port *op = ovn_port_find(ports, nbsp->name); + struct ovn_port *op = ovn_port_find(ls_ports, nbsp->name); if (!op || op->nbsp != nbsp || op->peer) { /* Do not allocate addresses for logical switch ports that * have a peer. */ @@ -3159,10 +3159,10 @@ op_get_name(const struct ovn_port *op) } static void -ovn_update_ipv6_prefix(struct hmap *ports) +ovn_update_ipv6_prefix(struct hmap *lr_ports) { const struct ovn_port *op; - HMAP_FOR_EACH (op, key_node, ports) { + HMAP_FOR_EACH (op, key_node, lr_ports) { if (!op->nbrp) { continue; } @@ -3705,7 +3705,7 @@ ovn_port_update_sbrec(struct northd_input *input_data, static void cleanup_mac_bindings(struct northd_input *input_data, struct hmap *datapaths, - struct hmap *ports) + struct hmap *lr_ports) { const struct sbrec_mac_binding *b; SBREC_MAC_BINDING_TABLE_FOR_EACH_SAFE (b, @@ -3714,7 +3714,7 @@ cleanup_mac_bindings(struct northd_input *input_data, ovn_datapath_from_sbrec(datapaths, b->datapath); if (!od || ovn_datapath_is_stale(od) || - !ovn_port_find(ports, b->logical_port)) { + !ovn_port_find(lr_ports, b->logical_port)) { sbrec_mac_binding_delete(b); } } @@ -3796,7 +3796,7 @@ create_or_get_service_mon(struct ovsdb_idl_txn *ovnsb_txn, static void ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn, struct ovn_northd_lb *lb, - struct hmap *monitor_map, struct hmap *ports) + struct hmap *monitor_map, struct hmap *ls_ports) { if (lb->template) { return; @@ -3827,7 +3827,7 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn, struct ovn_northd_lb *lb, if (p) { *p = 0; p++; - op = ovn_port_find(ports, port_name); + op = ovn_port_find(ls_ports, port_name); struct sockaddr_storage svc_mon_src_addr; if (!inet_parse_address(p, &svc_mon_src_addr)) { static struct vlog_rate_limit rl = @@ -4105,7 +4105,7 @@ build_lbs(struct northd_input *input_data, struct hmap *datapaths, static void build_lb_svcs(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *ports, + struct hmap *ls_ports, struct hmap *lbs) { struct hmap monitor_map = HMAP_INITIALIZER(&monitor_map); @@ -4124,7 +4124,7 @@ build_lb_svcs(struct northd_input *input_data, struct ovn_northd_lb *lb; HMAP_FOR_EACH (lb, hmap_node, lbs) { - ovn_lb_svc_create(ovnsb_txn, lb, &monitor_map, ports); + ovn_lb_svc_create(ovnsb_txn, lb, &monitor_map, ls_ports); } struct service_monitor_info *mon_info; @@ -4298,14 +4298,14 @@ build_lb_count_dps(struct hmap *lbs) * networks to have been parsed. */ static void -build_lb_port_related_data(struct hmap *datapaths, struct hmap *ports, +build_lb_port_related_data(struct hmap *datapaths, struct hmap *ls_ports, struct hmap *lbs, struct hmap *lb_groups, struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn) { build_lrouter_lbs_check(datapaths); build_lrouter_lbs_reachable_ips(datapaths, lbs, lb_groups); - build_lb_svcs(input_data, ovnsb_txn, ports, lbs); + build_lb_svcs(input_data, ovnsb_txn, ls_ports, lbs); build_lswitch_lbs_from_lrouter(lbs, lb_groups); } @@ -4572,7 +4572,8 @@ build_ports(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, struct ovsdb_idl_index *sbrec_chassis_by_name, struct ovsdb_idl_index *sbrec_chassis_by_hostname, - struct hmap *datapaths, struct hmap *ports) + struct hmap *datapaths, struct hmap *ls_ports, + struct hmap *lr_ports) { struct ovs_list sb_only, nb_only, both; struct hmap tag_alloc_table = HMAP_INITIALIZER(&tag_alloc_table); @@ -4582,6 +4583,9 @@ build_ports(struct northd_input *input_data, struct sset active_ha_chassis_grps = SSET_INITIALIZER(&active_ha_chassis_grps); + /* Borrow ls_ports for joining NB and SB for both LSPs and LRPs. + * We will split them later. */ + struct hmap *ports = ls_ports; join_logical_ports(input_data, datapaths, ports, &chassis_qdisc_queues, &tag_alloc_table, &sb_only, &nb_only, &both); @@ -4653,8 +4657,19 @@ build_ports(struct northd_input *input_data, ovn_port_destroy(ports, op); } } + + /* Move logical router ports to lr_ports, and logical switch ports will + * remain in ports/ls_ports. */ + HMAP_FOR_EACH_SAFE (op, key_node, ports) { + if (!op->nbrp) { + continue; + } + hmap_remove(ports, &op->key_node); + hmap_insert(lr_ports, &op->key_node, op->key_node.hash); + } + if (remove_mac_bindings) { - cleanup_mac_bindings(input_data, datapaths, ports); + cleanup_mac_bindings(input_data, datapaths, lr_ports); } tag_alloc_destroy(&tag_alloc_table); @@ -4900,14 +4915,14 @@ ovn_igmp_group_get_address(const struct sbrec_igmp_group *sb_igmp_group, static struct ovn_port ** ovn_igmp_group_get_ports(const struct sbrec_igmp_group *sb_igmp_group, - size_t *n_ports, const struct hmap *ovn_ports) + size_t *n_ports, const struct hmap *ls_ports) { struct ovn_port **ports = NULL; *n_ports = 0; for (size_t i = 0; i < sb_igmp_group->n_ports; i++) { struct ovn_port *port = - ovn_port_find(ovn_ports, sb_igmp_group->ports[i]->logical_port); + ovn_port_find(ls_ports, sb_igmp_group->ports[i]->logical_port); if (!port || !port->nbsp) { continue; @@ -5666,9 +5681,7 @@ static void build_lswitch_port_sec_op(struct ovn_port *op, struct hmap *lflows, struct ds *actions, struct ds *match) { - if (!op->nbsp) { - return; - } + ovs_assert(op->nbsp); if (lsp_is_external(op->nbsp)) { return; @@ -5731,9 +5744,7 @@ build_lswitch_learn_fdb_op( struct ovn_port *op, struct hmap *lflows, struct ds *actions, struct ds *match) { - if (!op->nbsp) { - return; - } + ovs_assert(op->nbsp); if (!op->n_ps_addrs && op->has_unknown && (!strcmp(op->nbsp->type, "") || (lsp_is_localnet(op->nbsp) && localnet_can_learn_mac(op->nbsp)))) { @@ -6626,10 +6637,10 @@ static void copy_ra_to_sb(struct ovn_port *op, const char *address_mode); static void -ovn_update_ipv6_options(struct hmap *ports) +ovn_update_ipv6_options(struct hmap *lr_ports) { struct ovn_port *op; - HMAP_FOR_EACH (op, key_node, ports) { + HMAP_FOR_EACH (op, key_node, lr_ports) { if (!op->nbrp || op->nbrp->peer || !op->peer) { continue; } @@ -6691,7 +6702,7 @@ ovn_update_ipv6_options(struct hmap *ports) static void build_port_group_lswitches(struct northd_input *input_data, struct hmap *pgs, - struct hmap *ports) + struct hmap *ls_ports) { hmap_init(pgs); @@ -6700,7 +6711,8 @@ build_port_group_lswitches(struct northd_input *input_data, input_data->nbrec_port_group_table) { struct ovn_port_group *pg = ovn_port_group_create(pgs, nb_pg); for (size_t i = 0; i < nb_pg->n_ports; i++) { - struct ovn_port *op = ovn_port_find(ports, nb_pg->ports[i]->name); + struct ovn_port *op = ovn_port_find(ls_ports, + nb_pg->ports[i]->name); if (!op) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); VLOG_ERR_RL(&rl, "lport %s in port group %s not found.", @@ -7770,7 +7782,7 @@ build_fwd_group_lflows(struct ovn_datapath *od, struct hmap *lflows) } static void -build_lrouter_groups__(struct hmap *ports, struct ovn_datapath *od) +build_lrouter_groups__(struct hmap *lr_ports, struct ovn_datapath *od) { ovs_assert((od && od->nbr && od->lr_group)); @@ -7788,7 +7800,7 @@ build_lrouter_groups__(struct hmap *ports, struct ovn_datapath *od) for (size_t i = 0; i < od->nbr->n_ports; i++) { struct ovn_port *router_port = - ovn_port_find(ports, od->nbr->ports[i]->name); + ovn_port_find(lr_ports, od->nbr->ports[i]->name); if (!router_port || !router_port->peer) { continue; @@ -7801,7 +7813,7 @@ build_lrouter_groups__(struct hmap *ports, struct ovn_datapath *od) peer_dp->lr_group = od->lr_group; od->lr_group->router_dps[od->lr_group->n_router_dps++] = peer_dp; - build_lrouter_groups__(ports, peer_dp); + build_lrouter_groups__(lr_ports, peer_dp); } } else { for (size_t j = 0; j < peer_dp->n_router_ports; j++) { @@ -7826,7 +7838,7 @@ build_lrouter_groups__(struct hmap *ports, struct ovn_datapath *od) router_dp->lr_group = od->lr_group; od->lr_group->router_dps[od->lr_group->n_router_dps++] = router_dp; - build_lrouter_groups__(ports, router_dp); + build_lrouter_groups__(lr_ports, router_dp); } } } @@ -7854,7 +7866,7 @@ build_lrouter_groups__(struct hmap *ports, struct ovn_datapath *od) * Each logical router can belong to only one group. */ static void -build_lrouter_groups(struct hmap *ports, struct ovs_list *lr_list) +build_lrouter_groups(struct hmap *lr_ports, struct ovs_list *lr_list) { struct ovn_datapath *od; size_t n_router_dps = ovs_list_size(lr_list); @@ -7868,7 +7880,7 @@ build_lrouter_groups(struct hmap *ports, struct ovs_list *lr_list) od->lr_group->router_dps[0] = od; od->lr_group->n_router_dps = 1; sset_init(&od->lr_group->ha_chassis_groups); - build_lrouter_groups__(ports, od); + build_lrouter_groups__(lr_ports, od); } } } @@ -8440,7 +8452,8 @@ build_lswitch_arp_nd_responder_skip_local(struct ovn_port *op, struct hmap *lflows, struct ds *match) { - if (!op->nbsp || !lsp_is_localnet(op->nbsp)) { + ovs_assert(op->nbsp); + if (!lsp_is_localnet(op->nbsp)) { return; } ds_clear(match); @@ -8456,14 +8469,12 @@ build_lswitch_arp_nd_responder_skip_local(struct ovn_port *op, static void build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, struct hmap *lflows, - const struct hmap *ports, + const struct hmap *ls_ports, const struct shash *meter_groups, struct ds *actions, struct ds *match) { - if (!op->nbsp) { - return; - } + ovs_assert(op->nbsp); if (!strcmp(op->nbsp->type, "virtual")) { /* Handle * - GARPs for virtual ip which belongs to a logical port @@ -8507,7 +8518,7 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, char *vparent; for (vparent = strtok_r(tokstr, ",", &save_ptr); vparent != NULL; vparent = strtok_r(NULL, ",", &save_ptr)) { - struct ovn_port *vp = ovn_port_find(ports, vparent); + struct ovn_port *vp = ovn_port_find(ls_ports, vparent); if (!vp || vp->od != op->od) { /* vparent name should be valid and it should belong * to the same logical switch. */ @@ -8856,9 +8867,7 @@ build_lswitch_dhcp_options_and_response(struct ovn_port *op, struct hmap *lflows, const struct shash *meter_groups) { - if (!op->nbsp) { - return; - } + ovs_assert(op->nbsp); if (!lsp_is_enabled(op->nbsp) || lsp_is_router(op->nbsp)) { /* Don't add the DHCP flows if the port is not enabled or if the * port is a router port. */ @@ -8959,7 +8968,8 @@ static void build_lswitch_external_port(struct ovn_port *op, struct hmap *lflows) { - if (!op->nbsp || !lsp_is_external(op->nbsp)) { + ovs_assert(op->nbsp); + if (!lsp_is_external(op->nbsp)) { return; } for (size_t i = 0; i < op->od->n_localnet_ports; i++) { @@ -9146,7 +9156,8 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op, struct ds *actions, struct ds *match) { - if (!op->nbsp || lsp_is_external(op->nbsp)) { + ovs_assert(op->nbsp); + if (lsp_is_external(op->nbsp)) { return; } @@ -9407,7 +9418,7 @@ static int bfd_get_unused_port(unsigned long *bfd_src_ports) void build_bfd_table(struct lflow_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *bfd_connections, struct hmap *ports) + struct hmap *bfd_connections, struct hmap *lr_ports) { struct hmap sb_only = HMAP_INITIALIZER(&sb_only); const struct sbrec_bfd *sb_bt; @@ -9472,14 +9483,15 @@ build_bfd_table(struct lflow_input *input_data, hmap_insert(bfd_connections, &bfd_e->hmap_node, hash); } - struct ovn_port *op = ovn_port_find(ports, nb_bt->logical_port); + struct ovn_port *op = ovn_port_find(lr_ports, nb_bt->logical_port); if (op) { op->has_bfd = true; } } HMAP_FOR_EACH_POP (bfd_e, hmap_node, &sb_only) { - struct ovn_port *op = ovn_port_find(ports, bfd_e->sb_bt->logical_port); + struct ovn_port *op = ovn_port_find(lr_ports, + bfd_e->sb_bt->logical_port); if (op) { op->has_bfd = false; } @@ -9503,7 +9515,7 @@ find_lrp_member_ip(const struct ovn_port *op, const char *ip_s) static struct ovn_port* get_outport_for_routing_policy_nexthop(struct ovn_datapath *od, - const struct hmap *ports, + const struct hmap *lr_ports, int priority, const char *nexthop) { if (nexthop == NULL) { @@ -9514,7 +9526,7 @@ get_outport_for_routing_policy_nexthop(struct ovn_datapath *od, for (int i = 0; i < od->nbr->n_ports; i++) { struct nbrec_logical_router_port *lrp = od->nbr->ports[i]; - struct ovn_port *out_port = ovn_port_find(ports, lrp->name); + struct ovn_port *out_port = ovn_port_find(lr_ports, lrp->name); if (out_port && find_lrp_member_ip(out_port, nexthop)) { return out_port; } @@ -9528,7 +9540,7 @@ get_outport_for_routing_policy_nexthop(struct ovn_datapath *od, static void build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od, - const struct hmap *ports, + const struct hmap *lr_ports, const struct nbrec_logical_router_policy *rule, const struct ovsdb_idl_row *stage_hint) { @@ -9541,7 +9553,7 @@ build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od, char *nexthop = (rule->n_nexthops == 1 ? rule->nexthops[0] : rule->nexthop); struct ovn_port *out_port = get_outport_for_routing_policy_nexthop( - od, ports, rule->priority, nexthop); + od, lr_ports, rule->priority, nexthop); if (!out_port) { return; } @@ -9593,7 +9605,7 @@ build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od, static void build_ecmp_routing_policy_flows(struct hmap *lflows, struct ovn_datapath *od, - const struct hmap *ports, + const struct hmap *lr_ports, const struct nbrec_logical_router_policy *rule, uint16_t ecmp_group_id) { @@ -9625,7 +9637,7 @@ build_ecmp_routing_policy_flows(struct hmap *lflows, struct ovn_datapath *od, for (size_t i = 0; i < rule->n_nexthops; i++) { struct ovn_port *out_port = get_outport_for_routing_policy_nexthop( - od, ports, rule->priority, rule->nexthops[i]); + od, lr_ports, rule->priority, rule->nexthops[i]); if (!out_port) { goto cleanup; } @@ -9774,14 +9786,14 @@ route_hash(struct parsed_route *route) static struct ovs_mutex bfd_lock = OVS_MUTEX_INITIALIZER; static bool -find_static_route_outport(struct ovn_datapath *od, const struct hmap *ports, +find_static_route_outport(struct ovn_datapath *od, const struct hmap *lr_ports, const struct nbrec_logical_router_static_route *route, bool is_ipv4, const char **p_lrp_addr_s, struct ovn_port **p_out_port); /* Parse and validate the route. Return the parsed route if successful. * Otherwise return NULL. */ static struct parsed_route * -parsed_routes_add(struct ovn_datapath *od, const struct hmap *ports, +parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, struct ovs_list *routes, struct simap *route_tables, const struct nbrec_logical_router_static_route *route, const struct hmap *bfd_connections) @@ -9833,7 +9845,7 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *ports, /* Verify that ip_prefix and nexthop are on the same network. */ if (!is_discard_route && - !find_static_route_outport(od, ports, route, + !find_static_route_outport(od, lr_ports, route, IN6_IS_ADDR_V4MAPPED(&prefix), NULL, NULL)) { return NULL; @@ -10067,14 +10079,14 @@ build_route_match(const struct ovn_port *op_inport, uint32_t rtb_id, /* Output: p_lrp_addr_s and p_out_port. */ static bool -find_static_route_outport(struct ovn_datapath *od, const struct hmap *ports, +find_static_route_outport(struct ovn_datapath *od, const struct hmap *lr_ports, const struct nbrec_logical_router_static_route *route, bool is_ipv4, const char **p_lrp_addr_s, struct ovn_port **p_out_port) { const char *lrp_addr_s = NULL; struct ovn_port *out_port = NULL; if (route->output_port) { - out_port = ovn_port_find(ports, route->output_port); + out_port = ovn_port_find(lr_ports, route->output_port); if (!out_port) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); VLOG_WARN_RL(&rl, "Bad out port %s for static route %s", @@ -10107,7 +10119,7 @@ find_static_route_outport(struct ovn_datapath *od, const struct hmap *ports, int i; for (i = 0; i < od->nbr->n_ports; i++) { struct nbrec_logical_router_port *lrp = od->nbr->ports[i]; - out_port = ovn_port_find(ports, lrp->name); + out_port = ovn_port_find(lr_ports, lrp->name); if (!out_port) { /* This should not happen. */ continue; @@ -10313,7 +10325,7 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, static void build_ecmp_route_flow(struct hmap *lflows, struct ovn_datapath *od, - bool ct_masked_mark, const struct hmap *ports, + bool ct_masked_mark, const struct hmap *lr_ports, struct ecmp_groups_node *eg) { @@ -10358,8 +10370,8 @@ build_ecmp_route_flow(struct hmap *lflows, struct ovn_datapath *od, /* Find the outgoing port. */ const char *lrp_addr_s = NULL; struct ovn_port *out_port = NULL; - if (!find_static_route_outport(od, ports, route, is_ipv4, &lrp_addr_s, - &out_port)) { + if (!find_static_route_outport(od, lr_ports, route, is_ipv4, + &lrp_addr_s, &out_port)) { continue; } /* Symmetric ECMP reply is only usable on gateway routers. @@ -10463,7 +10475,7 @@ add_route(struct hmap *lflows, struct ovn_datapath *od, static void build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, - const struct hmap *ports, + const struct hmap *lr_ports, const struct parsed_route *route_) { const char *lrp_addr_s = NULL; @@ -10473,7 +10485,7 @@ build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, /* Find the outgoing port. */ if (!route_->is_discard_route) { - if (!find_static_route_outport(od, ports, route, + if (!find_static_route_outport(od, lr_ports, route, IN6_IS_ADDR_V4MAPPED(&route_->prefix), &lrp_addr_s, &out_port)) { return; @@ -11481,7 +11493,8 @@ build_lrouter_force_snat_flows_op(struct ovn_port *op, struct hmap *lflows, struct ds *match, struct ds *actions) { - if (!op->nbrp || !op->peer || !op->od->lb_force_snat_router_ip) { + ovs_assert(op->nbrp); + if (!op->peer || !op->od->lb_force_snat_router_ip) { return; } @@ -11708,9 +11721,7 @@ build_adm_ctrl_flows_for_lrouter_port( struct ovn_port *op, struct hmap *lflows, struct ds *match, struct ds *actions) { - if (!op->nbrp) { - return; - } + ovs_assert(op->nbrp); if (!lrport_is_enabled(op->nbrp)) { /* Drop packets from disabled logical ports (since logical flow @@ -11879,9 +11890,7 @@ build_neigh_learning_flows_for_lrouter_port( struct ovn_port *op, struct hmap *lflows, struct ds *match, struct ds *actions) { - if (!op->nbrp) { - return; - } + ovs_assert(op->nbrp); bool learn_from_arp_request = smap_get_bool(&op->od->nbr->options, "always_learn_from_arp_request", true); @@ -11944,7 +11953,8 @@ build_ND_RA_flows_for_lrouter_port( struct ds *match, struct ds *actions, const struct shash *meter_groups) { - if (!op->nbrp || op->nbrp->peer || !op->peer) { + ovs_assert(op->nbrp); + if (op->nbrp->peer || !op->peer) { return; } @@ -12089,50 +12099,68 @@ build_ip_routing_pre_flows_for_lrouter(struct ovn_datapath *od, * IP_ROUTING remembers ECMP group id and selects a member id, and advances * to table IP_ROUTING_ECMP, which sets outport, eth.src and * REG_NEXT_HOP_IPV4/REG_NEXT_HOP_IPV6 for the selected ECMP member. + * + * This function adds routes for directly connected subnets configured on the + * LRP 'op'. */ static void -build_ip_routing_flows_for_lrouter_port( - struct ovn_port *op, const struct hmap *ports, struct hmap *lflows) +build_ip_routing_flows_for_lrp( + struct ovn_port *op, struct hmap *lflows) { - if (op->nbrp) { + ovs_assert(op->nbrp); + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + add_route(lflows, op->od, op, op->lrp_networks.ipv4_addrs[i].addr_s, + op->lrp_networks.ipv4_addrs[i].network_s, + op->lrp_networks.ipv4_addrs[i].plen, NULL, false, 0, + &op->nbrp->header_, false, ROUTE_PRIO_OFFSET_CONNECTED); + } - for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - add_route(lflows, op->od, op, op->lrp_networks.ipv4_addrs[i].addr_s, - op->lrp_networks.ipv4_addrs[i].network_s, - op->lrp_networks.ipv4_addrs[i].plen, NULL, false, 0, - &op->nbrp->header_, false, ROUTE_PRIO_OFFSET_CONNECTED); - } + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + add_route(lflows, op->od, op, op->lrp_networks.ipv6_addrs[i].addr_s, + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen, NULL, false, 0, + &op->nbrp->header_, false, ROUTE_PRIO_OFFSET_CONNECTED); + } +} - for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { - add_route(lflows, op->od, op, op->lrp_networks.ipv6_addrs[i].addr_s, - op->lrp_networks.ipv6_addrs[i].network_s, - op->lrp_networks.ipv6_addrs[i].plen, NULL, false, 0, - &op->nbrp->header_, false, ROUTE_PRIO_OFFSET_CONNECTED); - } - } else if (lsp_is_router(op->nbsp)) { - struct ovn_port *peer = ovn_port_get_peer(ports, op); - if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs) { - return; - } +/* Logical router ingress table IP_ROUTING : IP Routing. + * + * For the LSP 'op' of type router, if there are logical router ports other + * than the LSP's peer connected to the logical switch, then for routable + * addresses (such as NAT IPs, LB VIPs, etc.) on each of the connected router + * ports, add routes to the LSP's peer router. + */ +static void +build_ip_routing_flows_for_router_type_lsp( + struct ovn_port *op, const struct hmap *lr_ports, struct hmap *lflows) +{ + ovs_assert(op->nbsp); + if (!lsp_is_router(op->nbsp)) { + return; + } - for (int i = 0; i < op->od->n_router_ports; i++) { - struct ovn_port *router_port = ovn_port_get_peer( - ports, op->od->router_ports[i]); - if (!router_port || !router_port->nbrp || router_port == peer) { - continue; - } + struct ovn_port *peer = ovn_port_get_peer(lr_ports, op); + if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs) { + return; + } - struct ovn_port_routable_addresses *ra = &router_port->routables; - for (size_t j = 0; j < ra->n_addrs; j++) { - struct lport_addresses *laddrs = &ra->laddrs[j]; - for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { - add_route(lflows, peer->od, peer, - peer->lrp_networks.ipv4_addrs[0].addr_s, - laddrs->ipv4_addrs[k].network_s, - laddrs->ipv4_addrs[k].plen, NULL, false, 0, - &peer->nbrp->header_, false, - ROUTE_PRIO_OFFSET_CONNECTED); - } + for (int i = 0; i < op->od->n_router_ports; i++) { + struct ovn_port *router_port = ovn_port_get_peer( + lr_ports, op->od->router_ports[i]); + if (!router_port || !router_port->nbrp || router_port == peer) { + continue; + } + + struct ovn_port_routable_addresses *ra = &router_port->routables; + for (size_t j = 0; j < ra->n_addrs; j++) { + struct lport_addresses *laddrs = &ra->laddrs[j]; + for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { + add_route(lflows, peer->od, peer, + peer->lrp_networks.ipv4_addrs[0].addr_s, + laddrs->ipv4_addrs[k].network_s, + laddrs->ipv4_addrs[k].plen, NULL, false, 0, + &peer->nbrp->header_, false, + ROUTE_PRIO_OFFSET_CONNECTED); } } } @@ -12141,7 +12169,7 @@ build_ip_routing_flows_for_lrouter_port( static void build_static_route_flows_for_lrouter( struct ovn_datapath *od, const struct chassis_features *features, - struct hmap *lflows, const struct hmap *ports, + struct hmap *lflows, const struct hmap *lr_ports, const struct hmap *bfd_connections) { if (!od->nbr) { @@ -12165,7 +12193,7 @@ build_static_route_flows_for_lrouter( for (int i = 0; i < od->nbr->n_static_routes; i++) { struct parsed_route *route = - parsed_routes_add(od, ports, &parsed_routes, &route_tables, + parsed_routes_add(od, lr_ports, &parsed_routes, &route_tables, od->nbr->static_routes[i], bfd_connections); if (!route) { continue; @@ -12190,11 +12218,11 @@ build_static_route_flows_for_lrouter( /* add a flow in IP_ROUTING, and one flow for each member in * IP_ROUTING_ECMP. */ build_ecmp_route_flow(lflows, od, features->ct_no_masked_label, - ports, group); + lr_ports, group); } const struct unique_routes_node *ur; HMAP_FOR_EACH (ur, hmap_node, &unique_routes) { - build_static_route_flow(lflows, od, ports, ur->route); + build_static_route_flow(lflows, od, lr_ports, ur->route); } ecmp_groups_destroy(&ecmp_groups); unique_routes_destroy(&unique_routes); @@ -12311,7 +12339,7 @@ build_mcast_lookup_flows_for_lrouter( static void build_ingress_policy_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows, - const struct hmap *ports) + const struct hmap *lr_ports) { if (!od->nbr) { return; @@ -12333,11 +12361,11 @@ build_ingress_policy_flows_for_lrouter( (!strcmp(rule->action, "reroute") && rule->n_nexthops > 1); if (is_ecmp_reroute) { - build_ecmp_routing_policy_flows(lflows, od, ports, rule, + build_ecmp_routing_policy_flows(lflows, od, lr_ports, rule, ecmp_group_id); ecmp_group_id++; } else { - build_routing_policy_flow(lflows, od, ports, rule, + build_routing_policy_flow(lflows, od, lr_ports, rule, &rule->header_); } } @@ -12405,94 +12433,105 @@ routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, * REG_NEXT_HOP_IPV4/REG_NEXT_HOP_IPV6 into an output port in outport and * an Ethernet address in eth.dst. */ + +/* This function adds ARP resolve flows related to a LRP. */ static void -build_arp_resolve_flows_for_lrouter_port( +build_arp_resolve_flows_for_lrp( struct ovn_port *op, struct hmap *lflows, - const struct hmap *ports, struct ds *match, struct ds *actions) { - if (op->nbsp && !lsp_is_enabled(op->nbsp)) { - return; - } - - 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); + ovs_assert(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->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->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); - 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 (is_l3dgw_port(op)) { - 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->cr_port->json_key); - ds_clear(actions); - ds_put_format(actions, "eth.dst = %s; next;", - op->lrp_networks.ea_s); + if (is_l3dgw_port(op)) { + 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->cr_port->json_key); + ds_clear(actions); + ds_put_format(actions, "eth.dst = %s; next;", + op->lrp_networks.ea_s); - ovn_lflow_add_with_hint(lflows, op->od, - S_ROUTER_IN_ARP_RESOLVE, 50, - ds_cstr(match), ds_cstr(actions), - &op->nbrp->header_); - } + ovn_lflow_add_with_hint(lflows, op->od, + S_ROUTER_IN_ARP_RESOLVE, 50, + ds_cstr(match), ds_cstr(actions), + &op->nbrp->header_); } + } - /* Drop IP traffic destined to router owned IPs. Part of it is dropped - * in stage "lr_in_ip_input" but traffic that could have been unSNATed - * but didn't match any existing session might still end up here. - * - * Priority 2. - */ - build_lrouter_drop_own_dest(op, S_ROUTER_IN_ARP_RESOLVE, 2, true, - lflows); - } else if (op->od->n_router_ports && !lsp_is_router(op->nbsp) - && strcmp(op->nbsp->type, "virtual")) { + /* Drop IP traffic destined to router owned IPs. Part of it is dropped + * in stage "lr_in_ip_input" but traffic that could have been unSNATed + * but didn't match any existing session might still end up here. + * + * Priority 2. + */ + build_lrouter_drop_own_dest(op, S_ROUTER_IN_ARP_RESOLVE, 2, true, + lflows); +} + +/* This function adds ARP resolve flows related to a LSP. */ +static void +build_arp_resolve_flows_for_lsp( + struct ovn_port *op, struct hmap *lflows, + const struct hmap *lr_ports, + struct ds *match, struct ds *actions) +{ + ovs_assert(op->nbsp); + if (!lsp_is_enabled(op->nbsp)) { + return; + } + + if (op->od->n_router_ports && !lsp_is_router(op->nbsp) + && 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 @@ -12508,7 +12547,7 @@ build_arp_resolve_flows_for_lrouter_port( * Logical_Switch_Port is connected to, as * 'peer'. */ struct ovn_port *peer = ovn_port_get_peer( - ports, op->od->router_ports[k]); + lr_ports, op->od->router_ports[k]); if (!peer || !peer->nbrp) { continue; } @@ -12539,7 +12578,7 @@ build_arp_resolve_flows_for_lrouter_port( * Logical_Switch_Port is connected to, as * 'peer'. */ struct ovn_port *peer = ovn_port_get_peer( - ports, op->od->router_ports[k]); + lr_ports, op->od->router_ports[k]); if (!peer || !peer->nbrp) { continue; } @@ -12570,7 +12609,7 @@ build_arp_resolve_flows_for_lrouter_port( * 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. */ - struct ovn_port *peer = ovn_port_get_peer(ports, op); + struct ovn_port *peer = ovn_port_get_peer(lr_ports, op); if (!peer || !peer->nbrp) { return; } @@ -12583,7 +12622,7 @@ build_arp_resolve_flows_for_lrouter_port( for (size_t i = 0; i < op->od->n_router_ports; i++) { struct ovn_port *router_port = - ovn_port_get_peer(ports, op->od->router_ports[i]); + ovn_port_get_peer(lr_ports, op->od->router_ports[i]); if (!router_port || !router_port->nbrp) { continue; } @@ -12632,7 +12671,6 @@ build_arp_resolve_flows_for_lrouter_port( } } } - } static void @@ -12716,7 +12754,7 @@ build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu, struct hmap *lflows, static void build_check_pkt_len_flows_for_lrp(struct ovn_port *op, struct hmap *lflows, - const struct hmap *ports, + const struct hmap *lr_ports, const struct shash *meter_groups, struct ds *match, struct ds *actions) @@ -12737,7 +12775,7 @@ build_check_pkt_len_flows_for_lrp(struct ovn_port *op, NULL); for (size_t i = 0; i < op->od->nbr->n_ports; i++) { - struct ovn_port *rp = ovn_port_find(ports, + struct ovn_port *rp = ovn_port_find(lr_ports, op->od->nbr->ports[i]->name); if (!rp || rp == op) { continue; @@ -12766,7 +12804,7 @@ build_check_pkt_len_flows_for_lrp(struct ovn_port *op, static void build_check_pkt_len_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows, - const struct hmap *ports, + const struct hmap *lr_ports, struct ds *match, struct ds *actions, const struct shash *meter_groups) { @@ -12781,12 +12819,12 @@ build_check_pkt_len_flows_for_lrouter( "next;"); for (size_t i = 0; i < od->nbr->n_ports; i++) { - struct ovn_port *rp = ovn_port_find(ports, + struct ovn_port *rp = ovn_port_find(lr_ports, od->nbr->ports[i]->name); if (!rp || !rp->nbrp) { continue; } - build_check_pkt_len_flows_for_lrp(rp, lflows, ports, meter_groups, + build_check_pkt_len_flows_for_lrp(rp, lflows, lr_ports, meter_groups, match, actions); } } @@ -12965,9 +13003,7 @@ build_egress_delivery_flows_for_lrouter_port( struct ovn_port *op, struct hmap *lflows, struct ds *match, struct ds *actions) { - if (!op->nbrp) { - return; - } + ovs_assert(op->nbrp); if (!lrport_is_enabled(op->nbrp)) { /* Drop packets to disabled logical ports (since logical flow * tables are default-drop). */ @@ -13076,7 +13112,8 @@ build_dhcpv6_reply_flows_for_lrouter_port( struct ovn_port *op, struct hmap *lflows, struct ds *match) { - if (!op->nbrp || op->l3dgw_port) { + ovs_assert(op->nbrp); + if (op->l3dgw_port) { return; } for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { @@ -13096,7 +13133,8 @@ build_ipv6_input_flows_for_lrouter_port( struct ds *match, struct ds *actions, const struct shash *meter_groups) { - if (!op->nbrp || is_cr_port(op)) { + ovs_assert(op->nbrp); + if (is_cr_port(op)) { return; } /* No ingress packets are accepted on a chassisredirect @@ -13313,9 +13351,10 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, struct ds *match, struct ds *actions, const struct shash *meter_groups) { + ovs_assert(op->nbrp); /* No ingress packets are accepted on a chassisredirect * port, so no need to program flows for that port. */ - if (!op->nbrp || is_cr_port(op)) { + if (is_cr_port(op)) { return; } if (op->lrp_networks.n_ipv4_addrs) { @@ -14091,7 +14130,7 @@ build_lrouter_ingress_flow(struct hmap *lflows, struct ovn_datapath *od, static int lrouter_check_nat_entry(struct ovn_datapath *od, const struct nbrec_nat *nat, - const struct hmap *ports, ovs_be32 *mask, + const struct hmap *lr_ports, ovs_be32 *mask, bool *is_v6, int *cidr_bits, struct eth_addr *mac, bool *distributed, struct ovn_port **nat_l3dgw_port) { @@ -14150,7 +14189,7 @@ lrouter_check_nat_entry(struct ovn_datapath *od, const struct nbrec_nat *nat, } } } else { - *nat_l3dgw_port = ovn_port_find(ports, nat->gateway_port->name); + *nat_l3dgw_port = ovn_port_find(lr_ports, nat->gateway_port->name); if (!(*nat_l3dgw_port) || (*nat_l3dgw_port)->od != od || !is_l3dgw_port(*nat_l3dgw_port)) { @@ -14219,7 +14258,9 @@ lrouter_check_nat_entry(struct ovn_datapath *od, const struct nbrec_nat *nat, /* NAT, Defrag and load balancing. */ static void build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, - const struct hmap *ports, struct ds *match, + const struct hmap *ls_ports, + const struct hmap *lr_ports, + struct ds *match, struct ds *actions, const struct shash *meter_groups, const struct chassis_features *features) @@ -14324,7 +14365,8 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, int cidr_bits; struct ovn_port *l3dgw_port; - if (lrouter_check_nat_entry(od, nat, ports, &mask, &is_v6, &cidr_bits, + if (lrouter_check_nat_entry(od, nat, lr_ports, &mask, &is_v6, + &cidr_bits, &mac, &distributed, &l3dgw_port) < 0) { continue; } @@ -14439,7 +14481,8 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, * the virtual port has not claimed yet becaused otherwise * the traffic will be centralized misconfiguring the TOR switch. */ - struct ovn_port *op = ovn_port_find(ports, nat->logical_port); + struct ovn_port *op = ovn_port_find(ls_ports, + nat->logical_port); if (op && op->nbsp && !strcmp(op->nbsp->type, "virtual")) { ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 80, ds_cstr(match), @@ -14548,7 +14591,8 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, struct lswitch_flow_build_info { const struct hmap *datapaths; - const struct hmap *ports; + const struct hmap *ls_ports; + const struct hmap *lr_ports; const struct hmap *port_groups; struct hmap *lflows; struct hmap *mcgroups; @@ -14598,13 +14642,13 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, build_ND_RA_flows_for_lrouter(od, lsi->lflows); build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows); build_static_route_flows_for_lrouter(od, lsi->features, - lsi->lflows, lsi->ports, + lsi->lflows, lsi->lr_ports, lsi->bfd_connections); build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match, &lsi->actions); - build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->ports); + build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports); build_arp_resolve_flows_for_lrouter(od, lsi->lflows); - build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->ports, + build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports, &lsi->match, &lsi->actions, lsi->meter_groups); build_gateway_redirect_flows_for_lrouter(od, lsi->lflows, &lsi->match, @@ -14613,18 +14657,22 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, &lsi->actions, lsi->meter_groups); build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows); build_lrouter_arp_nd_for_datapath(od, lsi->lflows, lsi->meter_groups); - build_lrouter_nat_defrag_and_lb(od, lsi->lflows, lsi->ports, &lsi->match, + build_lrouter_nat_defrag_and_lb(od, lsi->lflows, lsi->ls_ports, + lsi->lr_ports, &lsi->match, &lsi->actions, lsi->meter_groups, lsi->features); build_lrouter_lb_affinity_default_flows(od, lsi->lflows); } -/* Helper function to combine all lflow generation which is iterated by port. +/* Helper function to combine all lflow generation which is iterated by logical + * switch port. */ static void -build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op, - struct lswitch_flow_build_info *lsi) +build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, + struct lswitch_flow_build_info *lsi) { + ovs_assert(op->nbsp); + /* Build Logical Switch Flows. */ build_lswitch_port_sec_op(op, lsi->lflows, &lsi->actions, &lsi->match); build_lswitch_learn_fdb_op(op, lsi->lflows, &lsi->actions, @@ -14632,7 +14680,7 @@ build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op, build_lswitch_arp_nd_responder_skip_local(op, lsi->lflows, &lsi->match); build_lswitch_arp_nd_responder_known_ips(op, lsi->lflows, - lsi->ports, + lsi->ls_ports, lsi->meter_groups, &lsi->actions, &lsi->match); @@ -14643,15 +14691,29 @@ build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op, &lsi->actions, &lsi->match); /* Build Logical Router Flows. */ + build_ip_routing_flows_for_router_type_lsp(op, lsi->lr_ports, + lsi->lflows); + build_arp_resolve_flows_for_lsp(op, lsi->lflows, lsi->lr_ports, + &lsi->match, &lsi->actions); +} + +/* Helper function to combine all lflow generation which is iterated by logical + * router port. All the flows built in this function are Logical Router flows. + */ +static void +build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, + struct lswitch_flow_build_info *lsi) +{ + ovs_assert(op->nbrp); build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, &lsi->actions); build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, &lsi->actions); - build_ip_routing_flows_for_lrouter_port(op, lsi->ports, lsi->lflows); + build_ip_routing_flows_for_lrp(op, lsi->lflows); build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, &lsi->actions, lsi->meter_groups); - build_arp_resolve_flows_for_lrouter_port(op, lsi->lflows, lsi->ports, - &lsi->match, &lsi->actions); + build_arp_resolve_flows_for_lrp(op, lsi->lflows, &lsi->match, + &lsi->actions); build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, &lsi->actions); build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match); @@ -14697,14 +14759,27 @@ build_lflows_thread(void *arg) } } for (bnum = control->id; - bnum <= lsi->ports->mask; + bnum <= lsi->ls_ports->mask; + bnum += control->pool->size) + { + HMAP_FOR_EACH_IN_PARALLEL (op, key_node, bnum, + lsi->ls_ports) { + if (stop_parallel_processing()) { + return NULL; + } + build_lswitch_and_lrouter_iterate_by_lsp(op, lsi); + } + } + for (bnum = control->id; + bnum <= lsi->lr_ports->mask; bnum += control->pool->size) { - HMAP_FOR_EACH_IN_PARALLEL (op, key_node, bnum, lsi->ports) { + HMAP_FOR_EACH_IN_PARALLEL (op, key_node, bnum, + lsi->lr_ports) { if (stop_parallel_processing()) { return NULL; } - build_lswitch_and_lrouter_iterate_by_op(op, lsi); + build_lswitch_and_lrouter_iterate_by_lrp(op, lsi); } } for (bnum = control->id; @@ -14785,7 +14860,8 @@ fix_flow_map_size(struct hmap *lflow_map, static void build_lswitch_and_lrouter_flows(const struct hmap *datapaths, - const struct hmap *ports, + const struct hmap *ls_ports, + const struct hmap *lr_ports, const struct hmap *port_groups, struct hmap *lflows, struct hmap *mcgroups, @@ -14812,7 +14888,8 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, */ lsiv[index].lflows = lflows; lsiv[index].datapaths = datapaths; - lsiv[index].ports = ports; + lsiv[index].ls_ports = ls_ports; + lsiv[index].lr_ports = lr_ports; lsiv[index].port_groups = port_groups; lsiv[index].mcgroups = mcgroups; lsiv[index].igmp_groups = igmp_groups; @@ -14844,7 +14921,8 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, struct ovn_igmp_group *igmp_group; struct lswitch_flow_build_info lsi = { .datapaths = datapaths, - .ports = ports, + .ls_ports = ls_ports, + .lr_ports = lr_ports, .port_groups = port_groups, .lflows = lflows, .mcgroups = mcgroups, @@ -14867,8 +14945,11 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, } stopwatch_stop(LFLOWS_DATAPATHS_STOPWATCH_NAME, time_msec()); stopwatch_start(LFLOWS_PORTS_STOPWATCH_NAME, time_msec()); - HMAP_FOR_EACH (op, key_node, ports) { - build_lswitch_and_lrouter_iterate_by_op(op, &lsi); + HMAP_FOR_EACH (op, key_node, ls_ports) { + build_lswitch_and_lrouter_iterate_by_lsp(op, &lsi); + } + HMAP_FOR_EACH (op, key_node, lr_ports) { + build_lswitch_and_lrouter_iterate_by_lrp(op, &lsi); } stopwatch_stop(LFLOWS_PORTS_STOPWATCH_NAME, time_msec()); stopwatch_start(LFLOWS_LBS_STOPWATCH_NAME, time_msec()); @@ -14951,7 +15032,8 @@ void run_update_worker_pool(int n_threads) static void build_mcast_groups(struct lflow_input *data, const struct hmap *datapaths, - const struct hmap *ports, + const struct hmap *ls_ports, + const struct hmap *lr_ports, struct hmap *mcast_groups, struct hmap *igmp_groups); @@ -14964,12 +15046,15 @@ void build_lflows(struct lflow_input *input_data, struct hmap mcast_groups; struct hmap igmp_groups; - build_mcast_groups(input_data, input_data->datapaths, input_data->ports, + build_mcast_groups(input_data, input_data->datapaths, + input_data->ls_ports, input_data->lr_ports, &mcast_groups, &igmp_groups); fast_hmap_size_for(&lflows, max_seen_lflow_size); - build_lswitch_and_lrouter_flows(input_data->datapaths, input_data->ports, + build_lswitch_and_lrouter_flows(input_data->datapaths, + input_data->ls_ports, + input_data->lr_ports, input_data->port_groups, &lflows, &mcast_groups, &igmp_groups, input_data->meter_groups, input_data->lbs, @@ -15743,7 +15828,8 @@ sync_template_vars(struct northd_input *input_data, } static void -destroy_datapaths_and_ports(struct hmap *datapaths, struct hmap *ports, +destroy_datapaths_and_ports(struct hmap *datapaths, struct hmap *ls_ports, + struct hmap *lr_ports, struct ovs_list *lr_list) { struct ovn_datapath *router_dp; @@ -15768,10 +15854,15 @@ destroy_datapaths_and_ports(struct hmap *datapaths, struct hmap *ports, hmap_destroy(datapaths); struct ovn_port *port; - HMAP_FOR_EACH_SAFE (port, key_node, ports) { - ovn_port_destroy(ports, port); + HMAP_FOR_EACH_SAFE (port, key_node, ls_ports) { + ovn_port_destroy(ls_ports, port); + } + hmap_destroy(ls_ports); + + HMAP_FOR_EACH_SAFE (port, key_node, lr_ports) { + ovn_port_destroy(lr_ports, port); } - hmap_destroy(ports); + hmap_destroy(lr_ports); } static void @@ -15810,7 +15901,8 @@ build_ip_mcast(struct northd_input *input_data, static void build_mcast_groups(struct lflow_input *input_data, const struct hmap *datapaths, - const struct hmap *ports, + const struct hmap *ls_ports, + const struct hmap *lr_ports, struct hmap *mcast_groups, struct hmap *igmp_groups) { @@ -15824,8 +15916,8 @@ build_mcast_groups(struct lflow_input *input_data, init_mcast_flow_count(od); } - HMAP_FOR_EACH (op, key_node, ports) { - if (op->nbrp && lrport_is_enabled(op->nbrp)) { + HMAP_FOR_EACH (op, key_node, lr_ports) { + if (lrport_is_enabled(op->nbrp)) { /* If this port is configured to always flood multicast traffic * add it to the MC_STATIC group. */ @@ -15833,7 +15925,11 @@ build_mcast_groups(struct lflow_input *input_data, ovn_multicast_add(mcast_groups, &mc_static, op); op->od->mcast_info.rtr.flood_static = true; } - } else if (op->nbsp && lsp_is_enabled(op->nbsp)) { + } + } + + HMAP_FOR_EACH (op, key_node, ls_ports) { + if (lsp_is_enabled(op->nbsp)) { ovn_multicast_add(mcast_groups, &mc_flood, op); if (!lsp_is_router(op->nbsp)) { @@ -15901,7 +15997,7 @@ build_mcast_groups(struct lflow_input *input_data, /* Extract the IGMP group ports from the SB entry. */ size_t n_igmp_ports; struct ovn_port **igmp_ports = - ovn_igmp_group_get_ports(sb_igmp, &n_igmp_ports, ports); + ovn_igmp_group_get_ports(sb_igmp, &n_igmp_ports, ls_ports); /* It can be that all ports in the IGMP group record already have * mcast_flood=true and then we can skip the group completely. @@ -16039,7 +16135,7 @@ static_mac_binding_by_port_ip(struct northd_input *input_data, static void build_static_mac_binding_table(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *ports) + struct hmap *lr_ports) { /* Cleanup SB Static_MAC_Binding entries which do not have corresponding * NB Static_MAC_Binding entries. */ @@ -16059,7 +16155,7 @@ build_static_mac_binding_table(struct northd_input *input_data, * from NB Static_MAC_Binding entries. */ NBREC_STATIC_MAC_BINDING_TABLE_FOR_EACH ( nb_smb, input_data->nbrec_static_mac_binding_table) { - struct ovn_port *op = ovn_port_find(ports, nb_smb->logical_port); + struct ovn_port *op = ovn_port_find(lr_ports, nb_smb->logical_port); if (op && op->nbrp) { struct ovn_datapath *od = op->od; if (od && od->sb) { @@ -16097,7 +16193,8 @@ void northd_init(struct northd_data *data) { hmap_init(&data->datapaths); - hmap_init(&data->ports); + hmap_init(&data->ls_ports); + hmap_init(&data->lr_ports); hmap_init(&data->port_groups); shash_init(&data->meter_groups); hmap_init(&data->lbs); @@ -16150,8 +16247,8 @@ northd_destroy(struct northd_data *data) */ cleanup_macam(); - destroy_datapaths_and_ports(&data->datapaths, &data->ports, - &data->lr_list); + destroy_datapaths_and_ports(&data->datapaths, &data->ls_ports, + &data->lr_ports, &data->lr_list); destroy_debug_config(); } @@ -16242,21 +16339,23 @@ ovnnb_db_run(struct northd_input *input_data, build_datapaths(input_data, ovnsb_txn, &data->datapaths, &data->lr_list); build_lbs(input_data, &data->datapaths, &data->lbs, &data->lb_groups); build_ports(input_data, ovnsb_txn, sbrec_chassis_by_name, - sbrec_chassis_by_hostname, - &data->datapaths, &data->ports); - build_lb_port_related_data(&data->datapaths, &data->ports, &data->lbs, - &data->lb_groups, input_data, ovnsb_txn); + sbrec_chassis_by_hostname, &data->datapaths, + &data->ls_ports, &data->lr_ports); + build_lb_port_related_data(&data->datapaths, &data->ls_ports, + &data->lbs, &data->lb_groups, input_data, + ovnsb_txn); build_lb_count_dps(&data->lbs); - build_ipam(&data->datapaths, &data->ports); - build_port_group_lswitches(input_data, &data->port_groups, &data->ports); - build_lrouter_groups(&data->ports, &data->lr_list); + build_ipam(&data->datapaths, &data->ls_ports); + build_port_group_lswitches(input_data, &data->port_groups, + &data->ls_ports); + build_lrouter_groups(&data->lr_ports, &data->lr_list); build_ip_mcast(input_data, ovnsb_txn, &data->datapaths); build_meter_groups(input_data, &data->meter_groups); - build_static_mac_binding_table(input_data, ovnsb_txn, &data->ports); + build_static_mac_binding_table(input_data, ovnsb_txn, &data->lr_ports); stopwatch_stop(BUILD_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); stopwatch_start(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); - ovn_update_ipv6_options(&data->ports); - ovn_update_ipv6_prefix(&data->ports); + ovn_update_ipv6_options(&data->lr_ports); + ovn_update_ipv6_prefix(&data->lr_ports); sync_lbs(input_data, ovnsb_txn, &data->datapaths, &data->lbs); sync_port_groups(input_data, ovnsb_txn, &data->port_groups); @@ -16534,7 +16633,7 @@ void northd_run(struct northd_input *input_data, input_data->sbrec_chassis_by_hostname); stopwatch_stop(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec()); stopwatch_start(OVNSB_DB_RUN_STOPWATCH_NAME, time_msec()); - ovnsb_db_run(input_data, ovnnb_txn, ovnsb_txn, &data->ports); + ovnsb_db_run(input_data, ovnnb_txn, ovnsb_txn, &data->ls_ports); stopwatch_stop(OVNSB_DB_RUN_STOPWATCH_NAME, time_msec()); } diff --git a/northd/northd.h b/northd/northd.h index 4d9055296e47..cdb521d46566 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -77,7 +77,8 @@ struct chassis_features { struct northd_data { /* Global state for 'en-northd'. */ struct hmap datapaths; - struct hmap ports; + struct hmap ls_ports; + struct hmap lr_ports; struct hmap port_groups; struct shash meter_groups; struct hmap lbs; @@ -102,7 +103,8 @@ struct lflow_input { struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp; const struct hmap *datapaths; - const struct hmap *ports; + const struct hmap *ls_ports; + const struct hmap *lr_ports; const struct hmap *port_groups; const struct shash *meter_groups; const struct hmap *lbs; From patchwork Tue Mar 21 06:02:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1759302 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PggyM4BBNz2476 for ; Tue, 21 Mar 2023 17:03:23 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id C98D361100; Tue, 21 Mar 2023 06:03:17 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org C98D361100 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id dUiOl98orCxA; Tue, 21 Mar 2023 06:03:10 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id 4EBE5610FD; Tue, 21 Mar 2023 06:03:09 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 4EBE5610FD Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 218A3C0091; Tue, 21 Mar 2023 06:03:08 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1DFC6C0032 for ; Tue, 21 Mar 2023 06:03:03 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id D90754182D for ; Tue, 21 Mar 2023 06:03:02 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org D90754182D X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id DOGBtHQe8uW6 for ; Tue, 21 Mar 2023 06:03:00 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 5133D417D0 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by smtp4.osuosl.org (Postfix) with ESMTPS id 5133D417D0 for ; Tue, 21 Mar 2023 06:02:59 +0000 (UTC) Received: (Authenticated sender: hzhou@ovn.org) by mail.gandi.net (Postfix) with ESMTPSA id 9E93CE0003; Tue, 21 Mar 2023 06:02:56 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Mon, 20 Mar 2023 23:02:32 -0700 Message-Id: <20230321060235.2256118-5-hzhou@ovn.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230321060235.2256118-1-hzhou@ovn.org> References: <20230321060235.2256118-1-hzhou@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 4/7] northd: Split switch and router datapaths. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Similar to the previous commit that splits switch ports and router ports, this patch splits the two types of datapaths in different hmap tables. This is also mainly to help for future incremental processing implementation. As a byproduct, the recompute performance is improved slightly. (Together with the previous commit that splits ports, scale test shows around ~4% improvment) Note: This patch didn't change the ovn_datapath structure, which is used by both switches and routers. It may be a followup improvement in the future if necessary, e.g. to reduce memory footprint. Signed-off-by: Han Zhou --- lib/lb.c | 15 +- lib/lb.h | 6 +- northd/en-lflow.c | 3 +- northd/en-sync-sb.c | 2 +- northd/mac-binding-aging.c | 2 +- northd/northd.c | 946 ++++++++++++++++++++----------------- northd/northd.h | 6 +- 7 files changed, 543 insertions(+), 437 deletions(-) diff --git a/lib/lb.c b/lib/lb.c index 66c8152750a1..37e05c31f918 100644 --- a/lib/lb.c +++ b/lib/lb.c @@ -521,7 +521,7 @@ ovn_lb_get_health_check(const struct nbrec_load_balancer *nbrec_lb, struct ovn_northd_lb * ovn_northd_lb_create(const struct nbrec_load_balancer *nbrec_lb, - size_t n_datapaths) + size_t n_ls_datapaths, size_t n_lr_datapaths) { bool template = smap_get_bool(&nbrec_lb->options, "template", false); bool is_udp = nullable_string_is_equal(nbrec_lb->protocol, "udp"); @@ -560,8 +560,8 @@ ovn_northd_lb_create(const struct nbrec_load_balancer *nbrec_lb, } lb->affinity_timeout = affinity_timeout; - lb->nb_ls_map = bitmap_allocate(n_datapaths); - lb->nb_lr_map = bitmap_allocate(n_datapaths); + lb->nb_ls_map = bitmap_allocate(n_ls_datapaths); + lb->nb_lr_map = bitmap_allocate(n_lr_datapaths); sset_init(&lb->ips_v4); sset_init(&lb->ips_v6); @@ -687,12 +687,13 @@ ovn_northd_lb_destroy(struct ovn_northd_lb *lb) /* Constructs a new 'struct ovn_lb_group' object from the Nb LB Group record * and a hash map of all existing 'struct ovn_northd_lb' objects. Space will - * be allocated for 'max_datapaths' logical switches and the same amount of + * be allocated for 'max_ls_datapaths' logical switches and 'max_lr_datapaths' * logical routers to which this LB Group is applied. Can be filled later * with ovn_lb_group_add_ls() and ovn_lb_group_add_lr() respectively. */ struct ovn_lb_group * ovn_lb_group_create(const struct nbrec_load_balancer_group *nbrec_lb_group, - const struct hmap *lbs, size_t max_datapaths) + const struct hmap *lbs, size_t max_ls_datapaths, + size_t max_lr_datapaths) { struct ovn_lb_group *lb_group; @@ -700,8 +701,8 @@ ovn_lb_group_create(const struct nbrec_load_balancer_group *nbrec_lb_group, lb_group->uuid = nbrec_lb_group->header_.uuid; lb_group->n_lbs = nbrec_lb_group->n_load_balancer; lb_group->lbs = xmalloc(lb_group->n_lbs * sizeof *lb_group->lbs); - lb_group->ls = xmalloc(max_datapaths * sizeof *lb_group->ls); - lb_group->lr = xmalloc(max_datapaths * sizeof *lb_group->lr); + lb_group->ls = xmalloc(max_ls_datapaths * sizeof *lb_group->ls); + lb_group->lr = xmalloc(max_lr_datapaths * sizeof *lb_group->lr); lb_group->lb_ips = ovn_lb_ip_set_create(); for (size_t i = 0; i < nbrec_lb_group->n_load_balancer; i++) { diff --git a/lib/lb.h b/lib/lb.h index ddd41703da44..ba48a0dac4f0 100644 --- a/lib/lb.h +++ b/lib/lb.h @@ -130,7 +130,8 @@ struct ovn_northd_lb_backend { }; struct ovn_northd_lb *ovn_northd_lb_create(const struct nbrec_load_balancer *, - size_t n_datapaths); + size_t n_ls_datapaths, + size_t n_lr_datapaths); struct ovn_northd_lb *ovn_northd_lb_find(const struct hmap *, const struct uuid *); const struct smap *ovn_northd_lb_get_vips(const struct ovn_northd_lb *); @@ -157,7 +158,8 @@ struct ovn_lb_group { struct ovn_lb_group *ovn_lb_group_create( const struct nbrec_load_balancer_group *, const struct hmap *lbs, - size_t max_datapaths); + size_t max_ls_datapaths, + size_t max_lr_datapaths); void ovn_lb_group_destroy(struct ovn_lb_group *lb_group); struct ovn_lb_group *ovn_lb_group_find(const struct hmap *lb_groups, const struct uuid *); diff --git a/northd/en-lflow.c b/northd/en-lflow.c index 9e7a2145e520..995c7cc10e33 100644 --- a/northd/en-lflow.c +++ b/northd/en-lflow.c @@ -54,7 +54,8 @@ void en_lflow_run(struct engine_node *node, void *data OVS_UNUSED) engine_get_input("SB_multicast_group", node), "sbrec_mcast_group_by_name"); - lflow_input.datapaths = &northd_data->datapaths; + lflow_input.ls_datapaths = &northd_data->ls_datapaths; + lflow_input.lr_datapaths = &northd_data->lr_datapaths; lflow_input.ls_ports = &northd_data->ls_ports; lflow_input.lr_ports = &northd_data->lr_ports; lflow_input.port_groups = &northd_data->port_groups; diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c index 6e33901a8a29..d4f4e60eabd6 100644 --- a/northd/en-sync-sb.c +++ b/northd/en-sync-sb.c @@ -91,7 +91,7 @@ en_sync_to_sb_addr_set_run(struct engine_node *node, void *data OVS_UNUSED) sync_addr_sets(nb_address_set_table, nb_port_group_table, sb_address_set_table, eng_ctx->ovnsb_idl_txn, - &northd_data->datapaths); + &northd_data->lr_datapaths); engine_set_node_state(node, EN_UPDATED); } diff --git a/northd/mac-binding-aging.c b/northd/mac-binding-aging.c index 1c30e979e1ac..3bdf1c2ea8d9 100644 --- a/northd/mac-binding-aging.c +++ b/northd/mac-binding-aging.c @@ -109,7 +109,7 @@ en_mac_binding_aging_run(struct engine_node *node, void *data OVS_UNUSED) "sbrec_mac_binding_by_datapath"); struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, &northd_data->datapaths) { + HMAP_FOR_EACH (od, key_node, &northd_data->lr_datapaths) { if (od->sb && od->nbr) { mac_binding_aging_run_for_datapath(od->sb, od->nbr, sbrec_mac_binding_by_datapath, diff --git a/northd/northd.c b/northd/northd.c index 10b16e685adf..baee1786469a 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -947,16 +947,24 @@ ovn_datapath_is_stale(const struct ovn_datapath *od) } static struct ovn_datapath * -ovn_datapath_from_sbrec(const struct hmap *datapaths, +ovn_datapath_from_sbrec(const struct hmap *ls_datapaths, + const struct hmap *lr_datapaths, const struct sbrec_datapath_binding *sb) { struct uuid key; + const struct hmap *dps; - if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key) && - !smap_get_uuid(&sb->external_ids, "logical-router", &key)) { + if (smap_get_uuid(&sb->external_ids, "logical-switch", &key)) { + dps = ls_datapaths; + } else if (smap_get_uuid(&sb->external_ids, "logical-router", &key)) { + dps = lr_datapaths; + } else { + return NULL; + } + if (!dps) { return NULL; } - struct ovn_datapath *od = ovn_datapath_find(datapaths, &key); + struct ovn_datapath *od = ovn_datapath_find(dps, &key); if (od && (od->sb == sb)) { return od; } @@ -1375,9 +1383,15 @@ ovn_datapath_assign_requested_tnl_id(struct northd_input *input_data, } } -/* Array of all datapaths, with 'od->index' being their index in the array. */ -static struct ovn_datapath **datapaths_array = NULL; -static size_t n_datapaths = 0; /* Size of the 'datapaths_array'. */ +/* Array of ls datapaths, with 'od->index' being their index in the array. */ +static struct ovn_datapath **ls_datapaths_array = NULL; +/* Size of the 'ls_datapaths_array'. */ +static size_t n_ls_datapaths = 0; + +/* Array of lr datapaths, with 'od->index' being their index in the array. */ +static struct ovn_datapath **lr_datapaths_array = NULL; +/* Size of the 'lr_datapaths_array'. */ +static size_t n_lr_datapaths = 0; /* Updates the southbound Datapath_Binding table so that it contains the * logical switches and routers specified by the northbound database. @@ -1387,11 +1401,13 @@ static size_t n_datapaths = 0; /* Size of the 'datapaths_array'. */ static void build_datapaths(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *datapaths, + struct hmap *ls_datapaths, + struct hmap *lr_datapaths, struct ovs_list *lr_list) { struct ovs_list sb_only, nb_only, both; + struct hmap *datapaths = ls_datapaths; join_datapaths(input_data, ovnsb_txn, datapaths, &sb_only, &nb_only, &both, lr_list); @@ -1444,17 +1460,37 @@ build_datapaths(struct northd_input *input_data, ovn_datapath_destroy(datapaths, od); } + /* Move lr datapaths to lr_datapaths, and ls datapaths will + * remain in datapaths/ls_datapaths. */ + HMAP_FOR_EACH_SAFE (od, key_node, datapaths) { + if (!od->nbr) { + ovs_assert(od->nbs); + continue; + } + hmap_remove(datapaths, &od->key_node); + hmap_insert(lr_datapaths, &od->key_node, od->key_node.hash); + } + /* Assign unique sequential indexes to all datapaths. These are not * visible outside of the northd loop, so, unlike the tunnel keys, it * doesn't matter if they are different on every iteration. */ size_t index = 0; - n_datapaths = hmap_count(datapaths); - datapaths_array = xrealloc(datapaths_array, - n_datapaths * sizeof *datapaths_array); - HMAP_FOR_EACH (od, key_node, datapaths) { + n_ls_datapaths = hmap_count(ls_datapaths); + ls_datapaths_array = xrealloc(ls_datapaths_array, + n_ls_datapaths * sizeof *ls_datapaths_array); + HMAP_FOR_EACH (od, key_node, ls_datapaths) { + od->index = index; + ls_datapaths_array[index++] = od; + } + + index = 0; + n_lr_datapaths = hmap_count(lr_datapaths); + lr_datapaths_array = xrealloc(lr_datapaths_array, + n_lr_datapaths * sizeof *lr_datapaths_array); + HMAP_FOR_EACH (od, key_node, lr_datapaths) { od->index = index; - datapaths_array[index++] = od; + lr_datapaths_array[index++] = od; } } @@ -2243,7 +2279,7 @@ update_dynamic_addresses(struct dynamic_address_update *update) } static void -build_ipam(struct hmap *datapaths, struct hmap *ls_ports) +build_ipam(struct hmap *ls_datapaths, struct hmap *ls_ports) { /* IPAM generally stands for IP address management. In non-virtualized * world, MAC addresses come with the hardware. But, with virtualized @@ -2257,10 +2293,8 @@ build_ipam(struct hmap *datapaths, struct hmap *ls_ports) struct ovs_list updates; ovs_list_init(&updates); - HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs) { - continue; - } + HMAP_FOR_EACH (od, key_node, ls_datapaths) { + ovs_assert(od->nbs); for (size_t i = 0; i < od->nbs->n_ports; i++) { const struct nbrec_logical_switch_port *nbsp = od->nbs->ports[i]; @@ -2440,8 +2474,8 @@ tag_alloc_create_new_tag(struct hmap *tag_alloc_table, static void join_logical_ports(struct northd_input *input_data, - struct hmap *datapaths, struct hmap *ports, - struct hmap *chassis_qdisc_queues, + struct hmap *ls_datapaths, struct hmap *lr_datapaths, + struct hmap *ports, struct hmap *chassis_qdisc_queues, struct hmap *tag_alloc_table, struct ovs_list *sb_only, struct ovs_list *nb_only, struct ovs_list *both) { @@ -2458,225 +2492,226 @@ join_logical_ports(struct northd_input *input_data, } struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { - if (od->nbs) { - size_t n_allocated_localnet_ports = 0; - for (size_t i = 0; i < od->nbs->n_ports; i++) { - const struct nbrec_logical_switch_port *nbsp - = od->nbs->ports[i]; - struct ovn_port *op = ovn_port_find_bound(ports, nbsp->name); - if (op && (op->od || op->nbsp || op->nbrp)) { - static struct vlog_rate_limit rl - = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "duplicate logical port %s", nbsp->name); - continue; - } else if (op && (!op->sb || op->sb->datapath == od->sb)) { - /* - * Handle cases where lport type was explicitly changed - * in the NBDB, in such cases: - * 1. remove the current sbrec of the affected lport from - * the port_binding table. - * - * 2. create a new sbrec with the same logical_port as the - * deleted lport and add it to the nb_only list which - * will make the northd handle this lport as a new - * created one and recompute everything that is needed - * for this lport. - * - * This change will affect container/virtual lport type - * changes only for now, this change is needed in - * contaier/virtual lport cases to avoid port type - * conflicts in the ovn-controller when the user clears - * the parent_port field in the container lport or updated - * the lport type. - * - */ - bool update_sbrec = false; - if (op->sb && lsp_is_type_changed(op->sb, nbsp, - &update_sbrec) - && update_sbrec) { - ovs_list_remove(&op->list); - sbrec_port_binding_delete(op->sb); - ovn_port_destroy(ports, op); - op = ovn_port_create(ports, nbsp->name, nbsp, - NULL, NULL); - ovs_list_push_back(nb_only, &op->list); - } else { - ovn_port_set_nb(op, nbsp, NULL); - ovs_list_remove(&op->list); - - uint32_t queue_id = smap_get_int(&op->sb->options, - "qdisc_queue_id", 0); - if (queue_id && op->sb->chassis) { - add_chassis_queue( - chassis_qdisc_queues, - &op->sb->chassis->header_.uuid, - queue_id); - } - - ovs_list_push_back(both, &op->list); - - /* This port exists due to a SB binding, but should - * not have been initialized fully. */ - ovs_assert(!op->n_lsp_addrs && !op->n_ps_addrs); - } - } else { - op = ovn_port_create(ports, nbsp->name, nbsp, NULL, NULL); + HMAP_FOR_EACH (od, key_node, ls_datapaths) { + ovs_assert(od->nbs); + size_t n_allocated_localnet_ports = 0; + for (size_t i = 0; i < od->nbs->n_ports; i++) { + const struct nbrec_logical_switch_port *nbsp + = od->nbs->ports[i]; + struct ovn_port *op = ovn_port_find_bound(ports, nbsp->name); + if (op && (op->od || op->nbsp || op->nbrp)) { + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "duplicate logical port %s", nbsp->name); + continue; + } else if (op && (!op->sb || op->sb->datapath == od->sb)) { + /* + * Handle cases where lport type was explicitly changed + * in the NBDB, in such cases: + * 1. remove the current sbrec of the affected lport from + * the port_binding table. + * + * 2. create a new sbrec with the same logical_port as the + * deleted lport and add it to the nb_only list which + * will make the northd handle this lport as a new + * created one and recompute everything that is needed + * for this lport. + * + * This change will affect container/virtual lport type + * changes only for now, this change is needed in + * contaier/virtual lport cases to avoid port type + * conflicts in the ovn-controller when the user clears + * the parent_port field in the container lport or updated + * the lport type. + * + */ + bool update_sbrec = false; + if (op->sb && lsp_is_type_changed(op->sb, nbsp, + &update_sbrec) + && update_sbrec) { + ovs_list_remove(&op->list); + sbrec_port_binding_delete(op->sb); + ovn_port_destroy(ports, op); + op = ovn_port_create(ports, nbsp->name, nbsp, + NULL, NULL); ovs_list_push_back(nb_only, &op->list); - } + } else { + ovn_port_set_nb(op, nbsp, NULL); + ovs_list_remove(&op->list); - if (lsp_is_localnet(nbsp)) { - if (od->n_localnet_ports >= n_allocated_localnet_ports) { - od->localnet_ports = x2nrealloc( - od->localnet_ports, &n_allocated_localnet_ports, - sizeof *od->localnet_ports); - } - od->localnet_ports[od->n_localnet_ports++] = op; - } + uint32_t queue_id = smap_get_int(&op->sb->options, + "qdisc_queue_id", 0); + if (queue_id && op->sb->chassis) { + add_chassis_queue( + chassis_qdisc_queues, + &op->sb->chassis->header_.uuid, + queue_id); + } - if (lsp_is_vtep(nbsp)) { - od->has_vtep_lports = true; - } + ovs_list_push_back(both, &op->list); - op->lsp_addrs - = xmalloc(sizeof *op->lsp_addrs * nbsp->n_addresses); - for (size_t j = 0; j < nbsp->n_addresses; j++) { - if (!strcmp(nbsp->addresses[j], "unknown")) { - op->has_unknown = true; - continue; - } - if (!strcmp(nbsp->addresses[j], "router")) { - continue; - } - if (is_dynamic_lsp_address(nbsp->addresses[j])) { - continue; - } else if (!extract_lsp_addresses(nbsp->addresses[j], - &op->lsp_addrs[op->n_lsp_addrs])) { - static struct vlog_rate_limit rl - = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_INFO_RL(&rl, "invalid syntax '%s' in logical " - "switch port addresses. No MAC " - "address found", - op->nbsp->addresses[j]); - continue; - } - op->n_lsp_addrs++; - } - op->n_lsp_non_router_addrs = op->n_lsp_addrs; - - op->ps_addrs - = xmalloc(sizeof *op->ps_addrs * nbsp->n_port_security); - for (size_t j = 0; j < nbsp->n_port_security; j++) { - if (!extract_lsp_addresses(nbsp->port_security[j], - &op->ps_addrs[op->n_ps_addrs])) { - static struct vlog_rate_limit rl - = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_INFO_RL(&rl, "invalid syntax '%s' in port " - "security. No MAC address found", - op->nbsp->port_security[j]); - continue; - } - op->n_ps_addrs++; + /* This port exists due to a SB binding, but should + * not have been initialized fully. */ + ovs_assert(!op->n_lsp_addrs && !op->n_ps_addrs); } + } else { + op = ovn_port_create(ports, nbsp->name, nbsp, NULL, NULL); + ovs_list_push_back(nb_only, &op->list); + } - op->od = od; - ovs_list_push_back(&od->port_list, &op->dp_node); - tag_alloc_add_existing_tags(tag_alloc_table, nbsp); + if (lsp_is_localnet(nbsp)) { + if (od->n_localnet_ports >= n_allocated_localnet_ports) { + od->localnet_ports = x2nrealloc( + od->localnet_ports, &n_allocated_localnet_ports, + sizeof *od->localnet_ports); + } + od->localnet_ports[od->n_localnet_ports++] = op; } - } else { - size_t n_allocated_l3dgw_ports = 0; - for (size_t i = 0; i < od->nbr->n_ports; i++) { - const struct nbrec_logical_router_port *nbrp - = od->nbr->ports[i]; - struct lport_addresses lrp_networks; - if (!extract_lrp_networks(nbrp, &lrp_networks)) { - static struct vlog_rate_limit rl - = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "bad 'mac' %s", nbrp->mac); + if (lsp_is_vtep(nbsp)) { + od->has_vtep_lports = true; + } + + op->lsp_addrs + = xmalloc(sizeof *op->lsp_addrs * nbsp->n_addresses); + for (size_t j = 0; j < nbsp->n_addresses; j++) { + if (!strcmp(nbsp->addresses[j], "unknown")) { + op->has_unknown = true; continue; } - - if (!lrp_networks.n_ipv4_addrs && !lrp_networks.n_ipv6_addrs) { + if (!strcmp(nbsp->addresses[j], "router")) { continue; } - - struct ovn_port *op = ovn_port_find_bound(ports, nbrp->name); - if (op && (op->od || op->nbsp || op->nbrp)) { + if (is_dynamic_lsp_address(nbsp->addresses[j])) { + continue; + } else if (!extract_lsp_addresses(nbsp->addresses[j], + &op->lsp_addrs[op->n_lsp_addrs])) { static struct vlog_rate_limit rl - = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "duplicate logical router port %s", - nbrp->name); - destroy_lport_addresses(&lrp_networks); + = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_INFO_RL(&rl, "invalid syntax '%s' in logical " + "switch port addresses. No MAC " + "address found", + op->nbsp->addresses[j]); continue; - } else if (op && (!op->sb || op->sb->datapath == od->sb)) { - ovn_port_set_nb(op, NULL, nbrp); - ovs_list_remove(&op->list); - ovs_list_push_back(both, &op->list); + } + op->n_lsp_addrs++; + } + op->n_lsp_non_router_addrs = op->n_lsp_addrs; - /* This port exists but should not have been - * initialized fully. */ - ovs_assert(!op->lrp_networks.n_ipv4_addrs - && !op->lrp_networks.n_ipv6_addrs); - } else { - op = ovn_port_create(ports, nbrp->name, NULL, nbrp, NULL); - ovs_list_push_back(nb_only, &op->list); + op->ps_addrs + = xmalloc(sizeof *op->ps_addrs * nbsp->n_port_security); + for (size_t j = 0; j < nbsp->n_port_security; j++) { + if (!extract_lsp_addresses(nbsp->port_security[j], + &op->ps_addrs[op->n_ps_addrs])) { + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_INFO_RL(&rl, "invalid syntax '%s' in port " + "security. No MAC address found", + op->nbsp->port_security[j]); + continue; } + op->n_ps_addrs++; + } - op->lrp_networks = lrp_networks; - op->od = od; - ovs_list_push_back(&od->port_list, &op->dp_node); + op->od = od; + ovs_list_push_back(&od->port_list, &op->dp_node); + tag_alloc_add_existing_tags(tag_alloc_table, nbsp); + } + } + HMAP_FOR_EACH (od, key_node, lr_datapaths) { + ovs_assert(od->nbr); + size_t n_allocated_l3dgw_ports = 0; + for (size_t i = 0; i < od->nbr->n_ports; i++) { + const struct nbrec_logical_router_port *nbrp + = od->nbr->ports[i]; - if (!od->redirect_bridged) { - const char *redirect_type = - smap_get(&nbrp->options, "redirect-type"); - od->redirect_bridged = - redirect_type && !strcasecmp(redirect_type, "bridged"); - } + struct lport_addresses lrp_networks; + if (!extract_lrp_networks(nbrp, &lrp_networks)) { + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad 'mac' %s", nbrp->mac); + continue; + } - if (op->nbrp->ha_chassis_group || - op->nbrp->n_gateway_chassis) { - /* Additional "derived" ovn_port crp represents the - * instance of op on the gateway chassis. */ - const char *gw_chassis = smap_get(&op->od->nbr->options, - "chassis"); - if (gw_chassis) { - static struct vlog_rate_limit rl - = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_WARN_RL(&rl, "Bad configuration: distributed " - "gateway port configured on port %s " - "on L3 gateway router", nbrp->name); - continue; - } + if (!lrp_networks.n_ipv4_addrs && !lrp_networks.n_ipv6_addrs) { + continue; + } - char *redirect_name = - ovn_chassis_redirect_name(nbrp->name); - struct ovn_port *crp = ovn_port_find(ports, redirect_name); - if (crp && crp->sb && crp->sb->datapath == od->sb) { - ovn_port_set_nb(crp, NULL, nbrp); - ovs_list_remove(&crp->list); - ovs_list_push_back(both, &crp->list); - } else { - crp = ovn_port_create(ports, redirect_name, - NULL, nbrp, NULL); - ovs_list_push_back(nb_only, &crp->list); - } - crp->l3dgw_port = op; - op->cr_port = crp; - crp->od = od; - free(redirect_name); + struct ovn_port *op = ovn_port_find_bound(ports, nbrp->name); + if (op && (op->od || op->nbsp || op->nbrp)) { + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "duplicate logical router port %s", + nbrp->name); + destroy_lport_addresses(&lrp_networks); + continue; + } else if (op && (!op->sb || op->sb->datapath == od->sb)) { + ovn_port_set_nb(op, NULL, nbrp); + ovs_list_remove(&op->list); + ovs_list_push_back(both, &op->list); + + /* This port exists but should not have been + * initialized fully. */ + ovs_assert(!op->lrp_networks.n_ipv4_addrs + && !op->lrp_networks.n_ipv6_addrs); + } else { + op = ovn_port_create(ports, nbrp->name, NULL, nbrp, NULL); + ovs_list_push_back(nb_only, &op->list); + } - /* Add to l3dgw_ports in od, for later use during flow - * creation. */ - if (od->n_l3dgw_ports == n_allocated_l3dgw_ports) { - od->l3dgw_ports = x2nrealloc(od->l3dgw_ports, - &n_allocated_l3dgw_ports, - sizeof *od->l3dgw_ports); - } - od->l3dgw_ports[od->n_l3dgw_ports++] = op; + op->lrp_networks = lrp_networks; + op->od = od; + ovs_list_push_back(&od->port_list, &op->dp_node); - assign_routable_addresses(op); + if (!od->redirect_bridged) { + const char *redirect_type = + smap_get(&nbrp->options, "redirect-type"); + od->redirect_bridged = + redirect_type && !strcasecmp(redirect_type, "bridged"); + } + + if (op->nbrp->ha_chassis_group || + op->nbrp->n_gateway_chassis) { + /* Additional "derived" ovn_port crp represents the + * instance of op on the gateway chassis. */ + const char *gw_chassis = smap_get(&op->od->nbr->options, + "chassis"); + if (gw_chassis) { + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL(&rl, "Bad configuration: distributed " + "gateway port configured on port %s " + "on L3 gateway router", nbrp->name); + continue; } + + char *redirect_name = + ovn_chassis_redirect_name(nbrp->name); + struct ovn_port *crp = ovn_port_find(ports, redirect_name); + if (crp && crp->sb && crp->sb->datapath == od->sb) { + ovn_port_set_nb(crp, NULL, nbrp); + ovs_list_remove(&crp->list); + ovs_list_push_back(both, &crp->list); + } else { + crp = ovn_port_create(ports, redirect_name, + NULL, nbrp, NULL); + ovs_list_push_back(nb_only, &crp->list); + } + crp->l3dgw_port = op; + op->cr_port = crp; + crp->od = od; + free(redirect_name); + + /* Add to l3dgw_ports in od, for later use during flow + * creation. */ + if (od->n_l3dgw_ports == n_allocated_l3dgw_ports) { + od->l3dgw_ports = x2nrealloc(od->l3dgw_ports, + &n_allocated_l3dgw_ports, + sizeof *od->l3dgw_ports); + } + od->l3dgw_ports[od->n_l3dgw_ports++] = op; + + assign_routable_addresses(op); } } } @@ -3704,14 +3739,14 @@ ovn_port_update_sbrec(struct northd_input *input_data, * deleted. */ static void cleanup_mac_bindings(struct northd_input *input_data, - struct hmap *datapaths, + struct hmap *lr_datapaths, struct hmap *lr_ports) { const struct sbrec_mac_binding *b; SBREC_MAC_BINDING_TABLE_FOR_EACH_SAFE (b, input_data->sbrec_mac_binding_table) { const struct ovn_datapath *od = - ovn_datapath_from_sbrec(datapaths, b->datapath); + ovn_datapath_from_sbrec(NULL, lr_datapaths, b->datapath); if (!od || ovn_datapath_is_stale(od) || !ovn_port_find(lr_ports, b->logical_port)) { @@ -3735,14 +3770,14 @@ cleanup_sb_ha_chassis_groups(struct northd_input *input_data, static void cleanup_stale_fdb_entries(struct northd_input *input_data, - struct hmap *datapaths) + struct hmap *ls_datapaths) { const struct sbrec_fdb *fdb_e; SBREC_FDB_TABLE_FOR_EACH_SAFE (fdb_e, input_data->sbrec_fdb_table) { bool delete = true; struct ovn_datapath *od - = ovn_datapath_find_by_key(datapaths, fdb_e->dp_key); + = ovn_datapath_find_by_key(ls_datapaths, fdb_e->dp_key); if (od) { if (ovn_tnlid_present(&od->port_tnlids, fdb_e->port_key)) { delete = false; @@ -3988,8 +4023,8 @@ build_lrouter_lb_ips(struct ovn_lb_ip_set *lb_ips, } static void -build_lbs(struct northd_input *input_data, struct hmap *datapaths, - struct hmap *lbs, struct hmap *lb_groups) +build_lbs(struct northd_input *input_data, struct hmap *ls_datapaths, + struct hmap *lr_datapaths, struct hmap *lbs, struct hmap *lb_groups) { const struct nbrec_load_balancer_group *nbrec_lb_group; struct ovn_lb_group *lb_group; @@ -4002,7 +4037,8 @@ build_lbs(struct northd_input *input_data, struct hmap *datapaths, NBREC_LOAD_BALANCER_TABLE_FOR_EACH (nbrec_lb, input_data->nbrec_load_balancer_table) { struct ovn_northd_lb *lb_nb = ovn_northd_lb_create(nbrec_lb, - n_datapaths); + n_ls_datapaths, + n_lr_datapaths); hmap_insert(lbs, &lb_nb->hmap_node, uuid_hash(&nbrec_lb->header_.uuid)); } @@ -4010,7 +4046,8 @@ build_lbs(struct northd_input *input_data, struct hmap *datapaths, NBREC_LOAD_BALANCER_GROUP_TABLE_FOR_EACH (nbrec_lb_group, input_data->nbrec_load_balancer_group_table) { lb_group = ovn_lb_group_create(nbrec_lb_group, lbs, - hmap_count(datapaths)); + hmap_count(ls_datapaths), + hmap_count(lr_datapaths)); for (size_t i = 0; i < lb_group->n_lbs; i++) { build_lrouter_lb_ips(lb_group->lb_ips, lb_group->lbs[i]); @@ -4021,7 +4058,7 @@ build_lbs(struct northd_input *input_data, struct hmap *datapaths, } struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { + HMAP_FOR_EACH (od, key_node, ls_datapaths) { if (!od->nbs) { continue; } @@ -4048,7 +4085,7 @@ build_lbs(struct northd_input *input_data, struct hmap *datapaths, } } - HMAP_FOR_EACH (od, key_node, datapaths) { + HMAP_FOR_EACH (od, key_node, lr_datapaths) { if (!od->nbr) { continue; } @@ -4198,11 +4235,11 @@ build_lrouter_lb_reachable_ips(struct ovn_datapath *od, } static void -build_lrouter_lbs_check(const struct hmap *datapaths) +build_lrouter_lbs_check(const struct hmap *lr_datapaths) { struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { + HMAP_FOR_EACH (od, key_node, lr_datapaths) { if (!od->nbr) { continue; } @@ -4221,12 +4258,12 @@ build_lrouter_lbs_check(const struct hmap *datapaths) } static void -build_lrouter_lbs_reachable_ips(struct hmap *datapaths, struct hmap *lbs, +build_lrouter_lbs_reachable_ips(struct hmap *lr_datapaths, struct hmap *lbs, struct hmap *lb_groups) { struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { + HMAP_FOR_EACH (od, key_node, lr_datapaths) { if (!od->nbr) { continue; } @@ -4263,8 +4300,8 @@ build_lswitch_lbs_from_lrouter(struct hmap *lbs, struct hmap *lb_groups) size_t index; HMAP_FOR_EACH (lb, hmap_node, lbs) { - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_lr_map) { - struct ovn_datapath *od = datapaths_array[index]; + BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) { + struct ovn_datapath *od = lr_datapaths_array[index]; ovn_northd_lb_add_ls(lb, od->n_ls_peers, od->ls_peers); } } @@ -4288,8 +4325,8 @@ build_lb_count_dps(struct hmap *lbs) struct ovn_northd_lb *lb; HMAP_FOR_EACH (lb, hmap_node, lbs) { - lb->n_nb_lr = bitmap_count1(lb->nb_lr_map, n_datapaths); - lb->n_nb_ls = bitmap_count1(lb->nb_ls_map, n_datapaths); + lb->n_nb_lr = bitmap_count1(lb->nb_lr_map, n_lr_datapaths); + lb->n_nb_ls = bitmap_count1(lb->nb_ls_map, n_ls_datapaths); } } @@ -4298,13 +4335,13 @@ build_lb_count_dps(struct hmap *lbs) * networks to have been parsed. */ static void -build_lb_port_related_data(struct hmap *datapaths, struct hmap *ls_ports, +build_lb_port_related_data(struct hmap *lr_datapaths, struct hmap *ls_ports, struct hmap *lbs, struct hmap *lb_groups, struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn) { - build_lrouter_lbs_check(datapaths); - build_lrouter_lbs_reachable_ips(datapaths, lbs, lb_groups); + build_lrouter_lbs_check(lr_datapaths); + build_lrouter_lbs_reachable_ips(lr_datapaths, lbs, lb_groups); build_lb_svcs(input_data, ovnsb_txn, ls_ports, lbs); build_lswitch_lbs_from_lrouter(lbs, lb_groups); } @@ -4318,12 +4355,13 @@ struct ovn_dp_group { static struct ovn_dp_group * ovn_dp_group_find(const struct hmap *dp_groups, - const unsigned long *dpg_bitmap, uint32_t hash) + const unsigned long *dpg_bitmap, size_t bitmap_len, + uint32_t hash) { struct ovn_dp_group *dpg; HMAP_FOR_EACH_WITH_HASH (dpg, node, hash, dp_groups) { - if (bitmap_equal(dpg->bitmap, dpg_bitmap, n_datapaths)) { + if (bitmap_equal(dpg->bitmap, dpg_bitmap, bitmap_len)) { return dpg; } } @@ -4332,14 +4370,16 @@ ovn_dp_group_find(const struct hmap *dp_groups, static struct sbrec_logical_dp_group * ovn_sb_insert_logical_dp_group(struct ovsdb_idl_txn *ovnsb_txn, - const unsigned long *dpg_bitmap) + const unsigned long *dpg_bitmap, + size_t bitmap_len, + struct ovn_datapath **datapaths_array) { struct sbrec_logical_dp_group *dp_group; const struct sbrec_datapath_binding **sb; size_t n = 0, index; - sb = xmalloc(bitmap_count1(dpg_bitmap, n_datapaths) * sizeof *sb); - BITMAP_FOR_EACH_1 (index, n_datapaths, dpg_bitmap) { + sb = xmalloc(bitmap_count1(dpg_bitmap, bitmap_len) * sizeof *sb); + BITMAP_FOR_EACH_1 (index, bitmap_len, dpg_bitmap) { sb[n++] = datapaths_array[index]->sb; } dp_group = sbrec_logical_dp_group_insert(ovnsb_txn); @@ -4355,7 +4395,7 @@ ovn_sb_insert_logical_dp_group(struct ovsdb_idl_txn *ovnsb_txn, */ static void sync_lbs(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *datapaths, struct hmap *lbs) + struct hmap *ls_datapaths, struct hmap *lbs) { struct hmap dp_groups = HMAP_INITIALIZER(&dp_groups); struct ovn_northd_lb *lb; @@ -4401,11 +4441,11 @@ sync_lbs(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, struct ovn_dp_group *dpg = xzalloc(sizeof *dpg); size_t i, n = 0; - dpg->bitmap = bitmap_allocate(n_datapaths); + dpg->bitmap = bitmap_allocate(n_ls_datapaths); for (i = 0; i < dp_group->n_datapaths; i++) { struct ovn_datapath *datapath_od; - datapath_od = ovn_datapath_from_sbrec(datapaths, + datapath_od = ovn_datapath_from_sbrec(ls_datapaths, NULL, dp_group->datapaths[i]); if (!datapath_od || ovn_datapath_is_stale(datapath_od)) { break; @@ -4416,7 +4456,8 @@ sync_lbs(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, if (i == dp_group->n_datapaths) { uint32_t hash = hash_int(n, 0); - if (!ovn_dp_group_find(&dp_groups, dpg->bitmap, hash)) { + if (!ovn_dp_group_find(&dp_groups, dpg->bitmap, n_ls_datapaths, + hash)) { dpg->dp_group = dp_group; hmap_insert(&dp_groups, &dpg->node, hash); continue; @@ -4459,12 +4500,15 @@ sync_lbs(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, uint32_t hash; hash = hash_int(lb->n_nb_ls, 0); - dpg = ovn_dp_group_find(&dp_groups, lb->nb_ls_map, hash); + dpg = ovn_dp_group_find(&dp_groups, lb->nb_ls_map, n_ls_datapaths, + hash); if (!dpg) { dpg = xzalloc(sizeof *dpg); dpg->dp_group = ovn_sb_insert_logical_dp_group(ovnsb_txn, - lb->nb_ls_map); - dpg->bitmap = bitmap_clone(lb->nb_ls_map, n_datapaths); + lb->nb_ls_map, + n_ls_datapaths, + ls_datapaths_array); + dpg->bitmap = bitmap_clone(lb->nb_ls_map, n_ls_datapaths); hmap_insert(&dp_groups, &dpg->node, hash); } @@ -4490,10 +4534,8 @@ sync_lbs(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, * schema for compatibility reasons. Reset it to empty, just in case. */ struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs) { - continue; - } + HMAP_FOR_EACH (od, key_node, ls_datapaths) { + ovs_assert(od->nbs); if (od->sb->n_load_balancers) { sbrec_datapath_binding_set_load_balancers(od->sb, NULL, 0); @@ -4572,8 +4614,8 @@ build_ports(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, struct ovsdb_idl_index *sbrec_chassis_by_name, struct ovsdb_idl_index *sbrec_chassis_by_hostname, - struct hmap *datapaths, struct hmap *ls_ports, - struct hmap *lr_ports) + struct hmap *ls_datapaths, struct hmap *lr_datapaths, + struct hmap *ls_ports, struct hmap *lr_ports) { struct ovs_list sb_only, nb_only, both; struct hmap tag_alloc_table = HMAP_INITIALIZER(&tag_alloc_table); @@ -4586,8 +4628,8 @@ build_ports(struct northd_input *input_data, /* Borrow ls_ports for joining NB and SB for both LSPs and LRPs. * We will split them later. */ struct hmap *ports = ls_ports; - join_logical_ports(input_data, - datapaths, ports, &chassis_qdisc_queues, + join_logical_ports(input_data, ls_datapaths, lr_datapaths, + ports, &chassis_qdisc_queues, &tag_alloc_table, &sb_only, &nb_only, &both); /* Purge stale Mac_Bindings if ports are deleted. */ @@ -4669,7 +4711,7 @@ build_ports(struct northd_input *input_data, } if (remove_mac_bindings) { - cleanup_mac_bindings(input_data, datapaths, lr_ports); + cleanup_mac_bindings(input_data, lr_datapaths, lr_ports); } tag_alloc_destroy(&tag_alloc_table); @@ -5101,11 +5143,11 @@ static int parallelization_state = STATE_NULL; static void ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od, - enum ovn_stage stage, uint16_t priority, + size_t dp_bitmap_len, enum ovn_stage stage, uint16_t priority, char *match, char *actions, char *io_port, char *ctrl_meter, char *stage_hint, const char *where) { - lflow->dpg_bitmap = bitmap_allocate(n_datapaths); + lflow->dpg_bitmap = bitmap_allocate(dp_bitmap_len); lflow->od = od; lflow->stage = stage; lflow->priority = priority; @@ -5219,14 +5261,15 @@ static thread_local size_t thread_lflow_counter = 0; static void ovn_dp_group_add_with_reference(struct ovn_lflow *lflow_ref, const struct ovn_datapath *od, - const unsigned long *dp_bitmap) + const unsigned long *dp_bitmap, + size_t bitmap_len) OVS_REQUIRES(fake_hash_mutex) { if (od) { bitmap_set1(lflow_ref->dpg_bitmap, od->index); } if (dp_bitmap) { - bitmap_or(lflow_ref->dpg_bitmap, dp_bitmap, n_datapaths); + bitmap_or(lflow_ref->dpg_bitmap, dp_bitmap, bitmap_len); } } @@ -5246,10 +5289,13 @@ do_ovn_lflow_add(struct hmap *lflow_map, const struct ovn_datapath *od, struct ovn_lflow *old_lflow; struct ovn_lflow *lflow; + size_t n_datapaths = ovn_stage_to_datapath_type(stage) == DP_SWITCH ? + n_ls_datapaths : n_lr_datapaths; + old_lflow = ovn_lflow_find(lflow_map, NULL, stage, priority, match, actions, ctrl_meter, hash); if (old_lflow) { - ovn_dp_group_add_with_reference(old_lflow, od, dp_bitmap); + ovn_dp_group_add_with_reference(old_lflow, od, dp_bitmap, n_datapaths); return; } @@ -5257,13 +5303,13 @@ do_ovn_lflow_add(struct hmap *lflow_map, const struct ovn_datapath *od, /* While adding new logical flows we're not setting single datapath, but * collecting a group. 'od' will be updated later for all flows with only * one datapath in a group, so it could be hashed correctly. */ - ovn_lflow_init(lflow, NULL, stage, priority, + ovn_lflow_init(lflow, NULL, n_datapaths, stage, priority, xstrdup(match), xstrdup(actions), io_port ? xstrdup(io_port) : NULL, nullable_xstrdup(ctrl_meter), ovn_lflow_hint(stage_hint), where); - ovn_dp_group_add_with_reference(lflow, od, dp_bitmap); + ovn_dp_group_add_with_reference(lflow, od, dp_bitmap, n_datapaths); if (parallelization_state != STATE_USE_PARALLELIZATION) { hmap_insert(lflow_map, &lflow->hmap_node, hash); @@ -5772,9 +5818,7 @@ static void build_lswitch_learn_fdb_od( struct ovn_datapath *od, struct hmap *lflows) { - if (!od->nbs) { - return; - } + ovs_assert(od->nbs); ovn_lflow_add(lflows, od, S_SWITCH_IN_LOOKUP_FDB, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_PUT_FDB, 0, "1", "next;"); } @@ -5786,9 +5830,7 @@ static void build_lswitch_output_port_sec_od(struct ovn_datapath *od, struct hmap *lflows) { - if (!od->nbs) { - return; - } + ovs_assert(od->nbs); ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 100, "eth.mcast", REGBIT_PORT_SEC_DROP" = 0; next;"); ovn_lflow_add(lflows, od, S_SWITCH_OUT_CHECK_PORT_SEC, 0, "1", @@ -7166,7 +7208,7 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, char *lb_action, const unsigned long *dp_bitmap) { if (!lb->affinity_timeout || - bitmap_is_all_zeros(dp_bitmap, n_datapaths)) { + bitmap_is_all_zeros(dp_bitmap, n_lr_datapaths)) { return; } @@ -7476,9 +7518,7 @@ static void build_lswitch_lb_affinity_default_flows(struct ovn_datapath *od, struct hmap *lflows) { - if (!od->nbs) { - return; - } + ovs_assert(od->nbs); ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_CHECK, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_LB_AFF_LEARN, 0, "1", "next;"); } @@ -7487,9 +7527,7 @@ static void build_lrouter_lb_affinity_default_flows(struct ovn_datapath *od, struct hmap *lflows) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_CHECK, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_ROUTER_IN_LB_AFF_LEARN, 0, "1", "next;"); } @@ -7539,9 +7577,9 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, if (reject) { size_t index; - dp_non_meter = bitmap_clone(lb->nb_ls_map, n_datapaths); - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_ls_map) { - struct ovn_datapath *od = datapaths_array[index]; + dp_non_meter = bitmap_clone(lb->nb_ls_map, n_ls_datapaths); + BITMAP_FOR_EACH_1 (index, n_ls_datapaths, lb->nb_ls_map) { + struct ovn_datapath *od = ls_datapaths_array[index]; meter = copp_meter_get(COPP_REJECT, od->nbs->copp, meter_groups); @@ -7717,8 +7755,8 @@ build_vtep_hairpin(struct ovn_datapath *od, struct hmap *lflows) static void build_fwd_group_lflows(struct ovn_datapath *od, struct hmap *lflows) { - - if (!od->nbs || !od->nbs->n_forwarding_groups) { + ovs_assert(od->nbs); + if (!od->nbs->n_forwarding_groups) { return; } struct ds match = DS_EMPTY_INITIALIZER; @@ -8399,9 +8437,7 @@ build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath *od, struct hmap *lflows, const struct shash *meter_groups) { - if (!od->nbs) { - return; - } + ovs_assert(od->nbs); ls_get_acl_flags(od); build_pre_acls(od, port_groups, lflows); @@ -8421,9 +8457,7 @@ static void build_lswitch_lflows_admission_control(struct ovn_datapath *od, struct hmap *lflows) { - if (!od->nbs) { - return; - } + ovs_assert(od->nbs); /* Logical VLANs not supported. */ if (!is_vlan_transparent(od)) { /* Block logical VLANs. */ @@ -8786,9 +8820,8 @@ static void build_lswitch_arp_nd_responder_default(struct ovn_datapath *od, struct hmap *lflows) { - if (od->nbs) { - ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;"); - } + ovs_assert(od->nbs); + ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;"); } /* Ingress table 19: ARP/ND responder for service monitor source ip. @@ -8921,9 +8954,7 @@ static void build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od, struct hmap *lflows) { - if (!od->nbs) { - return; - } + ovs_assert(od->nbs); ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_OPTIONS, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_RESPONSE, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 0, "1", "next;"); @@ -8939,7 +8970,8 @@ build_lswitch_dns_lookup_and_response(struct ovn_datapath *od, struct hmap *lflows, const struct shash *meter_groups) { - if (!od->nbs || !ls_has_dns_records(od->nbs)) { + ovs_assert(od->nbs); + if (!ls_has_dns_records(od->nbs)) { return; } ovn_lflow_metered(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 100, @@ -8986,9 +9018,7 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, struct ds *actions, const struct shash *meter_groups) { - if (!od->nbs) { - return; - } + ovs_assert(od->nbs); ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 110, "eth.dst == $svc_monitor_mac", @@ -10650,14 +10680,14 @@ build_gw_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx, bool build_non_meter = false; size_t index; - if (bitmap_is_all_zeros(dp_bitmap, n_datapaths)) { + if (bitmap_is_all_zeros(dp_bitmap, n_lr_datapaths)) { return; } if (ctx->reject) { - dp_non_meter = bitmap_clone(dp_bitmap, n_datapaths); - BITMAP_FOR_EACH_1 (index, n_datapaths, dp_bitmap) { - struct ovn_datapath *od = datapaths_array[index]; + dp_non_meter = bitmap_clone(dp_bitmap, n_lr_datapaths); + BITMAP_FOR_EACH_1 (index, n_lr_datapaths, dp_bitmap) { + struct ovn_datapath *od = lr_datapaths_array[index]; const char *meter; meter = copp_meter_get(COPP_REJECT, od->nbr->copp, @@ -10795,15 +10825,15 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, unsigned long *dp_bitmap[LROUTER_NAT_LB_FLOW_MAX + 2]; for (size_t i = 0; i < LROUTER_NAT_LB_FLOW_MAX + 2; i++) { - dp_bitmap[i] = bitmap_allocate(n_datapaths); + dp_bitmap[i] = bitmap_allocate(n_lr_datapaths); } /* Group gw router since we do not have datapath dependency in * lflow generation for them. */ size_t index; - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_lr_map) { - struct ovn_datapath *od = datapaths_array[index]; + BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) { + struct ovn_datapath *od = lr_datapaths_array[index]; enum lrouter_nat_lb_flow_type type; if (lb->skip_snat) { @@ -10897,8 +10927,8 @@ build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, } size_t index; - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_ls_map) { - struct ovn_datapath *od = datapaths_array[index]; + BITMAP_FOR_EACH_1 (index, n_ls_datapaths, lb->nb_ls_map) { + struct ovn_datapath *od = ls_datapaths_array[index]; ovn_lflow_add_with_hint__(lflows, od, S_SWITCH_IN_PRE_LB, 130, ds_cstr(match), @@ -11001,8 +11031,8 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, continue; } - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_lr_map) { - struct ovn_datapath *od = datapaths_array[index]; + BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) { + struct ovn_datapath *od = lr_datapaths_array[index]; ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, 130, ds_cstr(match), ds_cstr(action), @@ -11015,8 +11045,8 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, } if (lb->skip_snat) { - BITMAP_FOR_EACH_1 (index, n_datapaths, lb->nb_lr_map) { - struct ovn_datapath *od = datapaths_array[index]; + BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) { + struct ovn_datapath *od = lr_datapaths_array[index]; ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120, "flags.skip_snat_for_lb == 1 && ip", "next;"); @@ -11619,9 +11649,7 @@ static void build_adm_ctrl_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); /* Logical VLANs not supported. * Broadcast/multicast source address is invalid. */ ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100, @@ -11776,9 +11804,7 @@ build_neigh_learning_flows_for_lrouter( struct ds *match, struct ds *actions, const struct shash *meter_groups) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); /* Learn MAC bindings from ARP/IPv6 ND. * @@ -12066,10 +12092,9 @@ build_ND_RA_flows_for_lrouter_port( static void build_ND_RA_flows_for_lrouter(struct ovn_datapath *od, struct hmap *lflows) { - if (od->nbr) { - ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_OPTIONS, 0, "1", "next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, "1", "next;"); - } + ovs_assert(od->nbr); + ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_OPTIONS, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, "1", "next;"); } /* Logical router ingress table IP_ROUTING_PRE: @@ -12078,10 +12103,9 @@ static void build_ip_routing_pre_flows_for_lrouter(struct ovn_datapath *od, struct hmap *lflows) { - if (od->nbr) { - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_PRE, 0, "1", - REG_ROUTE_TABLE_ID" = 0; next;"); - } + ovs_assert(od->nbr); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_PRE, 0, "1", + REG_ROUTE_TABLE_ID" = 0; next;"); } /* Logical router ingress table IP_ROUTING : IP Routing. @@ -12172,9 +12196,7 @@ build_static_route_flows_for_lrouter( struct hmap *lflows, const struct hmap *lr_ports, const struct hmap *bfd_connections) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP); ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING); ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 150, @@ -12238,9 +12260,7 @@ build_mcast_lookup_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows, struct ds *match, struct ds *actions) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); /* Drop IPv6 multicast traffic that shouldn't be forwarded, * i.e., router solicitation and router advertisement. @@ -12341,9 +12361,7 @@ build_ingress_policy_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows, const struct hmap *lr_ports) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); /* This is a catch-all rule. It has the lowest priority (0) * does a match-all("1") and pass-through (next) */ ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY, 0, "1", @@ -12376,9 +12394,7 @@ static void build_arp_resolve_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); /* Multicast packets already have the outport set so just advance to * next table (priority 500). */ ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 500, @@ -12808,9 +12824,7 @@ build_check_pkt_len_flows_for_lrouter( struct ds *match, struct ds *actions, const struct shash *meter_groups) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); /* Packets are allowed by default. */ ovn_lflow_add(lflows, od, S_ROUTER_IN_CHK_PKT_LEN, 0, "1", @@ -12835,9 +12849,7 @@ build_gateway_redirect_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows, struct ds *match, struct ds *actions) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); for (size_t i = 0; i < od->n_l3dgw_ports; i++) { if (l3dgw_port_has_associated_vtep_lports(od->l3dgw_ports[i])) { /* Skip adding redirect lflow for vtep-enabled l3dgw ports. @@ -12924,9 +12936,7 @@ build_arp_request_flows_for_lrouter( struct ds *match, struct ds *actions, const struct shash *meter_groups) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); for (int i = 0; i < od->nbr->n_static_routes; i++) { const struct nbrec_logical_router_static_route *route; @@ -13044,9 +13054,7 @@ static void build_misc_local_traffic_drop_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); /* Allow IGMP and MLD packets (with TTL = 1) if the router is * configured to flood them statically on some ports. */ @@ -13300,9 +13308,7 @@ build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od, struct hmap *lflows, const struct shash *meter_groups) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); /* Priority-90-92 flows handle ARP requests and ND packets. Most are * per logical port but DNAT addresses can be handled per datapath * for non gateway router ports. @@ -14265,9 +14271,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, const struct shash *meter_groups, const struct chassis_features *features) { - if (!od->nbr) { - return; - } + ovs_assert(od->nbr); /* Packets are allowed by default. */ ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 0, "1", "next;"); @@ -14590,7 +14594,8 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, struct lswitch_flow_build_info { - const struct hmap *datapaths; + const struct hmap *ls_datapaths; + const struct hmap *lr_datapaths; const struct hmap *ls_ports; const struct hmap *lr_ports; const struct hmap *port_groups; @@ -14608,17 +14613,16 @@ struct lswitch_flow_build_info { }; /* Helper function to combine all lflow generation which is iterated by - * datapath. + * logical switch datapath. * * When extending the function new "work data" must be added to the lsi * struct, not passed as an argument. */ - static void -build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, +build_lswitch_and_lrouter_iterate_by_ls(struct ovn_datapath *od, struct lswitch_flow_build_info *lsi) { - /* Build Logical Switch Flows. */ + ovs_assert(od->nbs); build_lswitch_lflows_pre_acl_and_acl(od, lsi->port_groups, lsi->features, lsi->lflows, @@ -14634,8 +14638,16 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, lsi->meter_groups); build_lswitch_output_port_sec_od(od, lsi->lflows); build_lswitch_lb_affinity_default_flows(od, lsi->lflows); +} - /* Build Logical Router Flows. */ +/* Helper function to combine all lflow generation which is iterated by + * logical router datapath. + */ +static void +build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od, + struct lswitch_flow_build_info *lsi) +{ + ovs_assert(od->nbr); build_adm_ctrl_flows_for_lrouter(od, lsi->lflows); build_neigh_learning_flows_for_lrouter(od, lsi->lflows, &lsi->match, &lsi->actions, lsi->meter_groups); @@ -14748,14 +14760,27 @@ build_lflows_thread(void *arg) if (lsi) { /* Iterate over bucket ThreadID, ThreadID+size, ... */ for (bnum = control->id; - bnum <= lsi->datapaths->mask; + bnum <= lsi->ls_datapaths->mask; + bnum += control->pool->size) + { + HMAP_FOR_EACH_IN_PARALLEL (od, key_node, bnum, + lsi->ls_datapaths) { + if (stop_parallel_processing()) { + return NULL; + } + build_lswitch_and_lrouter_iterate_by_ls(od, lsi); + } + } + for (bnum = control->id; + bnum <= lsi->lr_datapaths->mask; bnum += control->pool->size) { - HMAP_FOR_EACH_IN_PARALLEL (od, key_node, bnum, lsi->datapaths) { + HMAP_FOR_EACH_IN_PARALLEL (od, key_node, bnum, + lsi->lr_datapaths) { if (stop_parallel_processing()) { return NULL; } - build_lswitch_and_lrouter_iterate_by_od(od, lsi); + build_lswitch_and_lrouter_iterate_by_lr(od, lsi); } } for (bnum = control->id; @@ -14859,7 +14884,8 @@ fix_flow_map_size(struct hmap *lflow_map, } static void -build_lswitch_and_lrouter_flows(const struct hmap *datapaths, +build_lswitch_and_lrouter_flows(const struct hmap *ls_datapaths, + const struct hmap *lr_datapaths, const struct hmap *ls_ports, const struct hmap *lr_ports, const struct hmap *port_groups, @@ -14887,7 +14913,8 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, * on a per-bucket level. */ lsiv[index].lflows = lflows; - lsiv[index].datapaths = datapaths; + lsiv[index].ls_datapaths = ls_datapaths; + lsiv[index].lr_datapaths = lr_datapaths; lsiv[index].ls_ports = ls_ports; lsiv[index].lr_ports = lr_ports; lsiv[index].port_groups = port_groups; @@ -14920,7 +14947,8 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, struct ovn_northd_lb *lb; struct ovn_igmp_group *igmp_group; struct lswitch_flow_build_info lsi = { - .datapaths = datapaths, + .ls_datapaths = ls_datapaths, + .lr_datapaths = lr_datapaths, .ls_ports = ls_ports, .lr_ports = lr_ports, .port_groups = port_groups, @@ -14940,8 +14968,11 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, * will move here and will be reogranized by iterator type. */ stopwatch_start(LFLOWS_DATAPATHS_STOPWATCH_NAME, time_msec()); - HMAP_FOR_EACH (od, key_node, datapaths) { - build_lswitch_and_lrouter_iterate_by_od(od, &lsi); + HMAP_FOR_EACH (od, key_node, ls_datapaths) { + build_lswitch_and_lrouter_iterate_by_ls(od, &lsi); + } + HMAP_FOR_EACH (od, key_node, lr_datapaths) { + build_lswitch_and_lrouter_iterate_by_lr(od, &lsi); } stopwatch_stop(LFLOWS_DATAPATHS_STOPWATCH_NAME, time_msec()); stopwatch_start(LFLOWS_PORTS_STOPWATCH_NAME, time_msec()); @@ -14978,7 +15009,7 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, } free(svc_check_match); - build_lswitch_flows(datapaths, lflows); + build_lswitch_flows(ls_datapaths, lflows); } static void @@ -14986,12 +15017,14 @@ ovn_sb_set_lflow_logical_dp_group( struct ovsdb_idl_txn *ovnsb_txn, struct hmap *dp_groups, const struct sbrec_logical_flow *sbflow, - const unsigned long *dpg_bitmap) + const unsigned long *dpg_bitmap, + size_t bitmap_len, + struct ovn_datapath **datapaths_array) { struct ovn_dp_group *dpg; size_t n_ods; - n_ods = bitmap_count1(dpg_bitmap, n_datapaths); + n_ods = bitmap_count1(dpg_bitmap, bitmap_len); if (!n_ods) { sbrec_logical_flow_set_logical_dp_group(sbflow, NULL); @@ -15000,11 +15033,14 @@ ovn_sb_set_lflow_logical_dp_group( ovs_assert(n_ods != 1); - dpg = ovn_dp_group_find(dp_groups, dpg_bitmap, hash_int(n_ods, 0)); + dpg = ovn_dp_group_find(dp_groups, dpg_bitmap, bitmap_len, + hash_int(n_ods, 0)); ovs_assert(dpg != NULL); if (!dpg->dp_group) { - dpg->dp_group = ovn_sb_insert_logical_dp_group(ovnsb_txn, dpg->bitmap); + dpg->dp_group = ovn_sb_insert_logical_dp_group(ovnsb_txn, dpg->bitmap, + bitmap_len, + datapaths_array); } sbrec_logical_flow_set_logical_dp_group(sbflow, dpg->dp_group); } @@ -15031,7 +15067,7 @@ void run_update_worker_pool(int n_threads) static void build_mcast_groups(struct lflow_input *data, - const struct hmap *datapaths, + const struct hmap *ls_datapaths, const struct hmap *ls_ports, const struct hmap *lr_ports, struct hmap *mcast_groups, @@ -15046,13 +15082,14 @@ void build_lflows(struct lflow_input *input_data, struct hmap mcast_groups; struct hmap igmp_groups; - build_mcast_groups(input_data, input_data->datapaths, + build_mcast_groups(input_data, input_data->ls_datapaths, input_data->ls_ports, input_data->lr_ports, &mcast_groups, &igmp_groups); fast_hmap_size_for(&lflows, max_seen_lflow_size); - build_lswitch_and_lrouter_flows(input_data->datapaths, + build_lswitch_and_lrouter_flows(input_data->ls_datapaths, + input_data->lr_datapaths, input_data->ls_ports, input_data->lr_ports, input_data->port_groups, &lflows, @@ -15076,7 +15113,8 @@ void build_lflows(struct lflow_input *input_data, stopwatch_start(LFLOWS_DP_GROUPS_STOPWATCH_NAME, time_msec()); /* Collecting all unique datapath groups. */ - struct hmap dp_groups = HMAP_INITIALIZER(&dp_groups); + struct hmap ls_dp_groups = HMAP_INITIALIZER(&ls_dp_groups); + struct hmap lr_dp_groups = HMAP_INITIALIZER(&lr_dp_groups); struct hmap single_dp_lflows; /* Single dp_flows will never grow bigger than lflows, @@ -15092,6 +15130,19 @@ void build_lflows(struct lflow_input *input_data, struct ovn_dp_group *dpg; uint32_t hash, n_ods; + struct hmap *dp_groups; + size_t n_datapaths; + struct ovn_datapath **datapaths_array; + if (ovn_stage_to_datapath_type(lflow->stage) == DP_SWITCH) { + n_datapaths = n_ls_datapaths; + dp_groups = &ls_dp_groups; + datapaths_array = ls_datapaths_array; + } else { + n_datapaths = n_lr_datapaths; + dp_groups = &lr_dp_groups; + datapaths_array = lr_datapaths_array; + } + n_ods = bitmap_count1(lflow->dpg_bitmap, n_datapaths); ovs_assert(n_ods); @@ -15117,11 +15168,12 @@ void build_lflows(struct lflow_input *input_data, } hash = hash_int(n_ods, 0); - dpg = ovn_dp_group_find(&dp_groups, lflow->dpg_bitmap, hash); + dpg = ovn_dp_group_find(dp_groups, lflow->dpg_bitmap, n_datapaths, + hash); if (!dpg) { dpg = xzalloc(sizeof *dpg); dpg->bitmap = bitmap_clone(lflow->dpg_bitmap, n_datapaths); - hmap_insert(&dp_groups, &dpg->node, hash); + hmap_insert(dp_groups, &dpg->node, hash); } lflow->dpg = dpg; } @@ -15147,7 +15199,9 @@ void build_lflows(struct lflow_input *input_data, struct sbrec_datapath_binding *dp = sbflow->logical_datapath; if (dp) { logical_datapath_od = ovn_datapath_from_sbrec( - input_data->datapaths, dp); + input_data->ls_datapaths, + input_data->lr_datapaths, + dp); if (logical_datapath_od && ovn_datapath_is_stale(logical_datapath_od)) { logical_datapath_od = NULL; @@ -15155,7 +15209,9 @@ void build_lflows(struct lflow_input *input_data, } for (i = 0; dp_group && i < dp_group->n_datapaths; i++) { logical_datapath_od = ovn_datapath_from_sbrec( - input_data->datapaths, dp_group->datapaths[i]); + input_data->ls_datapaths, + input_data->lr_datapaths, + dp_group->datapaths[i]); if (logical_datapath_od && !ovn_datapath_is_stale(logical_datapath_od)) { break; @@ -15179,6 +15235,18 @@ void build_lflows(struct lflow_input *input_data, sbflow->priority, sbflow->match, sbflow->actions, sbflow->controller_meter, sbflow->hash); if (lflow) { + struct hmap *dp_groups; + size_t n_datapaths; + struct ovn_datapath **datapaths_array; + if (ovn_stage_to_datapath_type(lflow->stage) == DP_SWITCH) { + n_datapaths = n_ls_datapaths; + dp_groups = &ls_dp_groups; + datapaths_array = ls_datapaths_array; + } else { + n_datapaths = n_lr_datapaths; + dp_groups = &lr_dp_groups; + datapaths_array = lr_datapaths_array; + } if (input_data->ovn_internal_version_changed) { const char *stage_name = smap_get_def(&sbflow->external_ids, "stage-name", ""); @@ -15231,7 +15299,8 @@ void build_lflows(struct lflow_input *input_data, /* Check all logical datapaths from the group. */ for (i = 0; i < dp_group->n_datapaths; i++) { od = ovn_datapath_from_sbrec( - input_data->datapaths, dp_group->datapaths[i]); + input_data->ls_datapaths, input_data->lr_datapaths, + dp_group->datapaths[i]); if (!od || ovn_datapath_is_stale(od)) { continue; } @@ -15244,8 +15313,10 @@ void build_lflows(struct lflow_input *input_data, } if (update_dp_group) { - ovn_sb_set_lflow_logical_dp_group(ovnsb_txn, &dp_groups, - sbflow, lflow->dpg_bitmap); + ovn_sb_set_lflow_logical_dp_group(ovnsb_txn, dp_groups, + sbflow, lflow->dpg_bitmap, + n_datapaths, + datapaths_array); } else if (lflow->dpg && !lflow->dpg->dp_group) { /* Setting relation between unique datapath group and * Sb DB datapath goup. */ @@ -15263,12 +15334,26 @@ void build_lflows(struct lflow_input *input_data, const char *pipeline = ovn_stage_get_pipeline_name(lflow->stage); uint8_t table = ovn_stage_get_table(lflow->stage); + struct hmap *dp_groups; + size_t n_datapaths; + struct ovn_datapath **datapaths_array; + if (ovn_stage_to_datapath_type(lflow->stage) == DP_SWITCH) { + n_datapaths = n_ls_datapaths; + dp_groups = &ls_dp_groups; + datapaths_array = ls_datapaths_array; + } else { + n_datapaths = n_lr_datapaths; + dp_groups = &lr_dp_groups; + datapaths_array = lr_datapaths_array; + } + sbflow = sbrec_logical_flow_insert(ovnsb_txn); if (lflow->od) { sbrec_logical_flow_set_logical_datapath(sbflow, lflow->od->sb); } - ovn_sb_set_lflow_logical_dp_group(ovnsb_txn, &dp_groups, - sbflow, lflow->dpg_bitmap); + ovn_sb_set_lflow_logical_dp_group(ovnsb_txn, dp_groups, + sbflow, lflow->dpg_bitmap, + n_datapaths, datapaths_array); sbrec_logical_flow_set_pipeline(sbflow, pipeline); sbrec_logical_flow_set_table_id(sbflow, table); sbrec_logical_flow_set_priority(sbflow, lflow->priority); @@ -15309,18 +15394,25 @@ void build_lflows(struct lflow_input *input_data, stopwatch_stop(LFLOWS_TO_SB_STOPWATCH_NAME, time_msec()); struct ovn_dp_group *dpg; - HMAP_FOR_EACH_POP (dpg, node, &dp_groups) { + HMAP_FOR_EACH_POP (dpg, node, &ls_dp_groups) { bitmap_free(dpg->bitmap); free(dpg); } - hmap_destroy(&dp_groups); + hmap_destroy(&ls_dp_groups); + HMAP_FOR_EACH_POP (dpg, node, &lr_dp_groups) { + bitmap_free(dpg->bitmap); + free(dpg); + } + hmap_destroy(&lr_dp_groups); /* Push changes to the Multicast_Group table to database. */ const struct sbrec_multicast_group *sbmc; SBREC_MULTICAST_GROUP_TABLE_FOR_EACH_SAFE (sbmc, input_data->sbrec_multicast_group_table) { struct ovn_datapath *od = ovn_datapath_from_sbrec( - input_data->datapaths, sbmc->datapath); + input_data->ls_datapaths, + input_data->lr_datapaths, + sbmc->datapath); if (!od || ovn_datapath_is_stale(od)) { sbrec_multicast_group_delete(sbmc); @@ -15705,12 +15797,13 @@ get_dns_info_from_hmap(struct hmap *dns_map, struct uuid *uuid) static void sync_dns_entries(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *datapaths) + struct hmap *ls_datapaths) { struct hmap dns_map = HMAP_INITIALIZER(&dns_map); struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs || !od->nbs->n_dns_records) { + HMAP_FOR_EACH (od, key_node, ls_datapaths) { + ovs_assert(od->nbs); + if (!od->nbs->n_dns_records) { continue; } @@ -15828,9 +15921,9 @@ sync_template_vars(struct northd_input *input_data, } static void -destroy_datapaths_and_ports(struct hmap *datapaths, struct hmap *ls_ports, - struct hmap *lr_ports, - struct ovs_list *lr_list) +destroy_datapaths_and_ports(struct hmap *ls_datapaths, + struct hmap *lr_datapaths, struct hmap *ls_ports, + struct hmap *lr_ports, struct ovs_list *lr_list) { struct ovn_datapath *router_dp; LIST_FOR_EACH_POP (router_dp, lr_list, lr_list) { @@ -15848,10 +15941,15 @@ destroy_datapaths_and_ports(struct hmap *datapaths, struct hmap *ls_ports, } struct ovn_datapath *dp; - HMAP_FOR_EACH_SAFE (dp, key_node, datapaths) { - ovn_datapath_destroy(datapaths, dp); + HMAP_FOR_EACH_SAFE (dp, key_node, ls_datapaths) { + ovn_datapath_destroy(ls_datapaths, dp); + } + hmap_destroy(ls_datapaths); + + HMAP_FOR_EACH_SAFE (dp, key_node, lr_datapaths) { + ovn_datapath_destroy(lr_datapaths, dp); } - hmap_destroy(datapaths); + hmap_destroy(lr_datapaths); struct ovn_port *port; HMAP_FOR_EACH_SAFE (port, key_node, ls_ports) { @@ -15868,14 +15966,12 @@ destroy_datapaths_and_ports(struct hmap *datapaths, struct hmap *ls_ports, static void build_ip_mcast(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *datapaths) + struct hmap *ls_datapaths) { struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs) { - continue; - } + HMAP_FOR_EACH (od, key_node, ls_datapaths) { + ovs_assert(od->nbs); const struct sbrec_ip_multicast *ip_mcast = ip_mcast_lookup(input_data->sbrec_ip_mcast_by_dp, od->sb); @@ -15891,7 +15987,7 @@ build_ip_mcast(struct northd_input *input_data, SBREC_IP_MULTICAST_TABLE_FOR_EACH_SAFE (sb, input_data->sbrec_ip_multicast_table) { - od = ovn_datapath_from_sbrec(datapaths, sb->datapath); + od = ovn_datapath_from_sbrec(ls_datapaths, NULL, sb->datapath); if (!od || ovn_datapath_is_stale(od)) { sbrec_ip_multicast_delete(sb); } @@ -15900,7 +15996,7 @@ build_ip_mcast(struct northd_input *input_data, static void build_mcast_groups(struct lflow_input *input_data, - const struct hmap *datapaths, + const struct hmap *ls_datapaths, const struct hmap *ls_ports, const struct hmap *lr_ports, struct hmap *mcast_groups, @@ -15912,7 +16008,7 @@ build_mcast_groups(struct lflow_input *input_data, hmap_init(igmp_groups); struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { + HMAP_FOR_EACH (od, key_node, ls_datapaths) { init_mcast_flow_count(od); } @@ -15976,7 +16072,7 @@ build_mcast_groups(struct lflow_input *input_data, } /* If the datapath value is stale, purge the group. */ - od = ovn_datapath_from_sbrec(datapaths, sb_igmp->datapath); + od = ovn_datapath_from_sbrec(ls_datapaths, NULL, sb_igmp->datapath); if (!od || ovn_datapath_is_stale(od)) { sbrec_igmp_group_delete(sb_igmp); @@ -16021,7 +16117,7 @@ build_mcast_groups(struct lflow_input *input_data, * IGMP groups are based on the groups learnt by their multicast enabled * peers. */ - HMAP_FOR_EACH (od, key_node, datapaths) { + HMAP_FOR_EACH (od, key_node, ls_datapaths) { if (ovs_list_is_empty(&od->mcast_info.groups)) { continue; @@ -16192,7 +16288,8 @@ build_static_mac_binding_table(struct northd_input *input_data, void northd_init(struct northd_data *data) { - hmap_init(&data->datapaths); + hmap_init(&data->ls_datapaths); + hmap_init(&data->lr_datapaths); hmap_init(&data->ls_ports); hmap_init(&data->lr_ports); hmap_init(&data->port_groups); @@ -16247,8 +16344,9 @@ northd_destroy(struct northd_data *data) */ cleanup_macam(); - destroy_datapaths_and_ports(&data->datapaths, &data->ls_ports, - &data->lr_ports, &data->lr_list); + destroy_datapaths_and_ports(&data->ls_datapaths, &data->lr_datapaths, + &data->ls_ports, &data->lr_ports, + &data->lr_list); destroy_debug_config(); } @@ -16336,20 +16434,22 @@ ovnnb_db_run(struct northd_input *input_data, init_debug_config(nb); - build_datapaths(input_data, ovnsb_txn, &data->datapaths, &data->lr_list); - build_lbs(input_data, &data->datapaths, &data->lbs, &data->lb_groups); + build_datapaths(input_data, ovnsb_txn, &data->ls_datapaths, + &data->lr_datapaths, &data->lr_list); + build_lbs(input_data, &data->ls_datapaths, &data->lr_datapaths, &data->lbs, + &data->lb_groups); build_ports(input_data, ovnsb_txn, sbrec_chassis_by_name, - sbrec_chassis_by_hostname, &data->datapaths, - &data->ls_ports, &data->lr_ports); - build_lb_port_related_data(&data->datapaths, &data->ls_ports, + sbrec_chassis_by_hostname, &data->ls_datapaths, + &data->lr_datapaths, &data->ls_ports, &data->lr_ports); + build_lb_port_related_data(&data->lr_datapaths, &data->ls_ports, &data->lbs, &data->lb_groups, input_data, ovnsb_txn); build_lb_count_dps(&data->lbs); - build_ipam(&data->datapaths, &data->ls_ports); + build_ipam(&data->ls_datapaths, &data->ls_ports); build_port_group_lswitches(input_data, &data->port_groups, &data->ls_ports); build_lrouter_groups(&data->lr_ports, &data->lr_list); - build_ip_mcast(input_data, ovnsb_txn, &data->datapaths); + build_ip_mcast(input_data, ovnsb_txn, &data->ls_datapaths); build_meter_groups(input_data, &data->meter_groups); build_static_mac_binding_table(input_data, ovnsb_txn, &data->lr_ports); stopwatch_stop(BUILD_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); @@ -16357,14 +16457,14 @@ ovnnb_db_run(struct northd_input *input_data, ovn_update_ipv6_options(&data->lr_ports); ovn_update_ipv6_prefix(&data->lr_ports); - sync_lbs(input_data, ovnsb_txn, &data->datapaths, &data->lbs); + sync_lbs(input_data, ovnsb_txn, &data->ls_datapaths, &data->lbs); sync_port_groups(input_data, ovnsb_txn, &data->port_groups); sync_meters(input_data, ovnsb_txn, &data->meter_groups); sync_mirrors(input_data, ovnsb_txn); - sync_dns_entries(input_data, ovnsb_txn, &data->datapaths); + sync_dns_entries(input_data, ovnsb_txn, &data->ls_datapaths); sync_template_vars(input_data, ovnsb_txn); - cleanup_stale_fdb_entries(input_data, &data->datapaths); + cleanup_stale_fdb_entries(input_data, &data->ls_datapaths); stopwatch_stop(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); /* Set up SB_Global (depends on chassis features). */ diff --git a/northd/northd.h b/northd/northd.h index cdb521d46566..cfd36e32c9a7 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -76,7 +76,8 @@ struct chassis_features { struct northd_data { /* Global state for 'en-northd'. */ - struct hmap datapaths; + struct hmap ls_datapaths; + struct hmap lr_datapaths; struct hmap ls_ports; struct hmap lr_ports; struct hmap port_groups; @@ -102,7 +103,8 @@ struct lflow_input { /* Indexes */ struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp; - const struct hmap *datapaths; + const struct hmap *ls_datapaths; + const struct hmap *lr_datapaths; const struct hmap *ls_ports; const struct hmap *lr_ports; const struct hmap *port_groups; From patchwork Tue Mar 21 06:02:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1759303 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PggyQ4cH5z2476 for ; Tue, 21 Mar 2023 17:03:26 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id BB9376112D; Tue, 21 Mar 2023 06:03:24 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org BB9376112D X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 6HZqv2ED4RCa; Tue, 21 Mar 2023 06:03:18 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id A4AAC61108; Tue, 21 Mar 2023 06:03:11 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org A4AAC61108 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id E55EDC007E; Tue, 21 Mar 2023 06:03:10 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 364B7C0035 for ; Tue, 21 Mar 2023 06:03:04 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 9995740B13 for ; Tue, 21 Mar 2023 06:03:03 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 9995740B13 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id b8aTjiP-LbkX for ; Tue, 21 Mar 2023 06:03:01 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org B186540989 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by smtp2.osuosl.org (Postfix) with ESMTPS id B186540989 for ; Tue, 21 Mar 2023 06:03:00 +0000 (UTC) Received: (Authenticated sender: hzhou@ovn.org) by mail.gandi.net (Postfix) with ESMTPSA id 6B36FE0007; Tue, 21 Mar 2023 06:02:58 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Mon, 20 Mar 2023 23:02:33 -0700 Message-Id: <20230321060235.2256118-6-hzhou@ovn.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230321060235.2256118-1-hzhou@ovn.org> References: <20230321060235.2256118-1-hzhou@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 5/7] northd: Expose real inputs through function arguments. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" The I-P engine node functions get inputs from the node's input data, and then call the real implementation functions (implemented in northd.c) with a xxx_input wrapper variable, and then in the called functions, it passes the variable further down to other functions, regardless of what fields are really used by those functions. This is fine when there is no real I-P implementation (i.e. we are always recompute), but to add incremental processing, we need to figure out which functions depend on which part of the input data, so that we can keep track of the logic that is needed to handle a specific change in the input data. Ideally, for incremental processing to work, we should be able to draw a dependency graph based on function prototypes. To fulfill this purpose, this patch refactors related functions to expose real inputs through function arguments. It made some of the function prototypes lengthy (in fact, not too much, because it turned out most of the functions only require very few members of the wrapper input data structure), but the dependencies are much more clear. Signed-off-by: Han Zhou --- northd/en-lflow.c | 7 +- northd/en-northd.c | 6 +- northd/northd.c | 447 +++++++++++++++++++++++++-------------------- northd/northd.h | 15 +- 4 files changed, 267 insertions(+), 208 deletions(-) diff --git a/northd/en-lflow.c b/northd/en-lflow.c index 995c7cc10e33..c1951c8c8c20 100644 --- a/northd/en-lflow.c +++ b/northd/en-lflow.c @@ -67,11 +67,14 @@ void en_lflow_run(struct engine_node *node, void *data OVS_UNUSED) northd_data->ovn_internal_version_changed; stopwatch_start(BUILD_LFLOWS_STOPWATCH_NAME, time_msec()); - build_bfd_table(&lflow_input, eng_ctx->ovnsb_idl_txn, + build_bfd_table(eng_ctx->ovnsb_idl_txn, + lflow_input.nbrec_bfd_table, + lflow_input.sbrec_bfd_table, &northd_data->bfd_connections, &northd_data->lr_ports); build_lflows(&lflow_input, eng_ctx->ovnsb_idl_txn); - bfd_cleanup_connections(&lflow_input, &northd_data->bfd_connections); + bfd_cleanup_connections(lflow_input.nbrec_bfd_table, + &northd_data->bfd_connections); stopwatch_stop(BUILD_LFLOWS_STOPWATCH_NAME, time_msec()); engine_set_node_state(node, EN_UPDATED); diff --git a/northd/en-northd.c b/northd/en-northd.c index 09fe8976af0d..38de18cdf0ce 100644 --- a/northd/en-northd.c +++ b/northd/en-northd.c @@ -62,9 +62,9 @@ void en_northd_run(struct engine_node *node, void *data) input_data.nbrec_nb_global_table = EN_OVSDB_GET(engine_get_input("NB_nb_global", node)); - input_data.nbrec_logical_switch = + input_data.nbrec_logical_switch_table = EN_OVSDB_GET(engine_get_input("NB_logical_switch", node)); - input_data.nbrec_logical_router = + input_data.nbrec_logical_router_table = EN_OVSDB_GET(engine_get_input("NB_logical_router", node)); input_data.nbrec_load_balancer_table = EN_OVSDB_GET(engine_get_input("NB_load_balancer", node)); @@ -93,7 +93,7 @@ void en_northd_run(struct engine_node *node, void *data) EN_OVSDB_GET(engine_get_input("SB_mac_binding", node)); input_data.sbrec_ha_chassis_group_table = EN_OVSDB_GET(engine_get_input("SB_ha_chassis_group", node)); - input_data.sbrec_chassis = + input_data.sbrec_chassis_table = EN_OVSDB_GET(engine_get_input("SB_chassis", node)); input_data.sbrec_fdb_table = EN_OVSDB_GET(engine_get_input("SB_fdb", node)); diff --git a/northd/northd.c b/northd/northd.c index baee1786469a..b62ae5dbcaa5 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -426,12 +426,12 @@ ovn_stage_to_datapath_type(enum ovn_stage stage) } static void -build_chassis_features(const struct northd_input *input_data, +build_chassis_features(const struct sbrec_chassis_table *sbrec_chassis_table, struct chassis_features *chassis_features) { const struct sbrec_chassis *chassis; - SBREC_CHASSIS_TABLE_FOR_EACH (chassis, input_data->sbrec_chassis) { + SBREC_CHASSIS_TABLE_FOR_EACH (chassis, sbrec_chassis_table) { /* Only consider local AZ chassis. Remote ones don't install * flows generated by the local northd. */ @@ -1207,7 +1207,9 @@ ovn_datapath_update_external_ids(struct ovn_datapath *od) } static void -join_datapaths(struct northd_input *input_data, +join_datapaths(const struct nbrec_logical_switch_table *nbrec_ls_table, + const struct nbrec_logical_router_table *nbrec_lr_table, + const struct sbrec_datapath_binding_table *sbrec_dp_table, struct ovsdb_idl_txn *ovnsb_txn, struct hmap *datapaths, struct ovs_list *sb_only, struct ovs_list *nb_only, struct ovs_list *both, @@ -1218,8 +1220,7 @@ join_datapaths(struct northd_input *input_data, ovs_list_init(both); const struct sbrec_datapath_binding *sb; - SBREC_DATAPATH_BINDING_TABLE_FOR_EACH_SAFE (sb, - input_data->sbrec_datapath_binding_table) { + SBREC_DATAPATH_BINDING_TABLE_FOR_EACH_SAFE (sb, sbrec_dp_table) { struct uuid key; if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key) && !smap_get_uuid(&sb->external_ids, "logical-router", &key)) { @@ -1249,8 +1250,7 @@ join_datapaths(struct northd_input *input_data, } const struct nbrec_logical_switch *nbs; - NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH (nbs, - input_data->nbrec_logical_switch) { + NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH (nbs, nbrec_ls_table) { struct ovn_datapath *od = ovn_datapath_find(datapaths, &nbs->header_.uuid); if (od) { @@ -1270,8 +1270,7 @@ join_datapaths(struct northd_input *input_data, } const struct nbrec_logical_router *nbr; - NBREC_LOGICAL_ROUTER_TABLE_FOR_EACH (nbr, - input_data->nbrec_logical_router) { + NBREC_LOGICAL_ROUTER_TABLE_FOR_EACH (nbr, nbrec_lr_table) { if (!lrouter_is_enabled(nbr)) { continue; } @@ -1309,10 +1308,10 @@ join_datapaths(struct northd_input *input_data, } static bool -is_vxlan_mode(struct northd_input *input_data) +is_vxlan_mode(const struct sbrec_chassis_table *sbrec_chassis_table) { const struct sbrec_chassis *chassis; - SBREC_CHASSIS_TABLE_FOR_EACH (chassis, input_data->sbrec_chassis) { + SBREC_CHASSIS_TABLE_FOR_EACH (chassis, sbrec_chassis_table) { for (int i = 0; i < chassis->n_encaps; i++) { if (!strcmp(chassis->encaps[i]->type, "vxlan")) { return true; @@ -1323,9 +1322,9 @@ is_vxlan_mode(struct northd_input *input_data) } static uint32_t -get_ovn_max_dp_key_local(struct northd_input *input_data) +get_ovn_max_dp_key_local(const struct sbrec_chassis_table *sbrec_chassis_table) { - if (is_vxlan_mode(input_data)) { + if (is_vxlan_mode(sbrec_chassis_table)) { /* OVN_MAX_DP_GLOBAL_NUM doesn't apply for vxlan mode. */ return OVN_MAX_DP_VXLAN_KEY; } @@ -1333,14 +1332,14 @@ get_ovn_max_dp_key_local(struct northd_input *input_data) } static void -ovn_datapath_allocate_key(struct northd_input *input_data, +ovn_datapath_allocate_key(const struct sbrec_chassis_table *sbrec_ch_table, struct hmap *datapaths, struct hmap *dp_tnlids, struct ovn_datapath *od, uint32_t *hint) { if (!od->tunnel_key) { od->tunnel_key = ovn_allocate_tnlid(dp_tnlids, "datapath", OVN_MIN_DP_KEY_LOCAL, - get_ovn_max_dp_key_local(input_data), + get_ovn_max_dp_key_local(sbrec_ch_table), hint); if (!od->tunnel_key) { if (od->sb) { @@ -1353,9 +1352,9 @@ ovn_datapath_allocate_key(struct northd_input *input_data, } static void -ovn_datapath_assign_requested_tnl_id(struct northd_input *input_data, - struct hmap *dp_tnlids, - struct ovn_datapath *od) +ovn_datapath_assign_requested_tnl_id( + const struct sbrec_chassis_table *sbrec_chassis_table, + struct hmap *dp_tnlids, struct ovn_datapath *od) { const struct smap *other_config = (od->nbs ? &od->nbs->other_config @@ -1363,7 +1362,7 @@ ovn_datapath_assign_requested_tnl_id(struct northd_input *input_data, uint32_t tunnel_key = smap_get_int(other_config, "requested-tnl-key", 0); if (tunnel_key) { const char *interconn_ts = smap_get(other_config, "interconn-ts"); - if (!interconn_ts && is_vxlan_mode(input_data) && + if (!interconn_ts && is_vxlan_mode(sbrec_chassis_table) && tunnel_key >= 1 << 12) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); VLOG_WARN_RL(&rl, "Tunnel key %"PRIu32" for datapath %s is " @@ -1399,8 +1398,11 @@ static size_t n_lr_datapaths = 0; * Initializes 'datapaths' to contain a "struct ovn_datapath" for every logical * switch and router. */ static void -build_datapaths(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, +build_datapaths(struct ovsdb_idl_txn *ovnsb_txn, + const struct nbrec_logical_switch_table *nbrec_ls_table, + const struct nbrec_logical_router_table *nbrec_lr_table, + const struct sbrec_datapath_binding_table *sbrec_dp_table, + const struct sbrec_chassis_table *sbrec_chassis_table, struct hmap *ls_datapaths, struct hmap *lr_datapaths, struct ovs_list *lr_list) @@ -1408,18 +1410,19 @@ build_datapaths(struct northd_input *input_data, struct ovs_list sb_only, nb_only, both; struct hmap *datapaths = ls_datapaths; - join_datapaths(input_data, ovnsb_txn, + join_datapaths(nbrec_ls_table, nbrec_lr_table, sbrec_dp_table, ovnsb_txn, datapaths, &sb_only, &nb_only, &both, lr_list); /* Assign explicitly requested tunnel ids first. */ struct hmap dp_tnlids = HMAP_INITIALIZER(&dp_tnlids); struct ovn_datapath *od; LIST_FOR_EACH (od, list, &both) { - ovn_datapath_assign_requested_tnl_id(input_data, &dp_tnlids, od); + ovn_datapath_assign_requested_tnl_id(sbrec_chassis_table, &dp_tnlids, + od); } LIST_FOR_EACH (od, list, &nb_only) { - ovn_datapath_assign_requested_tnl_id(input_data, &dp_tnlids, od); - } + ovn_datapath_assign_requested_tnl_id(sbrec_chassis_table, &dp_tnlids, + od); } /* Keep nonconflicting tunnel IDs that are already assigned. */ LIST_FOR_EACH (od, list, &both) { @@ -1431,11 +1434,11 @@ build_datapaths(struct northd_input *input_data, /* Assign new tunnel ids where needed. */ uint32_t hint = 0; LIST_FOR_EACH_SAFE (od, list, &both) { - ovn_datapath_allocate_key(input_data, + ovn_datapath_allocate_key(sbrec_chassis_table, datapaths, &dp_tnlids, od, &hint); } LIST_FOR_EACH_SAFE (od, list, &nb_only) { - ovn_datapath_allocate_key(input_data, + ovn_datapath_allocate_key(sbrec_chassis_table, datapaths, &dp_tnlids, od, &hint); } @@ -2473,7 +2476,7 @@ tag_alloc_create_new_tag(struct hmap *tag_alloc_table, static void -join_logical_ports(struct northd_input *input_data, +join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, struct hmap *ls_datapaths, struct hmap *lr_datapaths, struct hmap *ports, struct hmap *chassis_qdisc_queues, struct hmap *tag_alloc_table, struct ovs_list *sb_only, @@ -2484,8 +2487,7 @@ join_logical_ports(struct northd_input *input_data, ovs_list_init(both); const struct sbrec_port_binding *sb; - SBREC_PORT_BINDING_TABLE_FOR_EACH (sb, - input_data->sbrec_port_binding_table) { + SBREC_PORT_BINDING_TABLE_FOR_EACH (sb, sbrec_pb_table) { struct ovn_port *op = ovn_port_create(ports, sb->logical_port, NULL, NULL, sb); ovs_list_push_back(sb_only, &op->list); @@ -3088,16 +3090,17 @@ chassis_group_list_changed( } static void -sync_ha_chassis_group_for_sbpb(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, - const struct nbrec_ha_chassis_group *nb_ha_grp, - struct ovsdb_idl_index *sbrec_chassis_by_name, - const struct sbrec_port_binding *pb) +sync_ha_chassis_group_for_sbpb( + struct ovsdb_idl_txn *ovnsb_txn, + struct ovsdb_idl_index *sbrec_chassis_by_name, + struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name, + const struct nbrec_ha_chassis_group *nb_ha_grp, + const struct sbrec_port_binding *pb) { bool new_sb_chassis_group = false; const struct sbrec_ha_chassis_group *sb_ha_grp = ha_chassis_group_lookup_by_name( - input_data->sbrec_ha_chassis_grp_by_name, nb_ha_grp->name); + sbrec_ha_chassis_grp_by_name, nb_ha_grp->name); if (!sb_ha_grp) { sb_ha_grp = sbrec_ha_chassis_group_insert(ovnsb_txn); @@ -3142,9 +3145,9 @@ sync_ha_chassis_group_for_sbpb(struct northd_input *input_data, */ static void copy_gw_chassis_from_nbrp_to_sbpb( - struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, struct ovsdb_idl_index *sbrec_chassis_by_name, + struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name, const struct nbrec_logical_router_port *lrp, const struct sbrec_port_binding *port_binding) { @@ -3153,7 +3156,7 @@ copy_gw_chassis_from_nbrp_to_sbpb( * for the distributed gateway router port. */ const struct sbrec_ha_chassis_group *sb_ha_chassis_group = ha_chassis_group_lookup_by_name( - input_data->sbrec_ha_chassis_grp_by_name, lrp->name); + sbrec_ha_chassis_grp_by_name, lrp->name); if (!sb_ha_chassis_group) { sb_ha_chassis_group = sbrec_ha_chassis_group_insert(ovnsb_txn); sbrec_ha_chassis_group_set_name(sb_ha_chassis_group, lrp->name); @@ -3317,13 +3320,14 @@ check_and_do_sb_mirror_deletion(const struct ovn_port *op) } static void -check_and_do_sb_mirror_addition(struct northd_input *input_data, - const struct ovn_port *op) +check_and_do_sb_mirror_addition( + const struct sbrec_mirror_table *sbrec_mirror_table, + const struct ovn_port *op) { for (size_t i = 0; i < op->nbsp->n_mirror_rules; i++) { const struct sbrec_mirror *sb_mirror; SBREC_MIRROR_TABLE_FOR_EACH (sb_mirror, - input_data->sbrec_mirror_table) { + sbrec_mirror_table) { if (!strcmp(sb_mirror->name, op->nbsp->mirror_rules[i]->name)) { /* Add the value to SB */ @@ -3335,11 +3339,12 @@ check_and_do_sb_mirror_addition(struct northd_input *input_data, } static void -sbrec_port_binding_update_mirror_rules(struct northd_input *input_data, - const struct ovn_port *op) +sbrec_port_binding_update_mirror_rules( + const struct sbrec_mirror_table *sbrec_mirror_table, + const struct ovn_port *op) { check_and_do_sb_mirror_deletion(op); - check_and_do_sb_mirror_addition(input_data, op); + check_and_do_sb_mirror_addition(sbrec_mirror_table, op); } /* Return true if given ovn_port has peer and this peer's ovn_datapath @@ -3351,10 +3356,11 @@ l3dgw_port_has_associated_vtep_lports(const struct ovn_port *op) } static void -ovn_port_update_sbrec(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, +ovn_port_update_sbrec(struct ovsdb_idl_txn *ovnsb_txn, struct ovsdb_idl_index *sbrec_chassis_by_name, struct ovsdb_idl_index *sbrec_chassis_by_hostname, + struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name, + const struct sbrec_mirror_table *sbrec_mirror_table, const struct ovn_port *op, struct hmap *chassis_qdisc_queues, struct sset *active_ha_chassis_grps) @@ -3388,9 +3394,11 @@ ovn_port_update_sbrec(struct northd_input *input_data, } /* HA Chassis group is set. Ignore 'gateway_chassis'. */ - sync_ha_chassis_group_for_sbpb(input_data, ovnsb_txn, + sync_ha_chassis_group_for_sbpb(ovnsb_txn, + sbrec_chassis_by_name, + sbrec_ha_chassis_grp_by_name, op->nbrp->ha_chassis_group, - sbrec_chassis_by_name, op->sb); + op->sb); sset_add(active_ha_chassis_grps, op->nbrp->ha_chassis_group->name); } else if (op->nbrp->n_gateway_chassis) { @@ -3399,10 +3407,9 @@ ovn_port_update_sbrec(struct northd_input *input_data, * associated with the lrp. */ if (sbpb_gw_chassis_needs_update(op->sb, op->nbrp, sbrec_chassis_by_name)) { - copy_gw_chassis_from_nbrp_to_sbpb(input_data, - ovnsb_txn, - sbrec_chassis_by_name, - op->nbrp, op->sb); + copy_gw_chassis_from_nbrp_to_sbpb( + ovnsb_txn, sbrec_chassis_by_name, + sbrec_ha_chassis_grp_by_name, op->nbrp, op->sb); } sset_add(active_ha_chassis_grps, op->nbrp->name); @@ -3536,9 +3543,10 @@ ovn_port_update_sbrec(struct northd_input *input_data, if (!strcmp(op->nbsp->type, "external")) { if (op->nbsp->ha_chassis_group) { sync_ha_chassis_group_for_sbpb( - input_data, - ovnsb_txn, op->nbsp->ha_chassis_group, - sbrec_chassis_by_name, op->sb); + ovnsb_txn, sbrec_chassis_by_name, + sbrec_ha_chassis_grp_by_name, + op->nbsp->ha_chassis_group, + op->sb); sset_add(active_ha_chassis_grps, op->nbsp->ha_chassis_group->name); } else { @@ -3718,7 +3726,7 @@ ovn_port_update_sbrec(struct northd_input *input_data, sbrec_port_binding_set_mirror_rules(op->sb, NULL, 0); } else { /* Check if SB DB update needed */ - sbrec_port_binding_update_mirror_rules(input_data, op); + sbrec_port_binding_update_mirror_rules(sbrec_mirror_table, op); } } @@ -3738,13 +3746,12 @@ ovn_port_update_sbrec(struct northd_input *input_data, /* Remove mac_binding entries that refer to logical_ports which are * deleted. */ static void -cleanup_mac_bindings(struct northd_input *input_data, - struct hmap *lr_datapaths, - struct hmap *lr_ports) +cleanup_mac_bindings( + const struct sbrec_mac_binding_table *sbrec_mac_binding_table, + struct hmap *lr_datapaths, struct hmap *lr_ports) { const struct sbrec_mac_binding *b; - SBREC_MAC_BINDING_TABLE_FOR_EACH_SAFE (b, - input_data->sbrec_mac_binding_table) { + SBREC_MAC_BINDING_TABLE_FOR_EACH_SAFE (b, sbrec_mac_binding_table) { const struct ovn_datapath *od = ovn_datapath_from_sbrec(NULL, lr_datapaths, b->datapath); @@ -3756,12 +3763,13 @@ cleanup_mac_bindings(struct northd_input *input_data, } static void -cleanup_sb_ha_chassis_groups(struct northd_input *input_data, - struct sset *active_ha_chassis_groups) +cleanup_sb_ha_chassis_groups( + const struct sbrec_ha_chassis_group_table *sbrec_ha_chassis_group_table, + struct sset *active_ha_chassis_groups) { const struct sbrec_ha_chassis_group *b; SBREC_HA_CHASSIS_GROUP_TABLE_FOR_EACH_SAFE (b, - input_data->sbrec_ha_chassis_group_table) { + sbrec_ha_chassis_group_table) { if (!sset_contains(active_ha_chassis_groups, b->name)) { sbrec_ha_chassis_group_delete(b); } @@ -3769,12 +3777,11 @@ cleanup_sb_ha_chassis_groups(struct northd_input *input_data, } static void -cleanup_stale_fdb_entries(struct northd_input *input_data, +cleanup_stale_fdb_entries(const struct sbrec_fdb_table *sbrec_fdb_table, struct hmap *ls_datapaths) { const struct sbrec_fdb *fdb_e; - SBREC_FDB_TABLE_FOR_EACH_SAFE (fdb_e, - input_data->sbrec_fdb_table) { + SBREC_FDB_TABLE_FOR_EACH_SAFE (fdb_e, sbrec_fdb_table) { bool delete = true; struct ovn_datapath *od = ovn_datapath_find_by_key(ls_datapaths, fdb_e->dp_key); @@ -4023,8 +4030,10 @@ build_lrouter_lb_ips(struct ovn_lb_ip_set *lb_ips, } static void -build_lbs(struct northd_input *input_data, struct hmap *ls_datapaths, - struct hmap *lr_datapaths, struct hmap *lbs, struct hmap *lb_groups) +build_lbs(const struct nbrec_load_balancer_table *nbrec_load_balancer_table, + const struct nbrec_load_balancer_group_table *nbrec_lb_group_table, + struct hmap *ls_datapaths, struct hmap *lr_datapaths, + struct hmap *lbs, struct hmap *lb_groups) { const struct nbrec_load_balancer_group *nbrec_lb_group; struct ovn_lb_group *lb_group; @@ -4034,8 +4043,7 @@ build_lbs(struct northd_input *input_data, struct hmap *ls_datapaths, hmap_init(lb_groups); const struct nbrec_load_balancer *nbrec_lb; - NBREC_LOAD_BALANCER_TABLE_FOR_EACH (nbrec_lb, - input_data->nbrec_load_balancer_table) { + NBREC_LOAD_BALANCER_TABLE_FOR_EACH (nbrec_lb, nbrec_load_balancer_table) { struct ovn_northd_lb *lb_nb = ovn_northd_lb_create(nbrec_lb, n_ls_datapaths, n_lr_datapaths); @@ -4044,7 +4052,7 @@ build_lbs(struct northd_input *input_data, struct hmap *ls_datapaths, } NBREC_LOAD_BALANCER_GROUP_TABLE_FOR_EACH (nbrec_lb_group, - input_data->nbrec_load_balancer_group_table) { + nbrec_lb_group_table) { lb_group = ovn_lb_group_create(nbrec_lb_group, lbs, hmap_count(ls_datapaths), hmap_count(lr_datapaths)); @@ -4140,16 +4148,17 @@ build_lbs(struct northd_input *input_data, struct hmap *ls_datapaths, } static void -build_lb_svcs(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *ls_ports, - struct hmap *lbs) +build_lb_svcs( + struct ovsdb_idl_txn *ovnsb_txn, + const struct sbrec_service_monitor_table *sbrec_service_monitor_table, + struct hmap *ls_ports, + struct hmap *lbs) { struct hmap monitor_map = HMAP_INITIALIZER(&monitor_map); const struct sbrec_service_monitor *sbrec_mon; SBREC_SERVICE_MONITOR_TABLE_FOR_EACH (sbrec_mon, - input_data->sbrec_service_monitor_table) { + sbrec_service_monitor_table) { uint32_t hash = sbrec_mon->port; hash = hash_string(sbrec_mon->ip, hash); hash = hash_string(sbrec_mon->logical_port, hash); @@ -4335,14 +4344,15 @@ build_lb_count_dps(struct hmap *lbs) * networks to have been parsed. */ static void -build_lb_port_related_data(struct hmap *lr_datapaths, struct hmap *ls_ports, - struct hmap *lbs, struct hmap *lb_groups, - struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn) +build_lb_port_related_data( + struct ovsdb_idl_txn *ovnsb_txn, + const struct sbrec_service_monitor_table *sbrec_service_monitor_table, + struct hmap *lr_datapaths, struct hmap *ls_ports, + struct hmap *lbs, struct hmap *lb_groups) { build_lrouter_lbs_check(lr_datapaths); build_lrouter_lbs_reachable_ips(lr_datapaths, lbs, lb_groups); - build_lb_svcs(input_data, ovnsb_txn, ls_ports, lbs); + build_lb_svcs(ovnsb_txn, sbrec_service_monitor_table, ls_ports, lbs); build_lswitch_lbs_from_lrouter(lbs, lb_groups); } @@ -4394,7 +4404,8 @@ ovn_sb_insert_logical_dp_group(struct ovsdb_idl_txn *ovnsb_txn, * Southbound database. */ static void -sync_lbs(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, +sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, + const struct sbrec_load_balancer_table *sbrec_load_balancer_table, struct hmap *ls_datapaths, struct hmap *lbs) { struct hmap dp_groups = HMAP_INITIALIZER(&dp_groups); @@ -4407,7 +4418,7 @@ sync_lbs(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, struct hmapx existing_lbs = HMAPX_INITIALIZER(&existing_lbs); const struct sbrec_load_balancer *sbrec_lb; SBREC_LOAD_BALANCER_TABLE_FOR_EACH_SAFE (sbrec_lb, - input_data->sbrec_load_balancer_table) { + sbrec_load_balancer_table) { const char *nb_lb_uuid = smap_get(&sbrec_lb->external_ids, "lb_id"); struct uuid lb_uuid; if (!nb_lb_uuid || !uuid_from_string(&lb_uuid, nb_lb_uuid)) { @@ -4557,15 +4568,15 @@ ovn_port_add_tnlid(struct ovn_port *op, uint32_t tunnel_key) } static void -ovn_port_assign_requested_tnl_id(struct northd_input *input_data, - struct ovn_port *op) +ovn_port_assign_requested_tnl_id( + const struct sbrec_chassis_table *sbrec_chassis_table, struct ovn_port *op) { const struct smap *options = (op->nbsp ? &op->nbsp->options : &op->nbrp->options); uint32_t tunnel_key = smap_get_int(options, "requested-tnl-key", 0); if (tunnel_key) { - if (is_vxlan_mode(input_data) && + if (is_vxlan_mode(sbrec_chassis_table) && tunnel_key >= OVN_VXLAN_MIN_MULTICAST) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); VLOG_WARN_RL(&rl, "Tunnel key %"PRIu32" for port %s " @@ -4584,12 +4595,12 @@ ovn_port_assign_requested_tnl_id(struct northd_input *input_data, } static void -ovn_port_allocate_key(struct northd_input *input_data, +ovn_port_allocate_key(const struct sbrec_chassis_table *sbrec_chassis_table, struct hmap *ports, struct ovn_port *op) { if (!op->tunnel_key) { - uint8_t key_bits = is_vxlan_mode(input_data)? 12 : 16; + uint8_t key_bits = is_vxlan_mode(sbrec_chassis_table)? 12 : 16; op->tunnel_key = ovn_allocate_tnlid(&op->od->port_tnlids, "port", 1, (1u << (key_bits - 1)) - 1, &op->od->port_key_hint); @@ -4610,12 +4621,17 @@ ovn_port_allocate_key(struct northd_input *input_data, * using the "struct ovn_datapath"s in 'datapaths' to look up logical * datapaths. */ static void -build_ports(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, - struct ovsdb_idl_index *sbrec_chassis_by_name, - struct ovsdb_idl_index *sbrec_chassis_by_hostname, - struct hmap *ls_datapaths, struct hmap *lr_datapaths, - struct hmap *ls_ports, struct hmap *lr_ports) +build_ports(struct ovsdb_idl_txn *ovnsb_txn, + const struct sbrec_port_binding_table *sbrec_port_binding_table, + const struct sbrec_chassis_table *sbrec_chassis_table, + const struct sbrec_mirror_table *sbrec_mirror_table, + const struct sbrec_mac_binding_table *sbrec_mac_binding_table, + const struct sbrec_ha_chassis_group_table *sbrec_ha_chassis_group_table, + struct ovsdb_idl_index *sbrec_chassis_by_name, + struct ovsdb_idl_index *sbrec_chassis_by_hostname, + struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name, + struct hmap *ls_datapaths, struct hmap *lr_datapaths, + struct hmap *ls_ports, struct hmap *lr_ports) { struct ovs_list sb_only, nb_only, both; struct hmap tag_alloc_table = HMAP_INITIALIZER(&tag_alloc_table); @@ -4628,7 +4644,7 @@ build_ports(struct northd_input *input_data, /* Borrow ls_ports for joining NB and SB for both LSPs and LRPs. * We will split them later. */ struct hmap *ports = ls_ports; - join_logical_ports(input_data, ls_datapaths, lr_datapaths, + join_logical_ports(sbrec_port_binding_table, ls_datapaths, lr_datapaths, ports, &chassis_qdisc_queues, &tag_alloc_table, &sb_only, &nb_only, &both); @@ -4638,10 +4654,10 @@ build_ports(struct northd_input *input_data, /* Assign explicitly requested tunnel ids first. */ struct ovn_port *op; LIST_FOR_EACH (op, list, &both) { - ovn_port_assign_requested_tnl_id(input_data, op); + ovn_port_assign_requested_tnl_id(sbrec_chassis_table, op); } LIST_FOR_EACH (op, list, &nb_only) { - ovn_port_assign_requested_tnl_id(input_data, op); + ovn_port_assign_requested_tnl_id(sbrec_chassis_table, op); } /* Keep nonconflicting tunnel IDs that are already assigned. */ @@ -4653,10 +4669,10 @@ build_ports(struct northd_input *input_data, /* Assign new tunnel ids where needed. */ LIST_FOR_EACH_SAFE (op, list, &both) { - ovn_port_allocate_key(input_data, ports, op); + ovn_port_allocate_key(sbrec_chassis_table, ports, op); } LIST_FOR_EACH_SAFE (op, list, &nb_only) { - ovn_port_allocate_key(input_data, ports, op); + ovn_port_allocate_key(sbrec_chassis_table, ports, op); } /* For logical ports that are in both databases, update the southbound @@ -4673,9 +4689,10 @@ build_ports(struct northd_input *input_data, if (op->nbsp) { tag_alloc_create_new_tag(&tag_alloc_table, op->nbsp); } - ovn_port_update_sbrec(input_data, - ovnsb_txn, sbrec_chassis_by_name, + ovn_port_update_sbrec(ovnsb_txn, sbrec_chassis_by_name, sbrec_chassis_by_hostname, + sbrec_ha_chassis_grp_by_name, + sbrec_mirror_table, op, &chassis_qdisc_queues, &active_ha_chassis_grps); } @@ -4683,10 +4700,11 @@ build_ports(struct northd_input *input_data, /* Add southbound record for each unmatched northbound record. */ LIST_FOR_EACH_SAFE (op, list, &nb_only) { op->sb = sbrec_port_binding_insert(ovnsb_txn); - ovn_port_update_sbrec(input_data, - ovnsb_txn, sbrec_chassis_by_name, - sbrec_chassis_by_hostname, op, - &chassis_qdisc_queues, + ovn_port_update_sbrec(ovnsb_txn, sbrec_chassis_by_name, + sbrec_chassis_by_hostname, + sbrec_ha_chassis_grp_by_name, + sbrec_mirror_table, + op, &chassis_qdisc_queues, &active_ha_chassis_grps); sbrec_port_binding_set_logical_port(op->sb, op->key); } @@ -4711,12 +4729,13 @@ build_ports(struct northd_input *input_data, } if (remove_mac_bindings) { - cleanup_mac_bindings(input_data, lr_datapaths, lr_ports); + cleanup_mac_bindings(sbrec_mac_binding_table, lr_datapaths, lr_ports); } tag_alloc_destroy(&tag_alloc_table); destroy_chassis_queues(&chassis_qdisc_queues); - cleanup_sb_ha_chassis_groups(input_data, &active_ha_chassis_grps); + cleanup_sb_ha_chassis_groups(sbrec_ha_chassis_group_table, + &active_ha_chassis_grps); sset_destroy(&active_ha_chassis_grps); } @@ -4901,7 +4920,7 @@ ovn_igmp_group_find(struct hmap *igmp_groups, } static struct ovn_igmp_group * -ovn_igmp_group_add(struct lflow_input *input_data, +ovn_igmp_group_add(struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp, struct hmap *igmp_groups, struct ovn_datapath *datapath, const struct in6_addr *address, @@ -4914,7 +4933,7 @@ ovn_igmp_group_add(struct lflow_input *input_data, igmp_group = xmalloc(sizeof *igmp_group); const struct sbrec_multicast_group *mcgroup = - mcast_group_lookup(input_data->sbrec_mcast_group_by_name_dp, + mcast_group_lookup(sbrec_mcast_group_by_name_dp, address_s, datapath->sb); @@ -6742,15 +6761,14 @@ ovn_update_ipv6_options(struct hmap *lr_ports) } static void -build_port_group_lswitches(struct northd_input *input_data, - struct hmap *pgs, - struct hmap *ls_ports) +build_port_group_lswitches( + const struct nbrec_port_group_table *nbrec_port_group_table, + struct hmap *pgs, struct hmap *ls_ports) { hmap_init(pgs); const struct nbrec_port_group *nb_pg; - NBREC_PORT_GROUP_TABLE_FOR_EACH (nb_pg, - input_data->nbrec_port_group_table) { + NBREC_PORT_GROUP_TABLE_FOR_EACH (nb_pg, nbrec_port_group_table) { struct ovn_port_group *pg = ovn_port_group_create(pgs, nb_pg); for (size_t i = 0; i < nb_pg->n_ports; i++) { struct ovn_port *op = ovn_port_find(ls_ports, @@ -9362,13 +9380,13 @@ bfd_port_lookup(const struct hmap *bfd_map, const char *logical_port, } void -bfd_cleanup_connections(struct lflow_input *input_data, +bfd_cleanup_connections(const struct nbrec_bfd_table *nbrec_bfd_table, struct hmap *bfd_map) { const struct nbrec_bfd *nb_bt; struct bfd_entry *bfd_e; - NBREC_BFD_TABLE_FOR_EACH (nb_bt, input_data->nbrec_bfd_table) { + NBREC_BFD_TABLE_FOR_EACH (nb_bt, nbrec_bfd_table) { bfd_e = bfd_port_lookup(bfd_map, nb_bt->logical_port, nb_bt->dst_ip); if (!bfd_e) { continue; @@ -9446,8 +9464,9 @@ static int bfd_get_unused_port(unsigned long *bfd_src_ports) } void -build_bfd_table(struct lflow_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, +build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn, + const struct nbrec_bfd_table *nbrec_bfd_table, + const struct sbrec_bfd_table *sbrec_bfd_table, struct hmap *bfd_connections, struct hmap *lr_ports) { struct hmap sb_only = HMAP_INITIALIZER(&sb_only); @@ -9458,7 +9477,7 @@ build_bfd_table(struct lflow_input *input_data, bfd_src_ports = bitmap_allocate(BFD_UDP_SRC_PORT_LEN); - SBREC_BFD_TABLE_FOR_EACH (sb_bt, input_data->sbrec_bfd_table) { + SBREC_BFD_TABLE_FOR_EACH (sb_bt, sbrec_bfd_table) { bfd_e = xmalloc(sizeof *bfd_e); bfd_e->sb_bt = sb_bt; hash = hash_string(sb_bt->dst_ip, 0); @@ -9468,7 +9487,7 @@ build_bfd_table(struct lflow_input *input_data, } const struct nbrec_bfd *nb_bt; - NBREC_BFD_TABLE_FOR_EACH (nb_bt, input_data->nbrec_bfd_table) { + NBREC_BFD_TABLE_FOR_EACH (nb_bt, nbrec_bfd_table) { if (!nb_bt->status) { /* default state is admin_down */ nbrec_bfd_set_status(nb_bt, "admin_down"); @@ -15066,7 +15085,8 @@ void run_update_worker_pool(int n_threads) } static void -build_mcast_groups(struct lflow_input *data, +build_mcast_groups(const struct sbrec_igmp_group_table *sbrec_igmp_group_table, + struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp, const struct hmap *ls_datapaths, const struct hmap *ls_ports, const struct hmap *lr_ports, @@ -15082,7 +15102,9 @@ void build_lflows(struct lflow_input *input_data, struct hmap mcast_groups; struct hmap igmp_groups; - build_mcast_groups(input_data, input_data->ls_datapaths, + build_mcast_groups(input_data->sbrec_igmp_group_table, + input_data->sbrec_mcast_group_by_name_dp, + input_data->ls_datapaths, input_data->ls_ports, input_data->lr_ports, &mcast_groups, &igmp_groups); @@ -15459,15 +15481,14 @@ void build_lflows(struct lflow_input *input_data, * contains lport uuids, while in OVN_Southbound we store the lport names. */ static void -sync_port_groups(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, +sync_port_groups(struct ovsdb_idl_txn *ovnsb_txn, + const struct sbrec_port_group_table *sbrec_port_group_table, struct hmap *pgs) { struct shash sb_port_groups = SHASH_INITIALIZER(&sb_port_groups); const struct sbrec_port_group *sb_port_group; - SBREC_PORT_GROUP_TABLE_FOR_EACH (sb_port_group, - input_data->sbrec_port_group_table) { + SBREC_PORT_GROUP_TABLE_FOR_EACH (sb_port_group, sbrec_port_group_table) { shash_add(&sb_port_groups, sb_port_group->name, sb_port_group); } @@ -15653,20 +15674,22 @@ sync_acl_fair_meter(struct ovsdb_idl_txn *ovnsb_txn, * a private copy of its meter in the SB table. */ static void -sync_meters(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, +sync_meters(struct ovsdb_idl_txn *ovnsb_txn, + const struct nbrec_meter_table *nbrec_meter_table, + const struct nbrec_acl_table *nbrec_acl_table, + const struct sbrec_meter_table *sbrec_meter_table, struct shash *meter_groups) { struct shash sb_meters = SHASH_INITIALIZER(&sb_meters); struct sset used_sb_meters = SSET_INITIALIZER(&used_sb_meters); const struct sbrec_meter *sb_meter; - SBREC_METER_TABLE_FOR_EACH (sb_meter, input_data->sbrec_meter_table) { + SBREC_METER_TABLE_FOR_EACH (sb_meter, sbrec_meter_table) { shash_add(&sb_meters, sb_meter->name, sb_meter); } const struct nbrec_meter *nb_meter; - NBREC_METER_TABLE_FOR_EACH (nb_meter, input_data->nbrec_meter_table) { + NBREC_METER_TABLE_FOR_EACH (nb_meter, nbrec_meter_table) { sync_meters_iterate_nb_meter(ovnsb_txn, nb_meter->name, nb_meter, &sb_meters, &used_sb_meters); } @@ -15677,7 +15700,7 @@ sync_meters(struct northd_input *input_data, * rate-limited. */ const struct nbrec_acl *acl; - NBREC_ACL_TABLE_FOR_EACH (acl, input_data->nbrec_acl_table) { + NBREC_ACL_TABLE_FOR_EACH (acl, nbrec_acl_table) { sync_acl_fair_meter(ovnsb_txn, meter_groups, acl, &sb_meters, &used_sb_meters); } @@ -15741,18 +15764,19 @@ sync_mirrors_iterate_nb_mirror(struct ovsdb_idl_txn *ovnsb_txn, } static void -sync_mirrors(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn) +sync_mirrors(struct ovsdb_idl_txn *ovnsb_txn, + const struct nbrec_mirror_table *nbrec_mirror_table, + const struct sbrec_mirror_table *sbrec_mirror_table) { struct shash sb_mirrors = SHASH_INITIALIZER(&sb_mirrors); const struct sbrec_mirror *sb_mirror; - SBREC_MIRROR_TABLE_FOR_EACH (sb_mirror, input_data->sbrec_mirror_table) { + SBREC_MIRROR_TABLE_FOR_EACH (sb_mirror, sbrec_mirror_table) { shash_add(&sb_mirrors, sb_mirror->name, sb_mirror); } const struct nbrec_mirror *nb_mirror; - NBREC_MIRROR_TABLE_FOR_EACH (nb_mirror, input_data->nbrec_mirror_table) { + NBREC_MIRROR_TABLE_FOR_EACH (nb_mirror, nbrec_mirror_table) { sync_mirrors_iterate_nb_mirror(ovnsb_txn, nb_mirror->name, nb_mirror, &sb_mirrors); shash_find_and_delete(&sb_mirrors, nb_mirror->name); @@ -15795,8 +15819,8 @@ get_dns_info_from_hmap(struct hmap *dns_map, struct uuid *uuid) } static void -sync_dns_entries(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, +sync_dns_entries(struct ovsdb_idl_txn *ovnsb_txn, + const struct sbrec_dns_table *sbrec_dns_table, struct hmap *ls_datapaths) { struct hmap dns_map = HMAP_INITIALIZER(&dns_map); @@ -15826,7 +15850,7 @@ sync_dns_entries(struct northd_input *input_data, } const struct sbrec_dns *sbrec_dns; - SBREC_DNS_TABLE_FOR_EACH_SAFE (sbrec_dns, input_data->sbrec_dns_table) { + SBREC_DNS_TABLE_FOR_EACH_SAFE (sbrec_dns, sbrec_dns_table) { const char *nb_dns_uuid = smap_get(&sbrec_dns->external_ids, "dns_id"); struct uuid dns_uuid; if (!nb_dns_uuid || !uuid_from_string(&dns_uuid, nb_dns_uuid)) { @@ -15884,8 +15908,10 @@ sync_dns_entries(struct northd_input *input_data, } static void -sync_template_vars(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn) +sync_template_vars( + struct ovsdb_idl_txn *ovnsb_txn, + const struct nbrec_chassis_template_var_table *nbrec_ch_template_var_table, + const struct sbrec_chassis_template_var_table *sbrec_ch_template_var_table) { struct shash nb_tvs = SHASH_INITIALIZER(&nb_tvs); @@ -15893,12 +15919,12 @@ sync_template_vars(struct northd_input *input_data, const struct sbrec_chassis_template_var *sb_tv; NBREC_CHASSIS_TEMPLATE_VAR_TABLE_FOR_EACH ( - nb_tv, input_data->nbrec_chassis_template_var_table) { + nb_tv, nbrec_ch_template_var_table) { shash_add(&nb_tvs, nb_tv->chassis, nb_tv); } SBREC_CHASSIS_TEMPLATE_VAR_TABLE_FOR_EACH_SAFE ( - sb_tv, input_data->sbrec_chassis_template_var_table) { + sb_tv, sbrec_ch_template_var_table) { nb_tv = shash_find_and_delete(&nb_tvs, sb_tv->chassis); if (!nb_tv) { sbrec_chassis_template_var_delete(sb_tv); @@ -15964,8 +15990,9 @@ destroy_datapaths_and_ports(struct hmap *ls_datapaths, } static void -build_ip_mcast(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, +build_ip_mcast(struct ovsdb_idl_txn *ovnsb_txn, + const struct sbrec_ip_multicast_table *sbrec_ip_multicast_table, + struct ovsdb_idl_index *sbrec_ip_mcast_by_dp, struct hmap *ls_datapaths) { struct ovn_datapath *od; @@ -15974,7 +16001,7 @@ build_ip_mcast(struct northd_input *input_data, ovs_assert(od->nbs); const struct sbrec_ip_multicast *ip_mcast = - ip_mcast_lookup(input_data->sbrec_ip_mcast_by_dp, od->sb); + ip_mcast_lookup(sbrec_ip_mcast_by_dp, od->sb); if (!ip_mcast) { ip_mcast = sbrec_ip_multicast_insert(ovnsb_txn); @@ -15985,8 +16012,7 @@ build_ip_mcast(struct northd_input *input_data, /* Delete southbound records without northbound matches. */ const struct sbrec_ip_multicast *sb; - SBREC_IP_MULTICAST_TABLE_FOR_EACH_SAFE (sb, - input_data->sbrec_ip_multicast_table) { + SBREC_IP_MULTICAST_TABLE_FOR_EACH_SAFE (sb, sbrec_ip_multicast_table) { od = ovn_datapath_from_sbrec(ls_datapaths, NULL, sb->datapath); if (!od || ovn_datapath_is_stale(od)) { sbrec_ip_multicast_delete(sb); @@ -15995,7 +16021,8 @@ build_ip_mcast(struct northd_input *input_data, } static void -build_mcast_groups(struct lflow_input *input_data, +build_mcast_groups(const struct sbrec_igmp_group_table *sbrec_igmp_group_table, + struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp, const struct hmap *ls_datapaths, const struct hmap *ls_ports, const struct hmap *lr_ports, @@ -16061,8 +16088,7 @@ build_mcast_groups(struct lflow_input *input_data, const struct sbrec_igmp_group *sb_igmp; - SBREC_IGMP_GROUP_TABLE_FOR_EACH_SAFE (sb_igmp, - input_data->sbrec_igmp_group_table) { + SBREC_IGMP_GROUP_TABLE_FOR_EACH_SAFE (sb_igmp, sbrec_igmp_group_table) { /* If this is a stale group (e.g., controller had crashed, * purge it). */ @@ -16106,8 +16132,8 @@ build_mcast_groups(struct lflow_input *input_data, * if the multicast group already exists. */ struct ovn_igmp_group *igmp_group = - ovn_igmp_group_add(input_data, igmp_groups, od, &group_address, - sb_igmp->address); + ovn_igmp_group_add(sbrec_mcast_group_by_name_dp, igmp_groups, od, + &group_address, sb_igmp->address); /* Add the extracted ports to the IGMP group. */ ovn_igmp_group_add_entry(igmp_group, igmp_ports, n_igmp_ports); @@ -16155,7 +16181,7 @@ build_mcast_groups(struct lflow_input *input_data, } struct ovn_igmp_group *igmp_group_rtr = - ovn_igmp_group_add(input_data, + ovn_igmp_group_add(sbrec_mcast_group_by_name_dp, igmp_groups, router_port->od, address, igmp_group->mcgroup.name); struct ovn_port **router_igmp_ports = @@ -16202,23 +16228,23 @@ build_mcast_groups(struct lflow_input *input_data, } static void -build_meter_groups(struct northd_input *input_data, +build_meter_groups(const struct nbrec_meter_table *nbrec_meter_table, struct shash *meter_groups) { const struct nbrec_meter *nb_meter; - NBREC_METER_TABLE_FOR_EACH (nb_meter, input_data->nbrec_meter_table) { + NBREC_METER_TABLE_FOR_EACH (nb_meter, nbrec_meter_table) { shash_add(meter_groups, nb_meter->name, nb_meter); } } static const struct nbrec_static_mac_binding * -static_mac_binding_by_port_ip(struct northd_input *input_data, - const char *logical_port, const char *ip) +static_mac_binding_by_port_ip( + const struct nbrec_static_mac_binding_table *nbrec_static_mb_table, + const char *logical_port, const char *ip) { const struct nbrec_static_mac_binding *nb_smb = NULL; - NBREC_STATIC_MAC_BINDING_TABLE_FOR_EACH ( - nb_smb, input_data->nbrec_static_mac_binding_table) { + NBREC_STATIC_MAC_BINDING_TABLE_FOR_EACH (nb_smb, nbrec_static_mb_table) { if (!strcmp(nb_smb->logical_port, logical_port) && !strcmp(nb_smb->ip, ip)) { break; @@ -16229,17 +16255,20 @@ static_mac_binding_by_port_ip(struct northd_input *input_data, } static void -build_static_mac_binding_table(struct northd_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *lr_ports) +build_static_mac_binding_table( + struct ovsdb_idl_txn *ovnsb_txn, + const struct nbrec_static_mac_binding_table *nbrec_static_mb_table, + const struct sbrec_static_mac_binding_table *sbrec_static_mb_table, + struct ovsdb_idl_index *sbrec_static_mac_binding_by_lport_ip, + struct hmap *lr_ports) { /* Cleanup SB Static_MAC_Binding entries which do not have corresponding * NB Static_MAC_Binding entries. */ const struct nbrec_static_mac_binding *nb_smb; const struct sbrec_static_mac_binding *sb_smb; SBREC_STATIC_MAC_BINDING_TABLE_FOR_EACH_SAFE (sb_smb, - input_data->sbrec_static_mac_binding_table) { - nb_smb = static_mac_binding_by_port_ip(input_data, + sbrec_static_mb_table) { + nb_smb = static_mac_binding_by_port_ip(nbrec_static_mb_table, sb_smb->logical_port, sb_smb->ip); if (!nb_smb) { @@ -16250,14 +16279,14 @@ build_static_mac_binding_table(struct northd_input *input_data, /* Create/Update SB Static_MAC_Binding entries with corresponding values * from NB Static_MAC_Binding entries. */ NBREC_STATIC_MAC_BINDING_TABLE_FOR_EACH ( - nb_smb, input_data->nbrec_static_mac_binding_table) { + nb_smb, nbrec_static_mb_table) { struct ovn_port *op = ovn_port_find(lr_ports, nb_smb->logical_port); if (op && op->nbrp) { struct ovn_datapath *od = op->od; if (od && od->sb) { const struct sbrec_static_mac_binding *mb = static_mac_binding_lookup( - input_data->sbrec_static_mac_binding_by_lport_ip, + sbrec_static_mac_binding_by_lport_ip, nb_smb->logical_port, nb_smb->ip); if (!mb) { /* Create new entry */ @@ -16354,9 +16383,7 @@ static void ovnnb_db_run(struct northd_input *input_data, struct northd_data *data, struct ovsdb_idl_txn *ovnnb_txn, - struct ovsdb_idl_txn *ovnsb_txn, - struct ovsdb_idl_index *sbrec_chassis_by_name, - struct ovsdb_idl_index *sbrec_chassis_by_hostname) + struct ovsdb_idl_txn *ovnsb_txn) { if (!ovnsb_txn || !ovnnb_txn) { return; @@ -16397,7 +16424,8 @@ ovnnb_db_run(struct northd_input *input_data, smap_replace(&options, "svc_monitor_mac", svc_monitor_mac); } - char *max_tunid = xasprintf("%d", get_ovn_max_dp_key_local(input_data)); + char *max_tunid = xasprintf("%d", + get_ovn_max_dp_key_local(input_data->sbrec_chassis_table)); smap_replace(&options, "max_tunid", max_tunid); free(max_tunid); @@ -16430,41 +16458,70 @@ ovnnb_db_run(struct northd_input *input_data, "install_ls_lb_from_router", false); - build_chassis_features(input_data, &data->features); + build_chassis_features(input_data->sbrec_chassis_table, &data->features); init_debug_config(nb); - build_datapaths(input_data, ovnsb_txn, &data->ls_datapaths, + build_datapaths(ovnsb_txn, + input_data->nbrec_logical_switch_table, + input_data->nbrec_logical_router_table, + input_data->sbrec_datapath_binding_table, + input_data->sbrec_chassis_table, + &data->ls_datapaths, &data->lr_datapaths, &data->lr_list); - build_lbs(input_data, &data->ls_datapaths, &data->lr_datapaths, &data->lbs, + build_lbs(input_data->nbrec_load_balancer_table, + input_data->nbrec_load_balancer_group_table, + &data->ls_datapaths, &data->lr_datapaths, &data->lbs, &data->lb_groups); - build_ports(input_data, ovnsb_txn, sbrec_chassis_by_name, - sbrec_chassis_by_hostname, &data->ls_datapaths, - &data->lr_datapaths, &data->ls_ports, &data->lr_ports); - build_lb_port_related_data(&data->lr_datapaths, &data->ls_ports, - &data->lbs, &data->lb_groups, input_data, - ovnsb_txn); + build_ports(ovnsb_txn, + input_data->sbrec_port_binding_table, + input_data->sbrec_chassis_table, + input_data->sbrec_mirror_table, + input_data->sbrec_mac_binding_table, + input_data->sbrec_ha_chassis_group_table, + input_data->sbrec_chassis_by_name, + input_data->sbrec_chassis_by_hostname, + input_data->sbrec_ha_chassis_grp_by_name, + &data->ls_datapaths, &data->lr_datapaths, &data->ls_ports, + &data->lr_ports); + build_lb_port_related_data(ovnsb_txn, + input_data->sbrec_service_monitor_table, + &data->lr_datapaths, &data->ls_ports, + &data->lbs, &data->lb_groups); build_lb_count_dps(&data->lbs); build_ipam(&data->ls_datapaths, &data->ls_ports); - build_port_group_lswitches(input_data, &data->port_groups, - &data->ls_ports); + build_port_group_lswitches(input_data->nbrec_port_group_table, + &data->port_groups, &data->ls_ports); build_lrouter_groups(&data->lr_ports, &data->lr_list); - build_ip_mcast(input_data, ovnsb_txn, &data->ls_datapaths); - build_meter_groups(input_data, &data->meter_groups); - build_static_mac_binding_table(input_data, ovnsb_txn, &data->lr_ports); + build_ip_mcast(ovnsb_txn, input_data->sbrec_ip_multicast_table, + input_data->sbrec_ip_mcast_by_dp, &data->ls_datapaths); + build_meter_groups(input_data->nbrec_meter_table, &data->meter_groups); + build_static_mac_binding_table(ovnsb_txn, + input_data->nbrec_static_mac_binding_table, + input_data->sbrec_static_mac_binding_table, + input_data->sbrec_static_mac_binding_by_lport_ip, + &data->lr_ports); stopwatch_stop(BUILD_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); stopwatch_start(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); ovn_update_ipv6_options(&data->lr_ports); ovn_update_ipv6_prefix(&data->lr_ports); - sync_lbs(input_data, ovnsb_txn, &data->ls_datapaths, &data->lbs); - sync_port_groups(input_data, ovnsb_txn, &data->port_groups); - sync_meters(input_data, ovnsb_txn, &data->meter_groups); - sync_mirrors(input_data, ovnsb_txn); - sync_dns_entries(input_data, ovnsb_txn, &data->ls_datapaths); - sync_template_vars(input_data, ovnsb_txn); - - cleanup_stale_fdb_entries(input_data, &data->ls_datapaths); + sync_lbs(ovnsb_txn, input_data->sbrec_load_balancer_table, + &data->ls_datapaths, &data->lbs); + sync_port_groups(ovnsb_txn, input_data->sbrec_port_group_table, + &data->port_groups); + sync_meters(ovnsb_txn, input_data->nbrec_meter_table, + input_data->nbrec_acl_table, input_data->sbrec_meter_table, + &data->meter_groups); + sync_mirrors(ovnsb_txn, input_data->nbrec_mirror_table, + input_data->sbrec_mirror_table); + sync_dns_entries(ovnsb_txn, input_data->sbrec_dns_table, + &data->ls_datapaths); + sync_template_vars(ovnsb_txn, input_data->nbrec_chassis_template_var_table, + input_data->sbrec_chassis_template_var_table); + + cleanup_stale_fdb_entries(input_data->sbrec_fdb_table, + &data->ls_datapaths); stopwatch_stop(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); /* Set up SB_Global (depends on chassis features). */ @@ -16728,9 +16785,7 @@ void northd_run(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn) { stopwatch_start(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec()); - ovnnb_db_run(input_data, data, ovnnb_txn, ovnsb_txn, - input_data->sbrec_chassis_by_name, - input_data->sbrec_chassis_by_hostname); + ovnnb_db_run(input_data, data, ovnnb_txn, ovnsb_txn); stopwatch_stop(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec()); stopwatch_start(OVNSB_DB_RUN_STOPWATCH_NAME, time_msec()); ovnsb_db_run(input_data, ovnnb_txn, ovnsb_txn, &data->ls_ports); diff --git a/northd/northd.h b/northd/northd.h index cfd36e32c9a7..c4563f0cb15a 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -25,8 +25,8 @@ struct northd_input { /* Northbound table references */ const struct nbrec_nb_global_table *nbrec_nb_global_table; - const struct nbrec_logical_switch_table *nbrec_logical_switch; - const struct nbrec_logical_router_table *nbrec_logical_router; + const struct nbrec_logical_switch_table *nbrec_logical_switch_table; + const struct nbrec_logical_router_table *nbrec_logical_router_table; const struct nbrec_load_balancer_table *nbrec_load_balancer_table; const struct nbrec_load_balancer_group_table *nbrec_load_balancer_group_table; @@ -45,7 +45,7 @@ struct northd_input { const struct sbrec_port_binding_table *sbrec_port_binding_table; const struct sbrec_mac_binding_table *sbrec_mac_binding_table; const struct sbrec_ha_chassis_group_table *sbrec_ha_chassis_group_table; - const struct sbrec_chassis_table *sbrec_chassis; + const struct sbrec_chassis_table *sbrec_chassis_table; const struct sbrec_fdb_table *sbrec_fdb_table; const struct sbrec_load_balancer_table *sbrec_load_balancer_table; const struct sbrec_service_monitor_table *sbrec_service_monitor_table; @@ -283,10 +283,11 @@ void northd_indices_create(struct northd_data *data, struct ovsdb_idl *ovnsb_idl); void build_lflows(struct lflow_input *input_data, struct ovsdb_idl_txn *ovnsb_txn); -void build_bfd_table(struct lflow_input *input_data, - struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *bfd_connections, struct hmap *ports); -void bfd_cleanup_connections(struct lflow_input *input_data, +void build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn, + const struct nbrec_bfd_table *, + const struct sbrec_bfd_table *, + struct hmap *bfd_connections, struct hmap *lr_ports); +void bfd_cleanup_connections(const struct nbrec_bfd_table *, struct hmap *bfd_map); void run_update_worker_pool(int n_threads); From patchwork Tue Mar 21 06:02:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1759304 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PggyQ6sy2z247k for ; Tue, 21 Mar 2023 17:03:26 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 502C8417E4; Tue, 21 Mar 2023 06:03:24 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 502C8417E4 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Zo9Pd5bElmxT; Tue, 21 Mar 2023 06:03:22 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id C9020402B1; Tue, 21 Mar 2023 06:03:13 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org C9020402B1 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id F1D87C008D; Tue, 21 Mar 2023 06:03:11 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1A670C0032 for ; Tue, 21 Mar 2023 06:03:05 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 6858540B29 for ; Tue, 21 Mar 2023 06:03:04 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 6858540B29 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id pXtYd_oJBCvJ for ; Tue, 21 Mar 2023 06:03:03 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org A11A440B03 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by smtp2.osuosl.org (Postfix) with ESMTPS id A11A440B03 for ; Tue, 21 Mar 2023 06:03:02 +0000 (UTC) Received: (Authenticated sender: hzhou@ovn.org) by mail.gandi.net (Postfix) with ESMTPSA id EC8EBE0004; Tue, 21 Mar 2023 06:02:59 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Mon, 20 Mar 2023 23:02:34 -0700 Message-Id: <20230321060235.2256118-7-hzhou@ovn.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230321060235.2256118-1-hzhou@ovn.org> References: <20230321060235.2256118-1-hzhou@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 6/7] en-northd.c: Remove unused dependencies. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" With the help of the previous refactor that exposes inputs explicitly, we could tell that there are many unused dependencies in the current I-P engine nodes. This patch removes the unused ones. Signed-off-by: Han Zhou --- northd/en-northd.c | 2 -- northd/inc-proc-northd.c | 62 ++-------------------------------------- northd/northd.h | 1 - 3 files changed, 2 insertions(+), 63 deletions(-) diff --git a/northd/en-northd.c b/northd/en-northd.c index 38de18cdf0ce..e8f3a844af71 100644 --- a/northd/en-northd.c +++ b/northd/en-northd.c @@ -109,8 +109,6 @@ void en_northd_run(struct engine_node *node, void *data) EN_OVSDB_GET(engine_get_input("SB_dns", node)); input_data.sbrec_ip_multicast_table = EN_OVSDB_GET(engine_get_input("SB_ip_multicast", node)); - input_data.sbrec_chassis_private_table = - EN_OVSDB_GET(engine_get_input("SB_chassis_private", node)); input_data.sbrec_static_mac_binding_table = EN_OVSDB_GET(engine_get_input("SB_static_mac_binding", node)); input_data.sbrec_chassis_template_var_table = diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c index b28f5518950c..d54aa19c7749 100644 --- a/northd/inc-proc-northd.c +++ b/northd/inc-proc-northd.c @@ -43,32 +43,15 @@ static unixctl_cb_func chassis_features_list; #define NB_NODES \ NB_NODE(nb_global, "nb_global") \ - NB_NODE(copp, "copp") \ NB_NODE(logical_switch, "logical_switch") \ - NB_NODE(logical_switch_port, "logical_switch_port") \ - NB_NODE(forwarding_group, "forwarding_group") \ NB_NODE(address_set, "address_set") \ NB_NODE(port_group, "port_group") \ NB_NODE(load_balancer, "load_balancer") \ NB_NODE(load_balancer_group, "load_balancer_group") \ - NB_NODE(load_balancer_health_check, "load_balancer_health_check") \ NB_NODE(acl, "acl") \ NB_NODE(logical_router, "logical_router") \ - NB_NODE(qos, "qos") \ NB_NODE(mirror, "mirror") \ NB_NODE(meter, "meter") \ - NB_NODE(meter_band, "meter_band") \ - NB_NODE(logical_router_port, "logical_router_port") \ - NB_NODE(logical_router_static_route, "logical_router_static_route") \ - NB_NODE(logical_router_policy, "logical_router_policy") \ - NB_NODE(nat, "nat") \ - NB_NODE(dhcp_options, "dhcp_options") \ - NB_NODE(connection, "connection") \ - NB_NODE(dns, "dns") \ - NB_NODE(ssl, "ssl") \ - NB_NODE(gateway_chassis, "gateway_chassis") \ - NB_NODE(ha_chassis_group, "ha_chassis_group") \ - NB_NODE(ha_chassis, "ha_chassis") \ NB_NODE(bfd, "bfd") \ NB_NODE(static_mac_binding, "static_mac_binding") \ NB_NODE(chassis_template_var, "chassis_template_var") @@ -92,30 +75,17 @@ static unixctl_cb_func chassis_features_list; #define SB_NODES \ SB_NODE(sb_global, "sb_global") \ SB_NODE(chassis, "chassis") \ - SB_NODE(chassis_private, "chassis_private") \ - SB_NODE(encap, "encap") \ SB_NODE(address_set, "address_set") \ SB_NODE(port_group, "port_group") \ SB_NODE(logical_flow, "logical_flow") \ - SB_NODE(logical_dp_group, "logical_DP_group") \ SB_NODE(multicast_group, "multicast_group") \ SB_NODE(mirror, "mirror") \ SB_NODE(meter, "meter") \ - SB_NODE(meter_band, "meter_band") \ SB_NODE(datapath_binding, "datapath_binding") \ SB_NODE(port_binding, "port_binding") \ SB_NODE(mac_binding, "mac_binding") \ - SB_NODE(dhcp_options, "dhcp_options") \ - SB_NODE(dhcpv6_options, "dhcpv6_options") \ - SB_NODE(connection, "connection") \ - SB_NODE(ssl, "ssl") \ SB_NODE(dns, "dns") \ - SB_NODE(rbac_role, "rbac_role") \ - SB_NODE(rbac_permission, "rbac_permission") \ - SB_NODE(gateway_chassis, "gateway_chassis") \ - SB_NODE(ha_chassis, "ha_chassis") \ SB_NODE(ha_chassis_group, "ha_chassis_group") \ - SB_NODE(controller_event, "controller_event") \ SB_NODE(ip_multicast, "ip_multicast") \ SB_NODE(igmp_group, "igmp_group") \ SB_NODE(service_monitor, "service_monitor") \ @@ -172,67 +142,39 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, /* Define relationships between nodes where first argument is dependent * on the second argument */ engine_add_input(&en_northd, &en_nb_nb_global, NULL); - engine_add_input(&en_northd, &en_nb_copp, NULL); engine_add_input(&en_northd, &en_nb_logical_switch, NULL); - engine_add_input(&en_northd, &en_nb_logical_switch_port, NULL); - engine_add_input(&en_northd, &en_nb_forwarding_group, NULL); engine_add_input(&en_northd, &en_nb_port_group, NULL); engine_add_input(&en_northd, &en_nb_load_balancer, NULL); engine_add_input(&en_northd, &en_nb_load_balancer_group, NULL); - engine_add_input(&en_northd, &en_nb_load_balancer_health_check, NULL); engine_add_input(&en_northd, &en_nb_acl, NULL); engine_add_input(&en_northd, &en_nb_logical_router, NULL); - engine_add_input(&en_northd, &en_nb_qos, NULL); engine_add_input(&en_northd, &en_nb_mirror, NULL); engine_add_input(&en_northd, &en_nb_meter, NULL); - engine_add_input(&en_northd, &en_nb_meter_band, NULL); - engine_add_input(&en_northd, &en_nb_logical_router_port, NULL); - engine_add_input(&en_northd, &en_nb_logical_router_static_route, NULL); - engine_add_input(&en_northd, &en_nb_logical_router_policy, NULL); - engine_add_input(&en_northd, &en_nb_nat, NULL); - engine_add_input(&en_northd, &en_nb_dhcp_options, NULL); - engine_add_input(&en_northd, &en_nb_connection, NULL); - engine_add_input(&en_northd, &en_nb_dns, NULL); - engine_add_input(&en_northd, &en_nb_ssl, NULL); - engine_add_input(&en_northd, &en_nb_gateway_chassis, NULL); - engine_add_input(&en_northd, &en_nb_ha_chassis_group, NULL); - engine_add_input(&en_northd, &en_nb_ha_chassis, NULL); engine_add_input(&en_northd, &en_nb_static_mac_binding, NULL); engine_add_input(&en_northd, &en_nb_chassis_template_var, NULL); engine_add_input(&en_northd, &en_sb_sb_global, NULL); engine_add_input(&en_northd, &en_sb_chassis, NULL); - engine_add_input(&en_northd, &en_sb_chassis_private, NULL); - engine_add_input(&en_northd, &en_sb_encap, NULL); engine_add_input(&en_northd, &en_sb_port_group, NULL); - engine_add_input(&en_northd, &en_sb_logical_dp_group, NULL); engine_add_input(&en_northd, &en_sb_mirror, NULL); engine_add_input(&en_northd, &en_sb_meter, NULL); - engine_add_input(&en_northd, &en_sb_meter_band, NULL); engine_add_input(&en_northd, &en_sb_datapath_binding, NULL); engine_add_input(&en_northd, &en_sb_port_binding, NULL); engine_add_input(&en_northd, &en_sb_mac_binding, NULL); - engine_add_input(&en_northd, &en_sb_dhcp_options, NULL); - engine_add_input(&en_northd, &en_sb_dhcpv6_options, NULL); - engine_add_input(&en_northd, &en_sb_connection, NULL); - engine_add_input(&en_northd, &en_sb_ssl, NULL); engine_add_input(&en_northd, &en_sb_dns, NULL); - engine_add_input(&en_northd, &en_sb_rbac_role, NULL); - engine_add_input(&en_northd, &en_sb_rbac_permission, NULL); - engine_add_input(&en_northd, &en_sb_gateway_chassis, NULL); - engine_add_input(&en_northd, &en_sb_ha_chassis, NULL); engine_add_input(&en_northd, &en_sb_ha_chassis_group, NULL); - engine_add_input(&en_northd, &en_sb_controller_event, NULL); engine_add_input(&en_northd, &en_sb_ip_multicast, NULL); engine_add_input(&en_northd, &en_sb_service_monitor, NULL); engine_add_input(&en_northd, &en_sb_load_balancer, NULL); engine_add_input(&en_northd, &en_sb_fdb, NULL); engine_add_input(&en_northd, &en_sb_static_mac_binding, NULL); engine_add_input(&en_northd, &en_sb_chassis_template_var, NULL); + engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL); engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL); engine_add_input(&en_mac_binding_aging, &en_northd, NULL); engine_add_input(&en_mac_binding_aging, &en_mac_binding_aging_waker, NULL); + engine_add_input(&en_lflow, &en_nb_bfd, NULL); engine_add_input(&en_lflow, &en_sb_bfd, NULL); engine_add_input(&en_lflow, &en_sb_logical_flow, NULL); diff --git a/northd/northd.h b/northd/northd.h index c4563f0cb15a..24d4f804992d 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -53,7 +53,6 @@ struct northd_input { const struct sbrec_meter_table *sbrec_meter_table; const struct sbrec_dns_table *sbrec_dns_table; const struct sbrec_ip_multicast_table *sbrec_ip_multicast_table; - const struct sbrec_chassis_private_table *sbrec_chassis_private_table; const struct sbrec_static_mac_binding_table *sbrec_static_mac_binding_table; const struct sbrec_chassis_template_var_table From patchwork Tue Mar 21 06:02:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1759305 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Pggyl5xX9z2476 for ; Tue, 21 Mar 2023 17:03:43 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id B745861ACB; Tue, 21 Mar 2023 06:03:41 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org B745861ACB X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id QimujcGM023l; Tue, 21 Mar 2023 06:03:33 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 6A437610E4; Tue, 21 Mar 2023 06:03:18 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 6A437610E4 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1A79DC007E; Tue, 21 Mar 2023 06:03:18 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2A25AC009D for ; Tue, 21 Mar 2023 06:03:14 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 716FB4184D for ; Tue, 21 Mar 2023 06:03:09 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 716FB4184D X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qn7AMKnl2ckl for ; Tue, 21 Mar 2023 06:03:04 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 333AE417D1 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by smtp4.osuosl.org (Postfix) with ESMTPS id 333AE417D1 for ; Tue, 21 Mar 2023 06:03:04 +0000 (UTC) Received: (Authenticated sender: hzhou@ovn.org) by mail.gandi.net (Postfix) with ESMTPSA id 95FC5E0007; Tue, 21 Mar 2023 06:03:01 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Mon, 20 Mar 2023 23:02:35 -0700 Message-Id: <20230321060235.2256118-8-hzhou@ovn.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230321060235.2256118-1-hzhou@ovn.org> References: <20230321060235.2256118-1-hzhou@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 7/7] northd: Move the datapaths arrays to ovn_datapaths struct. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" In the current code, many functions depends on the global datapaths arrays variables, which is convenient. However, for incremental processing framework to track dependencies properly, we should avoid using global variables and purely depends on engine inputs (and function inputs, for the functions called by engine nodes' handlers). This patch moves the datapaths arrays to a new ovn_datapaths struct, which wraps the datapaths arrays together with the corresponding datapaths hmap table, because they are in fact for the same data, and the array is just an index of the data. The variable for the size of the array is replaced by a helper function which simply reads the size of the hmap. Signed-off-by: Han Zhou --- northd/en-sync-sb.c | 17 +- northd/mac-binding-aging.c | 2 +- northd/northd.c | 514 ++++++++++++++++++++----------------- northd/northd.h | 22 +- 4 files changed, 306 insertions(+), 249 deletions(-) diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c index d4f4e60eabd6..1e4e73ebcdf6 100644 --- a/northd/en-sync-sb.c +++ b/northd/en-sync-sb.c @@ -37,11 +37,11 @@ VLOG_DEFINE_THIS_MODULE(en_sync_to_sb); static void sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name, const char **addrs, size_t n_addrs, struct shash *sb_address_sets); -static void sync_addr_sets(const struct nbrec_address_set_table *, +static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, + const struct nbrec_address_set_table *, const struct nbrec_port_group_table *, const struct sbrec_address_set_table *, - struct ovsdb_idl_txn *ovnsb_txn, - struct hmap *datapaths); + const struct ovn_datapaths *lr_datapaths); static const struct sbrec_address_set *sb_address_set_lookup_by_name( struct ovsdb_idl_index *, const char *name); static void update_sb_addr_set(const char **nb_addresses, size_t n_addresses, @@ -89,8 +89,8 @@ en_sync_to_sb_addr_set_run(struct engine_node *node, void *data OVS_UNUSED) const struct engine_context *eng_ctx = engine_get_context(); struct northd_data *northd_data = engine_get_input_data("northd", node); - sync_addr_sets(nb_address_set_table, nb_port_group_table, - sb_address_set_table, eng_ctx->ovnsb_idl_txn, + sync_addr_sets(eng_ctx->ovnsb_idl_txn, nb_address_set_table, + nb_port_group_table, sb_address_set_table, &northd_data->lr_datapaths); engine_set_node_state(node, EN_UPDATED); @@ -228,10 +228,11 @@ sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name, * in OVN_Northbound, so that the address sets used in Logical_Flows in * OVN_Southbound is checked against the proper set.*/ static void -sync_addr_sets(const struct nbrec_address_set_table *nb_address_set_table, +sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, + const struct nbrec_address_set_table *nb_address_set_table, const struct nbrec_port_group_table *nb_port_group_table, const struct sbrec_address_set_table *sb_address_set_table, - struct ovsdb_idl_txn *ovnsb_txn, struct hmap *datapaths) + const struct ovn_datapaths *lr_datapaths) { struct shash sb_address_sets = SHASH_INITIALIZER(&sb_address_sets); @@ -271,7 +272,7 @@ sync_addr_sets(const struct nbrec_address_set_table *nb_address_set_table, /* Sync router load balancer VIP generated address sets. */ struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { + HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { if (!od->nbr) { continue; } diff --git a/northd/mac-binding-aging.c b/northd/mac-binding-aging.c index 3bdf1c2ea8d9..6db00c1660f2 100644 --- a/northd/mac-binding-aging.c +++ b/northd/mac-binding-aging.c @@ -109,7 +109,7 @@ en_mac_binding_aging_run(struct engine_node *node, void *data OVS_UNUSED) "sbrec_mac_binding_by_datapath"); struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, &northd_data->lr_datapaths) { + HMAP_FOR_EACH (od, key_node, &northd_data->lr_datapaths.datapaths) { if (od->sb && od->nbr) { mac_binding_aging_run_for_datapath(od->sb, od->nbr, sbrec_mac_binding_by_datapath, diff --git a/northd/northd.c b/northd/northd.c index b62ae5dbcaa5..3313ebec8430 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -1382,15 +1382,30 @@ ovn_datapath_assign_requested_tnl_id( } } -/* Array of ls datapaths, with 'od->index' being their index in the array. */ -static struct ovn_datapath **ls_datapaths_array = NULL; -/* Size of the 'ls_datapaths_array'. */ -static size_t n_ls_datapaths = 0; +static inline size_t +ods_size(const struct ovn_datapaths *datapaths) +{ + return hmap_count(&datapaths->datapaths); +} -/* Array of lr datapaths, with 'od->index' being their index in the array. */ -static struct ovn_datapath **lr_datapaths_array = NULL; -/* Size of the 'lr_datapaths_array'. */ -static size_t n_lr_datapaths = 0; +static void +ods_build_array_index(struct ovn_datapaths *datapaths) +{ + /* Assign unique sequential indexes to all datapaths. These are not + * visible outside of the northd loop, so, unlike the tunnel keys, it + * doesn't matter if they are different on every iteration. */ + size_t index = 0; + + datapaths->array = xrealloc(datapaths->array, + ods_size(datapaths) * sizeof *datapaths->array); + + struct ovn_datapath *od; + HMAP_FOR_EACH (od, key_node, &datapaths->datapaths) { + od->index = index; + datapaths->array[index++] = od; + od->datapaths = datapaths; + } +} /* Updates the southbound Datapath_Binding table so that it contains the * logical switches and routers specified by the northbound database. @@ -1403,13 +1418,13 @@ build_datapaths(struct ovsdb_idl_txn *ovnsb_txn, const struct nbrec_logical_router_table *nbrec_lr_table, const struct sbrec_datapath_binding_table *sbrec_dp_table, const struct sbrec_chassis_table *sbrec_chassis_table, - struct hmap *ls_datapaths, - struct hmap *lr_datapaths, + struct ovn_datapaths *ls_datapaths, + struct ovn_datapaths *lr_datapaths, struct ovs_list *lr_list) { struct ovs_list sb_only, nb_only, both; - struct hmap *datapaths = ls_datapaths; + struct hmap *datapaths = &ls_datapaths->datapaths; join_datapaths(nbrec_ls_table, nbrec_lr_table, sbrec_dp_table, ovnsb_txn, datapaths, &sb_only, &nb_only, &both, lr_list); @@ -1471,30 +1486,12 @@ build_datapaths(struct ovsdb_idl_txn *ovnsb_txn, continue; } hmap_remove(datapaths, &od->key_node); - hmap_insert(lr_datapaths, &od->key_node, od->key_node.hash); + hmap_insert(&lr_datapaths->datapaths, &od->key_node, + od->key_node.hash); } - /* Assign unique sequential indexes to all datapaths. These are not - * visible outside of the northd loop, so, unlike the tunnel keys, it - * doesn't matter if they are different on every iteration. */ - size_t index = 0; - - n_ls_datapaths = hmap_count(ls_datapaths); - ls_datapaths_array = xrealloc(ls_datapaths_array, - n_ls_datapaths * sizeof *ls_datapaths_array); - HMAP_FOR_EACH (od, key_node, ls_datapaths) { - od->index = index; - ls_datapaths_array[index++] = od; - } - - index = 0; - n_lr_datapaths = hmap_count(lr_datapaths); - lr_datapaths_array = xrealloc(lr_datapaths_array, - n_lr_datapaths * sizeof *lr_datapaths_array); - HMAP_FOR_EACH (od, key_node, lr_datapaths) { - od->index = index; - lr_datapaths_array[index++] = od; - } + ods_build_array_index(ls_datapaths); + ods_build_array_index(lr_datapaths); } /* Structure representing logical router port @@ -4032,7 +4029,8 @@ build_lrouter_lb_ips(struct ovn_lb_ip_set *lb_ips, static void build_lbs(const struct nbrec_load_balancer_table *nbrec_load_balancer_table, const struct nbrec_load_balancer_group_table *nbrec_lb_group_table, - struct hmap *ls_datapaths, struct hmap *lr_datapaths, + struct ovn_datapaths *ls_datapaths, + struct ovn_datapaths *lr_datapaths, struct hmap *lbs, struct hmap *lb_groups) { const struct nbrec_load_balancer_group *nbrec_lb_group; @@ -4045,8 +4043,8 @@ build_lbs(const struct nbrec_load_balancer_table *nbrec_load_balancer_table, const struct nbrec_load_balancer *nbrec_lb; NBREC_LOAD_BALANCER_TABLE_FOR_EACH (nbrec_lb, nbrec_load_balancer_table) { struct ovn_northd_lb *lb_nb = ovn_northd_lb_create(nbrec_lb, - n_ls_datapaths, - n_lr_datapaths); + ods_size(ls_datapaths), + ods_size(lr_datapaths)); hmap_insert(lbs, &lb_nb->hmap_node, uuid_hash(&nbrec_lb->header_.uuid)); } @@ -4054,8 +4052,8 @@ build_lbs(const struct nbrec_load_balancer_table *nbrec_load_balancer_table, NBREC_LOAD_BALANCER_GROUP_TABLE_FOR_EACH (nbrec_lb_group, nbrec_lb_group_table) { lb_group = ovn_lb_group_create(nbrec_lb_group, lbs, - hmap_count(ls_datapaths), - hmap_count(lr_datapaths)); + ods_size(ls_datapaths), + ods_size(lr_datapaths)); for (size_t i = 0; i < lb_group->n_lbs; i++) { build_lrouter_lb_ips(lb_group->lb_ips, lb_group->lbs[i]); @@ -4066,7 +4064,7 @@ build_lbs(const struct nbrec_load_balancer_table *nbrec_load_balancer_table, } struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, ls_datapaths) { + HMAP_FOR_EACH (od, key_node, &ls_datapaths->datapaths) { if (!od->nbs) { continue; } @@ -4093,7 +4091,7 @@ build_lbs(const struct nbrec_load_balancer_table *nbrec_load_balancer_table, } } - HMAP_FOR_EACH (od, key_node, lr_datapaths) { + HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { if (!od->nbr) { continue; } @@ -4244,11 +4242,11 @@ build_lrouter_lb_reachable_ips(struct ovn_datapath *od, } static void -build_lrouter_lbs_check(const struct hmap *lr_datapaths) +build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) { struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, lr_datapaths) { + HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { if (!od->nbr) { continue; } @@ -4267,12 +4265,12 @@ build_lrouter_lbs_check(const struct hmap *lr_datapaths) } static void -build_lrouter_lbs_reachable_ips(struct hmap *lr_datapaths, struct hmap *lbs, - struct hmap *lb_groups) +build_lrouter_lbs_reachable_ips(struct ovn_datapaths *lr_datapaths, + struct hmap *lbs, struct hmap *lb_groups) { struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, lr_datapaths) { + HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { if (!od->nbr) { continue; } @@ -4299,7 +4297,8 @@ build_lrouter_lbs_reachable_ips(struct hmap *lr_datapaths, struct hmap *lbs, } static void -build_lswitch_lbs_from_lrouter(struct hmap *lbs, struct hmap *lb_groups) +build_lswitch_lbs_from_lrouter(struct ovn_datapaths *lr_datapaths, + struct hmap *lbs, struct hmap *lb_groups) { if (!install_ls_lb_from_router) { return; @@ -4309,8 +4308,8 @@ build_lswitch_lbs_from_lrouter(struct hmap *lbs, struct hmap *lb_groups) size_t index; HMAP_FOR_EACH (lb, hmap_node, lbs) { - BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) { - struct ovn_datapath *od = lr_datapaths_array[index]; + BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths), lb->nb_lr_map) { + struct ovn_datapath *od = lr_datapaths->array[index]; ovn_northd_lb_add_ls(lb, od->n_ls_peers, od->ls_peers); } } @@ -4329,7 +4328,9 @@ build_lswitch_lbs_from_lrouter(struct hmap *lbs, struct hmap *lb_groups) } static void -build_lb_count_dps(struct hmap *lbs) +build_lb_count_dps(struct hmap *lbs, + size_t n_ls_datapaths, + size_t n_lr_datapaths) { struct ovn_northd_lb *lb; @@ -4347,13 +4348,13 @@ static void build_lb_port_related_data( struct ovsdb_idl_txn *ovnsb_txn, const struct sbrec_service_monitor_table *sbrec_service_monitor_table, - struct hmap *lr_datapaths, struct hmap *ls_ports, + struct ovn_datapaths *lr_datapaths, struct hmap *ls_ports, struct hmap *lbs, struct hmap *lb_groups) { build_lrouter_lbs_check(lr_datapaths); build_lrouter_lbs_reachable_ips(lr_datapaths, lbs, lb_groups); build_lb_svcs(ovnsb_txn, sbrec_service_monitor_table, ls_ports, lbs); - build_lswitch_lbs_from_lrouter(lbs, lb_groups); + build_lswitch_lbs_from_lrouter(lr_datapaths, lbs, lb_groups); } @@ -4381,16 +4382,15 @@ ovn_dp_group_find(const struct hmap *dp_groups, static struct sbrec_logical_dp_group * ovn_sb_insert_logical_dp_group(struct ovsdb_idl_txn *ovnsb_txn, const unsigned long *dpg_bitmap, - size_t bitmap_len, - struct ovn_datapath **datapaths_array) + const struct ovn_datapaths *datapaths) { struct sbrec_logical_dp_group *dp_group; const struct sbrec_datapath_binding **sb; size_t n = 0, index; - sb = xmalloc(bitmap_count1(dpg_bitmap, bitmap_len) * sizeof *sb); - BITMAP_FOR_EACH_1 (index, bitmap_len, dpg_bitmap) { - sb[n++] = datapaths_array[index]->sb; + sb = xmalloc(bitmap_count1(dpg_bitmap, ods_size(datapaths)) * sizeof *sb); + BITMAP_FOR_EACH_1 (index, ods_size(datapaths), dpg_bitmap) { + sb[n++] = datapaths->array[index]->sb; } dp_group = sbrec_logical_dp_group_insert(ovnsb_txn); sbrec_logical_dp_group_set_datapaths( @@ -4406,10 +4406,11 @@ ovn_sb_insert_logical_dp_group(struct ovsdb_idl_txn *ovnsb_txn, static void sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, const struct sbrec_load_balancer_table *sbrec_load_balancer_table, - struct hmap *ls_datapaths, struct hmap *lbs) + struct ovn_datapaths *ls_datapaths, struct hmap *lbs) { struct hmap dp_groups = HMAP_INITIALIZER(&dp_groups); struct ovn_northd_lb *lb; + size_t bitmap_len = ods_size(ls_datapaths); /* Delete any stale SB load balancer rows and collect existing valid * datapath groups. */ @@ -4452,11 +4453,12 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, struct ovn_dp_group *dpg = xzalloc(sizeof *dpg); size_t i, n = 0; - dpg->bitmap = bitmap_allocate(n_ls_datapaths); + dpg->bitmap = bitmap_allocate(bitmap_len); for (i = 0; i < dp_group->n_datapaths; i++) { struct ovn_datapath *datapath_od; - datapath_od = ovn_datapath_from_sbrec(ls_datapaths, NULL, + datapath_od = ovn_datapath_from_sbrec(&ls_datapaths->datapaths, + NULL, dp_group->datapaths[i]); if (!datapath_od || ovn_datapath_is_stale(datapath_od)) { break; @@ -4467,7 +4469,7 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, if (i == dp_group->n_datapaths) { uint32_t hash = hash_int(n, 0); - if (!ovn_dp_group_find(&dp_groups, dpg->bitmap, n_ls_datapaths, + if (!ovn_dp_group_find(&dp_groups, dpg->bitmap, bitmap_len, hash)) { dpg->dp_group = dp_group; hmap_insert(&dp_groups, &dpg->node, hash); @@ -4511,15 +4513,14 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, uint32_t hash; hash = hash_int(lb->n_nb_ls, 0); - dpg = ovn_dp_group_find(&dp_groups, lb->nb_ls_map, n_ls_datapaths, + dpg = ovn_dp_group_find(&dp_groups, lb->nb_ls_map, bitmap_len, hash); if (!dpg) { dpg = xzalloc(sizeof *dpg); dpg->dp_group = ovn_sb_insert_logical_dp_group(ovnsb_txn, lb->nb_ls_map, - n_ls_datapaths, - ls_datapaths_array); - dpg->bitmap = bitmap_clone(lb->nb_ls_map, n_ls_datapaths); + ls_datapaths); + dpg->bitmap = bitmap_clone(lb->nb_ls_map, bitmap_len); hmap_insert(&dp_groups, &dpg->node, hash); } @@ -4545,7 +4546,7 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, * schema for compatibility reasons. Reset it to empty, just in case. */ struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, ls_datapaths) { + HMAP_FOR_EACH (od, key_node, &ls_datapaths->datapaths) { ovs_assert(od->nbs); if (od->sb->n_load_balancers) { @@ -5297,7 +5298,7 @@ ovn_dp_group_add_with_reference(struct ovn_lflow *lflow_ref, */ static void do_ovn_lflow_add(struct hmap *lflow_map, const struct ovn_datapath *od, - const unsigned long *dp_bitmap, + const unsigned long *dp_bitmap, size_t dp_bitmap_len, uint32_t hash, enum ovn_stage stage, uint16_t priority, const char *match, const char *actions, const char *io_port, const struct ovsdb_idl_row *stage_hint, @@ -5308,13 +5309,14 @@ do_ovn_lflow_add(struct hmap *lflow_map, const struct ovn_datapath *od, struct ovn_lflow *old_lflow; struct ovn_lflow *lflow; - size_t n_datapaths = ovn_stage_to_datapath_type(stage) == DP_SWITCH ? - n_ls_datapaths : n_lr_datapaths; + size_t bitmap_len = od ? ods_size(od->datapaths) : dp_bitmap_len; + ovs_assert(bitmap_len); old_lflow = ovn_lflow_find(lflow_map, NULL, stage, priority, match, actions, ctrl_meter, hash); if (old_lflow) { - ovn_dp_group_add_with_reference(old_lflow, od, dp_bitmap, n_datapaths); + ovn_dp_group_add_with_reference(old_lflow, od, dp_bitmap, + bitmap_len); return; } @@ -5322,13 +5324,13 @@ do_ovn_lflow_add(struct hmap *lflow_map, const struct ovn_datapath *od, /* While adding new logical flows we're not setting single datapath, but * collecting a group. 'od' will be updated later for all flows with only * one datapath in a group, so it could be hashed correctly. */ - ovn_lflow_init(lflow, NULL, n_datapaths, stage, priority, + ovn_lflow_init(lflow, NULL, bitmap_len, stage, priority, xstrdup(match), xstrdup(actions), io_port ? xstrdup(io_port) : NULL, nullable_xstrdup(ctrl_meter), ovn_lflow_hint(stage_hint), where); - ovn_dp_group_add_with_reference(lflow, od, dp_bitmap, n_datapaths); + ovn_dp_group_add_with_reference(lflow, od, dp_bitmap, bitmap_len); if (parallelization_state != STATE_USE_PARALLELIZATION) { hmap_insert(lflow_map, &lflow->hmap_node, hash); @@ -5341,7 +5343,7 @@ do_ovn_lflow_add(struct hmap *lflow_map, const struct ovn_datapath *od, /* Adds a row with the specified contents to the Logical_Flow table. */ static void ovn_lflow_add_at(struct hmap *lflow_map, const struct ovn_datapath *od, - const unsigned long *dp_bitmap, + const unsigned long *dp_bitmap, size_t dp_bitmap_len, enum ovn_stage stage, uint16_t priority, const char *match, const char *actions, const char *io_port, const char *ctrl_meter, @@ -5360,8 +5362,9 @@ ovn_lflow_add_at(struct hmap *lflow_map, const struct ovn_datapath *od, actions); hash_lock = lflow_hash_lock(lflow_map, hash); - do_ovn_lflow_add(lflow_map, od, dp_bitmap, hash, stage, priority, - match, actions, io_port, stage_hint, where, ctrl_meter); + do_ovn_lflow_add(lflow_map, od, dp_bitmap, dp_bitmap_len, hash, stage, + priority, match, actions, io_port, stage_hint, where, + ctrl_meter); lflow_hash_unlock(hash_lock); } @@ -5371,7 +5374,7 @@ __ovn_lflow_add_default_drop(struct hmap *lflow_map, enum ovn_stage stage, const char *where) { - ovn_lflow_add_at(lflow_map, od, NULL, stage, 0, "1", + ovn_lflow_add_at(lflow_map, od, NULL, 0, stage, 0, "1", debug_drop_action(), NULL, NULL, NULL, where ); } @@ -5380,18 +5383,20 @@ __ovn_lflow_add_default_drop(struct hmap *lflow_map, #define ovn_lflow_add_with_hint__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ ACTIONS, IN_OUT_PORT, CTRL_METER, \ STAGE_HINT) \ - ovn_lflow_add_at(LFLOW_MAP, OD, NULL, STAGE, PRIORITY, MATCH, ACTIONS, \ + ovn_lflow_add_at(LFLOW_MAP, OD, NULL, 0, STAGE, PRIORITY, MATCH, ACTIONS, \ IN_OUT_PORT, CTRL_METER, STAGE_HINT, OVS_SOURCE_LOCATOR) #define ovn_lflow_add_with_hint(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ ACTIONS, STAGE_HINT) \ - ovn_lflow_add_at(LFLOW_MAP, OD, NULL, STAGE, PRIORITY, MATCH, ACTIONS, \ + ovn_lflow_add_at(LFLOW_MAP, OD, NULL, 0, STAGE, PRIORITY, MATCH, ACTIONS, \ NULL, NULL, STAGE_HINT, OVS_SOURCE_LOCATOR) -#define ovn_lflow_add_with_dp_group(LFLOW_MAP, DP_BITMAP, STAGE, PRIORITY, \ - MATCH, ACTIONS, STAGE_HINT) \ - ovn_lflow_add_at(LFLOW_MAP, NULL, DP_BITMAP, STAGE, PRIORITY, MATCH, \ - ACTIONS, NULL, NULL, STAGE_HINT, OVS_SOURCE_LOCATOR) +#define ovn_lflow_add_with_dp_group(LFLOW_MAP, DP_BITMAP, DP_BITMAP_LEN, \ + STAGE, PRIORITY, MATCH, ACTIONS, \ + STAGE_HINT) \ + ovn_lflow_add_at(LFLOW_MAP, NULL, DP_BITMAP, DP_BITMAP_LEN, STAGE, \ + PRIORITY, MATCH, ACTIONS, NULL, NULL, STAGE_HINT, \ + OVS_SOURCE_LOCATOR) #define ovn_lflow_add_default_drop(LFLOW_MAP, OD, STAGE) \ __ovn_lflow_add_default_drop(LFLOW_MAP, OD, STAGE, OVS_SOURCE_LOCATOR) @@ -5410,11 +5415,11 @@ __ovn_lflow_add_default_drop(struct hmap *lflow_map, #define ovn_lflow_add_with_lport_and_hint(LFLOW_MAP, OD, STAGE, PRIORITY, \ MATCH, ACTIONS, IN_OUT_PORT, \ STAGE_HINT) \ - ovn_lflow_add_at(LFLOW_MAP, OD, NULL, STAGE, PRIORITY, MATCH, ACTIONS, \ + ovn_lflow_add_at(LFLOW_MAP, OD, NULL, 0, STAGE, PRIORITY, MATCH, ACTIONS, \ IN_OUT_PORT, NULL, STAGE_HINT, OVS_SOURCE_LOCATOR) #define ovn_lflow_add(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS) \ - ovn_lflow_add_at(LFLOW_MAP, OD, NULL, STAGE, PRIORITY, MATCH, ACTIONS, \ + ovn_lflow_add_at(LFLOW_MAP, OD, NULL, 0, STAGE, PRIORITY, MATCH, ACTIONS, \ NULL, NULL, NULL, OVS_SOURCE_LOCATOR) #define ovn_lflow_metered(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, \ @@ -7126,8 +7131,9 @@ build_qos(struct ovn_datapath *od, struct hmap *lflows) { static void build_lb_rules_pre_stateful(struct hmap *lflows, struct ovn_northd_lb *lb, - bool ct_lb_mark, struct ds *match, - struct ds *action) + bool ct_lb_mark, + const struct ovn_datapaths *ls_datapaths, + struct ds *match, struct ds *action) { if (!lb->n_nb_ls) { return; @@ -7178,8 +7184,9 @@ build_lb_rules_pre_stateful(struct hmap *lflows, struct ovn_northd_lb *lb, } ovn_lflow_add_with_dp_group( - lflows, lb->nb_ls_map, S_SWITCH_IN_PRE_STATEFUL, 120, - ds_cstr(match), ds_cstr(action), &lb->nlb->header_); + lflows, lb->nb_ls_map, ods_size(ls_datapaths), + S_SWITCH_IN_PRE_STATEFUL, 120, ds_cstr(match), ds_cstr(action), + &lb->nlb->header_); } } @@ -7223,18 +7230,19 @@ build_lb_rules_pre_stateful(struct hmap *lflows, struct ovn_northd_lb *lb, static void build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, struct ovn_lb_vip *lb_vip, char *new_lb_match, - char *lb_action, const unsigned long *dp_bitmap) + char *lb_action, const unsigned long *dp_bitmap, + const struct ovn_datapaths *lr_datapaths) { if (!lb->affinity_timeout || - bitmap_is_all_zeros(dp_bitmap, n_lr_datapaths)) { + bitmap_is_all_zeros(dp_bitmap, ods_size(lr_datapaths))) { return; } static char *aff_check = REGBIT_KNOWN_LB_SESSION" = chk_lb_aff(); next;"; ovn_lflow_add_with_dp_group( - lflows, dp_bitmap, S_ROUTER_IN_LB_AFF_CHECK, 100, - new_lb_match, aff_check, &lb->nlb->header_); + lflows, dp_bitmap, ods_size(lr_datapaths), S_ROUTER_IN_LB_AFF_CHECK, + 100, new_lb_match, aff_check, &lb->nlb->header_); struct ds aff_action = DS_EMPTY_INITIALIZER; struct ds aff_action_learn = DS_EMPTY_INITIALIZER; @@ -7333,13 +7341,13 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, /* Forward to OFTABLE_CHK_LB_AFFINITY table to store flow tuple. */ ovn_lflow_add_with_dp_group( - lflows, dp_bitmap, S_ROUTER_IN_LB_AFF_LEARN, 100, - ds_cstr(&aff_match_learn), ds_cstr(&aff_action_learn), - &lb->nlb->header_); + lflows, dp_bitmap, ods_size(lr_datapaths), + S_ROUTER_IN_LB_AFF_LEARN, 100, ds_cstr(&aff_match_learn), + ds_cstr(&aff_action_learn), &lb->nlb->header_); /* Use already selected backend within affinity timeslot. */ ovn_lflow_add_with_dp_group( - lflows, dp_bitmap, S_ROUTER_IN_DNAT, 150, + lflows, dp_bitmap, ods_size(lr_datapaths), S_ROUTER_IN_DNAT, 150, ds_cstr(&aff_match), ds_cstr(&aff_action), &lb->nlb->header_); ds_truncate(&aff_action, aff_action_len); @@ -7397,7 +7405,8 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, */ static void build_lb_affinity_ls_flows(struct hmap *lflows, struct ovn_northd_lb *lb, - struct ovn_lb_vip *lb_vip) + struct ovn_lb_vip *lb_vip, + const struct ovn_datapaths *ls_datapaths) { if (!lb->affinity_timeout || !lb->n_nb_ls) { return; @@ -7422,8 +7431,9 @@ build_lb_affinity_ls_flows(struct hmap *lflows, struct ovn_northd_lb *lb, static char *aff_check = REGBIT_KNOWN_LB_SESSION" = chk_lb_aff(); next;"; ovn_lflow_add_with_dp_group( - lflows, lb->nb_ls_map, S_SWITCH_IN_LB_AFF_CHECK, 100, - ds_cstr(&new_lb_match), aff_check, &lb->nlb->header_); + lflows, lb->nb_ls_map, ods_size(ls_datapaths), + S_SWITCH_IN_LB_AFF_CHECK, 100, ds_cstr(&new_lb_match), aff_check, + &lb->nlb->header_); ds_destroy(&new_lb_match); struct ds aff_action = DS_EMPTY_INITIALIZER; @@ -7511,13 +7521,13 @@ build_lb_affinity_ls_flows(struct hmap *lflows, struct ovn_northd_lb *lb, /* Forward to OFTABLE_CHK_LB_AFFINITY table to store flow tuple. */ ovn_lflow_add_with_dp_group( - lflows, lb->nb_ls_map, S_SWITCH_IN_LB_AFF_LEARN, 100, - ds_cstr(&aff_match_learn), ds_cstr(&aff_action_learn), - &lb->nlb->header_); + lflows, lb->nb_ls_map, ods_size(ls_datapaths), + S_SWITCH_IN_LB_AFF_LEARN, 100, ds_cstr(&aff_match_learn), + ds_cstr(&aff_action_learn), &lb->nlb->header_); /* Use already selected backend within affinity timeslot. */ ovn_lflow_add_with_dp_group( - lflows, lb->nb_ls_map, S_SWITCH_IN_LB, 150, + lflows, lb->nb_ls_map, ods_size(ls_datapaths), S_SWITCH_IN_LB, 150, ds_cstr(&aff_match), ds_cstr(&aff_action), &lb->nlb->header_); ds_truncate(&aff_action, aff_action_len); @@ -7552,6 +7562,7 @@ build_lrouter_lb_affinity_default_flows(struct ovn_datapath *od, static void build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, + const struct ovn_datapaths *ls_datapaths, const struct chassis_features *features, struct ds *match, struct ds *action, const struct shash *meter_groups) { @@ -7588,16 +7599,16 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, priority = 120; } - build_lb_affinity_ls_flows(lflows, lb, lb_vip); + build_lb_affinity_ls_flows(lflows, lb, lb_vip, ls_datapaths); unsigned long *dp_non_meter = NULL; bool build_non_meter = false; if (reject) { size_t index; - dp_non_meter = bitmap_clone(lb->nb_ls_map, n_ls_datapaths); - BITMAP_FOR_EACH_1 (index, n_ls_datapaths, lb->nb_ls_map) { - struct ovn_datapath *od = ls_datapaths_array[index]; + dp_non_meter = bitmap_clone(lb->nb_ls_map, ods_size(ls_datapaths)); + BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), lb->nb_ls_map) { + struct ovn_datapath *od = ls_datapaths->array[index]; meter = copp_meter_get(COPP_REJECT, od->nbs->copp, meter_groups); @@ -7615,7 +7626,7 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, if (!reject || build_non_meter) { ovn_lflow_add_with_dp_group( lflows, dp_non_meter ? dp_non_meter : lb->nb_ls_map, - S_SWITCH_IN_LB, priority, + ods_size(ls_datapaths), S_SWITCH_IN_LB, priority, ds_cstr(match), ds_cstr(action), &lb->nlb->header_); } bitmap_free(dp_non_meter); @@ -8414,7 +8425,7 @@ is_vlan_transparent(const struct ovn_datapath *od) } static void -build_lswitch_flows(const struct hmap *datapaths, +build_lswitch_flows(const struct ovn_datapaths *ls_datapaths, struct hmap *lflows) { /* This flow table structure is documented in ovn-northd(8), so please @@ -8424,7 +8435,7 @@ build_lswitch_flows(const struct hmap *datapaths, /* Ingress table 25/26: Destination lookup for unknown MACs * (priority 0). */ - HMAP_FOR_EACH (od, key_node, datapaths) { + HMAP_FOR_EACH (od, key_node, &ls_datapaths->datapaths) { if (!od->nbs) { continue; } @@ -10693,20 +10704,22 @@ build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx, static void build_gw_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx, enum lrouter_nat_lb_flow_type type, + const struct ovn_datapaths *lr_datapaths, const unsigned long *dp_bitmap) { unsigned long *dp_non_meter = NULL; bool build_non_meter = false; size_t index; + size_t bitmap_len = ods_size(lr_datapaths); - if (bitmap_is_all_zeros(dp_bitmap, n_lr_datapaths)) { + if (bitmap_is_all_zeros(dp_bitmap, bitmap_len)) { return; } if (ctx->reject) { - dp_non_meter = bitmap_clone(dp_bitmap, n_lr_datapaths); - BITMAP_FOR_EACH_1 (index, n_lr_datapaths, dp_bitmap) { - struct ovn_datapath *od = lr_datapaths_array[index]; + dp_non_meter = bitmap_clone(dp_bitmap, bitmap_len); + BITMAP_FOR_EACH_1 (index, bitmap_len, dp_bitmap) { + struct ovn_datapath *od = lr_datapaths->array[index]; const char *meter; meter = copp_meter_get(COPP_REJECT, od->nbr->copp, @@ -10723,15 +10736,15 @@ build_gw_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx, } if (!ctx->reject || build_non_meter) { ovn_lflow_add_with_dp_group(ctx->lflows, - dp_non_meter ? dp_non_meter : dp_bitmap, + dp_non_meter ? dp_non_meter : dp_bitmap, ods_size(lr_datapaths), S_ROUTER_IN_DNAT, ctx->prio, ds_cstr(ctx->new_match), ctx->new_action[type], &ctx->lb->nlb->header_); } bitmap_free(dp_non_meter); ovn_lflow_add_with_dp_group( - ctx->lflows, dp_bitmap, S_ROUTER_IN_DNAT, ctx->prio, - ds_cstr(ctx->est_match), ctx->est_action[type], + ctx->lflows, dp_bitmap, ods_size(lr_datapaths), S_ROUTER_IN_DNAT, + ctx->prio, ds_cstr(ctx->est_match), ctx->est_action[type], &ctx->lb->nlb->header_); } @@ -10739,6 +10752,7 @@ static void build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, struct ovn_northd_lb *lb, struct ovn_northd_lb_vip *vips_nb, + const struct ovn_datapaths *lr_datapaths, struct hmap *lflows, struct ds *match, struct ds *action, const struct shash *meter_groups, @@ -10843,16 +10857,17 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, }; unsigned long *dp_bitmap[LROUTER_NAT_LB_FLOW_MAX + 2]; + size_t bitmap_len = ods_size(lr_datapaths); for (size_t i = 0; i < LROUTER_NAT_LB_FLOW_MAX + 2; i++) { - dp_bitmap[i] = bitmap_allocate(n_lr_datapaths); + dp_bitmap[i] = bitmap_allocate(bitmap_len); } /* Group gw router since we do not have datapath dependency in * lflow generation for them. */ size_t index; - BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) { - struct ovn_datapath *od = lr_datapaths_array[index]; + BITMAP_FOR_EACH_1 (index, bitmap_len, lb->nb_lr_map) { + struct ovn_datapath *od = lr_datapaths->array[index]; enum lrouter_nat_lb_flow_type type; if (lb->skip_snat) { @@ -10898,7 +10913,8 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, } for (size_t type = 0; type < LROUTER_NAT_LB_FLOW_MAX; type++) { - build_gw_lrouter_nat_flows_for_lb(&ctx, type, dp_bitmap[type]); + build_gw_lrouter_nat_flows_for_lb(&ctx, type, lr_datapaths, + dp_bitmap[type]); } /* LB affinity flows for datapaths where CMS has specified @@ -10906,7 +10922,8 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, */ build_lb_affinity_lr_flows(lflows, lb, lb_vip, ds_cstr(match), "flags.force_snat_for_lb = 1; ", - dp_bitmap[LROUTER_NAT_LB_AFF_FORCE_SNAT]); + dp_bitmap[LROUTER_NAT_LB_AFF_FORCE_SNAT], + lr_datapaths); /* LB affinity flows for datapaths where CMS has specified * skip_snat_for_lb floag option or regular datapaths. @@ -10914,7 +10931,8 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, char *lb_aff_action = lb->skip_snat ? "flags.skip_snat_for_lb = 1; " : NULL; build_lb_affinity_lr_flows(lflows, lb, lb_vip, ds_cstr(match), - lb_aff_action, dp_bitmap[LROUTER_NAT_LB_AFF]); + lb_aff_action, dp_bitmap[LROUTER_NAT_LB_AFF], + lr_datapaths); ds_destroy(&unsnat_match); ds_destroy(&undnat_match); @@ -10930,6 +10948,7 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, static void build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, const struct shash *meter_groups, + const struct ovn_datapaths *ls_datapaths, const struct chassis_features *features, struct ds *match, struct ds *action) { @@ -10946,8 +10965,8 @@ build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, } size_t index; - BITMAP_FOR_EACH_1 (index, n_ls_datapaths, lb->nb_ls_map) { - struct ovn_datapath *od = ls_datapaths_array[index]; + BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), lb->nb_ls_map) { + struct ovn_datapath *od = ls_datapaths->array[index]; ovn_lflow_add_with_hint__(lflows, od, S_SWITCH_IN_PRE_LB, 130, ds_cstr(match), @@ -10971,8 +10990,9 @@ build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, * connection, so it is okay if we do not hit the above match on * REGBIT_CONNTRACK_COMMIT. */ build_lb_rules_pre_stateful(lflows, lb, features->ct_no_masked_label, - match, action); - build_lb_rules(lflows, lb, features, match, action, meter_groups); + ls_datapaths, match, action); + build_lb_rules(lflows, lb, ls_datapaths, features, match, action, + meter_groups); } /* If there are any load balancing rules, we should send the packet to @@ -10986,6 +11006,7 @@ build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, static void build_lrouter_defrag_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, + const struct ovn_datapaths *lr_datapaths, struct ds *match) { if (!lb->n_nb_lr) { @@ -11021,8 +11042,8 @@ build_lrouter_defrag_flows_for_lb(struct ovn_northd_lb *lb, ds_put_format(&defrag_actions, "ct_dnat;"); ovn_lflow_add_with_dp_group( - lflows, lb->nb_lr_map, S_ROUTER_IN_DEFRAG, prio, - ds_cstr(match), ds_cstr(&defrag_actions), &lb->nlb->header_); + lflows, lb->nb_lr_map, ods_size(lr_datapaths), S_ROUTER_IN_DEFRAG, + prio, ds_cstr(match), ds_cstr(&defrag_actions), &lb->nlb->header_); } ds_destroy(&defrag_actions); } @@ -11030,6 +11051,7 @@ build_lrouter_defrag_flows_for_lb(struct ovn_northd_lb *lb, static void build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, const struct shash *meter_groups, + const struct ovn_datapaths *lr_datapaths, const struct chassis_features *features, struct ds *match, struct ds *action) { @@ -11043,15 +11065,15 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, struct ovn_lb_vip *lb_vip = &lb->vips[i]; build_lrouter_nat_flows_for_lb(lb_vip, lb, &lb->vips_nb[i], - lflows, match, action, meter_groups, - features); + lr_datapaths, lflows, match, action, + meter_groups, features); if (!build_empty_lb_event_flow(lb_vip, lb, match, action)) { continue; } - BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) { - struct ovn_datapath *od = lr_datapaths_array[index]; + BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths), lb->nb_lr_map) { + struct ovn_datapath *od = lr_datapaths->array[index]; ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, 130, ds_cstr(match), ds_cstr(action), @@ -11064,8 +11086,8 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, } if (lb->skip_snat) { - BITMAP_FOR_EACH_1 (index, n_lr_datapaths, lb->nb_lr_map) { - struct ovn_datapath *od = lr_datapaths_array[index]; + BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths), lb->nb_lr_map) { + struct ovn_datapath *od = lr_datapaths->array[index]; ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120, "flags.skip_snat_for_lb == 1 && ip", "next;"); @@ -14613,8 +14635,8 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, struct lswitch_flow_build_info { - const struct hmap *ls_datapaths; - const struct hmap *lr_datapaths; + const struct ovn_datapaths *ls_datapaths; + const struct ovn_datapaths *lr_datapaths; const struct hmap *ls_ports; const struct hmap *lr_ports; const struct hmap *port_groups; @@ -14779,11 +14801,11 @@ build_lflows_thread(void *arg) if (lsi) { /* Iterate over bucket ThreadID, ThreadID+size, ... */ for (bnum = control->id; - bnum <= lsi->ls_datapaths->mask; + bnum <= lsi->ls_datapaths->datapaths.mask; bnum += control->pool->size) { HMAP_FOR_EACH_IN_PARALLEL (od, key_node, bnum, - lsi->ls_datapaths) { + &lsi->ls_datapaths->datapaths) { if (stop_parallel_processing()) { return NULL; } @@ -14791,11 +14813,11 @@ build_lflows_thread(void *arg) } } for (bnum = control->id; - bnum <= lsi->lr_datapaths->mask; + bnum <= lsi->lr_datapaths->datapaths.mask; bnum += control->pool->size) { HMAP_FOR_EACH_IN_PARALLEL (od, key_node, bnum, - lsi->lr_datapaths) { + &lsi->lr_datapaths->datapaths) { if (stop_parallel_processing()) { return NULL; } @@ -14838,13 +14860,16 @@ build_lflows_thread(void *arg) &lsi->match, &lsi->actions); build_lrouter_defrag_flows_for_lb(lb, lsi->lflows, + lsi->lr_datapaths, &lsi->match); build_lrouter_flows_for_lb(lb, lsi->lflows, lsi->meter_groups, + lsi->lr_datapaths, lsi->features, &lsi->match, &lsi->actions); build_lswitch_flows_for_lb(lb, lsi->lflows, lsi->meter_groups, + lsi->ls_datapaths, lsi->features, &lsi->match, &lsi->actions); } @@ -14903,8 +14928,8 @@ fix_flow_map_size(struct hmap *lflow_map, } static void -build_lswitch_and_lrouter_flows(const struct hmap *ls_datapaths, - const struct hmap *lr_datapaths, +build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, + const struct ovn_datapaths *lr_datapaths, const struct hmap *ls_ports, const struct hmap *lr_ports, const struct hmap *port_groups, @@ -14987,10 +15012,10 @@ build_lswitch_and_lrouter_flows(const struct hmap *ls_datapaths, * will move here and will be reogranized by iterator type. */ stopwatch_start(LFLOWS_DATAPATHS_STOPWATCH_NAME, time_msec()); - HMAP_FOR_EACH (od, key_node, ls_datapaths) { + HMAP_FOR_EACH (od, key_node, &ls_datapaths->datapaths) { build_lswitch_and_lrouter_iterate_by_ls(od, &lsi); } - HMAP_FOR_EACH (od, key_node, lr_datapaths) { + HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { build_lswitch_and_lrouter_iterate_by_lr(od, &lsi); } stopwatch_stop(LFLOWS_DATAPATHS_STOPWATCH_NAME, time_msec()); @@ -15007,11 +15032,14 @@ build_lswitch_and_lrouter_flows(const struct hmap *ls_datapaths, build_lswitch_arp_nd_service_monitor(lb, lsi.lflows, &lsi.actions, &lsi.match); - build_lrouter_defrag_flows_for_lb(lb, lsi.lflows, &lsi.match); + build_lrouter_defrag_flows_for_lb(lb, lsi.lflows, lsi.lr_datapaths, + &lsi.match); build_lrouter_flows_for_lb(lb, lsi.lflows, lsi.meter_groups, - lsi.features, &lsi.match, &lsi.actions); + lsi.lr_datapaths, lsi.features, + &lsi.match, &lsi.actions); build_lswitch_flows_for_lb(lb, lsi.lflows, lsi.meter_groups, - lsi.features, &lsi.match, &lsi.actions); + lsi.ls_datapaths, lsi.features, + &lsi.match, &lsi.actions); } stopwatch_stop(LFLOWS_LBS_STOPWATCH_NAME, time_msec()); stopwatch_start(LFLOWS_IGMP_STOPWATCH_NAME, time_msec()); @@ -15037,11 +15065,11 @@ ovn_sb_set_lflow_logical_dp_group( struct hmap *dp_groups, const struct sbrec_logical_flow *sbflow, const unsigned long *dpg_bitmap, - size_t bitmap_len, - struct ovn_datapath **datapaths_array) + const struct ovn_datapaths *datapaths) { struct ovn_dp_group *dpg; size_t n_ods; + size_t bitmap_len = ods_size(datapaths); n_ods = bitmap_count1(dpg_bitmap, bitmap_len); @@ -15058,8 +15086,7 @@ ovn_sb_set_lflow_logical_dp_group( if (!dpg->dp_group) { dpg->dp_group = ovn_sb_insert_logical_dp_group(ovnsb_txn, dpg->bitmap, - bitmap_len, - datapaths_array); + datapaths); } sbrec_logical_flow_set_logical_dp_group(sbflow, dpg->dp_group); } @@ -15087,7 +15114,7 @@ void run_update_worker_pool(int n_threads) static void build_mcast_groups(const struct sbrec_igmp_group_table *sbrec_igmp_group_table, struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp, - const struct hmap *ls_datapaths, + const struct ovn_datapaths *ls_datapaths, const struct hmap *ls_ports, const struct hmap *lr_ports, struct hmap *mcast_groups, @@ -15156,13 +15183,13 @@ void build_lflows(struct lflow_input *input_data, size_t n_datapaths; struct ovn_datapath **datapaths_array; if (ovn_stage_to_datapath_type(lflow->stage) == DP_SWITCH) { - n_datapaths = n_ls_datapaths; + n_datapaths = ods_size(input_data->ls_datapaths); + datapaths_array = input_data->ls_datapaths->array; dp_groups = &ls_dp_groups; - datapaths_array = ls_datapaths_array; } else { - n_datapaths = n_lr_datapaths; + n_datapaths = ods_size(input_data->lr_datapaths); + datapaths_array = input_data->lr_datapaths->array; dp_groups = &lr_dp_groups; - datapaths_array = lr_datapaths_array; } n_ods = bitmap_count1(lflow->dpg_bitmap, n_datapaths); @@ -15221,9 +15248,9 @@ void build_lflows(struct lflow_input *input_data, struct sbrec_datapath_binding *dp = sbflow->logical_datapath; if (dp) { logical_datapath_od = ovn_datapath_from_sbrec( - input_data->ls_datapaths, - input_data->lr_datapaths, - dp); + &input_data->ls_datapaths->datapaths, + &input_data->lr_datapaths->datapaths, + dp); if (logical_datapath_od && ovn_datapath_is_stale(logical_datapath_od)) { logical_datapath_od = NULL; @@ -15231,9 +15258,9 @@ void build_lflows(struct lflow_input *input_data, } for (i = 0; dp_group && i < dp_group->n_datapaths; i++) { logical_datapath_od = ovn_datapath_from_sbrec( - input_data->ls_datapaths, - input_data->lr_datapaths, - dp_group->datapaths[i]); + &input_data->ls_datapaths->datapaths, + &input_data->lr_datapaths->datapaths, + dp_group->datapaths[i]); if (logical_datapath_od && !ovn_datapath_is_stale(logical_datapath_od)) { break; @@ -15259,15 +15286,15 @@ void build_lflows(struct lflow_input *input_data, if (lflow) { struct hmap *dp_groups; size_t n_datapaths; - struct ovn_datapath **datapaths_array; + const struct ovn_datapaths *datapaths; if (ovn_stage_to_datapath_type(lflow->stage) == DP_SWITCH) { - n_datapaths = n_ls_datapaths; + n_datapaths = ods_size(input_data->ls_datapaths); + datapaths = input_data->ls_datapaths; dp_groups = &ls_dp_groups; - datapaths_array = ls_datapaths_array; } else { - n_datapaths = n_lr_datapaths; + n_datapaths = ods_size(input_data->lr_datapaths); + datapaths = input_data->lr_datapaths; dp_groups = &lr_dp_groups; - datapaths_array = lr_datapaths_array; } if (input_data->ovn_internal_version_changed) { const char *stage_name = smap_get_def(&sbflow->external_ids, @@ -15321,7 +15348,8 @@ void build_lflows(struct lflow_input *input_data, /* Check all logical datapaths from the group. */ for (i = 0; i < dp_group->n_datapaths; i++) { od = ovn_datapath_from_sbrec( - input_data->ls_datapaths, input_data->lr_datapaths, + &input_data->ls_datapaths->datapaths, + &input_data->lr_datapaths->datapaths, dp_group->datapaths[i]); if (!od || ovn_datapath_is_stale(od)) { continue; @@ -15337,8 +15365,7 @@ void build_lflows(struct lflow_input *input_data, if (update_dp_group) { ovn_sb_set_lflow_logical_dp_group(ovnsb_txn, dp_groups, sbflow, lflow->dpg_bitmap, - n_datapaths, - datapaths_array); + datapaths); } else if (lflow->dpg && !lflow->dpg->dp_group) { /* Setting relation between unique datapath group and * Sb DB datapath goup. */ @@ -15357,16 +15384,13 @@ void build_lflows(struct lflow_input *input_data, uint8_t table = ovn_stage_get_table(lflow->stage); struct hmap *dp_groups; - size_t n_datapaths; - struct ovn_datapath **datapaths_array; + const struct ovn_datapaths *datapaths; if (ovn_stage_to_datapath_type(lflow->stage) == DP_SWITCH) { - n_datapaths = n_ls_datapaths; + datapaths = input_data->ls_datapaths; dp_groups = &ls_dp_groups; - datapaths_array = ls_datapaths_array; } else { - n_datapaths = n_lr_datapaths; + datapaths = input_data->lr_datapaths; dp_groups = &lr_dp_groups; - datapaths_array = lr_datapaths_array; } sbflow = sbrec_logical_flow_insert(ovnsb_txn); @@ -15375,7 +15399,8 @@ void build_lflows(struct lflow_input *input_data, } ovn_sb_set_lflow_logical_dp_group(ovnsb_txn, dp_groups, sbflow, lflow->dpg_bitmap, - n_datapaths, datapaths_array); + datapaths); + sbrec_logical_flow_set_pipeline(sbflow, pipeline); sbrec_logical_flow_set_table_id(sbflow, table); sbrec_logical_flow_set_priority(sbflow, lflow->priority); @@ -15432,9 +15457,9 @@ void build_lflows(struct lflow_input *input_data, SBREC_MULTICAST_GROUP_TABLE_FOR_EACH_SAFE (sbmc, input_data->sbrec_multicast_group_table) { struct ovn_datapath *od = ovn_datapath_from_sbrec( - input_data->ls_datapaths, - input_data->lr_datapaths, - sbmc->datapath); + &input_data->ls_datapaths->datapaths, + &input_data->lr_datapaths->datapaths, + sbmc->datapath); if (!od || ovn_datapath_is_stale(od)) { sbrec_multicast_group_delete(sbmc); @@ -15945,49 +15970,6 @@ sync_template_vars( } shash_destroy(&nb_tvs); } - -static void -destroy_datapaths_and_ports(struct hmap *ls_datapaths, - struct hmap *lr_datapaths, struct hmap *ls_ports, - struct hmap *lr_ports, struct ovs_list *lr_list) -{ - struct ovn_datapath *router_dp; - LIST_FOR_EACH_POP (router_dp, lr_list, lr_list) { - if (router_dp->lr_group) { - struct lrouter_group *lr_group = router_dp->lr_group; - - for (size_t i = 0; i < lr_group->n_router_dps; i++) { - lr_group->router_dps[i]->lr_group = NULL; - } - - free(lr_group->router_dps); - sset_destroy(&lr_group->ha_chassis_groups); - free(lr_group); - } - } - - struct ovn_datapath *dp; - HMAP_FOR_EACH_SAFE (dp, key_node, ls_datapaths) { - ovn_datapath_destroy(ls_datapaths, dp); - } - hmap_destroy(ls_datapaths); - - HMAP_FOR_EACH_SAFE (dp, key_node, lr_datapaths) { - ovn_datapath_destroy(lr_datapaths, dp); - } - hmap_destroy(lr_datapaths); - - struct ovn_port *port; - HMAP_FOR_EACH_SAFE (port, key_node, ls_ports) { - ovn_port_destroy(ls_ports, port); - } - hmap_destroy(ls_ports); - - HMAP_FOR_EACH_SAFE (port, key_node, lr_ports) { - ovn_port_destroy(lr_ports, port); - } - hmap_destroy(lr_ports); -} static void build_ip_mcast(struct ovsdb_idl_txn *ovnsb_txn, @@ -16023,7 +16005,7 @@ build_ip_mcast(struct ovsdb_idl_txn *ovnsb_txn, static void build_mcast_groups(const struct sbrec_igmp_group_table *sbrec_igmp_group_table, struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp, - const struct hmap *ls_datapaths, + const struct ovn_datapaths *ls_datapaths, const struct hmap *ls_ports, const struct hmap *lr_ports, struct hmap *mcast_groups, @@ -16035,7 +16017,7 @@ build_mcast_groups(const struct sbrec_igmp_group_table *sbrec_igmp_group_table, hmap_init(igmp_groups); struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, ls_datapaths) { + HMAP_FOR_EACH (od, key_node, &ls_datapaths->datapaths) { init_mcast_flow_count(od); } @@ -16098,7 +16080,8 @@ build_mcast_groups(const struct sbrec_igmp_group_table *sbrec_igmp_group_table, } /* If the datapath value is stale, purge the group. */ - od = ovn_datapath_from_sbrec(ls_datapaths, NULL, sb_igmp->datapath); + od = ovn_datapath_from_sbrec(&ls_datapaths->datapaths, NULL, + sb_igmp->datapath); if (!od || ovn_datapath_is_stale(od)) { sbrec_igmp_group_delete(sb_igmp); @@ -16143,7 +16126,7 @@ build_mcast_groups(const struct sbrec_igmp_group_table *sbrec_igmp_group_table, * IGMP groups are based on the groups learnt by their multicast enabled * peers. */ - HMAP_FOR_EACH (od, key_node, ls_datapaths) { + HMAP_FOR_EACH (od, key_node, &ls_datapaths->datapaths) { if (ovs_list_is_empty(&od->mcast_info.groups)) { continue; @@ -16313,12 +16296,68 @@ build_static_mac_binding_table( } } } + +static void +ovn_datapaths_init(struct ovn_datapaths *datapaths) +{ + hmap_init(&datapaths->datapaths); + datapaths->array = NULL; +} + +static void +ovn_datapaths_destroy(struct ovn_datapaths *datapaths) +{ + struct ovn_datapath *dp; + HMAP_FOR_EACH_SAFE (dp, key_node, &datapaths->datapaths) { + ovn_datapath_destroy(&datapaths->datapaths, dp); + } + hmap_destroy(&datapaths->datapaths); + + free(datapaths->array); + datapaths->array = NULL; +} + +static void +destroy_datapaths_and_ports(struct ovn_datapaths *ls_datapaths, + struct ovn_datapaths *lr_datapaths, + struct hmap *ls_ports, struct hmap *lr_ports, + struct ovs_list *lr_list) +{ + struct ovn_datapath *router_dp; + LIST_FOR_EACH_POP (router_dp, lr_list, lr_list) { + if (router_dp->lr_group) { + struct lrouter_group *lr_group = router_dp->lr_group; + + for (size_t i = 0; i < lr_group->n_router_dps; i++) { + lr_group->router_dps[i]->lr_group = NULL; + } + + free(lr_group->router_dps); + sset_destroy(&lr_group->ha_chassis_groups); + free(lr_group); + } + } + + ovn_datapaths_destroy(ls_datapaths); + ovn_datapaths_destroy(lr_datapaths); + + struct ovn_port *port; + HMAP_FOR_EACH_SAFE (port, key_node, ls_ports) { + ovn_port_destroy(ls_ports, port); + } + hmap_destroy(ls_ports); + + HMAP_FOR_EACH_SAFE (port, key_node, lr_ports) { + ovn_port_destroy(lr_ports, port); + } + hmap_destroy(lr_ports); +} void northd_init(struct northd_data *data) { - hmap_init(&data->ls_datapaths); - hmap_init(&data->lr_datapaths); + ovn_datapaths_init(&data->ls_datapaths); + ovn_datapaths_init(&data->lr_datapaths); hmap_init(&data->ls_ports); hmap_init(&data->lr_ports); hmap_init(&data->port_groups); @@ -16482,19 +16521,22 @@ ovnnb_db_run(struct northd_input *input_data, input_data->sbrec_chassis_by_name, input_data->sbrec_chassis_by_hostname, input_data->sbrec_ha_chassis_grp_by_name, - &data->ls_datapaths, &data->lr_datapaths, &data->ls_ports, - &data->lr_ports); + &data->ls_datapaths.datapaths, &data->lr_datapaths.datapaths, + &data->ls_ports, &data->lr_ports); build_lb_port_related_data(ovnsb_txn, input_data->sbrec_service_monitor_table, &data->lr_datapaths, &data->ls_ports, &data->lbs, &data->lb_groups); - build_lb_count_dps(&data->lbs); - build_ipam(&data->ls_datapaths, &data->ls_ports); + build_lb_count_dps(&data->lbs, + ods_size(&data->ls_datapaths), + ods_size(&data->lr_datapaths)); + build_ipam(&data->ls_datapaths.datapaths, &data->ls_ports); build_port_group_lswitches(input_data->nbrec_port_group_table, &data->port_groups, &data->ls_ports); build_lrouter_groups(&data->lr_ports, &data->lr_list); build_ip_mcast(ovnsb_txn, input_data->sbrec_ip_multicast_table, - input_data->sbrec_ip_mcast_by_dp, &data->ls_datapaths); + input_data->sbrec_ip_mcast_by_dp, + &data->ls_datapaths.datapaths); build_meter_groups(input_data->nbrec_meter_table, &data->meter_groups); build_static_mac_binding_table(ovnsb_txn, input_data->nbrec_static_mac_binding_table, @@ -16516,12 +16558,12 @@ ovnnb_db_run(struct northd_input *input_data, sync_mirrors(ovnsb_txn, input_data->nbrec_mirror_table, input_data->sbrec_mirror_table); sync_dns_entries(ovnsb_txn, input_data->sbrec_dns_table, - &data->ls_datapaths); + &data->ls_datapaths.datapaths); sync_template_vars(ovnsb_txn, input_data->nbrec_chassis_template_var_table, input_data->sbrec_chassis_template_var_table); cleanup_stale_fdb_entries(input_data->sbrec_fdb_table, - &data->ls_datapaths); + &data->ls_datapaths.datapaths); stopwatch_stop(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); /* Set up SB_Global (depends on chassis features). */ diff --git a/northd/northd.h b/northd/northd.h index 24d4f804992d..6d5f2bb74ce0 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -73,10 +73,21 @@ struct chassis_features { bool ct_lb_related; }; +/* A collection of datapaths. E.g. all logical switch datapaths, or all + * logical router datapaths. */ +struct ovn_datapaths { + /* Contains struct ovn_datapath elements. */ + struct hmap datapaths; + + /* The array index of each element in 'datapaths'. */ + struct ovn_datapath **array; +}; + + struct northd_data { /* Global state for 'en-northd'. */ - struct hmap ls_datapaths; - struct hmap lr_datapaths; + struct ovn_datapaths ls_datapaths; + struct ovn_datapaths lr_datapaths; struct hmap ls_ports; struct hmap lr_ports; struct hmap port_groups; @@ -102,8 +113,8 @@ struct lflow_input { /* Indexes */ struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp; - const struct hmap *ls_datapaths; - const struct hmap *lr_datapaths; + const struct ovn_datapaths *ls_datapaths; + const struct ovn_datapaths *lr_datapaths; const struct hmap *ls_ports; const struct hmap *lr_ports; const struct hmap *port_groups; @@ -191,6 +202,9 @@ struct ovn_datapath { size_t index; /* A unique index across all datapaths. * Datapath indexes are sequential and start from zero. */ + struct ovn_datapaths *datapaths; /* The collection of datapaths that + contains this datapath. */ + const struct nbrec_logical_switch *nbs; /* May be NULL. */ const struct nbrec_logical_router *nbr; /* May be NULL. */ const struct sbrec_datapath_binding *sb; /* May be NULL. */