From patchwork Fri Jun 24 04:13:57 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryan Moats X-Patchwork-Id: 640009 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (archives.nicira.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id 3rbQ4t3RsVz9sD9 for ; Fri, 24 Jun 2016 14:16:30 +1000 (AEST) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id B660710B84; Thu, 23 Jun 2016 21:16:29 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx1e4.cudamail.com (mx1.cudamail.com [69.90.118.67]) by archives.nicira.com (Postfix) with ESMTPS id 0E82E10B80 for ; Thu, 23 Jun 2016 21:16:29 -0700 (PDT) Received: from bar5.cudamail.com (unknown [192.168.21.12]) by mx1e4.cudamail.com (Postfix) with ESMTPS id 8D8441E0440 for ; Thu, 23 Jun 2016 22:16:28 -0600 (MDT) X-ASG-Debug-ID: 1466741787-09eadd24bb13f350001-byXFYA Received: from mx1-pf1.cudamail.com ([192.168.24.1]) by bar5.cudamail.com with ESMTP id XwI0OagKISO9pjwU (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Thu, 23 Jun 2016 22:16:27 -0600 (MDT) X-Barracuda-Envelope-From: rmoats@oc7146733065.ibm.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.24.1 Received: from unknown (HELO eastrmfepo202.cox.net) (68.230.241.217) by mx1-pf1.cudamail.com with SMTP; 24 Jun 2016 04:16:27 -0000 Received-SPF: none (mx1-pf1.cudamail.com: domain at oc7146733065.ibm.com does not designate permitted sender hosts) X-Barracuda-Apparent-Source-IP: 68.230.241.217 X-Barracuda-RBL-IP: 68.230.241.217 Received: from eastrmimpo109.cox.net ([68.230.241.222]) by eastrmfepo202.cox.net (InterMail vM.8.01.05.28 201-2260-151-171-20160122) with ESMTP id <20160624041626.HWMJ7655.eastrmfepo202.cox.net@eastrmimpo109.cox.net> for ; Fri, 24 Jun 2016 00:16:26 -0400 Received: from oc7146733065.ibm.com ([68.13.99.247]) by eastrmimpo109.cox.net with cox id AUGR1t00G5LF6cs01UGRyG; Fri, 24 Jun 2016 00:16:26 -0400 X-CT-Class: Clean X-CT-Score: 0.00 X-CT-RefID: str=0001.0A020203.576CB41A.009C, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0 X-CT-Spam: 0 X-Authority-Analysis: v=2.1 cv=X8XcKQje c=1 sm=1 tr=0 a=Jmqd6mthTashISSy/JkQqg==:117 a=Jmqd6mthTashISSy/JkQqg==:17 a=L9H7d07YOLsA:10 a=9cW_t1CCXrUA:10 a=s5jvgZ67dGcA:10 a=pD_ry4oyNxEA:10 a=VnNF1IyMAAAA:8 a=dS4kKn5qHk1bnNvxjRsA:9 a=eJx_pQhC5m0sQ2F6:21 a=skCgnbhlp52w9zbo2JeP:22 X-CM-Score: 0.00 Authentication-Results: cox.net; none Received: by oc7146733065.ibm.com (Postfix, from userid 500) id 031471880318; Thu, 23 Jun 2016 23:16:24 -0500 (CDT) X-CudaMail-Envelope-Sender: rmoats@oc7146733065.ibm.com From: Ryan Moats To: dev@openvswitch.org X-CudaMail-MID: CM-E1-622094010 X-CudaMail-DTE: 062316 X-CudaMail-Originating-IP: 68.230.241.217 Date: Thu, 23 Jun 2016 23:13:57 -0500 X-ASG-Orig-Subj: [##CM-E1-622094010##][PATCH v19 4/7] Refactor port binding processing in physical.c Message-Id: <1466741640-5766-5-git-send-email-rmoats@us.ibm.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1466741640-5766-1-git-send-email-rmoats@us.ibm.com> References: <1466741640-5766-1-git-send-email-rmoats@us.ibm.com> X-Barracuda-Connect: UNKNOWN[192.168.24.1] X-Barracuda-Start-Time: 1466741787 X-Barracuda-Encrypted: ECDHE-RSA-AES256-GCM-SHA384 X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 X-Barracuda-Spam-Score: 0.60 X-Barracuda-Spam-Status: No, SCORE=0.60 using global scores of TAG_LEVEL=3.5 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=4.0 tests=BSF_SC5_MJ1963, RDNS_NONE X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.30711 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.10 RDNS_NONE Delivered to trusted network by a host with no rDNS 0.50 BSF_SC5_MJ1963 Custom Rule MJ1963 Subject: [ovs-dev] [PATCH v19 4/7] Refactor port binding processing in physical.c X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" iExtract block from SBREC_PORT_BINDING_FOR_EACH block in physical_run to helper method so that it can be reused when doing incremental processing. Side effects: - localvif_to_oport and tunnels are now static file scoped. - the is_new parameter is added for use in a later patch set. Signed-off-by: Ryan Moats --- ovn/controller/physical.c | 614 ++++++++++++++++++++++++---------------------- 1 file changed, 314 insertions(+), 300 deletions(-) diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c index 846ca37..4991bdd 100644 --- a/ovn/controller/physical.c +++ b/ovn/controller/physical.c @@ -54,6 +54,10 @@ physical_register_ovs_idl(struct ovsdb_idl *ovs_idl) /* UUID to identify OF flows not associated with ovsdb rows. */ static struct uuid *hc_uuid = NULL; +static struct simap localvif_to_ofport = + SIMAP_INITIALIZER(&localvif_to_ofport); +static struct hmap tunnels = HMAP_INITIALIZER(&tunnels); + /* Maps from a chassis to the OpenFlow port number of the tunnel that can be * used to reach that chassis. */ struct chassis_tunnel { @@ -64,11 +68,11 @@ struct chassis_tunnel { }; static struct chassis_tunnel * -chassis_tunnel_find(struct hmap *tunnels, const char *chassis_id) +chassis_tunnel_find(const char *chassis_id) { struct chassis_tunnel *tun; HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), - tunnels) { + &tunnels) { if (!strcmp(tun->chassis_id, chassis_id)) { return tun; } @@ -149,14 +153,315 @@ get_localnet_port(struct hmap *local_datapaths, int64_t tunnel_key) return ld ? ld->localnet_port : NULL; } +static void +consider_port_binding(enum mf_field_id mff_ovn_geneve, + const struct simap *ct_zones, + struct hmap *local_datapaths, + struct hmap *patched_datapaths, + const struct sbrec_port_binding *binding, + struct ofpbuf *ofpacts_p, bool is_new) +{ + /* Skip the port binding if the port is on a datapath that is neither + * local nor with any logical patch port connected, because local ports + * would never need to talk to those ports. + * + * Even with this approach there could still be unnecessary port + * bindings processed. A better approach would be a kind of "flood + * fill" algorithm: + * + * 1. Initialize set S to the logical datapaths that have a port + * located on the hypervisor. + * + * 2. For each patch port P in a logical datapath in S, add the + * logical datapath of the remote end of P to S. Iterate + * until S reaches a fixed point. + * + * This can be implemented in northd, which can generate the sets and + * save it on each port-binding record in SB, and ovn-controller can + * use the information directly. However, there can be update storms + * when a pair of patch ports are added/removed to connect/disconnect + * large lrouters and lswitches. This need to be studied further. + */ + uint32_t dp_key = binding->datapath->tunnel_key; + uint32_t port_key = binding->tunnel_key; + if (!get_local_datapath(local_datapaths, dp_key) + && !get_patched_datapath(patched_datapaths, dp_key)) { + return; + } + + /* Find the OpenFlow port for the logical port, as 'ofport'. This is + * one of: + * + * - If the port is a VIF on the chassis we're managing, the + * OpenFlow port for the VIF. 'tun' will be NULL. + * + * The same logic handles logical patch ports, as well as + * localnet patch ports. + * + * For a container nested inside a VM and accessible via a VLAN, + * 'tag' is the VLAN ID; otherwise 'tag' is 0. + * + * For a localnet patch port, if a VLAN ID was configured, 'tag' + * is set to that VLAN ID; otherwise 'tag' is 0. + * + * - If the port is on a remote chassis, the OpenFlow port for a + * tunnel to the VIF's remote chassis. 'tun' identifies that + * tunnel. + */ + + int tag = 0; + ofp_port_t ofport; + bool is_remote = false; + if (binding->parent_port && *binding->parent_port) { + if (!binding->tag) { + return; + } + ofport = u16_to_ofp(simap_get(&localvif_to_ofport, + binding->parent_port)); + if (ofport) { + tag = *binding->tag; + } + } else { + ofport = u16_to_ofp(simap_get(&localvif_to_ofport, + binding->logical_port)); + if (!strcmp(binding->type, "localnet") && ofport && binding->tag) { + tag = *binding->tag; + } + } + + const struct chassis_tunnel *tun = NULL; + const struct sbrec_port_binding *localnet_port = + get_localnet_port(local_datapaths, dp_key); + if (!ofport) { + /* It is remote port, may be reached by tunnel or localnet port */ + is_remote = true; + if (!binding->chassis) { + return; + } + if (localnet_port) { + ofport = u16_to_ofp(simap_get(&localvif_to_ofport, + localnet_port->logical_port)); + if (!ofport) { + return; + } + } else { + tun = chassis_tunnel_find(binding->chassis->name); + if (!tun) { + return; + } + ofport = tun->ofport; + } + } + + struct match match; + if (!is_remote) { + int zone_id = simap_get(ct_zones, binding->logical_port); + /* Packets that arrive from a vif can belong to a VM or + * to a container located inside that VM. Packets that + * arrive from containers have a tag (vlan) associated with them. + */ + + /* Table 0, Priority 150 and 100. + * ============================== + * + * Priority 150 is for tagged traffic. This may be containers in a + * VM or a VLAN on a local network. For such traffic, match on the + * tags and then strip the tag. + * + * Priority 100 is for traffic belonging to VMs or untagged locally + * connected networks. + * + * For both types of traffic: set MFF_LOG_INPORT to the logical + * input port, MFF_LOG_DATAPATH to the logical datapath, and + * resubmit into the logical ingress pipeline starting at table + * 16. */ + ofpbuf_clear(ofpacts_p); + match_init_catchall(&match); + match_set_in_port(&match, ofport); + + /* Match a VLAN tag and strip it, including stripping priority tags + * (e.g. VLAN ID 0). In the latter case we'll add a second flow + * for frames that lack any 802.1Q header later. */ + if (tag || !strcmp(binding->type, "localnet")) { + match_set_dl_vlan(&match, htons(tag)); + ofpact_put_STRIP_VLAN(ofpacts_p); + } + + /* Remember the size with just strip vlan added so far, + * as we're going to remove this with ofpbuf_pull() later. */ + uint32_t ofpacts_orig_size = ofpacts_p->size; + + if (zone_id) { + put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, ofpacts_p); + } + + int zone_id_dnat, zone_id_snat; + char *dnat = alloc_nat_zone_key(binding, "dnat"); + char *snat = alloc_nat_zone_key(binding, "snat"); + zone_id_dnat = simap_get(ct_zones, dnat); + if (zone_id_dnat) { + put_load(zone_id_dnat, MFF_LOG_DNAT_ZONE, 0, 32, ofpacts_p); + } + free(dnat); + + zone_id_snat = simap_get(ct_zones, snat); + if (zone_id_snat) { + put_load(zone_id_snat, MFF_LOG_SNAT_ZONE, 0, 32, ofpacts_p); + } + free(snat); + + /* Set MFF_LOG_DATAPATH and MFF_LOG_INPORT. */ + put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, ofpacts_p); + put_load(port_key, MFF_LOG_INPORT, 0, 32, ofpacts_p); + + /* Resubmit to first logical ingress pipeline table. */ + put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts_p); + ofctrl_add_flow(OFTABLE_PHY_TO_LOG, + tag ? 150 : 100, &match, ofpacts_p, + &binding->header_.uuid, is_new); + + if (!tag && !strcmp(binding->type, "localnet")) { + /* Add a second flow for frames that lack any 802.1Q + * header. For these, drop the OFPACT_STRIP_VLAN + * action. */ + ofpbuf_pull(ofpacts_p, ofpacts_orig_size); + match_set_dl_tci_masked(&match, 0, htons(VLAN_CFI)); + ofctrl_add_flow(0, 100, &match, ofpacts_p, + &binding->header_.uuid, is_new); + } + + /* Table 33, priority 100. + * ======================= + * + * Implements output to local hypervisor. Each flow matches a + * logical output port on the local hypervisor, and resubmits to + * table 34. + */ + + match_init_catchall(&match); + ofpbuf_clear(ofpacts_p); + + /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */ + match_set_metadata(&match, htonll(dp_key)); + match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); + + if (zone_id) { + put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, ofpacts_p); + } + if (zone_id_dnat) { + put_load(zone_id_dnat, MFF_LOG_DNAT_ZONE, 0, 32, ofpacts_p); + } + if (zone_id_snat) { + put_load(zone_id_snat, MFF_LOG_SNAT_ZONE, 0, 32, ofpacts_p); + } + + /* Resubmit to table 34. */ + put_resubmit(OFTABLE_DROP_LOOPBACK, ofpacts_p); + ofctrl_add_flow(OFTABLE_LOCAL_OUTPUT, 100, &match, ofpacts_p, + &binding->header_.uuid, is_new); + + /* Table 34, Priority 100. + * ======================= + * + * Drop packets whose logical inport and outport are the same. */ + match_init_catchall(&match); + ofpbuf_clear(ofpacts_p); + match_set_metadata(&match, htonll(dp_key)); + match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, port_key); + match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); + ofctrl_add_flow(OFTABLE_DROP_LOOPBACK, 100, &match, ofpacts_p, + &binding->header_.uuid, is_new); + + /* Table 64, Priority 100. + * ======================= + * + * Deliver the packet to the local vif. */ + match_init_catchall(&match); + ofpbuf_clear(ofpacts_p); + match_set_metadata(&match, htonll(dp_key)); + match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); + if (tag) { + /* For containers sitting behind a local vif, tag the packets + * before delivering them. */ + struct ofpact_vlan_vid *vlan_vid; + vlan_vid = ofpact_put_SET_VLAN_VID(ofpacts_p); + vlan_vid->vlan_vid = tag; + vlan_vid->push_vlan_if_needed = true; + + /* A packet might need to hair-pin back into its ingress + * OpenFlow port (to a different logical port, which we already + * checked back in table 34), so set the in_port to zero. */ + put_stack(MFF_IN_PORT, ofpact_put_STACK_PUSH(ofpacts_p)); + put_load(0, MFF_IN_PORT, 0, 16, ofpacts_p); + } + ofpact_put_OUTPUT(ofpacts_p)->port = ofport; + if (tag) { + /* Revert the tag added to the packets headed to containers + * in the previous step. If we don't do this, the packets + * that are to be broadcasted to a VM in the same logical + * switch will also contain the tag. Also revert the zero'd + * in_port. */ + ofpact_put_STRIP_VLAN(ofpacts_p); + put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p)); + } + ofctrl_add_flow(OFTABLE_LOG_TO_PHY, 100, &match, ofpacts_p, + &binding->header_.uuid, is_new); + } else if (!tun) { + /* Remote port connected by localnet port */ + /* Table 33, priority 100. + * ======================= + * + * Implements switching to localnet port. Each flow matches a + * logical output port on remote hypervisor, switch the output port + * to connected localnet port and resubmits to same table. + */ + + match_init_catchall(&match); + ofpbuf_clear(ofpacts_p); + + /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */ + match_set_metadata(&match, htonll(dp_key)); + match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); + + put_load(localnet_port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, ofpacts_p); + + /* Resubmit to table 33. */ + put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p); + ofctrl_add_flow(OFTABLE_LOCAL_OUTPUT, 100, &match, ofpacts_p, + &binding->header_.uuid, is_new); + } else { + /* Remote port connected by tunnel */ + /* Table 32, priority 100. + * ======================= + * + * Implements output to remote hypervisors. Each flow matches an + * output port that includes a logical port on a remote hypervisor, + * and tunnels the packet to that hypervisor. + */ + + match_init_catchall(&match); + ofpbuf_clear(ofpacts_p); + + /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */ + match_set_metadata(&match, htonll(dp_key)); + match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); + + put_encapsulation(mff_ovn_geneve, tun, binding->datapath, + port_key, ofpacts_p); + + /* Output to tunnel. */ + ofpact_put_OUTPUT(ofpacts_p)->port = ofport; + ofctrl_add_flow(OFTABLE_REMOTE_OUTPUT, 100, &match, ofpacts_p, + &binding->header_.uuid, is_new); + } +} + void physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve, const struct ovsrec_bridge *br_int, const char *this_chassis_id, const struct simap *ct_zones, struct hmap *local_datapaths, struct hmap *patched_datapaths) { - struct simap localvif_to_ofport = SIMAP_INITIALIZER(&localvif_to_ofport); - struct hmap tunnels = HMAP_INITIALIZER(&tunnels); if (!hc_uuid) { hc_uuid = xmalloc(sizeof(struct uuid)); uuid_generate(hc_uuid); @@ -241,300 +546,9 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve, * 64 for logical-to-physical translation. */ const struct sbrec_port_binding *binding; SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) { - /* Skip the port binding if the port is on a datapath that is neither - * local nor with any logical patch port connected, because local ports - * would never need to talk to those ports. - * - * Even with this approach there could still be unnecessary port - * bindings processed. A better approach would be a kind of "flood - * fill" algorithm: - * - * 1. Initialize set S to the logical datapaths that have a port - * located on the hypervisor. - * - * 2. For each patch port P in a logical datapath in S, add the - * logical datapath of the remote end of P to S. Iterate - * until S reaches a fixed point. - * - * This can be implemented in northd, which can generate the sets and - * save it on each port-binding record in SB, and ovn-controller can - * use the information directly. However, there can be update storms - * when a pair of patch ports are added/removed to connect/disconnect - * large lrouters and lswitches. This need to be studied further. - */ - uint32_t dp_key = binding->datapath->tunnel_key; - uint32_t port_key = binding->tunnel_key; - if (!get_local_datapath(local_datapaths, dp_key) - && !get_patched_datapath(patched_datapaths, dp_key)) { - continue; - } - - /* Find the OpenFlow port for the logical port, as 'ofport'. This is - * one of: - * - * - If the port is a VIF on the chassis we're managing, the - * OpenFlow port for the VIF. 'tun' will be NULL. - * - * The same logic handles logical patch ports, as well as - * localnet patch ports. - * - * For a container nested inside a VM and accessible via a VLAN, - * 'tag' is the VLAN ID; otherwise 'tag' is 0. - * - * For a localnet patch port, if a VLAN ID was configured, 'tag' - * is set to that VLAN ID; otherwise 'tag' is 0. - * - * - If the port is on a remote chassis, the OpenFlow port for a - * tunnel to the VIF's remote chassis. 'tun' identifies that - * tunnel. - */ - - int tag = 0; - ofp_port_t ofport; - bool is_remote = false; - if (binding->parent_port && *binding->parent_port) { - if (!binding->tag) { - continue; - } - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, - binding->parent_port)); - if (ofport) { - tag = *binding->tag; - } - } else { - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, - binding->logical_port)); - if (!strcmp(binding->type, "localnet") && ofport && binding->tag) { - tag = *binding->tag; - } - } - - const struct chassis_tunnel *tun = NULL; - const struct sbrec_port_binding *localnet_port = - get_localnet_port(local_datapaths, dp_key); - if (!ofport) { - /* It is remote port, may be reached by tunnel or localnet port */ - is_remote = true; - if (!binding->chassis) { - continue; - } - if (localnet_port) { - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, - localnet_port->logical_port)); - if (!ofport) { - continue; - } - } else { - tun = chassis_tunnel_find(&tunnels, binding->chassis->name); - if (!tun) { - continue; - } - ofport = tun->ofport; - } - } - - struct match match; - if (!is_remote) { - int zone_id = simap_get(ct_zones, binding->logical_port); - /* Packets that arrive from a vif can belong to a VM or - * to a container located inside that VM. Packets that - * arrive from containers have a tag (vlan) associated with them. - */ - - /* Table 0, Priority 150 and 100. - * ============================== - * - * Priority 150 is for tagged traffic. This may be containers in a - * VM or a VLAN on a local network. For such traffic, match on the - * tags and then strip the tag. - * - * Priority 100 is for traffic belonging to VMs or untagged locally - * connected networks. - * - * For both types of traffic: set MFF_LOG_INPORT to the logical - * input port, MFF_LOG_DATAPATH to the logical datapath, and - * resubmit into the logical ingress pipeline starting at table - * 16. */ - ofpbuf_clear(&ofpacts); - match_init_catchall(&match); - match_set_in_port(&match, ofport); - - /* Match a VLAN tag and strip it, including stripping priority tags - * (e.g. VLAN ID 0). In the latter case we'll add a second flow - * for frames that lack any 802.1Q header later. */ - if (tag || !strcmp(binding->type, "localnet")) { - match_set_dl_vlan(&match, htons(tag)); - ofpact_put_STRIP_VLAN(&ofpacts); - } - - /* Remember the size with just strip vlan added so far, - * as we're going to remove this with ofpbuf_pull() later. */ - uint32_t ofpacts_orig_size = ofpacts.size; - - if (zone_id) { - put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); - } - - int zone_id_dnat, zone_id_snat; - char *dnat = alloc_nat_zone_key(binding, "dnat"); - char *snat = alloc_nat_zone_key(binding, "snat"); - zone_id_dnat = simap_get(ct_zones, dnat); - if (zone_id_dnat) { - put_load(zone_id_dnat, MFF_LOG_DNAT_ZONE, 0, 32, &ofpacts); - } - free(dnat); - - zone_id_snat = simap_get(ct_zones, snat); - if (zone_id_snat) { - put_load(zone_id_snat, MFF_LOG_SNAT_ZONE, 0, 32, &ofpacts); - } - free(snat); - - /* Set MFF_LOG_DATAPATH and MFF_LOG_INPORT. */ - put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts); - put_load(port_key, MFF_LOG_INPORT, 0, 32, &ofpacts); - - /* Resubmit to first logical ingress pipeline table. */ - put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &ofpacts); - ofctrl_add_flow(OFTABLE_PHY_TO_LOG, - tag ? 150 : 100, &match, &ofpacts, - &binding->header_.uuid, true); - - if (!tag && !strcmp(binding->type, "localnet")) { - /* Add a second flow for frames that lack any 802.1Q - * header. For these, drop the OFPACT_STRIP_VLAN - * action. */ - ofpbuf_pull(&ofpacts, ofpacts_orig_size); - match_set_dl_tci_masked(&match, 0, htons(VLAN_CFI)); - ofctrl_add_flow(0, 100, &match, &ofpacts, - &binding->header_.uuid, true); - } - - /* Table 33, priority 100. - * ======================= - * - * Implements output to local hypervisor. Each flow matches a - * logical output port on the local hypervisor, and resubmits to - * table 34. - */ - - match_init_catchall(&match); - ofpbuf_clear(&ofpacts); - - /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */ - match_set_metadata(&match, htonll(dp_key)); - match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); - - if (zone_id) { - put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); - } - if (zone_id_dnat) { - put_load(zone_id_dnat, MFF_LOG_DNAT_ZONE, 0, 32, &ofpacts); - } - if (zone_id_snat) { - put_load(zone_id_snat, MFF_LOG_SNAT_ZONE, 0, 32, &ofpacts); - } - - /* Resubmit to table 34. */ - put_resubmit(OFTABLE_DROP_LOOPBACK, &ofpacts); - ofctrl_add_flow(OFTABLE_LOCAL_OUTPUT, 100, &match, &ofpacts, - &binding->header_.uuid, true); - - /* Table 34, Priority 100. - * ======================= - * - * Drop packets whose logical inport and outport are the same. */ - match_init_catchall(&match); - ofpbuf_clear(&ofpacts); - match_set_metadata(&match, htonll(dp_key)); - match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, port_key); - match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); - ofctrl_add_flow(OFTABLE_DROP_LOOPBACK, 100, &match, &ofpacts, - &binding->header_.uuid, true); - - /* Table 64, Priority 100. - * ======================= - * - * Deliver the packet to the local vif. */ - match_init_catchall(&match); - ofpbuf_clear(&ofpacts); - match_set_metadata(&match, htonll(dp_key)); - match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); - if (tag) { - /* For containers sitting behind a local vif, tag the packets - * before delivering them. */ - struct ofpact_vlan_vid *vlan_vid; - vlan_vid = ofpact_put_SET_VLAN_VID(&ofpacts); - vlan_vid->vlan_vid = tag; - vlan_vid->push_vlan_if_needed = true; - - /* A packet might need to hair-pin back into its ingress - * OpenFlow port (to a different logical port, which we already - * checked back in table 34), so set the in_port to zero. */ - put_stack(MFF_IN_PORT, ofpact_put_STACK_PUSH(&ofpacts)); - put_load(0, MFF_IN_PORT, 0, 16, &ofpacts); - } - ofpact_put_OUTPUT(&ofpacts)->port = ofport; - if (tag) { - /* Revert the tag added to the packets headed to containers - * in the previous step. If we don't do this, the packets - * that are to be broadcasted to a VM in the same logical - * switch will also contain the tag. Also revert the zero'd - * in_port. */ - ofpact_put_STRIP_VLAN(&ofpacts); - put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(&ofpacts)); - } - ofctrl_add_flow(OFTABLE_LOG_TO_PHY, 100, &match, &ofpacts, - &binding->header_.uuid, true); - } else if (!tun) { - /* Remote port connected by localnet port */ - /* Table 33, priority 100. - * ======================= - * - * Implements switching to localnet port. Each flow matches a - * logical output port on remote hypervisor, switch the output port - * to connected localnet port and resubmits to same table. - */ - - match_init_catchall(&match); - ofpbuf_clear(&ofpacts); - - /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */ - match_set_metadata(&match, htonll(dp_key)); - match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); - - put_load(localnet_port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts); - - /* Resubmit to table 33. */ - put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts); - ofctrl_add_flow(OFTABLE_LOCAL_OUTPUT, 100, &match, &ofpacts, - &binding->header_.uuid, true); - } else { - /* Remote port connected by tunnel */ - /* Table 32, priority 100. - * ======================= - * - * Implements output to remote hypervisors. Each flow matches an - * output port that includes a logical port on a remote hypervisor, - * and tunnels the packet to that hypervisor. - */ - - match_init_catchall(&match); - ofpbuf_clear(&ofpacts); - - /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */ - match_set_metadata(&match, htonll(dp_key)); - match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); - - put_encapsulation(mff_ovn_geneve, tun, binding->datapath, - port_key, &ofpacts); - - /* Output to tunnel. */ - ofpact_put_OUTPUT(&ofpacts)->port = ofport; - ofctrl_add_flow(OFTABLE_REMOTE_OUTPUT, 100, &match, &ofpacts, - &binding->header_.uuid, true); + consider_port_binding(mff_ovn_geneve, ct_zones, local_datapaths, + patched_datapaths, binding, &ofpacts, true); } - } /* Handle output to multicast groups, in tables 32 and 33. */ const struct sbrec_multicast_group *mc; @@ -628,7 +642,7 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve, const struct chassis_tunnel *prev = NULL; SSET_FOR_EACH (chassis, &remote_chassis) { const struct chassis_tunnel *tun - = chassis_tunnel_find(&tunnels, chassis); + = chassis_tunnel_find(chassis); if (!tun) { continue; } @@ -757,9 +771,9 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve, hc_uuid, true); ofpbuf_uninit(&ofpacts); - simap_destroy(&localvif_to_ofport); + simap_clear(&localvif_to_ofport); HMAP_FOR_EACH_POP (tun, hmap_node, &tunnels) { free(tun); } - hmap_destroy(&tunnels); + hmap_clear(&tunnels); }