LCOV - code coverage report
Current view: top level - ovn/controller-vtep - binding.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 89 90 98.9 %
Date: 2016-09-14 01:02:56 Functions: 6 6 100.0 %
Branches: 64 74 86.5 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2015 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                 :            : 
      19                 :            : #include "openvswitch/shash.h"
      20                 :            : #include "lib/smap.h"
      21                 :            : #include "lib/util.h"
      22                 :            : #include "openvswitch/vlog.h"
      23                 :            : #include "ovn-controller-vtep.h"
      24                 :            : #include "ovn/lib/ovn-sb-idl.h"
      25                 :            : #include "vtep/vtep-idl.h"
      26                 :            : 
      27                 :         14 : VLOG_DEFINE_THIS_MODULE(binding);
      28                 :            : 
      29                 :            : /*
      30                 :            :  * This module scans through the Port_Binding table in ovnsb.  If there is a
      31                 :            :  * logical port binding entry for logical switch in vtep gateway chassis's
      32                 :            :  * 'vtep_logical_switches' column, sets the binding's chassis column to the
      33                 :            :  * corresponding vtep gateway chassis.
      34                 :            :  *
      35                 :            :  */
      36                 :            : 
      37                 :            : 
      38                 :            : /* Returns true if the 'vtep_lswitch' specified in 'port_binding_rec'
      39                 :            :  * has already been bound to another port binding entry, and resets
      40                 :            :  * 'port_binding_rec''s chassis column.  Otherwise, updates 'ls_to_pb'
      41                 :            :  * and returns false. */
      42                 :            : static bool
      43                 :        172 : check_pb_conflict(struct shash *ls_to_pb,
      44                 :            :                   const struct sbrec_port_binding *port_binding_rec,
      45                 :            :                   const char *chassis_name,
      46                 :            :                   const char *vtep_lswitch)
      47                 :            : {
      48                 :        172 :     const struct sbrec_port_binding *pb_conflict =
      49                 :            :         shash_find_data(ls_to_pb, vtep_lswitch);
      50                 :            : 
      51         [ +  + ]:        172 :     if (pb_conflict) {
      52         [ +  - ]:          5 :         VLOG_WARN("logical switch (%s), on vtep gateway chassis "
      53                 :            :                   "(%s) has already been associated with logical "
      54                 :            :                   "port (%s), ignore logical port (%s)",
      55                 :            :                   vtep_lswitch, chassis_name,
      56                 :            :                   pb_conflict->logical_port,
      57                 :            :                   port_binding_rec->logical_port);
      58                 :          5 :         sbrec_port_binding_set_chassis(port_binding_rec, NULL);
      59                 :            : 
      60                 :          5 :         return true;
      61                 :            :     }
      62                 :            : 
      63                 :        167 :     shash_add(ls_to_pb, vtep_lswitch, port_binding_rec);
      64                 :        167 :     return false;
      65                 :            : }
      66                 :            : 
      67                 :            : /* Returns true if the 'vtep_lswitch' specified in 'port_binding_rec'
      68                 :            :  * has already been bound to a different datapath, and resets
      69                 :            :  * 'port_binding_rec''s chassis column.  Otherwise, updates 'ls_to_db' and
      70                 :            :  * returns false. */
      71                 :            : static bool
      72                 :        172 : check_db_conflict(struct shash *ls_to_db,
      73                 :            :                   const struct sbrec_port_binding *port_binding_rec,
      74                 :            :                   const char *chassis_name,
      75                 :            :                   const char *vtep_lswitch)
      76                 :            : {
      77                 :        172 :     const struct sbrec_datapath_binding *db_conflict =
      78                 :            :         shash_find_data(ls_to_db, vtep_lswitch);
      79                 :            : 
      80 [ +  + ][ +  + ]:        172 :     if (db_conflict && db_conflict != port_binding_rec->datapath) {
      81         [ +  - ]:          2 :         VLOG_WARN("logical switch (%s), on vtep gateway chassis "
      82                 :            :                   "(%s) has already been associated with logical "
      83                 :            :                   "datapath (with tunnel key %"PRId64"), ignore "
      84                 :            :                   "logical port (%s) which belongs to logical "
      85                 :            :                   "datapath (with tunnel key %"PRId64")",
      86                 :            :                   vtep_lswitch, chassis_name,
      87                 :            :                   db_conflict->tunnel_key,
      88                 :            :                   port_binding_rec->logical_port,
      89                 :            :                   port_binding_rec->datapath->tunnel_key);
      90                 :          2 :         sbrec_port_binding_set_chassis(port_binding_rec, NULL);
      91                 :            : 
      92                 :          2 :         return true;
      93                 :            :     }
      94                 :            : 
      95                 :        170 :     shash_replace(ls_to_db, vtep_lswitch, port_binding_rec->datapath);
      96                 :        170 :     return false;
      97                 :            : }
      98                 :            : 
      99                 :            : /* Updates the 'port_binding_rec''s chassis column to 'chassis_rec'. */
     100                 :            : static void
     101                 :        174 : update_pb_chassis(const struct sbrec_port_binding *port_binding_rec,
     102                 :            :                   const struct sbrec_chassis *chassis_rec)
     103                 :            : {
     104         [ +  + ]:        174 :     if (port_binding_rec->chassis != chassis_rec) {
     105 [ +  + ][ -  + ]:         19 :         if (chassis_rec && port_binding_rec->chassis) {
     106         [ #  # ]:          0 :             VLOG_DBG("Changing chassis association of logical "
     107                 :            :                      "port (%s) from (%s) to (%s)",
     108                 :            :                      port_binding_rec->logical_port,
     109                 :            :                      port_binding_rec->chassis->name,
     110                 :            :                      chassis_rec->name);
     111                 :            :         }
     112                 :         19 :         sbrec_port_binding_set_chassis(port_binding_rec, chassis_rec);
     113                 :            :     }
     114                 :        174 : }
     115                 :            : 
     116                 :            : 
     117                 :            : /* Checks and updates logical port to vtep logical switch bindings for each
     118                 :            :  * physical switch in VTEP. */
     119                 :            : void
     120                 :        269 : binding_run(struct controller_vtep_ctx *ctx)
     121                 :            : {
     122         [ +  + ]:        269 :     if (!ctx->ovnsb_idl_txn) {
     123                 :         45 :         return;
     124                 :            :     }
     125                 :            : 
     126                 :            :     /* 'ls_to_db'
     127                 :            :      *
     128                 :            :      * Maps vtep logical switch name to the datapath binding entry.  This is
     129                 :            :      * used to guarantee that each vtep logical switch is only included
     130                 :            :      * in only one ovn datapath (ovn logical switch).  See check_db_conflict()
     131                 :            :      * for details.
     132                 :            :      *
     133                 :            :      * 'ls_to_pb'
     134                 :            :      *
     135                 :            :      * Maps vtep logical switch name to the port binding entry.  This is used
     136                 :            :      * to guarantee that each vtep logical switch on a vtep physical switch
     137                 :            :      * is only bound to one logical port.  See check_pb_conflict() for
     138                 :            :      * details.
     139                 :            :      *
     140                 :            :      */
     141                 :        224 :     struct shash ls_to_db = SHASH_INITIALIZER(&ls_to_db);
     142                 :            : 
     143                 :            :     /* Stores the 'chassis' and the 'ls_to_pb' map related to
     144                 :            :      * a vtep physcial switch. */
     145                 :            :     struct ps {
     146                 :            :         const struct sbrec_chassis *chassis_rec;
     147                 :            :         struct shash ls_to_pb;
     148                 :            :     };
     149                 :        224 :     struct shash ps_map = SHASH_INITIALIZER(&ps_map);
     150                 :            :     const struct vteprec_physical_switch *pswitch;
     151         [ +  + ]:        462 :     VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch, ctx->vtep_idl) {
     152                 :        238 :         const struct sbrec_chassis *chassis_rec
     153                 :        238 :             = get_chassis_by_name(ctx->ovnsb_idl, pswitch->name);
     154                 :        238 :         struct ps *ps = xmalloc(sizeof *ps);
     155                 :            :         size_t i;
     156                 :            : 
     157                 :            :         /* 'chassis_rec' must exist. */
     158         [ -  + ]:        238 :         ovs_assert(chassis_rec);
     159                 :        238 :         ps->chassis_rec = chassis_rec;
     160                 :        238 :         shash_init(&ps->ls_to_pb);
     161         [ +  + ]:        468 :         for (i = 0; i < chassis_rec->n_vtep_logical_switches; i++) {
     162                 :        230 :             shash_add(&ps->ls_to_pb, chassis_rec->vtep_logical_switches[i],
     163                 :            :                       NULL);
     164                 :            :         }
     165                 :        238 :         shash_add(&ps_map, chassis_rec->name, ps);
     166                 :            :     }
     167                 :            : 
     168                 :        224 :     ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn,
     169                 :            :                               "ovn-controller-vtep: updating bindings");
     170                 :            : 
     171                 :            :     const struct sbrec_port_binding *port_binding_rec;
     172                 :            :     /* Port binding for vtep gateway chassis must have type "vtep",
     173                 :            :      * and matched physical switch name and logical switch name. */
     174         [ +  + ]:        647 :     SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->ovnsb_idl) {
     175                 :        423 :         const char *type = port_binding_rec->type;
     176                 :        423 :         const char *vtep_pswitch = smap_get(&port_binding_rec->options,
     177                 :            :                                             "vtep-physical-switch");
     178                 :        423 :         const char *vtep_lswitch = smap_get(&port_binding_rec->options,
     179                 :            :                                             "vtep-logical-switch");
     180                 :        423 :         struct ps *ps
     181         [ +  + ]:        423 :             = vtep_pswitch ? shash_find_data(&ps_map, vtep_pswitch) : NULL;
     182                 :        423 :         bool found_ls
     183 [ +  + ][ +  - ]:        423 :             = ps && vtep_lswitch && shash_find(&ps->ls_to_pb, vtep_lswitch);
                 [ +  + ]
     184                 :            : 
     185 [ +  + ][ +  + ]:        595 :         if (!strcmp(type, "vtep") && found_ls) {
     186                 :            :             bool pb_conflict, db_conflict;
     187                 :            : 
     188                 :        172 :             pb_conflict = check_pb_conflict(&ps->ls_to_pb, port_binding_rec,
     189                 :        172 :                                             ps->chassis_rec->name,
     190                 :            :                                             vtep_lswitch);
     191                 :        172 :             db_conflict = check_db_conflict(&ls_to_db, port_binding_rec,
     192                 :        172 :                                             ps->chassis_rec->name,
     193                 :            :                                             vtep_lswitch);
     194                 :            :             /* Updates port binding's chassis column when there
     195                 :            :              * is no conflict. */
     196 [ +  + ][ +  + ]:        172 :             if (!pb_conflict && !db_conflict) {
     197                 :        165 :                 update_pb_chassis(port_binding_rec, ps->chassis_rec);
     198                 :            :             }
     199         [ +  + ]:        251 :         } else if (port_binding_rec->chassis
     200         [ +  + ]:        163 :                    && shash_find(&ps_map, port_binding_rec->chassis->name)) {
     201                 :            :             /* Resets 'port_binding_rec' since it is no longer bound to
     202                 :            :              * any vtep logical switch. */
     203                 :          4 :             update_pb_chassis(port_binding_rec, NULL);
     204                 :            :         }
     205                 :            :     }
     206                 :            : 
     207                 :            :     struct shash_node *iter, *next;
     208 [ +  + ][ -  + ]:        462 :     SHASH_FOR_EACH_SAFE (iter, next, &ps_map) {
                 [ +  + ]
     209                 :        238 :         struct ps *ps = iter->data;
     210                 :            :         struct shash_node *node;
     211                 :            : 
     212 [ +  + ][ -  + ]:        635 :         SHASH_FOR_EACH (node, &ps->ls_to_pb) {
     213         [ +  + ]:        397 :             if (!node->data) {
     214                 :            :                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     215         [ -  + ]:        230 :                 VLOG_DBG_RL(&rl, "No port binding entry for logical switch (%s)"
     216                 :            :                             "on vtep gateway chassis (%s)", node->name,
     217                 :            :                             ps->chassis_rec->name);
     218                 :            :             }
     219                 :            :         }
     220                 :        238 :         shash_delete(&ps_map, iter);
     221                 :        238 :         shash_destroy(&ps->ls_to_pb);
     222                 :        238 :         free(ps);
     223                 :            :     }
     224                 :        224 :     shash_destroy(&ls_to_db);
     225                 :        224 :     shash_destroy(&ps_map);
     226                 :            : }
     227                 :            : 
     228                 :            : /* Removes all port binding association with vtep gateway chassis.
     229                 :            :  * Returns true when done (i.e. there is no change made to 'ctx->ovnsb_idl'),
     230                 :            :  * otherwise returns false. */
     231                 :            : bool
     232                 :         27 : binding_cleanup(struct controller_vtep_ctx *ctx)
     233                 :            : {
     234         [ +  + ]:         27 :     if (!ctx->ovnsb_idl_txn) {
     235                 :         13 :         return false;
     236                 :            :     }
     237                 :            : 
     238                 :         14 :     struct shash ch_to_pb = SHASH_INITIALIZER(&ch_to_pb);
     239                 :            :     const struct sbrec_port_binding *port_binding_rec;
     240                 :         14 :     bool all_done = true;
     241                 :            :     /* Hashs all port binding entries using the associated chassis name. */
     242         [ +  + ]:         46 :     SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->ovnsb_idl) {
     243         [ +  + ]:         32 :         if (port_binding_rec->chassis) {
     244                 :         13 :             shash_add(&ch_to_pb, port_binding_rec->chassis->name,
     245                 :            :                       port_binding_rec);
     246                 :            :         }
     247                 :            :     }
     248                 :            : 
     249                 :         14 :     ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn,
     250                 :            :                               "ovn-controller-vtep: removing bindings");
     251                 :            : 
     252                 :            :     const struct vteprec_physical_switch *pswitch;
     253         [ +  + ]:         28 :     VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch, ctx->vtep_idl) {
     254                 :         14 :         const struct sbrec_chassis *chassis_rec
     255                 :         14 :             = get_chassis_by_name(ctx->ovnsb_idl, pswitch->name);
     256                 :            : 
     257         [ +  + ]:         14 :         if (!chassis_rec) {
     258                 :          7 :             continue;
     259                 :            :         }
     260                 :            : 
     261                 :            :         for (;;) {
     262                 :         12 :             port_binding_rec = shash_find_and_delete(&ch_to_pb,
     263                 :         12 :                                                      chassis_rec->name);
     264         [ +  + ]:         12 :             if (!port_binding_rec) {
     265                 :          7 :                 break;
     266                 :            :             }
     267                 :          5 :             all_done = false;
     268                 :          5 :             update_pb_chassis(port_binding_rec, NULL);
     269                 :          5 :         }
     270                 :            :     }
     271                 :         14 :     shash_destroy(&ch_to_pb);
     272                 :            : 
     273                 :         27 :     return all_done;
     274                 :            : }

Generated by: LCOV version 1.12