LCOV - code coverage report
Current view: top level - ovn/controller - physical.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 362 379 95.5 %
Date: 2016-09-14 01:02:56 Functions: 12 12 100.0 %
Branches: 197 226 87.2 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2015, 2016 Nicira, Inc.
       2                 :            :  *
       3                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       4                 :            :  * you may not use this file except in compliance with the License.
       5                 :            :  * You may obtain a copy of the License at:
       6                 :            :  *
       7                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       8                 :            :  *
       9                 :            :  * Unless required by applicable law or agreed to in writing, software
      10                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      11                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :            :  * See the License for the specific language governing permissions and
      13                 :            :  * limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <config.h>
      17                 :            : #include "binding.h"
      18                 :            : #include "byte-order.h"
      19                 :            : #include "flow.h"
      20                 :            : #include "lflow.h"
      21                 :            : #include "lib/poll-loop.h"
      22                 :            : #include "ofctrl.h"
      23                 :            : #include "openvswitch/hmap.h"
      24                 :            : #include "openvswitch/match.h"
      25                 :            : #include "openvswitch/ofp-actions.h"
      26                 :            : #include "openvswitch/ofpbuf.h"
      27                 :            : #include "openvswitch/vlog.h"
      28                 :            : #include "ovn-controller.h"
      29                 :            : #include "ovn/lib/ovn-sb-idl.h"
      30                 :            : #include "ovn/lib/ovn-util.h"
      31                 :            : #include "physical.h"
      32                 :            : #include "openvswitch/shash.h"
      33                 :            : #include "simap.h"
      34                 :            : #include "smap.h"
      35                 :            : #include "sset.h"
      36                 :            : #include "util.h"
      37                 :            : #include "vswitch-idl.h"
      38                 :            : 
      39                 :         94 : VLOG_DEFINE_THIS_MODULE(physical);
      40                 :            : 
      41                 :            : void
      42                 :         44 : physical_register_ovs_idl(struct ovsdb_idl *ovs_idl)
      43                 :            : {
      44                 :         44 :     ovsdb_idl_add_table(ovs_idl, &ovsrec_table_bridge);
      45                 :         44 :     ovsdb_idl_add_column(ovs_idl, &ovsrec_bridge_col_ports);
      46                 :            : 
      47                 :         44 :     ovsdb_idl_add_table(ovs_idl, &ovsrec_table_port);
      48                 :         44 :     ovsdb_idl_add_column(ovs_idl, &ovsrec_port_col_name);
      49                 :         44 :     ovsdb_idl_add_column(ovs_idl, &ovsrec_port_col_interfaces);
      50                 :         44 :     ovsdb_idl_add_column(ovs_idl, &ovsrec_port_col_external_ids);
      51                 :            : 
      52                 :         44 :     ovsdb_idl_add_table(ovs_idl, &ovsrec_table_interface);
      53                 :         44 :     ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_name);
      54                 :         44 :     ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_ofport);
      55                 :         44 :     ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_external_ids);
      56                 :         44 : }
      57                 :            : 
      58                 :            : static struct simap localvif_to_ofport =
      59                 :            :     SIMAP_INITIALIZER(&localvif_to_ofport);
      60                 :            : static struct hmap tunnels = HMAP_INITIALIZER(&tunnels);
      61                 :            : 
      62                 :            : /* Maps from a chassis to the OpenFlow port number of the tunnel that can be
      63                 :            :  * used to reach that chassis. */
      64                 :            : struct chassis_tunnel {
      65                 :            :     struct hmap_node hmap_node;
      66                 :            :     const char *chassis_id;
      67                 :            :     ofp_port_t ofport;
      68                 :            :     enum chassis_tunnel_type type;
      69                 :            : };
      70                 :            : 
      71                 :            : static struct chassis_tunnel *
      72                 :      32502 : chassis_tunnel_find(const char *chassis_id)
      73                 :            : {
      74                 :            :     struct chassis_tunnel *tun;
      75 [ +  + ][ -  + ]:      32502 :     HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0),
      76                 :            :                              &tunnels) {
      77         [ +  - ]:      32064 :         if (!strcmp(tun->chassis_id, chassis_id)) {
      78                 :      32064 :             return tun;
      79                 :            :         }
      80                 :            :     }
      81                 :        438 :     return NULL;
      82                 :            : }
      83                 :            : 
      84                 :            : static void
      85                 :     272575 : put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits,
      86                 :            :          struct ofpbuf *ofpacts)
      87                 :            : {
      88                 :     272575 :     struct ofpact_set_field *sf = ofpact_put_set_field(ofpacts,
      89                 :            :                                                        mf_from_id(dst), NULL,
      90                 :            :                                                        NULL);
      91                 :     272575 :     ovs_be64 n_value = htonll(value);
      92                 :     272575 :     bitwise_copy(&n_value, 8, 0, sf->value, sf->field->n_bytes, ofs, n_bits);
      93                 :     272575 :     bitwise_one(ofpact_set_field_mask(sf), sf->field->n_bytes, ofs, n_bits);
      94                 :     272575 : }
      95                 :            : 
      96                 :            : static void
      97                 :      35155 : put_move(enum mf_field_id src, int src_ofs,
      98                 :            :          enum mf_field_id dst, int dst_ofs,
      99                 :            :          int n_bits,
     100                 :            :          struct ofpbuf *ofpacts)
     101                 :            : {
     102                 :      35155 :     struct ofpact_reg_move *move = ofpact_put_REG_MOVE(ofpacts);
     103                 :      35155 :     move->src.field = mf_from_id(src);
     104                 :      35155 :     move->src.ofs = src_ofs;
     105                 :      35155 :     move->src.n_bits = n_bits;
     106                 :      35155 :     move->dst.field = mf_from_id(dst);
     107                 :      35155 :     move->dst.ofs = dst_ofs;
     108                 :      35155 :     move->dst.n_bits = n_bits;
     109                 :      35155 : }
     110                 :            : 
     111                 :            : static void
     112                 :     171587 : put_resubmit(uint8_t table_id, struct ofpbuf *ofpacts)
     113                 :            : {
     114                 :     171587 :     struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(ofpacts);
     115                 :     171587 :     resubmit->in_port = OFPP_IN_PORT;
     116                 :     171587 :     resubmit->table_id = table_id;
     117                 :     171587 : }
     118                 :            : 
     119                 :            : static void
     120                 :      25302 : put_encapsulation(enum mf_field_id mff_ovn_geneve,
     121                 :            :                   const struct chassis_tunnel *tun,
     122                 :            :                   const struct sbrec_datapath_binding *datapath,
     123                 :            :                   uint16_t outport, struct ofpbuf *ofpacts)
     124                 :            : {
     125         [ +  + ]:      25302 :     if (tun->type == GENEVE) {
     126                 :      25254 :         put_load(datapath->tunnel_key, MFF_TUN_ID, 0, 24, ofpacts);
     127                 :      25254 :         put_load(outport, mff_ovn_geneve, 0, 32, ofpacts);
     128                 :      25254 :         put_move(MFF_LOG_INPORT, 0, mff_ovn_geneve, 16, 15, ofpacts);
     129         [ -  + ]:         48 :     } else if (tun->type == STT) {
     130                 :          0 :         put_load(datapath->tunnel_key | (outport << 24), MFF_TUN_ID, 0, 64,
     131                 :            :                  ofpacts);
     132                 :          0 :         put_move(MFF_LOG_INPORT, 0, MFF_TUN_ID, 40, 15, ofpacts);
     133         [ +  - ]:         48 :     } else if (tun->type == VXLAN) {
     134                 :         48 :         put_load(datapath->tunnel_key, MFF_TUN_ID, 0, 24, ofpacts);
     135                 :            :     } else {
     136                 :          0 :         OVS_NOT_REACHED();
     137                 :            :     }
     138                 :      25302 : }
     139                 :            : 
     140                 :            : static void
     141                 :      72576 : put_stack(enum mf_field_id field, struct ofpact_stack *stack)
     142                 :            : {
     143                 :      72576 :     stack->subfield.field = mf_from_id(field);
     144                 :      72576 :     stack->subfield.ofs = 0;
     145                 :      72576 :     stack->subfield.n_bits = stack->subfield.field->n_bits;
     146                 :      72576 : }
     147                 :            : 
     148                 :            : static const struct sbrec_port_binding*
     149                 :      83514 : get_localnet_port(struct hmap *local_datapaths, int64_t tunnel_key)
     150                 :            : {
     151                 :      83514 :     struct local_datapath *ld = get_local_datapath(local_datapaths,
     152                 :            :                                                    tunnel_key);
     153         [ +  + ]:      83514 :     return ld ? ld->localnet_port : NULL;
     154                 :            : }
     155                 :            : 
     156                 :            : static void
     157                 :      62691 : consider_port_binding(enum mf_field_id mff_ovn_geneve,
     158                 :            :                       const struct simap *ct_zones,
     159                 :            :                       struct hmap *local_datapaths,
     160                 :            :                       struct hmap *patched_datapaths,
     161                 :            :                       const struct sbrec_port_binding *binding,
     162                 :            :                       struct ofpbuf *ofpacts_p,
     163                 :            :                       struct hmap *flow_table)
     164                 :            : {
     165                 :            :     /* Skip the port binding if the port is on a datapath that is neither
     166                 :            :      * local nor with any logical patch port connected, because local ports
     167                 :            :      * would never need to talk to those ports.
     168                 :            :      *
     169                 :            :      * Even with this approach there could still be unnecessary port
     170                 :            :      * bindings processed. A better approach would be a kind of "flood
     171                 :            :      * fill" algorithm:
     172                 :            :      *
     173                 :            :      *   1. Initialize set S to the logical datapaths that have a port
     174                 :            :      *      located on the hypervisor.
     175                 :            :      *
     176                 :            :      *   2. For each patch port P in a logical datapath in S, add the
     177                 :            :      *      logical datapath of the remote end of P to S.  Iterate
     178                 :            :      *      until S reaches a fixed point.
     179                 :            :      *
     180                 :            :      * This can be implemented in northd, which can generate the sets and
     181                 :            :      * save it on each port-binding record in SB, and ovn-controller can
     182                 :            :      * use the information directly. However, there can be update storms
     183                 :            :      * when a pair of patch ports are added/removed to connect/disconnect
     184                 :            :      * large lrouters and lswitches. This need to be studied further.
     185                 :            :      */
     186                 :      62691 :     uint32_t dp_key = binding->datapath->tunnel_key;
     187                 :      62691 :     uint32_t port_key = binding->tunnel_key;
     188         [ +  + ]:      62691 :     if (!get_local_datapath(local_datapaths, dp_key)
     189         [ +  + ]:      19085 :         && !get_patched_datapath(patched_datapaths, dp_key)) {
     190                 :       7280 :         return;
     191                 :            :     }
     192                 :            : 
     193                 :            :     /* Find the OpenFlow port for the logical port, as 'ofport'.  This is
     194                 :            :      * one of:
     195                 :            :      *
     196                 :            :      *     - If the port is a VIF on the chassis we're managing, the
     197                 :            :      *       OpenFlow port for the VIF.  'tun' will be NULL.
     198                 :            :      *
     199                 :            :      *       The same logic handles logical patch ports, as well as
     200                 :            :      *       localnet patch ports.
     201                 :            :      *
     202                 :            :      *       For a container nested inside a VM and accessible via a VLAN,
     203                 :            :      *       'tag' is the VLAN ID; otherwise 'tag' is 0.
     204                 :            :      *
     205                 :            :      *       For a localnet patch port, if a VLAN ID was configured, 'tag'
     206                 :            :      *       is set to that VLAN ID; otherwise 'tag' is 0.
     207                 :            :      *
     208                 :            :      *     - If the port is on a remote chassis, the OpenFlow port for a
     209                 :            :      *       tunnel to the VIF's remote chassis.  'tun' identifies that
     210                 :            :      *       tunnel.
     211                 :            :      */
     212                 :            : 
     213                 :      60825 :     int tag = 0;
     214                 :            :     ofp_port_t ofport;
     215                 :      60825 :     bool is_remote = false;
     216 [ +  + ][ -  + ]:      60825 :     if (binding->parent_port && *binding->parent_port) {
     217         [ #  # ]:          0 :         if (!binding->tag) {
     218                 :          0 :             return;
     219                 :            :         }
     220                 :          0 :         ofport = u16_to_ofp(simap_get(&localvif_to_ofport,
     221                 :          0 :                                       binding->parent_port));
     222         [ #  # ]:          0 :         if (ofport) {
     223                 :          0 :             tag = *binding->tag;
     224                 :            :         }
     225                 :            :     } else {
     226                 :      60825 :         ofport = u16_to_ofp(simap_get(&localvif_to_ofport,
     227                 :      60825 :                                       binding->logical_port));
     228         [ +  + ]:      60825 :         if ((!strcmp(binding->type, "localnet")
     229         [ -  + ]:      60404 :             || !strcmp(binding->type, "l2gateway"))
     230 [ +  + ][ +  + ]:        421 :             && ofport && binding->tag) {
     231                 :         98 :             tag = *binding->tag;
     232                 :            :         }
     233                 :            :     }
     234                 :            : 
     235                 :      60825 :     const struct chassis_tunnel *tun = NULL;
     236                 :      60825 :     const struct sbrec_port_binding *localnet_port =
     237                 :      60825 :         get_localnet_port(local_datapaths, dp_key);
     238         [ +  + ]:      60825 :     if (!ofport) {
     239                 :            :         /* It is remote port, may be reached by tunnel or localnet port */
     240                 :      24635 :         is_remote = true;
     241         [ +  + ]:      24635 :         if (!binding->chassis) {
     242                 :       5201 :             return;
     243                 :            :         }
     244         [ +  + ]:      19434 :         if (localnet_port) {
     245                 :        299 :             ofport = u16_to_ofp(simap_get(&localvif_to_ofport,
     246                 :        299 :                                           localnet_port->logical_port));
     247         [ +  + ]:        299 :             if (!ofport) {
     248                 :         32 :                 return;
     249                 :            :             }
     250                 :            :         } else {
     251                 :      19135 :             tun = chassis_tunnel_find(binding->chassis->name);
     252         [ +  + ]:      19135 :             if (!tun) {
     253                 :        181 :                 return;
     254                 :            :             }
     255                 :      18954 :             ofport = tun->ofport;
     256                 :            :         }
     257                 :            :     }
     258                 :            : 
     259                 :            :     struct match match;
     260         [ +  + ]:      55411 :     if (!is_remote) {
     261                 :      36190 :         int zone_id = simap_get(ct_zones, binding->logical_port);
     262                 :            :         /* Packets that arrive from a vif can belong to a VM or
     263                 :            :          * to a container located inside that VM. Packets that
     264                 :            :          * arrive from containers have a tag (vlan) associated with them.
     265                 :            :          */
     266                 :            : 
     267                 :            :         /* Table 0, Priority 150 and 100.
     268                 :            :          * ==============================
     269                 :            :          *
     270                 :            :          * Priority 150 is for tagged traffic. This may be containers in a
     271                 :            :          * VM or a VLAN on a local network. For such traffic, match on the
     272                 :            :          * tags and then strip the tag.
     273                 :            :          *
     274                 :            :          * Priority 100 is for traffic belonging to VMs or untagged locally
     275                 :            :          * connected networks.
     276                 :            :          *
     277                 :            :          * For both types of traffic: set MFF_LOG_INPORT to the logical
     278                 :            :          * input port, MFF_LOG_DATAPATH to the logical datapath, and
     279                 :            :          * resubmit into the logical ingress pipeline starting at table
     280                 :            :          * 16. */
     281                 :      36190 :         ofpbuf_clear(ofpacts_p);
     282                 :      36190 :         match_init_catchall(&match);
     283                 :      36190 :         match_set_in_port(&match, ofport);
     284                 :            : 
     285                 :            :         /* Match a VLAN tag and strip it, including stripping priority tags
     286                 :            :          * (e.g. VLAN ID 0).  In the latter case we'll add a second flow
     287                 :            :          * for frames that lack any 802.1Q header later. */
     288 [ +  + ][ +  + ]:      36190 :         if (tag || !strcmp(binding->type, "localnet")
     289         [ -  + ]:      35867 :             || !strcmp(binding->type, "l2gateway")) {
     290                 :        323 :             match_set_dl_vlan(&match, htons(tag));
     291                 :        323 :             ofpact_put_STRIP_VLAN(ofpacts_p);
     292                 :            :         }
     293                 :            : 
     294                 :            :         /* Remember the size with just strip vlan added so far,
     295                 :            :          * as we're going to remove this with ofpbuf_pull() later. */
     296                 :      36190 :         uint32_t ofpacts_orig_size = ofpacts_p->size;
     297                 :            : 
     298         [ +  + ]:      36190 :         if (zone_id) {
     299                 :      12709 :             put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, ofpacts_p);
     300                 :            :         }
     301                 :            : 
     302                 :            :         int zone_id_dnat, zone_id_snat;
     303                 :      36190 :         const struct uuid *key = &binding->datapath->header_.uuid;
     304                 :      36190 :         char *dnat = alloc_nat_zone_key(key, "dnat");
     305                 :      36190 :         char *snat = alloc_nat_zone_key(key, "snat");
     306                 :            : 
     307                 :      36190 :         zone_id_dnat = simap_get(ct_zones, dnat);
     308         [ +  + ]:      36190 :         if (zone_id_dnat) {
     309                 :        689 :             put_load(zone_id_dnat, MFF_LOG_DNAT_ZONE, 0, 32, ofpacts_p);
     310                 :            :         }
     311                 :      36190 :         free(dnat);
     312                 :            : 
     313                 :      36190 :         zone_id_snat = simap_get(ct_zones, snat);
     314         [ +  + ]:      36190 :         if (zone_id_snat) {
     315                 :        689 :             put_load(zone_id_snat, MFF_LOG_SNAT_ZONE, 0, 32, ofpacts_p);
     316                 :            :         }
     317                 :      36190 :         free(snat);
     318                 :            : 
     319                 :            :         /* Set MFF_LOG_DATAPATH and MFF_LOG_INPORT. */
     320                 :      36190 :         put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, ofpacts_p);
     321                 :      36190 :         put_load(port_key, MFF_LOG_INPORT, 0, 32, ofpacts_p);
     322                 :            : 
     323                 :            :         /* Resubmit to first logical ingress pipeline table. */
     324                 :      36190 :         put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts_p);
     325         [ +  + ]:      36190 :         ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG,
     326                 :            :                         tag ? 150 : 100, &match, ofpacts_p);
     327                 :            : 
     328 [ +  + ][ +  + ]:      36190 :         if (!tag && (!strcmp(binding->type, "localnet")
     329         [ -  + ]:      35867 :                      || !strcmp(binding->type, "l2gateway"))) {
     330                 :            : 
     331                 :            :             /* Add a second flow for frames that lack any 802.1Q
     332                 :            :              * header.  For these, drop the OFPACT_STRIP_VLAN
     333                 :            :              * action. */
     334                 :        225 :             ofpbuf_pull(ofpacts_p, ofpacts_orig_size);
     335                 :        225 :             match_set_dl_tci_masked(&match, 0, htons(VLAN_CFI));
     336                 :        225 :             ofctrl_add_flow(flow_table, 0, 100, &match, ofpacts_p);
     337                 :            :         }
     338                 :            : 
     339                 :            :         /* Table 33, priority 100.
     340                 :            :          * =======================
     341                 :            :          *
     342                 :            :          * Implements output to local hypervisor.  Each flow matches a
     343                 :            :          * logical output port on the local hypervisor, and resubmits to
     344                 :            :          * table 34.
     345                 :            :          */
     346                 :            : 
     347                 :      36190 :         match_init_catchall(&match);
     348                 :      36190 :         ofpbuf_clear(ofpacts_p);
     349                 :            : 
     350                 :            :         /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */
     351                 :      36190 :         match_set_metadata(&match, htonll(dp_key));
     352                 :      36190 :         match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
     353                 :            : 
     354         [ +  + ]:      36190 :         if (zone_id) {
     355                 :      12709 :             put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, ofpacts_p);
     356                 :            :         }
     357         [ +  + ]:      36190 :         if (zone_id_dnat) {
     358                 :        689 :             put_load(zone_id_dnat, MFF_LOG_DNAT_ZONE, 0, 32, ofpacts_p);
     359                 :            :         }
     360         [ +  + ]:      36190 :         if (zone_id_snat) {
     361                 :        689 :             put_load(zone_id_snat, MFF_LOG_SNAT_ZONE, 0, 32, ofpacts_p);
     362                 :            :         }
     363                 :            : 
     364                 :            :         /* Resubmit to table 34. */
     365                 :      36190 :         put_resubmit(OFTABLE_CHECK_LOOPBACK, ofpacts_p);
     366                 :      36190 :         ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100,
     367                 :            :                         &match, ofpacts_p);
     368                 :            : 
     369                 :            :         /* Table 34, Priority 100.
     370                 :            :          * =======================
     371                 :            :          *
     372                 :            :          * Drop packets whose logical inport and outport are the same
     373                 :            :          * and the MLF_ALLOW_LOOPBACK flag is not set. */
     374                 :      36190 :         match_init_catchall(&match);
     375                 :      36190 :         ofpbuf_clear(ofpacts_p);
     376                 :      36190 :         match_set_metadata(&match, htonll(dp_key));
     377                 :      36190 :         match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
     378                 :            :                              0, MLF_ALLOW_LOOPBACK);
     379                 :      36190 :         match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, port_key);
     380                 :      36190 :         match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
     381                 :      36190 :         ofctrl_add_flow(flow_table, OFTABLE_CHECK_LOOPBACK, 100,
     382                 :            :                         &match, ofpacts_p);
     383                 :            : 
     384                 :            :         /* Table 64, Priority 100.
     385                 :            :          * =======================
     386                 :            :          *
     387                 :            :          * If the packet is supposed to hair-pin because the "loopback"
     388                 :            :          * flag is set, temporarily set the in_port to zero, resubmit to
     389                 :            :          * table 65 for logical-to-physical translation, then restore
     390                 :            :          * the port number. */
     391                 :      36190 :         match_init_catchall(&match);
     392                 :      36190 :         ofpbuf_clear(ofpacts_p);
     393                 :      36190 :         match_set_metadata(&match, htonll(dp_key));
     394                 :      36190 :         match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
     395                 :            :                              MLF_ALLOW_LOOPBACK, MLF_ALLOW_LOOPBACK);
     396                 :      36190 :         match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
     397                 :            : 
     398                 :      36190 :         put_stack(MFF_IN_PORT, ofpact_put_STACK_PUSH(ofpacts_p));
     399                 :      36190 :         put_load(0, MFF_IN_PORT, 0, 16, ofpacts_p);
     400                 :      36190 :         put_resubmit(OFTABLE_LOG_TO_PHY, ofpacts_p);
     401                 :      36190 :         put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p));
     402                 :      36190 :         ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100,
     403                 :            :                         &match, ofpacts_p);
     404                 :            : 
     405                 :            :         /* Table 65, Priority 100.
     406                 :            :          * =======================
     407                 :            :          *
     408                 :            :          * Deliver the packet to the local vif. */
     409                 :      36190 :         match_init_catchall(&match);
     410                 :      36190 :         ofpbuf_clear(ofpacts_p);
     411                 :      36190 :         match_set_metadata(&match, htonll(dp_key));
     412                 :      36190 :         match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
     413         [ +  + ]:      36190 :         if (tag) {
     414                 :            :             /* For containers sitting behind a local vif, tag the packets
     415                 :            :              * before delivering them. */
     416                 :            :             struct ofpact_vlan_vid *vlan_vid;
     417                 :         98 :             vlan_vid = ofpact_put_SET_VLAN_VID(ofpacts_p);
     418                 :         98 :             vlan_vid->vlan_vid = tag;
     419                 :         98 :             vlan_vid->push_vlan_if_needed = true;
     420                 :            : 
     421                 :            :             /* A packet might need to hair-pin back into its ingress
     422                 :            :              * OpenFlow port (to a different logical port, which we already
     423                 :            :              * checked back in table 34), so set the in_port to zero. */
     424                 :         98 :             put_stack(MFF_IN_PORT, ofpact_put_STACK_PUSH(ofpacts_p));
     425                 :         98 :             put_load(0, MFF_IN_PORT, 0, 16, ofpacts_p);
     426                 :            :         }
     427                 :      36190 :         ofpact_put_OUTPUT(ofpacts_p)->port = ofport;
     428         [ +  + ]:      36190 :         if (tag) {
     429                 :            :             /* Revert the tag added to the packets headed to containers
     430                 :            :              * in the previous step. If we don't do this, the packets
     431                 :            :              * that are to be broadcasted to a VM in the same logical
     432                 :            :              * switch will also contain the tag. Also revert the zero'd
     433                 :            :              * in_port. */
     434                 :         98 :             ofpact_put_STRIP_VLAN(ofpacts_p);
     435                 :         98 :             put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p));
     436                 :            :         }
     437                 :      36190 :         ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 100,
     438                 :            :                         &match, ofpacts_p);
     439         [ +  + ]:      19221 :     } else if (!tun) {
     440                 :            :         /* Remote port connected by localnet port */
     441                 :            :         /* Table 33, priority 100.
     442                 :            :          * =======================
     443                 :            :          *
     444                 :            :          * Implements switching to localnet port. Each flow matches a
     445                 :            :          * logical output port on remote hypervisor, switch the output port
     446                 :            :          * to connected localnet port and resubmits to same table.
     447                 :            :          */
     448                 :            : 
     449                 :        267 :         match_init_catchall(&match);
     450                 :        267 :         ofpbuf_clear(ofpacts_p);
     451                 :            : 
     452                 :            :         /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */
     453                 :        267 :         match_set_metadata(&match, htonll(dp_key));
     454                 :        267 :         match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
     455                 :            : 
     456                 :        267 :         put_load(localnet_port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, ofpacts_p);
     457                 :            : 
     458                 :            :         /* Resubmit to table 33. */
     459                 :        267 :         put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p);
     460                 :        267 :         ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100,
     461                 :            :                         &match, ofpacts_p);
     462                 :            :     } else {
     463                 :            :         /* Remote port connected by tunnel */
     464                 :            : 
     465                 :            :         /* Table 32, priority 150 and 100.
     466                 :            :          * ===============================
     467                 :            :          *
     468                 :            :          * Priority 150 is for packets received from a VXLAN tunnel
     469                 :            :          * which get resubmitted to OFTABLE_LOG_INGRESS_PIPELINE due to
     470                 :            :          * lack of needed metadata in VXLAN, explicitly skip sending
     471                 :            :          * back out any tunnels and resubmit to table 33 for local
     472                 :            :          * delivery.
     473                 :            :          *
     474                 :            :          * Priority 100 is for all other traffic which need to be sent
     475                 :            :          * to a remote hypervisor.  Each flow matches an output port
     476                 :            :          * that includes a logical port on a remote hypervisor, and
     477                 :            :          * tunnels the packet to that hypervisor.
     478                 :            :          */
     479                 :      18954 :         match_init_catchall(&match);
     480                 :      18954 :         ofpbuf_clear(ofpacts_p);
     481                 :      18954 :         match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
     482                 :            :                              MLF_RCV_FROM_VXLAN, MLF_RCV_FROM_VXLAN);
     483                 :            : 
     484                 :            :         /* Resubmit to table 33. */
     485                 :      18954 :         put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p);
     486                 :      18954 :         ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, &match,
     487                 :            :                         ofpacts_p);
     488                 :            : 
     489                 :            : 
     490                 :      18954 :         match_init_catchall(&match);
     491                 :      18954 :         ofpbuf_clear(ofpacts_p);
     492                 :            : 
     493                 :            :         /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */
     494                 :      18954 :         match_set_metadata(&match, htonll(dp_key));
     495                 :      18954 :         match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
     496                 :            : 
     497                 :      18954 :         put_encapsulation(mff_ovn_geneve, tun, binding->datapath,
     498                 :            :                           port_key, ofpacts_p);
     499                 :            : 
     500                 :            :         /* Output to tunnel. */
     501                 :      18954 :         ofpact_put_OUTPUT(ofpacts_p)->port = ofport;
     502                 :      55411 :         ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 100,
     503                 :            :                         &match, ofpacts_p);
     504                 :            :     }
     505                 :            : }
     506                 :            : 
     507                 :            : static void
     508                 :      11174 : consider_mc_group(enum mf_field_id mff_ovn_geneve,
     509                 :            :                   const struct simap *ct_zones,
     510                 :            :                   struct hmap *local_datapaths,
     511                 :            :                   const struct sbrec_multicast_group *mc,
     512                 :            :                   struct ofpbuf *ofpacts_p,
     513                 :            :                   struct ofpbuf *remote_ofpacts_p,
     514                 :            :                   struct hmap *flow_table)
     515                 :            : {
     516                 :      11174 :     struct sset remote_chassis = SSET_INITIALIZER(&remote_chassis);
     517                 :            :     struct match match;
     518                 :            : 
     519                 :      11174 :     match_init_catchall(&match);
     520                 :      11174 :     match_set_metadata(&match, htonll(mc->datapath->tunnel_key));
     521                 :      11174 :     match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, mc->tunnel_key);
     522                 :            : 
     523                 :            :     /* Go through all of the ports in the multicast group:
     524                 :            :      *
     525                 :            :      *    - For remote ports, add the chassis to 'remote_chassis'.
     526                 :            :      *
     527                 :            :      *    - For local ports (other than logical patch ports), add actions
     528                 :            :      *      to 'ofpacts_p' to set the output port and resubmit.
     529                 :            :      *
     530                 :            :      *    - For logical patch ports, add actions to 'remote_ofpacts_p'
     531                 :            :      *      instead.  (If we put them in 'ofpacts', then the output
     532                 :            :      *      would happen on every hypervisor in the multicast group,
     533                 :            :      *      effectively duplicating the packet.)
     534                 :            :      */
     535                 :      11174 :     ofpbuf_clear(ofpacts_p);
     536                 :      11174 :     ofpbuf_clear(remote_ofpacts_p);
     537         [ +  + ]:      66417 :     for (size_t i = 0; i < mc->n_ports; i++) {
     538                 :      55243 :         struct sbrec_port_binding *port = mc->ports[i];
     539                 :            : 
     540         [ -  + ]:      55243 :         if (port->datapath != mc->datapath) {
     541                 :            :             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
     542         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, UUID_FMT": multicast group contains ports "
     543                 :            :                          "in wrong datapath",
     544                 :            :                          UUID_ARGS(&mc->header_.uuid));
     545                 :          0 :             continue;
     546                 :            :         }
     547                 :            : 
     548                 :      55243 :         int zone_id = simap_get(ct_zones, port->logical_port);
     549         [ +  + ]:      55243 :         if (zone_id) {
     550                 :      14893 :             put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, ofpacts_p);
     551                 :            :         }
     552                 :            : 
     553         [ +  + ]:      55243 :         if (!strcmp(port->type, "patch")) {
     554                 :      11825 :             put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32,
     555                 :            :                      remote_ofpacts_p);
     556                 :      11825 :             put_resubmit(OFTABLE_CHECK_LOOPBACK, remote_ofpacts_p);
     557 [ +  + ][ +  + ]:      43794 :         } else if (simap_contains(&localvif_to_ofport,
     558         [ -  + ]:        376 :                            (port->parent_port && *port->parent_port)
     559                 :            :                            ? port->parent_port : port->logical_port)) {
     560                 :      14585 :             put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, ofpacts_p);
     561                 :      14585 :             put_resubmit(OFTABLE_CHECK_LOOPBACK, ofpacts_p);
     562 [ +  + ][ +  + ]:      28833 :         } else if (port->chassis && !get_localnet_port(local_datapaths,
     563                 :      22689 :                                          mc->datapath->tunnel_key)) {
     564                 :            :             /* Add remote chassis only when localnet port not exist,
     565                 :            :              * otherwise multicast will reach remote ports through localnet
     566                 :            :              * port. */
     567                 :      22391 :             sset_add(&remote_chassis, port->chassis->name);
     568                 :            :         }
     569                 :            :     }
     570                 :            : 
     571                 :            :     /* Table 33, priority 100.
     572                 :            :      * =======================
     573                 :            :      *
     574                 :            :      * Handle output to the local logical ports in the multicast group, if
     575                 :            :      * any. */
     576                 :      11174 :     bool local_ports = ofpacts_p->size > 0;
     577         [ +  + ]:      11174 :     if (local_ports) {
     578                 :            :         /* Following delivery to local logical ports, restore the multicast
     579                 :            :          * group as the logical output port. */
     580                 :       7050 :         put_load(mc->tunnel_key, MFF_LOG_OUTPORT, 0, 32, ofpacts_p);
     581                 :            : 
     582                 :       7050 :         ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100,
     583                 :            :                         &match, ofpacts_p);
     584                 :            :     }
     585                 :            : 
     586                 :            :     /* Table 32, priority 100.
     587                 :            :      * =======================
     588                 :            :      *
     589                 :            :      * Handle output to the remote chassis in the multicast group, if
     590                 :            :      * any. */
     591 [ +  + ][ +  + ]:      11174 :     if (!sset_is_empty(&remote_chassis) || remote_ofpacts_p->size > 0) {
     592         [ +  + ]:       8165 :         if (remote_ofpacts_p->size > 0) {
     593                 :            :             /* Following delivery to logical patch ports, restore the
     594                 :            :              * multicast group as the logical output port. */
     595                 :       4855 :             put_load(mc->tunnel_key, MFF_LOG_OUTPORT, 0, 32,
     596                 :            :                      remote_ofpacts_p);
     597                 :            :         }
     598                 :            : 
     599                 :            :         const char *chassis;
     600                 :       8165 :         const struct chassis_tunnel *prev = NULL;
     601 [ +  + ][ +  + ]:      18215 :         SSET_FOR_EACH (chassis, &remote_chassis) {
                 [ +  + ]
     602                 :      10050 :             const struct chassis_tunnel *tun
     603                 :            :                 = chassis_tunnel_find(chassis);
     604         [ +  + ]:      10050 :             if (!tun) {
     605                 :        220 :                 continue;
     606                 :            :             }
     607                 :            : 
     608 [ +  + ][ +  + ]:       9830 :             if (!prev || tun->type != prev->type) {
     609                 :       6348 :                 put_encapsulation(mff_ovn_geneve, tun, mc->datapath,
     610                 :       6348 :                                   mc->tunnel_key, remote_ofpacts_p);
     611                 :       6348 :                 prev = tun;
     612                 :            :             }
     613                 :       9830 :             ofpact_put_OUTPUT(remote_ofpacts_p)->port = tun->ofport;
     614                 :            :         }
     615                 :            : 
     616         [ +  + ]:       8165 :         if (remote_ofpacts_p->size) {
     617         [ +  + ]:       8040 :             if (local_ports) {
     618                 :       4574 :                 put_resubmit(OFTABLE_LOCAL_OUTPUT, remote_ofpacts_p);
     619                 :            :             }
     620                 :       8040 :             ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 100,
     621                 :            :                             &match, remote_ofpacts_p);
     622                 :            :         }
     623                 :            :     }
     624                 :      11174 :     sset_destroy(&remote_chassis);
     625                 :      11174 : }
     626                 :            : 
     627                 :            : void
     628                 :       3167 : physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve,
     629                 :            :              const struct ovsrec_bridge *br_int, const char *this_chassis_id,
     630                 :            :              const struct simap *ct_zones, struct hmap *flow_table,
     631                 :            :              struct hmap *local_datapaths, struct hmap *patched_datapaths)
     632                 :            : {
     633                 :            : 
     634                 :            :     /* This bool tracks physical mapping changes. */
     635                 :       3167 :     bool physical_map_changed = false;
     636                 :            : 
     637                 :       3167 :     struct simap new_localvif_to_ofport =
     638                 :            :         SIMAP_INITIALIZER(&new_localvif_to_ofport);
     639                 :       3167 :     struct simap new_tunnel_to_ofport =
     640                 :            :         SIMAP_INITIALIZER(&new_tunnel_to_ofport);
     641         [ +  + ]:      47616 :     for (int i = 0; i < br_int->n_ports; i++) {
     642                 :      44449 :         const struct ovsrec_port *port_rec = br_int->ports[i];
     643         [ +  + ]:      44449 :         if (!strcmp(port_rec->name, br_int->name)) {
     644                 :       3167 :             continue;
     645                 :            :         }
     646                 :            : 
     647                 :      41282 :         const char *chassis_id = smap_get(&port_rec->external_ids,
     648                 :            :                                           "ovn-chassis-id");
     649 [ +  + ][ -  + ]:      41282 :         if (chassis_id && !strcmp(chassis_id, this_chassis_id)) {
     650                 :          0 :             continue;
     651                 :            :         }
     652                 :            : 
     653                 :      41282 :         const char *localnet = smap_get(&port_rec->external_ids,
     654                 :            :                                         "ovn-localnet-port");
     655                 :      41282 :         const char *l2gateway = smap_get(&port_rec->external_ids,
     656                 :            :                                         "ovn-l2gateway-port");
     657                 :      41282 :         const char *l3gateway = smap_get(&port_rec->external_ids,
     658                 :            :                                         "ovn-l3gateway-port");
     659                 :      41282 :         const char *logpatch = smap_get(&port_rec->external_ids,
     660                 :            :                                         "ovn-logical-patch-port");
     661                 :            : 
     662         [ +  + ]:      55148 :         for (int j = 0; j < port_rec->n_interfaces; j++) {
     663                 :      41282 :             const struct ovsrec_interface *iface_rec = port_rec->interfaces[j];
     664                 :            : 
     665                 :            :             /* Get OpenFlow port number. */
     666         [ +  + ]:      41282 :             if (!iface_rec->n_ofport) {
     667                 :       1100 :                 continue;
     668                 :            :             }
     669                 :      40182 :             int64_t ofport = iface_rec->ofport[0];
     670 [ +  - ][ -  + ]:      40182 :             if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) {
     671                 :          0 :                 continue;
     672                 :            :             }
     673                 :            : 
     674                 :            :             /* Record as patch to local net, logical patch port, chassis, or
     675                 :            :              * local logical port. */
     676                 :      40182 :             bool is_patch = !strcmp(iface_rec->type, "patch");
     677 [ +  + ][ +  + ]:      40182 :             if (is_patch && localnet) {
     678                 :            :                 /* localnet patch ports can be handled just like VIFs. */
     679                 :        327 :                 simap_put(&new_localvif_to_ofport, localnet, ofport);
     680                 :        327 :                 break;
     681 [ +  + ][ -  + ]:      39855 :             } else if (is_patch && l2gateway) {
     682                 :            :                 /* L2 gateway patch ports can be handled just like VIFs. */
     683                 :          0 :                 simap_put(&new_localvif_to_ofport, l2gateway, ofport);
     684                 :          0 :                 break;
     685 [ +  + ][ +  + ]:      39855 :             } else if (is_patch && l3gateway) {
     686                 :            :                 /* L3 gateway patch ports can be handled just like VIFs. */
     687                 :        643 :                 simap_put(&new_localvif_to_ofport, l3gateway, ofport);
     688                 :        643 :                 break;
     689 [ +  + ][ +  - ]:      39212 :             } else if (is_patch && logpatch) {
     690                 :            :                 /* Logical patch ports can be handled just like VIFs. */
     691                 :      23129 :                 simap_put(&new_localvif_to_ofport, logpatch, ofport);
     692                 :      23129 :                 break;
     693         [ +  + ]:      16083 :             } else if (chassis_id) {
     694                 :            :                 enum chassis_tunnel_type tunnel_type;
     695         [ +  + ]:       3318 :                 if (!strcmp(iface_rec->type, "geneve")) {
     696                 :       3292 :                     tunnel_type = GENEVE;
     697         [ +  + ]:       3292 :                     if (!mff_ovn_geneve) {
     698                 :          1 :                         continue;
     699                 :            :                     }
     700         [ +  + ]:         26 :                 } else if (!strcmp(iface_rec->type, "stt")) {
     701                 :          4 :                     tunnel_type = STT;
     702         [ +  - ]:         22 :                 } else if (!strcmp(iface_rec->type, "vxlan")) {
     703                 :         22 :                     tunnel_type = VXLAN;
     704                 :            :                 } else {
     705                 :          0 :                     continue;
     706                 :            :                 }
     707                 :            : 
     708                 :       3317 :                 simap_put(&new_tunnel_to_ofport, chassis_id, ofport);
     709                 :       3317 :                 struct chassis_tunnel *tun = chassis_tunnel_find(chassis_id);
     710         [ +  + ]:       3317 :                 if (tun) {
     711                 :            :                     /* If the tunnel's ofport has changed, update. */
     712 [ +  + ][ +  + ]:       3280 :                     if (tun->ofport != u16_to_ofp(ofport) ||
     713                 :       3278 :                         tun->type != tunnel_type) {
     714                 :          3 :                         tun->ofport = u16_to_ofp(ofport);
     715                 :          3 :                         tun->type = tunnel_type;
     716                 :       3280 :                         physical_map_changed = true;
     717                 :            :                     }
     718                 :            :                 } else {
     719                 :         37 :                     tun = xmalloc(sizeof *tun);
     720                 :         37 :                     hmap_insert(&tunnels, &tun->hmap_node,
     721                 :            :                                 hash_string(chassis_id, 0));
     722                 :         37 :                     tun->chassis_id = chassis_id;
     723                 :         37 :                     tun->ofport = u16_to_ofp(ofport);
     724                 :         37 :                     tun->type = tunnel_type;
     725                 :         37 :                     physical_map_changed = true;
     726                 :            :                 }
     727                 :       3317 :                 break;
     728                 :            :             } else {
     729                 :      12765 :                 const char *iface_id = smap_get(&iface_rec->external_ids,
     730                 :            :                                                 "iface-id");
     731         [ +  - ]:      12765 :                 if (iface_id) {
     732                 :      12765 :                     simap_put(&new_localvif_to_ofport, iface_id, ofport);
     733                 :            :                 }
     734                 :            :             }
     735                 :            :         }
     736                 :            :     }
     737                 :            : 
     738                 :            :     /* Remove tunnels that are no longer here. */
     739                 :            :     struct chassis_tunnel *tun, *tun_next;
     740 [ +  + ][ -  + ]:       6503 :     HMAP_FOR_EACH_SAFE (tun, tun_next, hmap_node, &tunnels) {
                 [ +  + ]
     741         [ +  + ]:       3336 :         if (!simap_find(&new_tunnel_to_ofport, tun->chassis_id)) {
     742                 :         19 :             hmap_remove(&tunnels, &tun->hmap_node);
     743                 :         19 :             physical_map_changed = true;
     744                 :         19 :             free(tun);
     745                 :            :         }
     746                 :            :     }
     747                 :            : 
     748                 :            :     /* Capture changed or removed openflow ports. */
     749                 :            :     struct simap_node *vif_name, *vif_name_next;
     750 [ +  + ][ -  + ]:      39741 :     SIMAP_FOR_EACH_SAFE (vif_name, vif_name_next, &localvif_to_ofport) {
                 [ +  + ]
     751                 :            :         int newport;
     752         [ +  + ]:      36574 :         if ((newport = simap_get(&new_localvif_to_ofport, vif_name->name))) {
     753         [ +  + ]:      36539 :             if (newport != simap_get(&localvif_to_ofport, vif_name->name)) {
     754                 :         30 :                 simap_put(&localvif_to_ofport, vif_name->name, newport);
     755                 :      36539 :                 physical_map_changed = true;
     756                 :            :             }
     757                 :            :         } else {
     758                 :         35 :             simap_find_and_delete(&localvif_to_ofport, vif_name->name);
     759                 :         35 :             physical_map_changed = true;
     760                 :            :         }
     761                 :            :     }
     762 [ +  + ][ -  + ]:      40031 :     SIMAP_FOR_EACH (vif_name, &new_localvif_to_ofport) {
     763         [ +  + ]:      36864 :         if (!simap_get(&localvif_to_ofport, vif_name->name)) {
     764                 :        325 :             simap_put(&localvif_to_ofport, vif_name->name,
     765                 :        325 :                       simap_get(&new_localvif_to_ofport, vif_name->name));
     766                 :        325 :             physical_map_changed = true;
     767                 :            :         }
     768                 :            :     }
     769         [ +  + ]:       3167 :     if (physical_map_changed) {
     770                 :            :         /* Reprocess logical flow table immediately. */
     771                 :        257 :         poll_immediate_wake();
     772                 :            :     }
     773                 :            : 
     774                 :            :     struct ofpbuf ofpacts;
     775                 :       3167 :     ofpbuf_init(&ofpacts, 0);
     776                 :            : 
     777                 :            :     /* Set up flows in table 0 for physical-to-logical translation and in table
     778                 :            :      * 64 for logical-to-physical translation. */
     779                 :            :     const struct sbrec_port_binding *binding;
     780         [ +  + ]:      65858 :     SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
     781                 :            :         /* Because it is possible in the above code to enter this
     782                 :            :          * for loop without having cleared the flow table first, we
     783                 :            :          * should clear the old flows to avoid collisions. */
     784                 :      62691 :         consider_port_binding(mff_ovn_geneve, ct_zones, local_datapaths,
     785                 :            :                               patched_datapaths, binding, &ofpacts,
     786                 :            :                               flow_table);
     787                 :            :     }
     788                 :            : 
     789                 :            :     /* Handle output to multicast groups, in tables 32 and 33. */
     790                 :            :     const struct sbrec_multicast_group *mc;
     791                 :            :     struct ofpbuf remote_ofpacts;
     792                 :       3167 :     ofpbuf_init(&remote_ofpacts, 0);
     793         [ +  + ]:      14341 :     SBREC_MULTICAST_GROUP_FOR_EACH (mc, ctx->ovnsb_idl) {
     794                 :            :         /* As multicast groups are always reprocessed each time,
     795                 :            :          * the first step is to clean the old flows for the group
     796                 :            :          * so that we avoid warning messages on collisions. */
     797                 :      11174 :         consider_mc_group(mff_ovn_geneve, ct_zones,
     798                 :            :                           local_datapaths, mc, &ofpacts, &remote_ofpacts,
     799                 :            :                           flow_table);
     800                 :            :     }
     801                 :            : 
     802                 :       3167 :     ofpbuf_uninit(&remote_ofpacts);
     803                 :            : 
     804                 :            :     /* Table 0, priority 100.
     805                 :            :      * ======================
     806                 :            :      *
     807                 :            :      * Process packets that arrive from a remote hypervisor (by matching
     808                 :            :      * on tunnel in_port). */
     809                 :            : 
     810                 :            :     /* Add flows for Geneve and STT encapsulations.  These
     811                 :            :      * encapsulations have metadata about the ingress and egress logical
     812                 :            :      * ports.  We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and
     813                 :            :      * MFF_LOG_OUTPORT from the tunnel key data, then resubmit to table
     814                 :            :      * 33 to handle packets to the local hypervisor. */
     815 [ +  + ][ -  + ]:       6484 :     HMAP_FOR_EACH (tun, hmap_node, &tunnels) {
     816                 :       3317 :         struct match match = MATCH_CATCHALL_INITIALIZER;
     817                 :       3317 :         match_set_in_port(&match, tun->ofport);
     818                 :            : 
     819                 :       3317 :         ofpbuf_clear(&ofpacts);
     820         [ +  + ]:       3317 :         if (tun->type == GENEVE) {
     821                 :       3291 :             put_move(MFF_TUN_ID, 0,  MFF_LOG_DATAPATH, 0, 24, &ofpacts);
     822                 :       3291 :             put_move(mff_ovn_geneve, 16, MFF_LOG_INPORT, 0, 15,
     823                 :            :                      &ofpacts);
     824                 :       3291 :             put_move(mff_ovn_geneve, 0, MFF_LOG_OUTPORT, 0, 16,
     825                 :            :                      &ofpacts);
     826         [ +  + ]:         26 :         } else if (tun->type == STT) {
     827                 :          4 :             put_move(MFF_TUN_ID, 40, MFF_LOG_INPORT,   0, 15, &ofpacts);
     828                 :          4 :             put_move(MFF_TUN_ID, 24, MFF_LOG_OUTPORT,  0, 16, &ofpacts);
     829                 :          4 :             put_move(MFF_TUN_ID,  0, MFF_LOG_DATAPATH, 0, 24, &ofpacts);
     830         [ +  - ]:         22 :         } else if (tun->type == VXLAN) {
     831                 :            :             /* We'll handle VXLAN later. */
     832                 :         22 :             continue;
     833                 :            :         } else {
     834                 :          0 :             OVS_NOT_REACHED();
     835                 :            :         }
     836                 :            : 
     837                 :       3295 :         put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
     838                 :            : 
     839                 :       3295 :         ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100, &match, &ofpacts);
     840                 :            :     }
     841                 :            : 
     842                 :            :     /* Add flows for VXLAN encapsulations.  Due to the limited amount of
     843                 :            :      * metadata, we only support VXLAN for connections to gateways.  The
     844                 :            :      * VNI is used to populate MFF_LOG_DATAPATH.  The gateway's logical
     845                 :            :      * port is set to MFF_LOG_INPORT.  Then the packet is resubmitted to
     846                 :            :      * table 16 to determine the logical egress port. */
     847 [ +  + ][ -  + ]:       6484 :     HMAP_FOR_EACH (tun, hmap_node, &tunnels) {
     848         [ +  + ]:       3317 :         if (tun->type != VXLAN) {
     849                 :       3295 :             continue;
     850                 :            :         }
     851                 :            : 
     852         [ +  + ]:         82 :         SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
     853                 :         60 :             struct match match = MATCH_CATCHALL_INITIALIZER;
     854                 :            : 
     855 [ +  + ][ +  + ]:         60 :             if (!binding->chassis ||
     856                 :         50 :                 strcmp(tun->chassis_id, binding->chassis->name)) {
     857                 :         44 :                 continue;
     858                 :            :             }
     859                 :            : 
     860                 :         16 :             match_set_in_port(&match, tun->ofport);
     861                 :         16 :             match_set_tun_id(&match, htonll(binding->datapath->tunnel_key));
     862                 :            : 
     863                 :         16 :             ofpbuf_clear(&ofpacts);
     864                 :         16 :             put_move(MFF_TUN_ID, 0,  MFF_LOG_DATAPATH, 0, 24, &ofpacts);
     865                 :         16 :             put_load(binding->tunnel_key, MFF_LOG_INPORT, 0, 15, &ofpacts);
     866                 :            :             /* For packets received from a vxlan tunnel, set a flag to that
     867                 :            :              * effect. */
     868                 :         16 :             put_load(1, MFF_LOG_FLAGS, MLF_RCV_FROM_VXLAN_BIT, 1, &ofpacts);
     869                 :         16 :             put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &ofpacts);
     870                 :            : 
     871                 :         16 :             ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100, &match,
     872                 :            :                             &ofpacts);
     873                 :            :         }
     874                 :            :     }
     875                 :            : 
     876                 :            :     /* Table 32, Priority 0.
     877                 :            :      * =======================
     878                 :            :      *
     879                 :            :      * Resubmit packets that are not directed at tunnels or part of a
     880                 :            :      * multicast group to the local output table. */
     881                 :            :     struct match match;
     882                 :       3167 :     match_init_catchall(&match);
     883                 :       3167 :     ofpbuf_clear(&ofpacts);
     884                 :       3167 :     put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
     885                 :       3167 :     ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 0, &match, &ofpacts);
     886                 :            : 
     887                 :            :     /* Table 34, Priority 0.
     888                 :            :      * =======================
     889                 :            :      *
     890                 :            :      * Resubmit packets that don't output to the ingress port (already checked
     891                 :            :      * in table 33) to the logical egress pipeline, clearing the logical
     892                 :            :      * registers (for consistent behavior with packets that get tunneled). */
     893                 :       3167 :     match_init_catchall(&match);
     894                 :       3167 :     ofpbuf_clear(&ofpacts);
     895         [ +  + ]:      34837 :     for (int i = 0; i < MFF_N_LOG_REGS; i++) {
     896                 :      31670 :         put_load(0, MFF_REG0 + i, 0, 32, &ofpacts);
     897                 :            :     }
     898                 :       3167 :     put_resubmit(OFTABLE_LOG_EGRESS_PIPELINE, &ofpacts);
     899                 :       3167 :     ofctrl_add_flow(flow_table, OFTABLE_CHECK_LOOPBACK, 0, &match, &ofpacts);
     900                 :            : 
     901                 :            :     /* Table 64, Priority 0.
     902                 :            :      * =======================
     903                 :            :      *
     904                 :            :      * Resubmit packets that do not have the MLF_ALLOW_LOOPBACK flag set
     905                 :            :      * to table 65 for logical-to-physical translation. */
     906                 :       3167 :     match_init_catchall(&match);
     907                 :       3167 :     ofpbuf_clear(&ofpacts);
     908                 :       3167 :     put_resubmit(OFTABLE_LOG_TO_PHY, &ofpacts);
     909                 :       3167 :     ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 0, &match, &ofpacts);
     910                 :            : 
     911                 :       3167 :     ofpbuf_uninit(&ofpacts);
     912                 :            : 
     913                 :       3167 :     simap_destroy(&new_localvif_to_ofport);
     914                 :       3167 :     simap_destroy(&new_tunnel_to_ofport);
     915                 :       3167 : }

Generated by: LCOV version 1.12