LCOV - code coverage report
Current view: top level - lib - bundle.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 112 124 90.3 %
Date: 2016-09-14 01:02:56 Functions: 9 9 100.0 %
Branches: 60 76 78.9 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2011, 2012, 2013, 2014, 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                 :            : 
      18                 :            : #include "bundle.h"
      19                 :            : 
      20                 :            : #include <arpa/inet.h>
      21                 :            : #include <inttypes.h>
      22                 :            : 
      23                 :            : #include "colors.h"
      24                 :            : #include "multipath.h"
      25                 :            : #include "nx-match.h"
      26                 :            : #include "openflow/nicira-ext.h"
      27                 :            : #include "openvswitch/dynamic-string.h"
      28                 :            : #include "openvswitch/meta-flow.h"
      29                 :            : #include "openvswitch/ofp-actions.h"
      30                 :            : #include "openvswitch/ofp-errors.h"
      31                 :            : #include "openvswitch/ofp-util.h"
      32                 :            : #include "openvswitch/ofpbuf.h"
      33                 :            : #include "openvswitch/vlog.h"
      34                 :            : #include "util.h"
      35                 :            : 
      36                 :      20190 : VLOG_DEFINE_THIS_MODULE(bundle);
      37                 :            : 
      38                 :            : static ofp_port_t
      39                 :    3250000 : execute_ab(const struct ofpact_bundle *bundle,
      40                 :            :            bool (*slave_enabled)(ofp_port_t ofp_port, void *aux), void *aux)
      41                 :            : {
      42                 :            :     size_t i;
      43                 :            : 
      44         [ +  + ]:    6400000 :     for (i = 0; i < bundle->n_slaves; i++) {
      45                 :    6350000 :         ofp_port_t slave = bundle->slaves[i];
      46         [ +  + ]:    6350000 :         if (slave_enabled(slave, aux)) {
      47                 :    3200000 :             return slave;
      48                 :            :         }
      49                 :            :     }
      50                 :            : 
      51                 :      50000 :     return OFPP_NONE;
      52                 :            : }
      53                 :            : 
      54                 :            : static ofp_port_t
      55                 :    1900004 : execute_hrw(const struct ofpact_bundle *bundle,
      56                 :            :             const struct flow *flow, struct flow_wildcards *wc,
      57                 :            :             bool (*slave_enabled)(ofp_port_t ofp_port, void *aux), void *aux)
      58                 :            : {
      59                 :            :     uint32_t flow_hash, best_hash;
      60                 :            :     int best, i;
      61                 :            : 
      62         [ +  + ]:    1900004 :     if (bundle->n_slaves > 1) {
      63                 :    1650004 :         flow_mask_hash_fields(flow, wc, bundle->fields);
      64                 :            :     }
      65                 :            : 
      66                 :    1900004 :     flow_hash = flow_hash_fields(flow, bundle->fields, bundle->basis);
      67                 :    1900004 :     best = -1;
      68                 :    1900004 :     best_hash = 0;
      69                 :            : 
      70         [ +  + ]:   10300012 :     for (i = 0; i < bundle->n_slaves; i++) {
      71         [ +  + ]:    8400008 :         if (slave_enabled(bundle->slaves[i], aux)) {
      72                 :    4150000 :             uint32_t hash = hash_2words(i, flow_hash);
      73                 :            : 
      74 [ +  + ][ +  + ]:    4150000 :             if (best < 0 || hash > best_hash) {
      75                 :    2698369 :                 best_hash = hash;
      76                 :    2698369 :                 best = i;
      77                 :            :             }
      78                 :            :         }
      79                 :            :     }
      80                 :            : 
      81         [ +  + ]:    1900004 :     return best >= 0 ? bundle->slaves[best] : OFPP_NONE;
      82                 :            : }
      83                 :            : 
      84                 :            : /* Executes 'bundle' on 'flow'.  Sets fields in 'wc' that were used to
      85                 :            :  * calculate the result.  Uses 'slave_enabled' to determine if the slave
      86                 :            :  * designated by 'ofp_port' is up.  Returns the chosen slave, or
      87                 :            :  * OFPP_NONE if none of the slaves are acceptable. */
      88                 :            : ofp_port_t
      89                 :    5150004 : bundle_execute(const struct ofpact_bundle *bundle,
      90                 :            :                const struct flow *flow, struct flow_wildcards *wc,
      91                 :            :                bool (*slave_enabled)(ofp_port_t ofp_port, void *aux),
      92                 :            :                void *aux)
      93                 :            : {
      94      [ +  +  - ]:    5150004 :     switch (bundle->algorithm) {
      95                 :            :     case NX_BD_ALG_HRW:
      96                 :    1900004 :         return execute_hrw(bundle, flow, wc, slave_enabled, aux);
      97                 :            : 
      98                 :            :     case NX_BD_ALG_ACTIVE_BACKUP:
      99                 :    3250000 :         return execute_ab(bundle, slave_enabled, aux);
     100                 :            : 
     101                 :            :     default:
     102                 :          0 :         OVS_NOT_REACHED();
     103                 :            :     }
     104                 :            : }
     105                 :            : 
     106                 :            : enum ofperr
     107                 :         45 : bundle_check(const struct ofpact_bundle *bundle, ofp_port_t max_ports,
     108                 :            :              const struct flow *flow)
     109                 :            : {
     110                 :            :     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     111                 :            :     size_t i;
     112                 :            : 
     113         [ +  + ]:         45 :     if (bundle->dst.field) {
     114                 :         24 :         enum ofperr error = mf_check_dst(&bundle->dst, flow);
     115         [ -  + ]:         24 :         if (error) {
     116                 :          0 :             return error;
     117                 :            :         }
     118                 :            :     }
     119                 :            : 
     120         [ +  + ]:        377 :     for (i = 0; i < bundle->n_slaves; i++) {
     121                 :        332 :         ofp_port_t ofp_port = bundle->slaves[i];
     122                 :            : 
     123         [ +  - ]:        332 :         if (ofp_port != OFPP_NONE) {
     124                 :        332 :             enum ofperr error = ofpact_check_output_port(ofp_port, max_ports);
     125         [ -  + ]:        332 :             if (error) {
     126         [ #  # ]:          0 :                 VLOG_WARN_RL(&rl, "invalid slave %"PRIu16, ofp_port);
     127                 :          0 :                 return error;
     128                 :            :             }
     129                 :            :         }
     130                 :            :         /* Controller slaves are unsupported due to the lack of a max_len
     131                 :            :          * argument. This may or may not change in the future.  There doesn't
     132                 :            :          * seem to be a real-world use-case for supporting it. */
     133         [ -  + ]:        332 :         if (ofp_port == OFPP_CONTROLLER) {
     134         [ #  # ]:          0 :             VLOG_WARN_RL(&rl, "unsupported controller slave");
     135                 :          0 :             return OFPERR_OFPBAC_BAD_OUT_PORT;
     136                 :            :         }
     137                 :            :     }
     138                 :            : 
     139                 :         45 :     return 0;
     140                 :            : }
     141                 :            : 
     142                 :            : 
     143                 :            : /* Helper for bundle_parse and bundle_parse_load.
     144                 :            :  *
     145                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     146                 :            :  * error.  The caller is responsible for freeing the returned string.*/
     147                 :            : static char * OVS_WARN_UNUSED_RESULT
     148                 :         20 : bundle_parse__(const char *s, char **save_ptr,
     149                 :            :                const char *fields, const char *basis, const char *algorithm,
     150                 :            :                const char *slave_type, const char *dst,
     151                 :            :                const char *slave_delim, struct ofpbuf *ofpacts)
     152                 :            : {
     153                 :            :     struct ofpact_bundle *bundle;
     154                 :            : 
     155         [ +  + ]:         20 :     if (!slave_delim) {
     156                 :          1 :         return xasprintf("%s: not enough arguments to bundle action", s);
     157                 :            :     }
     158                 :            : 
     159         [ +  + ]:         19 :     if (strcasecmp(slave_delim, "slaves")) {
     160                 :          1 :         return xasprintf("%s: missing slave delimiter, expected `slaves' "
     161                 :            :                          "got `%s'", s, slave_delim);
     162                 :            :     }
     163                 :            : 
     164                 :         18 :     bundle = ofpact_put_BUNDLE(ofpacts);
     165                 :            : 
     166                 :            :     for (;;) {
     167                 :            :         ofp_port_t slave_port;
     168                 :            :         char *slave;
     169                 :            : 
     170                 :         88 :         slave = strtok_r(NULL, ", []", save_ptr);
     171 [ +  + ][ +  - ]:         88 :         if (!slave || bundle->n_slaves >= BUNDLE_MAX_SLAVES) {
     172                 :            :             break;
     173                 :            :         }
     174                 :            : 
     175         [ -  + ]:         70 :         if (!ofputil_port_from_string(slave, &slave_port)) {
     176                 :          0 :             return xasprintf("%s: bad port number", slave);
     177                 :            :         }
     178                 :         70 :         ofpbuf_put(ofpacts, &slave_port, sizeof slave_port);
     179                 :            : 
     180                 :         70 :         bundle = ofpacts->header;
     181                 :         70 :         bundle->n_slaves++;
     182                 :         70 :     }
     183                 :         18 :     ofpact_finish_BUNDLE(ofpacts, &bundle);
     184                 :         18 :     bundle->basis = atoi(basis);
     185                 :            : 
     186         [ +  + ]:         18 :     if (!strcasecmp(fields, "eth_src")) {
     187                 :          5 :         bundle->fields = NX_HASH_FIELDS_ETH_SRC;
     188         [ +  + ]:         13 :     } else if (!strcasecmp(fields, "symmetric_l4")) {
     189                 :         12 :         bundle->fields = NX_HASH_FIELDS_SYMMETRIC_L4;
     190         [ -  + ]:          1 :     } else if (!strcasecmp(fields, "symmetric_l3l4")) {
     191                 :          0 :         bundle->fields = NX_HASH_FIELDS_SYMMETRIC_L3L4;
     192         [ -  + ]:          1 :     } else if (!strcasecmp(fields, "symmetric_l3l4+udp")) {
     193                 :          0 :         bundle->fields = NX_HASH_FIELDS_SYMMETRIC_L3L4_UDP;
     194                 :            :     } else {
     195                 :          1 :         return xasprintf("%s: unknown fields `%s'", s, fields);
     196                 :            :     }
     197                 :            : 
     198         [ +  + ]:         17 :     if (!strcasecmp(algorithm, "active_backup")) {
     199                 :          3 :         bundle->algorithm = NX_BD_ALG_ACTIVE_BACKUP;
     200         [ +  + ]:         14 :     } else if (!strcasecmp(algorithm, "hrw")) {
     201                 :         13 :         bundle->algorithm = NX_BD_ALG_HRW;
     202                 :            :     } else {
     203                 :          1 :         return xasprintf("%s: unknown algorithm `%s'", s, algorithm);
     204                 :            :     }
     205                 :            : 
     206         [ +  + ]:         16 :     if (strcasecmp(slave_type, "ofport")) {
     207                 :          1 :         return xasprintf("%s: unknown slave_type `%s'", s, slave_type);
     208                 :            :     }
     209                 :            : 
     210         [ +  + ]:         15 :     if (dst) {
     211                 :         10 :         char *error = mf_parse_subfield(&bundle->dst, dst);
     212         [ -  + ]:         10 :         if (error) {
     213                 :          0 :             return error;
     214                 :            :         }
     215                 :            : 
     216         [ -  + ]:         10 :         if (!mf_nxm_header(bundle->dst.field->id)) {
     217                 :          0 :             return xasprintf("%s: experimenter OXM field '%s' not supported",
     218                 :            :                              s, dst);
     219                 :            :         }
     220                 :            :     }
     221                 :            : 
     222                 :         20 :     return NULL;
     223                 :            : }
     224                 :            : 
     225                 :            : /* Converts a bundle action string contained in 's' to an nx_action_bundle and
     226                 :            :  * stores it in 'b'.  Sets 'b''s l2 pointer to NULL.
     227                 :            :  *
     228                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     229                 :            :  * error.  The caller is responsible for freeing the returned string. */
     230                 :            : char * OVS_WARN_UNUSED_RESULT
     231                 :         10 : bundle_parse(const char *s, struct ofpbuf *ofpacts)
     232                 :            : {
     233                 :            :     char *fields, *basis, *algorithm, *slave_type, *slave_delim;
     234                 :            :     char *tokstr, *save_ptr;
     235                 :            :     char *error;
     236                 :            : 
     237                 :         10 :     save_ptr = NULL;
     238                 :         10 :     tokstr = xstrdup(s);
     239                 :         10 :     fields = strtok_r(tokstr, ", ", &save_ptr);
     240                 :         10 :     basis = strtok_r(NULL, ", ", &save_ptr);
     241                 :         10 :     algorithm = strtok_r(NULL, ", ", &save_ptr);
     242                 :         10 :     slave_type = strtok_r(NULL, ", ", &save_ptr);
     243                 :         10 :     slave_delim = strtok_r(NULL, ": ", &save_ptr);
     244                 :            : 
     245                 :         10 :     error = bundle_parse__(s, &save_ptr, fields, basis, algorithm, slave_type,
     246                 :            :                            NULL, slave_delim, ofpacts);
     247                 :         10 :     free(tokstr);
     248                 :            : 
     249                 :         10 :     return error;
     250                 :            : }
     251                 :            : 
     252                 :            : /* Converts a bundle_load action string contained in 's' to an nx_action_bundle
     253                 :            :  * and stores it in 'b'.  Sets 'b''s l2 pointer to NULL.
     254                 :            :  *
     255                 :            :  * Returns NULL if successful, otherwise a malloc()'d string describing the
     256                 :            :  * error.  The caller is responsible for freeing the returned string.*/
     257                 :            : char * OVS_WARN_UNUSED_RESULT
     258                 :         10 : bundle_parse_load(const char *s, struct ofpbuf *ofpacts)
     259                 :            : {
     260                 :            :     char *fields, *basis, *algorithm, *slave_type, *dst, *slave_delim;
     261                 :            :     char *tokstr, *save_ptr;
     262                 :            :     char *error;
     263                 :            : 
     264                 :         10 :     save_ptr = NULL;
     265                 :         10 :     tokstr = xstrdup(s);
     266                 :         10 :     fields = strtok_r(tokstr, ", ", &save_ptr);
     267                 :         10 :     basis = strtok_r(NULL, ", ", &save_ptr);
     268                 :         10 :     algorithm = strtok_r(NULL, ", ", &save_ptr);
     269                 :         10 :     slave_type = strtok_r(NULL, ", ", &save_ptr);
     270                 :         10 :     dst = strtok_r(NULL, ", ", &save_ptr);
     271                 :         10 :     slave_delim = strtok_r(NULL, ": ", &save_ptr);
     272                 :            : 
     273                 :         10 :     error = bundle_parse__(s, &save_ptr, fields, basis, algorithm, slave_type,
     274                 :            :                            dst, slave_delim, ofpacts);
     275                 :            : 
     276                 :         10 :     free(tokstr);
     277                 :            : 
     278                 :         10 :     return error;
     279                 :            : }
     280                 :            : 
     281                 :            : /* Appends a human-readable representation of 'nab' to 's'. */
     282                 :            : void
     283                 :         19 : bundle_format(const struct ofpact_bundle *bundle, struct ds *s)
     284                 :            : {
     285                 :            :     const char *action, *fields, *algorithm;
     286                 :            :     size_t i;
     287                 :            : 
     288                 :         19 :     fields = flow_hash_fields_to_str(bundle->fields);
     289                 :            : 
     290      [ +  +  - ]:         19 :     switch (bundle->algorithm) {
     291                 :            :     case NX_BD_ALG_HRW:
     292                 :         17 :         algorithm = "hrw";
     293                 :         17 :         break;
     294                 :            :     case NX_BD_ALG_ACTIVE_BACKUP:
     295                 :          2 :         algorithm = "active_backup";
     296                 :          2 :         break;
     297                 :            :     default:
     298                 :          0 :         algorithm = "<unknown>";
     299                 :            :     }
     300                 :            : 
     301         [ +  + ]:         19 :     action = bundle->dst.field ? "bundle_load" : "bundle";
     302                 :            : 
     303                 :         19 :     ds_put_format(s, "%s%s(%s%s,%"PRIu16",%s,%s,", colors.paren, action,
     304                 :         19 :                   colors.end, fields, bundle->basis, algorithm, "ofport");
     305                 :            : 
     306         [ +  + ]:         19 :     if (bundle->dst.field) {
     307                 :         10 :         mf_format_subfield(&bundle->dst, s);
     308                 :         10 :         ds_put_char(s, ',');
     309                 :            :     }
     310                 :            : 
     311                 :         19 :     ds_put_format(s, "%sslaves:%s", colors.param, colors.end);
     312         [ +  + ]:        163 :     for (i = 0; i < bundle->n_slaves; i++) {
     313         [ +  + ]:        144 :         if (i) {
     314                 :        127 :             ds_put_char(s, ',');
     315                 :            :         }
     316                 :            : 
     317                 :        144 :         ofputil_format_port(bundle->slaves[i], s);
     318                 :            :     }
     319                 :            : 
     320                 :         19 :     ds_put_format(s, "%s)%s", colors.paren, colors.end);
     321                 :         19 : }

Generated by: LCOV version 1.12