LCOV - code coverage report
Current view: top level - ovn/controller - ofctrl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 297 387 76.7 %
Date: 2016-09-14 01:02:56 Functions: 34 37 91.9 %
Branches: 131 244 53.7 %

           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 "bitmap.h"
      18                 :            : #include "byte-order.h"
      19                 :            : #include "dirs.h"
      20                 :            : #include "flow.h"
      21                 :            : #include "hash.h"
      22                 :            : #include "lflow.h"
      23                 :            : #include "ofctrl.h"
      24                 :            : #include "openflow/openflow.h"
      25                 :            : #include "openvswitch/dynamic-string.h"
      26                 :            : #include "openvswitch/hmap.h"
      27                 :            : #include "openvswitch/list.h"
      28                 :            : #include "openvswitch/match.h"
      29                 :            : #include "openvswitch/ofp-actions.h"
      30                 :            : #include "openvswitch/ofp-msgs.h"
      31                 :            : #include "openvswitch/ofp-parse.h"
      32                 :            : #include "openvswitch/ofp-print.h"
      33                 :            : #include "openvswitch/ofp-util.h"
      34                 :            : #include "openvswitch/ofpbuf.h"
      35                 :            : #include "openvswitch/vlog.h"
      36                 :            : #include "ovn-controller.h"
      37                 :            : #include "ovn/actions.h"
      38                 :            : #include "poll-loop.h"
      39                 :            : #include "physical.h"
      40                 :            : #include "rconn.h"
      41                 :            : #include "socket-util.h"
      42                 :            : #include "util.h"
      43                 :            : #include "vswitch-idl.h"
      44                 :            : 
      45                 :         94 : VLOG_DEFINE_THIS_MODULE(ofctrl);
      46                 :            : 
      47                 :            : /* An OpenFlow flow. */
      48                 :            : struct ovn_flow {
      49                 :            :     struct hmap_node hmap_node; /* For match based hashing. */
      50                 :            :     struct ovs_list list_node; /* For handling lists of flows. */
      51                 :            : 
      52                 :            :     /* Key. */
      53                 :            :     uint8_t table_id;
      54                 :            :     uint16_t priority;
      55                 :            :     struct match match;
      56                 :            : 
      57                 :            :     /* Data. */
      58                 :            :     struct ofpact *ofpacts;
      59                 :            :     size_t ofpacts_len;
      60                 :            : };
      61                 :            : 
      62                 :            : static uint32_t ovn_flow_hash(const struct ovn_flow *);
      63                 :            : static struct ovn_flow *ovn_flow_lookup(struct hmap *flow_table,
      64                 :            :                                         const struct ovn_flow *target);
      65                 :            : static char *ovn_flow_to_string(const struct ovn_flow *);
      66                 :            : static void ovn_flow_log(const struct ovn_flow *, const char *action);
      67                 :            : static void ovn_flow_destroy(struct ovn_flow *);
      68                 :            : 
      69                 :            : /* OpenFlow connection to the switch. */
      70                 :            : static struct rconn *swconn;
      71                 :            : 
      72                 :            : /* Last seen sequence number for 'swconn'.  When this differs from
      73                 :            :  * rconn_get_connection_seqno(rconn), 'swconn' has reconnected. */
      74                 :            : static unsigned int seqno;
      75                 :            : 
      76                 :            : /* Connection state machine. */
      77                 :            : #define STATES                                  \
      78                 :            :     STATE(S_NEW)                                \
      79                 :            :     STATE(S_TLV_TABLE_REQUESTED)                \
      80                 :            :     STATE(S_TLV_TABLE_MOD_SENT)                 \
      81                 :            :     STATE(S_CLEAR_FLOWS)                        \
      82                 :            :     STATE(S_UPDATE_FLOWS)
      83                 :            : enum ofctrl_state {
      84                 :            : #define STATE(NAME) NAME,
      85                 :            :     STATES
      86                 :            : #undef STATE
      87                 :            : };
      88                 :            : 
      89                 :            : /* An in-flight update to the switch's flow table.
      90                 :            :  *
      91                 :            :  * When we receive a barrier reply from the switch with the given 'xid', we
      92                 :            :  * know that the switch is caught up to northbound database sequence number
      93                 :            :  * 'nb_cfg' (and make that available to the client via ofctrl_get_cur_cfg(), so
      94                 :            :  * that it can store it into our Chassis record's nb_cfg column). */
      95                 :            : struct ofctrl_flow_update {
      96                 :            :     struct ovs_list list_node;  /* In 'flow_updates'. */
      97                 :            :     ovs_be32 xid;               /* OpenFlow transaction ID for barrier. */
      98                 :            :     int64_t nb_cfg;             /* Northbound database sequence number. */
      99                 :            : };
     100                 :            : 
     101                 :            : static struct ofctrl_flow_update *
     102                 :       1640 : ofctrl_flow_update_from_list_node(const struct ovs_list *list_node)
     103                 :            : {
     104                 :       1640 :     return CONTAINER_OF(list_node, struct ofctrl_flow_update, list_node);
     105                 :            : }
     106                 :            : 
     107                 :            : /* Currently in-flight updates. */
     108                 :            : static struct ovs_list flow_updates;
     109                 :            : 
     110                 :            : /* nb_cfg of latest committed flow update. */
     111                 :            : static int64_t cur_cfg;
     112                 :            : 
     113                 :            : /* Current state. */
     114                 :            : static enum ofctrl_state state;
     115                 :            : 
     116                 :            : /* Transaction IDs for messages in flight to the switch. */
     117                 :            : static ovs_be32 xid, xid2;
     118                 :            : 
     119                 :            : /* Counter for in-flight OpenFlow messages on 'swconn'.  We only send a new
     120                 :            :  * round of flow table modifications to the switch when the counter falls to
     121                 :            :  * zero, to avoid unbounded buffering. */
     122                 :            : static struct rconn_packet_counter *tx_counter;
     123                 :            : 
     124                 :            : /* Flow table of "struct ovn_flow"s, that holds the flow table currently
     125                 :            :  * installed in the switch. */
     126                 :            : static struct hmap installed_flows;
     127                 :            : 
     128                 :            : /* A reference to the group_table. */
     129                 :            : static struct group_table *groups;
     130                 :            : 
     131                 :            : /* MFF_* field ID for our Geneve option.  In S_TLV_TABLE_MOD_SENT, this is
     132                 :            :  * the option we requested (we don't know whether we obtained it yet).  In
     133                 :            :  * S_CLEAR_FLOWS or S_UPDATE_FLOWS, this is really the option we have. */
     134                 :            : static enum mf_field_id mff_ovn_geneve;
     135                 :            : 
     136                 :            : static ovs_be32 queue_msg(struct ofpbuf *);
     137                 :            : 
     138                 :            : static struct ofpbuf *encode_flow_mod(struct ofputil_flow_mod *);
     139                 :            : 
     140                 :            : static struct ofpbuf *encode_group_mod(const struct ofputil_group_mod *);
     141                 :            : 
     142                 :            : static void ovn_flow_table_clear(struct hmap *flow_table);
     143                 :            : static void ovn_flow_table_destroy(struct hmap *flow_table);
     144                 :            : 
     145                 :            : static void ofctrl_recv(const struct ofp_header *, enum ofptype);
     146                 :            : 
     147                 :            : void
     148                 :         44 : ofctrl_init(struct group_table *group_table)
     149                 :            : {
     150                 :         44 :     swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION);
     151                 :         44 :     tx_counter = rconn_packet_counter_create();
     152                 :         44 :     hmap_init(&installed_flows);
     153                 :         44 :     ovs_list_init(&flow_updates);
     154                 :         44 :     groups = group_table;
     155                 :         44 : }
     156                 :            : 
     157                 :            : /* S_NEW, for a new connection.
     158                 :            :  *
     159                 :            :  * Sends NXT_TLV_TABLE_REQUEST and transitions to
     160                 :            :  * S_TLV_TABLE_REQUESTED. */
     161                 :            : 
     162                 :            : static void
     163                 :         46 : run_S_NEW(void)
     164                 :            : {
     165                 :         46 :     struct ofpbuf *buf = ofpraw_alloc(OFPRAW_NXT_TLV_TABLE_REQUEST,
     166                 :         46 :                                       rconn_get_version(swconn), 0);
     167                 :         46 :     xid = queue_msg(buf);
     168                 :         46 :     state = S_TLV_TABLE_REQUESTED;
     169                 :         46 : }
     170                 :            : 
     171                 :            : static void
     172                 :          0 : recv_S_NEW(const struct ofp_header *oh OVS_UNUSED,
     173                 :            :            enum ofptype type OVS_UNUSED)
     174                 :            : {
     175                 :          0 :     OVS_NOT_REACHED();
     176                 :            : }
     177                 :            : 
     178                 :            : /* S_TLV_TABLE_REQUESTED, when NXT_TLV_TABLE_REQUEST has been sent
     179                 :            :  * and we're waiting for a reply.
     180                 :            :  *
     181                 :            :  * If we receive an NXT_TLV_TABLE_REPLY:
     182                 :            :  *
     183                 :            :  *     - If it contains our tunnel metadata option, assign its field ID to
     184                 :            :  *       mff_ovn_geneve and transition to S_CLEAR_FLOWS.
     185                 :            :  *
     186                 :            :  *     - Otherwise, if there is an unused tunnel metadata field ID, send
     187                 :            :  *       NXT_TLV_TABLE_MOD and OFPT_BARRIER_REQUEST, and transition to
     188                 :            :  *       S_TLV_TABLE_MOD_SENT.
     189                 :            :  *
     190                 :            :  *     - Otherwise, log an error, disable Geneve, and transition to
     191                 :            :  *       S_CLEAR_FLOWS.
     192                 :            :  *
     193                 :            :  * If we receive an OFPT_ERROR:
     194                 :            :  *
     195                 :            :  *     - Log an error, disable Geneve, and transition to S_CLEAR_FLOWS. */
     196                 :            : 
     197                 :            : static void
     198                 :         50 : run_S_TLV_TABLE_REQUESTED(void)
     199                 :            : {
     200                 :         50 : }
     201                 :            : 
     202                 :            : static bool
     203                 :         46 : process_tlv_table_reply(const struct ofputil_tlv_table_reply *reply)
     204                 :            : {
     205                 :            :     const struct ofputil_tlv_map *map;
     206                 :         46 :     uint64_t md_free = UINT64_MAX;
     207                 :            :     BUILD_ASSERT(TUN_METADATA_NUM_OPTS == 64);
     208                 :            : 
     209         [ -  + ]:         46 :     LIST_FOR_EACH (map, list_node, &reply->mappings) {
     210         [ #  # ]:          0 :         if (map->option_class == OVN_GENEVE_CLASS
     211         [ #  # ]:          0 :             && map->option_type == OVN_GENEVE_TYPE
     212         [ #  # ]:          0 :             && map->option_len == OVN_GENEVE_LEN) {
     213         [ #  # ]:          0 :             if (map->index >= TUN_METADATA_NUM_OPTS) {
     214         [ #  # ]:          0 :                 VLOG_ERR("desired Geneve tunnel option 0x%"PRIx16","
     215                 :            :                          "%"PRIu8",%"PRIu8" already in use with "
     216                 :            :                          "unsupported index %"PRIu16,
     217                 :            :                          map->option_class, map->option_type,
     218                 :            :                          map->option_len, map->index);
     219                 :          0 :                 return false;
     220                 :            :             } else {
     221                 :          0 :                 mff_ovn_geneve = MFF_TUN_METADATA0 + map->index;
     222                 :          0 :                 state = S_CLEAR_FLOWS;
     223                 :          0 :                 return true;
     224                 :            :             }
     225                 :            :         }
     226                 :            : 
     227         [ #  # ]:          0 :         if (map->index < TUN_METADATA_NUM_OPTS) {
     228                 :          0 :             md_free &= ~(UINT64_C(1) << map->index);
     229                 :            :         }
     230                 :            :     }
     231                 :            : 
     232         [ -  + ]:         46 :     VLOG_DBG("OVN Geneve option not found");
     233         [ -  + ]:         46 :     if (!md_free) {
     234         [ #  # ]:          0 :         VLOG_ERR("no Geneve options free for use by OVN");
     235                 :          0 :         return false;
     236                 :            :     }
     237                 :            : 
     238                 :         46 :     unsigned int index = rightmost_1bit_idx(md_free);
     239                 :         46 :     mff_ovn_geneve = MFF_TUN_METADATA0 + index;
     240                 :            :     struct ofputil_tlv_map tm;
     241                 :         46 :     tm.option_class = OVN_GENEVE_CLASS;
     242                 :         46 :     tm.option_type = OVN_GENEVE_TYPE;
     243                 :         46 :     tm.option_len = OVN_GENEVE_LEN;
     244                 :         46 :     tm.index = index;
     245                 :            : 
     246                 :            :     struct ofputil_tlv_table_mod ttm;
     247                 :         46 :     ttm.command = NXTTMC_ADD;
     248                 :         46 :     ovs_list_init(&ttm.mappings);
     249                 :         46 :     ovs_list_push_back(&ttm.mappings, &tm.list_node);
     250                 :            : 
     251                 :         46 :     xid = queue_msg(ofputil_encode_tlv_table_mod(OFP13_VERSION, &ttm));
     252                 :         46 :     xid2 = queue_msg(ofputil_encode_barrier_request(OFP13_VERSION));
     253                 :         46 :     state = S_TLV_TABLE_MOD_SENT;
     254                 :            : 
     255                 :         46 :     return true;
     256                 :            : }
     257                 :            : 
     258                 :            : static void
     259                 :         46 : recv_S_TLV_TABLE_REQUESTED(const struct ofp_header *oh, enum ofptype type)
     260                 :            : {
     261         [ -  + ]:         46 :     if (oh->xid != xid) {
     262                 :          0 :         ofctrl_recv(oh, type);
     263                 :          0 :         return;
     264         [ +  - ]:         46 :     } else if (type == OFPTYPE_NXT_TLV_TABLE_REPLY) {
     265                 :            :         struct ofputil_tlv_table_reply reply;
     266                 :         46 :         enum ofperr error = ofputil_decode_tlv_table_reply(oh, &reply);
     267         [ +  - ]:         46 :         if (!error) {
     268                 :         46 :             bool ok = process_tlv_table_reply(&reply);
     269                 :         46 :             ofputil_uninit_tlv_table(&reply.mappings);
     270         [ +  - ]:         46 :             if (ok) {
     271                 :         46 :                 return;
     272                 :            :             }
     273                 :            :         } else {
     274         [ #  # ]:          0 :             VLOG_ERR("failed to decode TLV table request (%s)",
     275                 :            :                      ofperr_to_string(error));
     276                 :            :         }
     277         [ #  # ]:          0 :     } else if (type == OFPTYPE_ERROR) {
     278         [ #  # ]:          0 :         VLOG_ERR("switch refused to allocate Geneve option (%s)",
     279                 :            :                  ofperr_to_string(ofperr_decode_msg(oh, NULL)));
     280                 :            :     } else {
     281                 :          0 :         char *s = ofp_to_string(oh, ntohs(oh->length), 1);
     282         [ #  # ]:          0 :         VLOG_ERR("unexpected reply to TLV table request (%s)", s);
     283                 :          0 :         free(s);
     284                 :            :     }
     285                 :            : 
     286                 :            :     /* Error path. */
     287                 :          0 :     mff_ovn_geneve = 0;
     288                 :          0 :     state = S_CLEAR_FLOWS;
     289                 :            : }
     290                 :            : 
     291                 :            : /* S_TLV_TABLE_MOD_SENT, when NXT_TLV_TABLE_MOD and OFPT_BARRIER_REQUEST
     292                 :            :  * have been sent and we're waiting for a reply to one or the other.
     293                 :            :  *
     294                 :            :  * If we receive an OFPT_ERROR:
     295                 :            :  *
     296                 :            :  *     - If the error is NXTTMFC_ALREADY_MAPPED or NXTTMFC_DUP_ENTRY, we
     297                 :            :  *       raced with some other controller.  Transition to S_NEW.
     298                 :            :  *
     299                 :            :  *     - Otherwise, log an error, disable Geneve, and transition to
     300                 :            :  *       S_CLEAR_FLOWS.
     301                 :            :  *
     302                 :            :  * If we receive OFPT_BARRIER_REPLY:
     303                 :            :  *
     304                 :            :  *     - Set the tunnel metadata field ID to the one that we requested.
     305                 :            :  *       Transition to S_CLEAR_FLOWS.
     306                 :            :  */
     307                 :            : 
     308                 :            : static void
     309                 :         80 : run_S_TLV_TABLE_MOD_SENT(void)
     310                 :            : {
     311                 :         80 : }
     312                 :            : 
     313                 :            : static void
     314                 :         46 : recv_S_TLV_TABLE_MOD_SENT(const struct ofp_header *oh, enum ofptype type)
     315                 :            : {
     316 [ +  - ][ -  + ]:         46 :     if (oh->xid != xid && oh->xid != xid2) {
     317                 :          0 :         ofctrl_recv(oh, type);
     318 [ +  - ][ +  - ]:         46 :     } else if (oh->xid == xid2 && type == OFPTYPE_BARRIER_REPLY) {
     319                 :         46 :         state = S_CLEAR_FLOWS;
     320 [ #  # ][ #  # ]:          0 :     } else if (oh->xid == xid && type == OFPTYPE_ERROR) {
     321                 :          0 :         enum ofperr error = ofperr_decode_msg(oh, NULL);
     322 [ #  # ][ #  # ]:          0 :         if (error == OFPERR_NXTTMFC_ALREADY_MAPPED ||
     323                 :            :             error == OFPERR_NXTTMFC_DUP_ENTRY) {
     324         [ #  # ]:          0 :             VLOG_INFO("raced with another controller adding "
     325                 :            :                       "Geneve option (%s); trying again",
     326                 :            :                       ofperr_to_string(error));
     327                 :          0 :             state = S_NEW;
     328                 :            :         } else {
     329         [ #  # ]:          0 :             VLOG_ERR("error adding Geneve option (%s)",
     330                 :            :                      ofperr_to_string(error));
     331                 :          0 :             goto error;
     332                 :            :         }
     333                 :            :     } else {
     334                 :          0 :         char *s = ofp_to_string(oh, ntohs(oh->length), 1);
     335         [ #  # ]:          0 :         VLOG_ERR("unexpected reply to Geneve option allocation request (%s)",
     336                 :            :                  s);
     337                 :          0 :         free(s);
     338                 :          0 :         goto error;
     339                 :            :     }
     340                 :         46 :     return;
     341                 :            : 
     342                 :            : error:
     343                 :          0 :     state = S_CLEAR_FLOWS;
     344                 :            : }
     345                 :            : 
     346                 :            : /* S_CLEAR_FLOWS, after we've established a Geneve metadata field ID and it's
     347                 :            :  * time to set up some flows.
     348                 :            :  *
     349                 :            :  * Sends an OFPT_TABLE_MOD to clear all flows, then transitions to
     350                 :            :  * S_UPDATE_FLOWS. */
     351                 :            : 
     352                 :            : static void
     353                 :         46 : run_S_CLEAR_FLOWS(void)
     354                 :            : {
     355                 :            :     /* Send a flow_mod to delete all flows. */
     356                 :         46 :     struct ofputil_flow_mod fm = {
     357                 :            :         .match = MATCH_CATCHALL_INITIALIZER,
     358                 :            :         .table_id = OFPTT_ALL,
     359                 :            :         .command = OFPFC_DELETE,
     360                 :            :     };
     361                 :         46 :     queue_msg(encode_flow_mod(&fm));
     362         [ -  + ]:         46 :     VLOG_DBG("clearing all flows");
     363                 :            : 
     364                 :            :     /* Clear installed_flows, to match the state of the switch. */
     365                 :         46 :     ovn_flow_table_clear(&installed_flows);
     366                 :            : 
     367                 :            :     /* Send a group_mod to delete all groups. */
     368                 :            :     struct ofputil_group_mod gm;
     369                 :         46 :     memset(&gm, 0, sizeof gm);
     370                 :         46 :     gm.command = OFPGC11_DELETE;
     371                 :         46 :     gm.group_id = OFPG_ALL;
     372                 :         46 :     gm.command_bucket_id = OFPG15_BUCKET_ALL;
     373                 :         46 :     ovs_list_init(&gm.buckets);
     374                 :         46 :     queue_msg(encode_group_mod(&gm));
     375                 :         46 :     ofputil_uninit_group_mod(&gm);
     376                 :            : 
     377                 :            :     /* Clear existing groups, to match the state of the switch. */
     378         [ +  - ]:         46 :     if (groups) {
     379                 :         46 :         ovn_group_table_clear(groups, true);
     380                 :            :     }
     381                 :            : 
     382                 :            :     /* All flow updates are irrelevant now. */
     383                 :            :     struct ofctrl_flow_update *fup, *next;
     384 [ -  + ][ -  + ]:         46 :     LIST_FOR_EACH_SAFE (fup, next, list_node, &flow_updates) {
     385                 :          0 :         ovs_list_remove(&fup->list_node);
     386                 :          0 :         free(fup);
     387                 :            :     }
     388                 :            : 
     389                 :         46 :     state = S_UPDATE_FLOWS;
     390                 :         46 : }
     391                 :            : 
     392                 :            : static void
     393                 :          0 : recv_S_CLEAR_FLOWS(const struct ofp_header *oh, enum ofptype type)
     394                 :            : {
     395                 :          0 :     ofctrl_recv(oh, type);
     396                 :          0 : }
     397                 :            : 
     398                 :            : /* S_UPDATE_FLOWS, for maintaining the flow table over time.
     399                 :            :  *
     400                 :            :  * Compare the installed flows to the ones we want.  Send OFPT_FLOW_MOD as
     401                 :            :  * necessary.
     402                 :            :  *
     403                 :            :  * This is a terminal state.  We only transition out of it if the connection
     404                 :            :  * drops. */
     405                 :            : 
     406                 :            : static void
     407                 :       4891 : run_S_UPDATE_FLOWS(void)
     408                 :            : {
     409                 :            :     /* Nothing to do here.
     410                 :            :      *
     411                 :            :      * Being in this state enables ofctrl_put() to work, however. */
     412                 :       4891 : }
     413                 :            : 
     414                 :            : static void
     415                 :       1831 : recv_S_UPDATE_FLOWS(const struct ofp_header *oh, enum ofptype type)
     416                 :            : {
     417 [ +  + ][ +  - ]:       3098 :     if (type == OFPTYPE_BARRIER_REPLY && !ovs_list_is_empty(&flow_updates)) {
     418                 :       1267 :         struct ofctrl_flow_update *fup = ofctrl_flow_update_from_list_node(
     419                 :       1267 :             ovs_list_front(&flow_updates));
     420         [ +  + ]:       1267 :         if (fup->xid == oh->xid) {
     421         [ +  - ]:        802 :             if (fup->nb_cfg >= cur_cfg) {
     422                 :        802 :                 cur_cfg = fup->nb_cfg;
     423                 :            :             }
     424                 :        802 :             ovs_list_remove(&fup->list_node);
     425                 :        802 :             free(fup);
     426                 :            :         }
     427                 :            :     } else {
     428                 :        564 :         ofctrl_recv(oh, type);
     429                 :            :     }
     430                 :       1831 : }
     431                 :            : 
     432                 :            : /* Runs the OpenFlow state machine against 'br_int', which is local to the
     433                 :            :  * hypervisor on which we are running.  Attempts to negotiate a Geneve option
     434                 :            :  * field for class OVN_GENEVE_CLASS, type OVN_GENEVE_TYPE.  If successful,
     435                 :            :  * returns the MFF_* field ID for the option, otherwise returns 0. */
     436                 :            : enum mf_field_id
     437                 :       3167 : ofctrl_run(const struct ovsrec_bridge *br_int)
     438                 :            : {
     439                 :       3167 :     char *target = xasprintf("unix:%s/%s.mgmt", ovs_rundir(), br_int->name);
     440         [ +  + ]:       3167 :     if (strcmp(target, rconn_get_target(swconn))) {
     441         [ +  - ]:         44 :         VLOG_INFO("%s: connecting to switch", target);
     442                 :         44 :         rconn_connect(swconn, target, target);
     443                 :            :     }
     444                 :       3167 :     free(target);
     445                 :            : 
     446                 :       3167 :     rconn_run(swconn);
     447                 :            : 
     448         [ +  + ]:       3167 :     if (!rconn_is_connected(swconn)) {
     449                 :         42 :         return 0;
     450                 :            :     }
     451         [ +  + ]:       3125 :     if (seqno != rconn_get_connection_seqno(swconn)) {
     452                 :         46 :         seqno = rconn_get_connection_seqno(swconn);
     453                 :         46 :         state = S_NEW;
     454                 :            :     }
     455                 :            : 
     456                 :       3125 :     bool progress = true;
     457 [ +  + ][ +  - ]:       8238 :     for (int i = 0; progress && i < 50; i++) {
     458                 :            :         /* Allow the state machine to run. */
     459                 :       5113 :         enum ofctrl_state old_state = state;
     460   [ +  +  +  +  :       5113 :         switch (state) {
                   +  - ]
     461                 :            : #define STATE(NAME) case NAME: run_##NAME(); break;
     462                 :       5113 :             STATES
     463                 :            : #undef STATE
     464                 :            :         default:
     465                 :          0 :             OVS_NOT_REACHED();
     466                 :            :         }
     467                 :            : 
     468                 :            :         /* Try to process a received packet. */
     469                 :       5113 :         struct ofpbuf *msg = rconn_recv(swconn);
     470         [ +  + ]:       5113 :         if (msg) {
     471                 :       1923 :             const struct ofp_header *oh = msg->data;
     472                 :            :             enum ofptype type;
     473                 :            :             enum ofperr error;
     474                 :            : 
     475                 :       1923 :             error = ofptype_decode(&type, oh);
     476         [ +  - ]:       1923 :             if (!error) {
     477   [ -  +  +  -  :       1923 :                 switch (state) {
                   +  - ]
     478                 :            : #define STATE(NAME) case NAME: recv_##NAME(oh, type); break;
     479                 :       1923 :                     STATES
     480                 :            : #undef STATE
     481                 :            :                 default:
     482                 :       1923 :                     OVS_NOT_REACHED();
     483                 :            :                 }
     484                 :            :             } else {
     485                 :          0 :                 char *s = ofp_to_string(oh, ntohs(oh->length), 1);
     486         [ #  # ]:          0 :                 VLOG_WARN("could not decode OpenFlow message (%s): %s",
     487                 :            :                           ofperr_to_string(error), s);
     488                 :          0 :                 free(s);
     489                 :            :             }
     490                 :            : 
     491                 :       1923 :             ofpbuf_delete(msg);
     492                 :            :         }
     493                 :            : 
     494                 :            :         /* If we did some work, plan to go around again. */
     495 [ +  + ][ +  + ]:       5113 :         progress = old_state != state || msg;
     496                 :            :     }
     497         [ -  + ]:       3125 :     if (progress) {
     498                 :            :         /* We bailed out to limit the amount of work we do in one go, to allow
     499                 :            :          * other code a chance to run.  We were still making progress at that
     500                 :            :          * point, so ensure that we come back again without waiting. */
     501                 :          0 :         poll_immediate_wake();
     502                 :            :     }
     503                 :            : 
     504 [ +  - ][ +  + ]:       3125 :     return (state == S_CLEAR_FLOWS || state == S_UPDATE_FLOWS
     505                 :            :             ? mff_ovn_geneve : 0);
     506                 :            : }
     507                 :            : 
     508                 :            : void
     509                 :       3167 : ofctrl_wait(void)
     510                 :            : {
     511                 :       3167 :     rconn_run_wait(swconn);
     512                 :       3167 :     rconn_recv_wait(swconn);
     513                 :       3167 : }
     514                 :            : 
     515                 :            : void
     516                 :         44 : ofctrl_destroy(void)
     517                 :            : {
     518                 :         44 :     rconn_destroy(swconn);
     519                 :         44 :     ovn_flow_table_destroy(&installed_flows);
     520                 :         44 :     rconn_packet_counter_destroy(tx_counter);
     521                 :         44 : }
     522                 :            : 
     523                 :            : int64_t
     524                 :       2670 : ofctrl_get_cur_cfg(void)
     525                 :            : {
     526                 :       2670 :     return cur_cfg;
     527                 :            : }
     528                 :            : 
     529                 :            : static ovs_be32
     530                 :      23031 : queue_msg(struct ofpbuf *msg)
     531                 :            : {
     532                 :      23031 :     const struct ofp_header *oh = msg->data;
     533                 :      23031 :     ovs_be32 xid = oh->xid;
     534                 :      23031 :     rconn_send(swconn, msg, tx_counter);
     535                 :      23031 :     return xid;
     536                 :            : }
     537                 :            : 
     538                 :            : static void
     539                 :        558 : log_openflow_rl(struct vlog_rate_limit *rl, enum vlog_level level,
     540                 :            :                 const struct ofp_header *oh, const char *title)
     541                 :            : {
     542         [ +  - ]:        558 :     if (!vlog_should_drop(&this_module, level, rl)) {
     543                 :        558 :         char *s = ofp_to_string(oh, ntohs(oh->length), 2);
     544                 :        558 :         vlog(&this_module, level, "%s: %s", title, s);
     545                 :        558 :         free(s);
     546                 :            :     }
     547                 :        558 : }
     548                 :            : 
     549                 :            : static void
     550                 :        564 : ofctrl_recv(const struct ofp_header *oh, enum ofptype type)
     551                 :            : {
     552         [ +  + ]:        564 :     if (type == OFPTYPE_ECHO_REQUEST) {
     553                 :          6 :         queue_msg(make_echo_reply(oh));
     554         [ +  - ]:        558 :     } else if (type == OFPTYPE_ERROR) {
     555                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
     556                 :        558 :         log_openflow_rl(&rl, VLL_INFO, oh, "OpenFlow error");
     557 [ #  # ][ #  # ]:          0 :     } else if (type != OFPTYPE_ECHO_REPLY &&
     558         [ #  # ]:          0 :                type != OFPTYPE_BARRIER_REPLY &&
     559         [ #  # ]:          0 :                type != OFPTYPE_PACKET_IN &&
     560         [ #  # ]:          0 :                type != OFPTYPE_PORT_STATUS &&
     561                 :            :                type != OFPTYPE_FLOW_REMOVED) {
     562                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
     563                 :          0 :         log_openflow_rl(&rl, VLL_DBG, oh, "OpenFlow packet ignored");
     564                 :            :     }
     565                 :        564 : }
     566                 :            : 
     567                 :            : /* Flow table interfaces to the rest of ovn-controller. */
     568                 :            : 
     569                 :            : /* Adds a flow to 'desired_flows' with the specified 'match' and 'actions' to
     570                 :            :  * the OpenFlow table numbered 'table_id' with the given 'priority'.  The
     571                 :            :  * caller retains ownership of 'match' and 'actions'.
     572                 :            :  *
     573                 :            :  * This just assembles the desired flow table in memory.  Nothing is actually
     574                 :            :  * sent to the switch until a later call to ofctrl_run().
     575                 :            :  *
     576                 :            :  * The caller should initialize its own hmap to hold the flows. */
     577                 :            : void
     578                 :    1051738 : ofctrl_add_flow(struct hmap *desired_flows,
     579                 :            :                 uint8_t table_id, uint16_t priority,
     580                 :            :                 const struct match *match, const struct ofpbuf *actions)
     581                 :            : {
     582                 :    1051738 :     struct ovn_flow *f = xmalloc(sizeof *f);
     583                 :    1051738 :     f->table_id = table_id;
     584                 :    1051738 :     f->priority = priority;
     585                 :    1051738 :     f->match = *match;
     586                 :    1051738 :     f->ofpacts = xmemdup(actions->data, actions->size);
     587                 :    1051738 :     f->ofpacts_len = actions->size;
     588                 :    1051738 :     f->hmap_node.hash = ovn_flow_hash(f);
     589                 :            : 
     590         [ +  + ]:    1051738 :     if (ovn_flow_lookup(desired_flows, f)) {
     591                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
     592         [ +  + ]:      17337 :         if (!VLOG_DROP_INFO(&rl)) {
     593                 :        118 :             char *s = ovn_flow_to_string(f);
     594         [ +  - ]:        118 :             VLOG_INFO("dropping duplicate flow: %s", s);
     595                 :        118 :             free(s);
     596                 :            :         }
     597                 :            : 
     598                 :      17337 :         ovn_flow_destroy(f);
     599                 :      17337 :         return;
     600                 :            :     }
     601                 :            : 
     602                 :    1034401 :     hmap_insert(desired_flows, &f->hmap_node, f->hmap_node.hash);
     603                 :            : }
     604                 :            : 
     605                 :            : 
     606                 :            : /* ovn_flow. */
     607                 :            : 
     608                 :            : /* Returns a hash of the key in 'f'. */
     609                 :            : static uint32_t
     610                 :    1051738 : ovn_flow_hash(const struct ovn_flow *f)
     611                 :            : {
     612                 :    1051738 :     return hash_2words((f->table_id << 16) | f->priority,
     613                 :            :                        match_hash(&f->match, 0));
     614                 :            : 
     615                 :            : }
     616                 :            : 
     617                 :            : /* Duplicate an ovn_flow structure. */
     618                 :            : struct ovn_flow *
     619                 :          0 : ofctrl_dup_flow(struct ovn_flow *src)
     620                 :            : {
     621                 :          0 :     struct ovn_flow *dst = xmalloc(sizeof *dst);
     622                 :          0 :     dst->table_id = src->table_id;
     623                 :          0 :     dst->priority = src->priority;
     624                 :          0 :     dst->match = src->match;
     625                 :          0 :     dst->ofpacts = xmemdup(src->ofpacts, src->ofpacts_len);
     626                 :          0 :     dst->ofpacts_len = src->ofpacts_len;
     627                 :          0 :     dst->hmap_node.hash = ovn_flow_hash(dst);
     628                 :          0 :     return dst;
     629                 :            : }
     630                 :            : 
     631                 :            : /* Finds and returns an ovn_flow in 'flow_table' whose key is identical to
     632                 :            :  * 'target''s key, or NULL if there is none. */
     633                 :            : static struct ovn_flow *
     634                 :    2052263 : ovn_flow_lookup(struct hmap *flow_table, const struct ovn_flow *target)
     635                 :            : {
     636                 :            :     struct ovn_flow *f;
     637                 :            : 
     638 [ +  + ][ -  + ]:    2052263 :     HMAP_FOR_EACH_WITH_HASH (f, hmap_node, target->hmap_node.hash,
     639                 :            :                              flow_table) {
     640         [ +  - ]:    1012224 :         if (f->table_id == target->table_id
     641         [ +  - ]:    1012224 :             && f->priority == target->priority
     642         [ +  - ]:    1012224 :             && match_equal(&f->match, &target->match)) {
     643                 :    1012224 :             return f;
     644                 :            :         }
     645                 :            :     }
     646                 :    1040039 :     return NULL;
     647                 :            : }
     648                 :            : 
     649                 :            : static char *
     650                 :        118 : ovn_flow_to_string(const struct ovn_flow *f)
     651                 :            : {
     652                 :        118 :     struct ds s = DS_EMPTY_INITIALIZER;
     653                 :        118 :     ds_put_format(&s, "table_id=%"PRIu8", ", f->table_id);
     654                 :        118 :     ds_put_format(&s, "priority=%"PRIu16", ", f->priority);
     655                 :        118 :     match_format(&f->match, &s, OFP_DEFAULT_PRIORITY);
     656                 :        118 :     ds_put_cstr(&s, ", actions=");
     657                 :        118 :     ofpacts_format(f->ofpacts, f->ofpacts_len, &s);
     658                 :        118 :     return ds_steal_cstr(&s);
     659                 :            : }
     660                 :            : 
     661                 :            : static void
     662                 :      21522 : ovn_flow_log(const struct ovn_flow *f, const char *action)
     663                 :            : {
     664         [ -  + ]:      21522 :     if (VLOG_IS_DBG_ENABLED()) {
     665                 :          0 :         char *s = ovn_flow_to_string(f);
     666         [ #  # ]:          0 :         VLOG_DBG("%s flow: %s", action, s);
     667                 :          0 :         free(s);
     668                 :            :     }
     669                 :      21522 : }
     670                 :            : 
     671                 :            : static void
     672                 :    1051738 : ovn_flow_destroy(struct ovn_flow *f)
     673                 :            : {
     674         [ +  - ]:    1051738 :     if (f) {
     675                 :    1051738 :         free(f->ofpacts);
     676                 :    1051738 :         free(f);
     677                 :            :     }
     678                 :    1051738 : }
     679                 :            : 
     680                 :            : /* Flow tables of struct ovn_flow. */
     681                 :            : 
     682                 :            : static void
     683                 :        246 : ovn_flow_table_clear(struct hmap *flow_table)
     684                 :            : {
     685                 :            :     struct ovn_flow *f, *next;
     686 [ +  + ][ -  + ]:      34122 :     HMAP_FOR_EACH_SAFE (f, next, hmap_node, flow_table) {
                 [ +  + ]
     687                 :      33876 :         hmap_remove(flow_table, &f->hmap_node);
     688                 :      33876 :         ovn_flow_destroy(f);
     689                 :            :     }
     690                 :        246 : }
     691                 :            : 
     692                 :            : static void
     693                 :         44 : ovn_flow_table_destroy(struct hmap *flow_table)
     694                 :            : {
     695                 :         44 :     ovn_flow_table_clear(flow_table);
     696                 :         44 :     hmap_destroy(flow_table);
     697                 :         44 : }
     698                 :            : 
     699                 :            : /* Flow table update. */
     700                 :            : 
     701                 :            : static struct ofpbuf *
     702                 :      21568 : encode_flow_mod(struct ofputil_flow_mod *fm)
     703                 :            : {
     704                 :      21568 :     fm->buffer_id = UINT32_MAX;
     705                 :      21568 :     fm->out_port = OFPP_ANY;
     706                 :      21568 :     fm->out_group = OFPG_ANY;
     707                 :      21568 :     return ofputil_encode_flow_mod(fm, OFPUTIL_P_OF13_OXM);
     708                 :            : }
     709                 :            : 
     710                 :            : static void
     711                 :      21522 : add_flow_mod(struct ofputil_flow_mod *fm, struct ovs_list *msgs)
     712                 :            : {
     713                 :      21522 :     struct ofpbuf *msg = encode_flow_mod(fm);
     714                 :      21522 :     ovs_list_push_back(msgs, &msg->list_node);
     715                 :      21522 : }
     716                 :            : 
     717                 :            : /* group_table. */
     718                 :            : 
     719                 :            : /* Finds and returns a group_info in 'existing_groups' whose key is identical
     720                 :            :  * to 'target''s key, or NULL if there is none. */
     721                 :            : static struct group_info *
     722                 :        135 : ovn_group_lookup(struct hmap *exisiting_groups,
     723                 :            :                  const struct group_info *target)
     724                 :            : {
     725                 :            :     struct group_info *e;
     726                 :            : 
     727 [ +  + ][ -  + ]:        135 :     HMAP_FOR_EACH_WITH_HASH(e, hmap_node, target->hmap_node.hash,
     728                 :            :                             exisiting_groups) {
     729         [ +  - ]:        123 :         if (e->group_id == target->group_id) {
     730                 :        123 :             return e;
     731                 :            :         }
     732                 :            :    }
     733                 :         12 :     return NULL;
     734                 :            : }
     735                 :            : 
     736                 :            : /* Clear either desired_groups or existing_groups in group_table. */
     737                 :            : void
     738                 :        202 : ovn_group_table_clear(struct group_table *group_table, bool existing)
     739                 :            : {
     740                 :            :     struct group_info *g, *next;
     741                 :        202 :     struct hmap *target_group = existing
     742                 :            :                                 ? &group_table->existing_groups
     743         [ +  + ]:        202 :                                 : &group_table->desired_groups;
     744                 :            : 
     745 [ +  - ][ -  + ]:        202 :     HMAP_FOR_EACH_SAFE (g, next, hmap_node, target_group) {
                 [ -  + ]
     746                 :          0 :         hmap_remove(target_group, &g->hmap_node);
     747                 :            :         /* Don't unset bitmap for desired group_info if the group_id
     748                 :            :          * was not freshly reserved. */
     749 [ #  # ][ #  # ]:          0 :         if (existing || g->new_group_id) {
     750                 :          0 :             bitmap_set0(group_table->group_ids, g->group_id);
     751                 :            :         }
     752                 :          0 :         ds_destroy(&g->group);
     753                 :          0 :         free(g);
     754                 :            :     }
     755                 :        202 : }
     756                 :            : 
     757                 :            : static struct ofpbuf *
     758                 :         52 : encode_group_mod(const struct ofputil_group_mod *gm)
     759                 :            : {
     760                 :         52 :     return ofputil_encode_group_mod(OFP13_VERSION, gm);
     761                 :            : }
     762                 :            : 
     763                 :            : static void
     764                 :          6 : add_group_mod(const struct ofputil_group_mod *gm, struct ovs_list *msgs)
     765                 :            : {
     766                 :          6 :     struct ofpbuf *msg = encode_group_mod(gm);
     767                 :          6 :     ovs_list_push_back(msgs, &msg->list_node);
     768                 :          6 : }
     769                 :            : 
     770                 :            : 
     771                 :            : /* Replaces the flow table on the switch, if possible, by the flows added
     772                 :            :  * with ofctrl_add_flow().
     773                 :            :  *
     774                 :            :  * Replaces the group table on the switch, if possible, by the contents of
     775                 :            :  * 'groups->desired_groups'.  Regardless of whether the group table
     776                 :            :  * is updated, this deletes all the groups from the
     777                 :            :  * 'groups->desired_groups' and frees them. (The hmap itself isn't
     778                 :            :  * destroyed.)
     779                 :            :  *
     780                 :            :  * This should be called after ofctrl_run() within the main loop. */
     781                 :            : void
     782                 :       3167 : ofctrl_put(struct hmap *flow_table, int64_t nb_cfg)
     783                 :            : {
     784                 :            :     /* The flow table can be updated if the connection to the switch is up and
     785                 :            :      * in the correct state and not backlogged with existing flow_mods.  (Our
     786                 :            :      * criteria for being backlogged appear very conservative, but the socket
     787                 :            :      * between ovn-controller and OVS provides some buffering.) */
     788         [ +  + ]:       3167 :     if (state != S_UPDATE_FLOWS
     789         [ +  + ]:       3080 :         || rconn_packet_counter_n_packets(tx_counter)) {
     790                 :        156 :         ovn_flow_table_clear(flow_table);
     791                 :        156 :         ovn_group_table_clear(groups, false);
     792                 :        156 :         return;
     793                 :            :     }
     794                 :            : 
     795                 :            :     /* OpenFlow messages to send to the switch to bring it up-to-date. */
     796                 :       3011 :     struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
     797                 :            : 
     798                 :            :     /* Iterate through all the desired groups. If there are new ones,
     799                 :            :      * add them to the switch. */
     800                 :            :     struct group_info *desired;
     801 [ +  + ][ -  + ]:       3058 :     HMAP_FOR_EACH(desired, hmap_node, &groups->desired_groups) {
     802         [ +  + ]:         47 :         if (!ovn_group_lookup(&groups->existing_groups, desired)) {
     803                 :            :             /* Create and install new group. */
     804                 :            :             struct ofputil_group_mod gm;
     805                 :            :             enum ofputil_protocol usable_protocols;
     806                 :            :             char *error;
     807                 :          6 :             struct ds group_string = DS_EMPTY_INITIALIZER;
     808                 :          6 :             ds_put_format(&group_string, "group_id=%u,%s",
     809                 :            :                           desired->group_id, ds_cstr(&desired->group));
     810                 :            : 
     811                 :          6 :             error = parse_ofp_group_mod_str(&gm, OFPGC11_ADD,
     812                 :          6 :                                             ds_cstr(&group_string),
     813                 :            :                                             &usable_protocols);
     814         [ +  - ]:          6 :             if (!error) {
     815                 :          6 :                 add_group_mod(&gm, &msgs);
     816                 :            :             } else {
     817                 :            :                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
     818         [ #  # ]:          0 :                 VLOG_ERR_RL(&rl, "new group %s %s", error,
     819                 :            :                          ds_cstr(&group_string));
     820                 :          0 :                 free(error);
     821                 :            :             }
     822                 :          6 :             ds_destroy(&group_string);
     823                 :          6 :             ofputil_uninit_group_mod(&gm);
     824                 :            :         }
     825                 :            :     }
     826                 :            : 
     827                 :            :     /* Iterate through all of the installed flows.  If any of them are no
     828                 :            :      * longer desired, delete them; if any of them should have different
     829                 :            :      * actions, update them. */
     830                 :            :     struct ovn_flow *i, *next;
     831 [ +  + ][ -  + ]:    1003536 :     HMAP_FOR_EACH_SAFE (i, next, hmap_node, &installed_flows) {
                 [ +  + ]
     832                 :    1000525 :         struct ovn_flow *d = ovn_flow_lookup(flow_table, i);
     833         [ +  + ]:    1000525 :         if (!d) {
     834                 :            :             /* Installed flow is no longer desirable.  Delete it from the
     835                 :            :              * switch and from installed_flows. */
     836                 :      16914 :             struct ofputil_flow_mod fm = {
     837                 :            :                 .match = i->match,
     838                 :       5638 :                 .priority = i->priority,
     839                 :       5638 :                 .table_id = i->table_id,
     840                 :            :                 .command = OFPFC_DELETE_STRICT,
     841                 :            :             };
     842                 :       5638 :             add_flow_mod(&fm, &msgs);
     843                 :       5638 :             ovn_flow_log(i, "removing installed");
     844                 :            : 
     845                 :       5638 :             hmap_remove(&installed_flows, &i->hmap_node);
     846                 :       5638 :             ovn_flow_destroy(i);
     847                 :            :         } else {
     848         [ +  + ]:     994887 :             if (!ofpacts_equal(i->ofpacts, i->ofpacts_len,
     849                 :     994887 :                                d->ofpacts, d->ofpacts_len)) {
     850                 :            :                 /* Update actions in installed flow. */
     851                 :       1690 :                 struct ofputil_flow_mod fm = {
     852                 :            :                     .match = i->match,
     853                 :        338 :                     .priority = i->priority,
     854                 :        338 :                     .table_id = i->table_id,
     855                 :        338 :                     .ofpacts = d->ofpacts,
     856                 :        338 :                     .ofpacts_len = d->ofpacts_len,
     857                 :            :                     .command = OFPFC_MODIFY_STRICT,
     858                 :            :                 };
     859                 :        338 :                 add_flow_mod(&fm, &msgs);
     860                 :        338 :                 ovn_flow_log(i, "updating installed");
     861                 :            : 
     862                 :            :                 /* Replace 'i''s actions by 'd''s. */
     863                 :        338 :                 free(i->ofpacts);
     864                 :        338 :                 i->ofpacts = d->ofpacts;
     865                 :        338 :                 i->ofpacts_len = d->ofpacts_len;
     866                 :        338 :                 d->ofpacts = NULL;
     867                 :        338 :                 d->ofpacts_len = 0;
     868                 :            :             }
     869                 :            : 
     870                 :     994887 :             hmap_remove(flow_table, &d->hmap_node);
     871                 :     994887 :             ovn_flow_destroy(d);
     872                 :            :         }
     873                 :            :     }
     874                 :            : 
     875                 :            :     /* The previous loop removed from 'flow_table' all of the flows that are
     876                 :            :      * already installed.  Thus, any flows remaining in 'flow_table' need to
     877                 :            :      * be added to the flow table. */
     878                 :            :     struct ovn_flow *d;
     879 [ +  + ][ -  + ]:      18557 :     HMAP_FOR_EACH_SAFE (d, next, hmap_node, flow_table) {
                 [ +  + ]
     880                 :            :         /* Send flow_mod to add flow. */
     881                 :      77730 :         struct ofputil_flow_mod fm = {
     882                 :            :             .match = d->match,
     883                 :      15546 :             .priority = d->priority,
     884                 :      15546 :             .table_id = d->table_id,
     885                 :      15546 :             .ofpacts = d->ofpacts,
     886                 :      15546 :             .ofpacts_len = d->ofpacts_len,
     887                 :            :             .command = OFPFC_ADD,
     888                 :            :         };
     889                 :      15546 :         add_flow_mod(&fm, &msgs);
     890                 :      15546 :         ovn_flow_log(d, "adding installed");
     891                 :            : 
     892                 :            :         /* Move 'd' from 'flow_table' to installed_flows. */
     893                 :      15546 :         hmap_remove(flow_table, &d->hmap_node);
     894                 :      15546 :         hmap_insert(&installed_flows, &d->hmap_node, d->hmap_node.hash);
     895                 :            :     }
     896                 :            : 
     897                 :            :     /* Iterate through the installed groups from previous runs. If they
     898                 :            :      * are not needed delete them. */
     899                 :            :     struct group_info *installed, *next_group;
     900 [ +  + ][ -  + ]:       3052 :     HMAP_FOR_EACH_SAFE(installed, next_group, hmap_node,
                 [ +  + ]
     901                 :            :                        &groups->existing_groups) {
     902         [ -  + ]:         41 :         if (!ovn_group_lookup(&groups->desired_groups, installed)) {
     903                 :            :             /* Delete the group. */
     904                 :            :             struct ofputil_group_mod gm;
     905                 :            :             enum ofputil_protocol usable_protocols;
     906                 :            :             char *error;
     907                 :          0 :             struct ds group_string = DS_EMPTY_INITIALIZER;
     908                 :          0 :             ds_put_format(&group_string, "group_id=%u", installed->group_id);
     909                 :            : 
     910                 :          0 :             error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE,
     911                 :          0 :                                             ds_cstr(&group_string),
     912                 :            :                                             &usable_protocols);
     913         [ #  # ]:          0 :             if (!error) {
     914                 :          0 :                 add_group_mod(&gm, &msgs);
     915                 :            :             } else {
     916                 :            :                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
     917         [ #  # ]:          0 :                 VLOG_ERR_RL(&rl, "Error deleting group %d: %s",
     918                 :            :                          installed->group_id, error);
     919                 :          0 :                 free(error);
     920                 :            :             }
     921                 :          0 :             ds_destroy(&group_string);
     922                 :          0 :             ofputil_uninit_group_mod(&gm);
     923                 :            : 
     924                 :            :             /* Remove 'installed' from 'groups->existing_groups' */
     925                 :          0 :             hmap_remove(&groups->existing_groups, &installed->hmap_node);
     926                 :          0 :             ds_destroy(&installed->group);
     927                 :            : 
     928                 :            :             /* Dealloc group_id. */
     929                 :          0 :             bitmap_set0(groups->group_ids, installed->group_id);
     930                 :          0 :             free(installed);
     931                 :            :         }
     932                 :            :     }
     933                 :            : 
     934                 :            :     /* Move the contents of desired_groups to existing_groups. */
     935 [ +  + ][ -  + ]:       3058 :     HMAP_FOR_EACH_SAFE(desired, next_group, hmap_node,
                 [ +  + ]
     936                 :            :                        &groups->desired_groups) {
     937                 :         47 :         hmap_remove(&groups->desired_groups, &desired->hmap_node);
     938         [ +  + ]:         47 :         if (!ovn_group_lookup(&groups->existing_groups, desired)) {
     939                 :          6 :             hmap_insert(&groups->existing_groups, &desired->hmap_node,
     940                 :            :                         desired->hmap_node.hash);
     941                 :            :         } else {
     942                 :         41 :            ds_destroy(&desired->group);
     943                 :         41 :            free(desired);
     944                 :            :         }
     945                 :            :     }
     946                 :            : 
     947         [ +  + ]:       3011 :     if (!ovs_list_is_empty(&msgs)) {
     948                 :            :         /* Add a barrier to the list of messages. */
     949                 :       1267 :         struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP13_VERSION);
     950                 :       1267 :         const struct ofp_header *oh = barrier->data;
     951                 :       1267 :         ovs_be32 xid = oh->xid;
     952                 :       1267 :         ovs_list_push_back(&msgs, &barrier->list_node);
     953                 :            : 
     954                 :            :         /* Queue the messages. */
     955                 :            :         struct ofpbuf *msg;
     956         [ +  + ]:      24062 :         LIST_FOR_EACH_POP (msg, list_node, &msgs) {
     957                 :      22795 :             queue_msg(msg);
     958                 :            :         }
     959                 :            : 
     960                 :            :         /* Track the flow update. */
     961                 :            :         struct ofctrl_flow_update *fup, *prev;
     962 [ +  + ][ +  + ]:       1267 :         LIST_FOR_EACH_REVERSE_SAFE (fup, prev, list_node, &flow_updates) {
     963         [ -  + ]:        465 :             if (nb_cfg < fup->nb_cfg) {
     964                 :            :                 /* This ofctrl_flow_update is for a configuration later than
     965                 :            :                  * 'nb_cfg'.  This should not normally happen, because it means
     966                 :            :                  * that 'nb_cfg' in the SB_Global table of the southbound
     967                 :            :                  * database decreased, and it should normally be monotonically
     968                 :            :                  * increasing. */
     969         [ #  # ]:          0 :                 VLOG_WARN("nb_cfg regressed from %"PRId64" to %"PRId64,
     970                 :            :                           fup->nb_cfg, nb_cfg);
     971                 :          0 :                 ovs_list_remove(&fup->list_node);
     972                 :          0 :                 free(fup);
     973         [ +  - ]:        465 :             } else if (nb_cfg == fup->nb_cfg) {
     974                 :            :                 /* This ofctrl_flow_update is for the same configuration as
     975                 :            :                  * 'nb_cfg'.  Probably, some change to the physical topology
     976                 :            :                  * means that we had to revise the OpenFlow flow table even
     977                 :            :                  * though the logical topology did not change.  Update fp->xid,
     978                 :            :                  * so that we don't send a notification that we're up-to-date
     979                 :            :                  * until we're really caught up. */
     980         [ -  + ]:        465 :                 VLOG_DBG("advanced xid target for nb_cfg=%"PRId64, nb_cfg);
     981                 :        465 :                 fup->xid = xid;
     982                 :        465 :                 goto done;
     983                 :            :             } else {
     984                 :          0 :                 break;
     985                 :            :             }
     986                 :            :         }
     987                 :            : 
     988                 :            :         /* Add a flow update. */
     989                 :        802 :         fup = xmalloc(sizeof *fup);
     990                 :        802 :         ovs_list_push_back(&flow_updates, &fup->list_node);
     991                 :        802 :         fup->xid = xid;
     992                 :       1267 :         fup->nb_cfg = nb_cfg;
     993                 :            :     done:;
     994         [ +  + ]:       1744 :     } else if (!ovs_list_is_empty(&flow_updates)) {
     995                 :            :         /* Getting up-to-date with 'nb_cfg' didn't require any extra flow table
     996                 :            :          * changes, so whenever we get up-to-date with the most recent flow
     997                 :            :          * table update, we're also up-to-date with 'nb_cfg'. */
     998                 :        373 :         struct ofctrl_flow_update *fup = ofctrl_flow_update_from_list_node(
     999                 :        373 :             ovs_list_back(&flow_updates));
    1000                 :        373 :         fup->nb_cfg = nb_cfg;
    1001                 :            :     } else {
    1002                 :            :         /* We were completely up-to-date before and still are. */
    1003                 :       3011 :         cur_cfg = nb_cfg;
    1004                 :            :     }
    1005                 :            : }

Generated by: LCOV version 1.12