LCOV - code coverage report
Current view: top level - ofproto - bond.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 516 753 68.5 %
Date: 2016-09-14 01:02:56 Functions: 51 62 82.3 %
Branches: 299 505 59.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : 
      19                 :            : #include "bond.h"
      20                 :            : 
      21                 :            : #include <limits.h>
      22                 :            : #include <stdint.h>
      23                 :            : #include <stdlib.h>
      24                 :            : #include <math.h>
      25                 :            : 
      26                 :            : #include "connectivity.h"
      27                 :            : #include "coverage.h"
      28                 :            : #include "dp-packet.h"
      29                 :            : #include "flow.h"
      30                 :            : #include "openvswitch/hmap.h"
      31                 :            : #include "lacp.h"
      32                 :            : #include "netdev.h"
      33                 :            : #include "odp-util.h"
      34                 :            : #include "ofproto/ofproto-dpif.h"
      35                 :            : #include "ofproto/ofproto-dpif-rid.h"
      36                 :            : #include "ofproto/ofproto-provider.h"
      37                 :            : #include "openvswitch/dynamic-string.h"
      38                 :            : #include "openvswitch/list.h"
      39                 :            : #include "openvswitch/match.h"
      40                 :            : #include "openvswitch/ofp-actions.h"
      41                 :            : #include "openvswitch/ofp-util.h"
      42                 :            : #include "openvswitch/ofpbuf.h"
      43                 :            : #include "openvswitch/vlog.h"
      44                 :            : #include "packets.h"
      45                 :            : #include "poll-loop.h"
      46                 :            : #include "seq.h"
      47                 :            : #include "openvswitch/shash.h"
      48                 :            : #include "timeval.h"
      49                 :            : #include "unixctl.h"
      50                 :            : #include "util.h"
      51                 :            : 
      52                 :       1288 : VLOG_DEFINE_THIS_MODULE(bond);
      53                 :            : 
      54                 :            : static struct ovs_rwlock rwlock = OVS_RWLOCK_INITIALIZER;
      55                 :            : static struct hmap all_bonds__ = HMAP_INITIALIZER(&all_bonds__);
      56                 :            : static struct hmap *const all_bonds OVS_GUARDED_BY(rwlock) = &all_bonds__;
      57                 :            : 
      58                 :            : /* Bit-mask for hashing a flow down to a bucket. */
      59                 :            : #define BOND_MASK 0xff
      60                 :            : #define BOND_BUCKETS (BOND_MASK + 1)
      61                 :            : 
      62                 :            : /* A hash bucket for mapping a flow to a slave.
      63                 :            :  * "struct bond" has an array of BOND_BUCKETS of these. */
      64                 :            : struct bond_entry {
      65                 :            :     struct bond_slave *slave;   /* Assigned slave, NULL if unassigned. */
      66                 :            :     uint64_t tx_bytes           /* Count of bytes recently transmitted. */
      67                 :            :         OVS_GUARDED_BY(rwlock);
      68                 :            :     struct ovs_list list_node;  /* In bond_slave's 'entries' list. */
      69                 :            : 
      70                 :            :     /* Recirculation.
      71                 :            :      *
      72                 :            :      * 'pr_rule' is the post-recirculation rule for this entry.
      73                 :            :      * 'pr_tx_bytes' is the most recently seen statistics for 'pr_rule', which
      74                 :            :      * is used to determine delta (applied to 'tx_bytes' above.) */
      75                 :            :     struct rule *pr_rule;
      76                 :            :     uint64_t pr_tx_bytes OVS_GUARDED_BY(rwlock);
      77                 :            : };
      78                 :            : 
      79                 :            : /* A bond slave, that is, one of the links comprising a bond. */
      80                 :            : struct bond_slave {
      81                 :            :     struct hmap_node hmap_node; /* In struct bond's slaves hmap. */
      82                 :            :     struct ovs_list list_node;  /* In struct bond's enabled_slaves list. */
      83                 :            :     struct bond *bond;          /* The bond that contains this slave. */
      84                 :            :     void *aux;                  /* Client-provided handle for this slave. */
      85                 :            : 
      86                 :            :     struct netdev *netdev;      /* Network device, owned by the client. */
      87                 :            :     uint64_t change_seq;        /* Tracks changes in 'netdev'. */
      88                 :            :     ofp_port_t  ofp_port;       /* OpenFlow port number. */
      89                 :            :     char *name;                 /* Name (a copy of netdev_get_name(netdev)). */
      90                 :            : 
      91                 :            :     /* Link status. */
      92                 :            :     long long delay_expires;    /* Time after which 'enabled' may change. */
      93                 :            :     bool enabled;               /* May be chosen for flows? */
      94                 :            :     bool may_enable;            /* Client considers this slave bondable. */
      95                 :            : 
      96                 :            :     /* Rebalancing info.  Used only by bond_rebalance(). */
      97                 :            :     struct ovs_list bal_node;   /* In bond_rebalance()'s 'bals' list. */
      98                 :            :     struct ovs_list entries;    /* 'struct bond_entry's assigned here. */
      99                 :            :     uint64_t tx_bytes;          /* Sum across 'tx_bytes' of entries. */
     100                 :            : };
     101                 :            : 
     102                 :            : /* A bond, that is, a set of network devices grouped to improve performance or
     103                 :            :  * robustness.  */
     104                 :            : struct bond {
     105                 :            :     struct hmap_node hmap_node; /* In 'all_bonds' hmap. */
     106                 :            :     char *name;                 /* Name provided by client. */
     107                 :            :     struct ofproto_dpif *ofproto; /* The bridge this bond belongs to. */
     108                 :            : 
     109                 :            :     /* Slaves. */
     110                 :            :     struct hmap slaves;
     111                 :            : 
     112                 :            :     /* Enabled slaves.
     113                 :            :      *
     114                 :            :      * Any reader or writer of 'enabled_slaves' must hold 'mutex'.
     115                 :            :      * (To prevent the bond_slave from disappearing they must also hold
     116                 :            :      * 'rwlock'.) */
     117                 :            :     struct ovs_mutex mutex OVS_ACQ_AFTER(rwlock);
     118                 :            :     struct ovs_list enabled_slaves OVS_GUARDED; /* Contains struct bond_slaves. */
     119                 :            : 
     120                 :            :     /* Bonding info. */
     121                 :            :     enum bond_mode balance;     /* Balancing mode, one of BM_*. */
     122                 :            :     struct bond_slave *active_slave;
     123                 :            :     int updelay, downdelay;     /* Delay before slave goes up/down, in ms. */
     124                 :            :     enum lacp_status lacp_status; /* Status of LACP negotiations. */
     125                 :            :     bool bond_revalidate;       /* True if flows need revalidation. */
     126                 :            :     uint32_t basis;             /* Basis for flow hash function. */
     127                 :            : 
     128                 :            :     /* SLB specific bonding info. */
     129                 :            :     struct bond_entry *hash;     /* An array of BOND_BUCKETS elements. */
     130                 :            :     int rebalance_interval;      /* Interval between rebalances, in ms. */
     131                 :            :     long long int next_rebalance; /* Next rebalancing time. */
     132                 :            :     bool send_learning_packets;
     133                 :            :     uint32_t recirc_id;          /* Non zero if recirculation can be used.*/
     134                 :            :     struct hmap pr_rule_ops;     /* Helps to maintain post recirculation rules.*/
     135                 :            : 
     136                 :            :     /* Store active slave to OVSDB. */
     137                 :            :     bool active_slave_changed; /* Set to true whenever the bond changes
     138                 :            :                                    active slave. It will be reset to false
     139                 :            :                                    after it is stored into OVSDB */
     140                 :            : 
     141                 :            :     /* Interface name may not be persistent across an OS reboot, use
     142                 :            :      * MAC address for identifing the active slave */
     143                 :            :     struct eth_addr active_slave_mac;
     144                 :            :                                /* The MAC address of the active interface. */
     145                 :            :     /* Legacy compatibility. */
     146                 :            :     bool lacp_fallback_ab; /* Fallback to active-backup on LACP failure. */
     147                 :            : 
     148                 :            :     struct ovs_refcount ref_cnt;
     149                 :            : };
     150                 :            : 
     151                 :            : /* What to do with an bond_recirc_rule. */
     152                 :            : enum bond_op {
     153                 :            :     ADD,        /* Add the rule to ofproto's flow table. */
     154                 :            :     DEL,        /* Delete the rule from the ofproto's flow table. */
     155                 :            : };
     156                 :            : 
     157                 :            : /* A rule to add to or delete from ofproto's internal flow table. */
     158                 :            : struct bond_pr_rule_op {
     159                 :            :     struct hmap_node hmap_node;
     160                 :            :     struct match match;
     161                 :            :     ofp_port_t out_ofport;
     162                 :            :     enum bond_op op;
     163                 :            :     struct rule **pr_rule;
     164                 :            : };
     165                 :            : 
     166                 :            : static void bond_entry_reset(struct bond *) OVS_REQ_WRLOCK(rwlock);
     167                 :            : static struct bond_slave *bond_slave_lookup(struct bond *, const void *slave_)
     168                 :            :     OVS_REQ_RDLOCK(rwlock);
     169                 :            : static void bond_enable_slave(struct bond_slave *, bool enable)
     170                 :            :     OVS_REQ_WRLOCK(rwlock);
     171                 :            : static void bond_link_status_update(struct bond_slave *)
     172                 :            :     OVS_REQ_WRLOCK(rwlock);
     173                 :            : static void bond_choose_active_slave(struct bond *)
     174                 :            :     OVS_REQ_WRLOCK(rwlock);
     175                 :            : static unsigned int bond_hash_src(const struct eth_addr mac,
     176                 :            :                                   uint16_t vlan, uint32_t basis);
     177                 :            : static unsigned int bond_hash_tcp(const struct flow *, uint16_t vlan,
     178                 :            :                                   uint32_t basis);
     179                 :            : static struct bond_entry *lookup_bond_entry(const struct bond *,
     180                 :            :                                             const struct flow *,
     181                 :            :                                             uint16_t vlan)
     182                 :            :     OVS_REQ_RDLOCK(rwlock);
     183                 :            : static struct bond_slave *get_enabled_slave(struct bond *)
     184                 :            :     OVS_REQ_RDLOCK(rwlock);
     185                 :            : static struct bond_slave *choose_output_slave(const struct bond *,
     186                 :            :                                               const struct flow *,
     187                 :            :                                               struct flow_wildcards *,
     188                 :            :                                               uint16_t vlan)
     189                 :            :     OVS_REQ_RDLOCK(rwlock);
     190                 :            : 
     191                 :            : /* Attempts to parse 's' as the name of a bond balancing mode.  If successful,
     192                 :            :  * stores the mode in '*balance' and returns true.  Otherwise returns false
     193                 :            :  * without modifying '*balance'. */
     194                 :            : bool
     195                 :         32 : bond_mode_from_string(enum bond_mode *balance, const char *s)
     196                 :            : {
     197         [ +  + ]:         32 :     if (!strcmp(s, bond_mode_to_string(BM_TCP))) {
     198                 :         16 :         *balance = BM_TCP;
     199         [ +  + ]:         16 :     } else if (!strcmp(s, bond_mode_to_string(BM_SLB))) {
     200                 :          2 :         *balance = BM_SLB;
     201         [ +  - ]:         14 :     } else if (!strcmp(s, bond_mode_to_string(BM_AB))) {
     202                 :         14 :         *balance = BM_AB;
     203                 :            :     } else {
     204                 :          0 :         return false;
     205                 :            :     }
     206                 :         32 :     return true;
     207                 :            : }
     208                 :            : 
     209                 :            : /* Returns a string representing 'balance'. */
     210                 :            : const char *
     211                 :         80 : bond_mode_to_string(enum bond_mode balance) {
     212   [ +  +  +  - ]:         80 :     switch (balance) {
     213                 :            :     case BM_TCP:
     214                 :         44 :         return "balance-tcp";
     215                 :            :     case BM_SLB:
     216                 :         16 :         return "balance-slb";
     217                 :            :     case BM_AB:
     218                 :         20 :         return "active-backup";
     219                 :            :     }
     220                 :          0 :     OVS_NOT_REACHED();
     221                 :            : }
     222                 :            : 
     223                 :            : 
     224                 :            : /* Creates and returns a new bond whose configuration is initially taken from
     225                 :            :  * 's'.
     226                 :            :  *
     227                 :            :  * The caller should register each slave on the new bond by calling
     228                 :            :  * bond_slave_register().  */
     229                 :            : struct bond *
     230                 :         19 : bond_create(const struct bond_settings *s, struct ofproto_dpif *ofproto)
     231                 :            : {
     232                 :            :     struct bond *bond;
     233                 :            : 
     234                 :         19 :     bond = xzalloc(sizeof *bond);
     235                 :         19 :     bond->ofproto = ofproto;
     236                 :         19 :     hmap_init(&bond->slaves);
     237                 :         19 :     ovs_list_init(&bond->enabled_slaves);
     238                 :         19 :     ovs_mutex_init(&bond->mutex);
     239                 :         19 :     ovs_refcount_init(&bond->ref_cnt);
     240                 :         19 :     hmap_init(&bond->pr_rule_ops);
     241                 :            : 
     242                 :         19 :     bond_reconfigure(bond, s);
     243                 :         19 :     return bond;
     244                 :            : }
     245                 :            : 
     246                 :            : struct bond *
     247                 :       6747 : bond_ref(const struct bond *bond_)
     248                 :            : {
     249                 :       6747 :     struct bond *bond = CONST_CAST(struct bond *, bond_);
     250                 :            : 
     251         [ +  - ]:       6747 :     if (bond) {
     252                 :       6747 :         ovs_refcount_ref(&bond->ref_cnt);
     253                 :            :     }
     254                 :       6747 :     return bond;
     255                 :            : }
     256                 :            : 
     257                 :            : /* Frees 'bond'. */
     258                 :            : void
     259                 :     234905 : bond_unref(struct bond *bond)
     260                 :            : {
     261                 :            :     struct bond_pr_rule_op *pr_op;
     262                 :            :     struct bond_slave *slave;
     263                 :            : 
     264 [ +  + ][ +  + ]:     234905 :     if (!bond || ovs_refcount_unref_relaxed(&bond->ref_cnt) != 1) {
     265                 :     234887 :         return;
     266                 :            :     }
     267                 :            : 
     268                 :         18 :     ovs_rwlock_wrlock(&rwlock);
     269                 :         18 :     hmap_remove(all_bonds, &bond->hmap_node);
     270                 :         18 :     ovs_rwlock_unlock(&rwlock);
     271                 :            : 
     272 [ +  - ][ -  + ]:         18 :     HMAP_FOR_EACH_POP (slave, hmap_node, &bond->slaves) {
                 [ -  + ]
     273                 :            :         /* Client owns 'slave->netdev'. */
     274                 :          0 :         free(slave->name);
     275                 :          0 :         free(slave);
     276                 :            :     }
     277                 :         18 :     hmap_destroy(&bond->slaves);
     278                 :            : 
     279                 :         18 :     ovs_mutex_destroy(&bond->mutex);
     280                 :         18 :     free(bond->hash);
     281                 :         18 :     free(bond->name);
     282                 :            : 
     283 [ +  + ][ -  + ]:       1298 :     HMAP_FOR_EACH_POP (pr_op, hmap_node, &bond->pr_rule_ops) {
                 [ +  + ]
     284                 :       1280 :         free(pr_op);
     285                 :            :     }
     286                 :         18 :     hmap_destroy(&bond->pr_rule_ops);
     287                 :            : 
     288         [ +  + ]:         18 :     if (bond->recirc_id) {
     289                 :         11 :         recirc_free_id(bond->recirc_id);
     290                 :            :     }
     291                 :            : 
     292                 :         18 :     free(bond);
     293                 :            : }
     294                 :            : 
     295                 :            : static void
     296                 :       1792 : add_pr_rule(struct bond *bond, const struct match *match,
     297                 :            :             ofp_port_t out_ofport, struct rule **rule)
     298                 :            : {
     299                 :       1792 :     uint32_t hash = match_hash(match, 0);
     300                 :            :     struct bond_pr_rule_op *pr_op;
     301                 :            : 
     302 [ -  + ][ -  + ]:       1792 :     HMAP_FOR_EACH_WITH_HASH(pr_op, hmap_node, hash, &bond->pr_rule_ops) {
     303         [ #  # ]:          0 :         if (match_equal(&pr_op->match, match)) {
     304                 :          0 :             pr_op->op = ADD;
     305                 :          0 :             pr_op->out_ofport = out_ofport;
     306                 :          0 :             pr_op->pr_rule = rule;
     307                 :          0 :             return;
     308                 :            :         }
     309                 :            :     }
     310                 :            : 
     311                 :       1792 :     pr_op = xmalloc(sizeof *pr_op);
     312                 :       1792 :     pr_op->match = *match;
     313                 :       1792 :     pr_op->op = ADD;
     314                 :       1792 :     pr_op->out_ofport = out_ofport;
     315                 :       1792 :     pr_op->pr_rule = rule;
     316                 :       1792 :     hmap_insert(&bond->pr_rule_ops, &pr_op->hmap_node, hash);
     317                 :            : }
     318                 :            : 
     319                 :            : static void
     320                 :         31 : update_recirc_rules(struct bond *bond)
     321                 :            :     OVS_REQ_WRLOCK(rwlock)
     322                 :            : {
     323                 :            :     struct match match;
     324                 :            :     struct bond_pr_rule_op *pr_op, *next_op;
     325                 :            :     uint64_t ofpacts_stub[128 / 8];
     326                 :            :     struct ofpbuf ofpacts;
     327                 :            :     int i;
     328                 :            : 
     329                 :         31 :     ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
     330                 :            : 
     331 [ +  + ][ -  + ]:        543 :     HMAP_FOR_EACH(pr_op, hmap_node, &bond->pr_rule_ops) {
     332                 :        512 :         pr_op->op = DEL;
     333                 :            :     }
     334                 :            : 
     335 [ +  - ][ +  - ]:         31 :     if (bond->hash && bond->recirc_id) {
     336         [ +  + ]:       7967 :         for (i = 0; i < BOND_BUCKETS; i++) {
     337                 :       7936 :             struct bond_slave *slave = bond->hash[i].slave;
     338                 :            : 
     339         [ +  + ]:       7936 :             if (slave) {
     340                 :       1792 :                 match_init_catchall(&match);
     341                 :       1792 :                 match_set_recirc_id(&match, bond->recirc_id);
     342                 :       1792 :                 match_set_dp_hash_masked(&match, i, BOND_MASK);
     343                 :            : 
     344                 :       1792 :                 add_pr_rule(bond, &match, slave->ofp_port,
     345                 :       1792 :                             &bond->hash[i].pr_rule);
     346                 :            :             }
     347                 :            :         }
     348                 :            :     }
     349                 :            : 
     350 [ +  + ][ -  + ]:       2335 :     HMAP_FOR_EACH_SAFE(pr_op, next_op, hmap_node, &bond->pr_rule_ops) {
                 [ +  + ]
     351                 :            :         int error;
     352      [ +  +  - ]:       2304 :         switch (pr_op->op) {
     353                 :            :         case ADD:
     354                 :       1792 :             ofpbuf_clear(&ofpacts);
     355                 :       1792 :             ofpact_put_OUTPUT(&ofpacts)->port = pr_op->out_ofport;
     356                 :       1792 :             error = ofproto_dpif_add_internal_flow(bond->ofproto,
     357                 :       1792 :                                                    &pr_op->match,
     358                 :            :                                                    RECIRC_RULE_PRIORITY, 0,
     359                 :            :                                                    &ofpacts, pr_op->pr_rule);
     360         [ -  + ]:       1792 :             if (error) {
     361                 :          0 :                 char *err_s = match_to_string(&pr_op->match,
     362                 :            :                                               RECIRC_RULE_PRIORITY);
     363                 :            : 
     364         [ #  # ]:          0 :                 VLOG_ERR("failed to add post recirculation flow %s", err_s);
     365                 :          0 :                 free(err_s);
     366                 :            :             }
     367                 :       1792 :             break;
     368                 :            : 
     369                 :            :         case DEL:
     370                 :        512 :             error = ofproto_dpif_delete_internal_flow(bond->ofproto,
     371                 :            :                                                       &pr_op->match,
     372                 :            :                                                       RECIRC_RULE_PRIORITY);
     373         [ -  + ]:        512 :             if (error) {
     374                 :          0 :                 char *err_s = match_to_string(&pr_op->match,
     375                 :            :                                               RECIRC_RULE_PRIORITY);
     376                 :            : 
     377         [ #  # ]:          0 :                 VLOG_ERR("failed to remove post recirculation flow %s", err_s);
     378                 :          0 :                 free(err_s);
     379                 :            :             }
     380                 :            : 
     381                 :        512 :             hmap_remove(&bond->pr_rule_ops, &pr_op->hmap_node);
     382                 :        512 :             *pr_op->pr_rule = NULL;
     383                 :        512 :             free(pr_op);
     384                 :        512 :             break;
     385                 :            :         }
     386                 :            :     }
     387                 :            : 
     388                 :         31 :     ofpbuf_uninit(&ofpacts);
     389                 :         31 : }
     390                 :            : 
     391                 :            : 
     392                 :            : /* Updates 'bond''s overall configuration to 's'.
     393                 :            :  *
     394                 :            :  * The caller should register each slave on 'bond' by calling
     395                 :            :  * bond_slave_register().  This is optional if none of the slaves'
     396                 :            :  * configuration has changed.  In any case it can't hurt.
     397                 :            :  *
     398                 :            :  * Returns true if the configuration has changed in such a way that requires
     399                 :            :  * flow revalidation.
     400                 :            :  * */
     401                 :            : bool
     402                 :         32 : bond_reconfigure(struct bond *bond, const struct bond_settings *s)
     403                 :            : {
     404                 :         32 :     bool revalidate = false;
     405                 :            : 
     406                 :         32 :     ovs_rwlock_wrlock(&rwlock);
     407 [ +  + ][ -  + ]:         32 :     if (!bond->name || strcmp(bond->name, s->name)) {
     408         [ -  + ]:         19 :         if (bond->name) {
     409                 :          0 :             hmap_remove(all_bonds, &bond->hmap_node);
     410                 :          0 :             free(bond->name);
     411                 :            :         }
     412                 :         19 :         bond->name = xstrdup(s->name);
     413                 :         19 :         hmap_insert(all_bonds, &bond->hmap_node, hash_string(bond->name, 0));
     414                 :            :     }
     415                 :            : 
     416                 :         32 :     bond->updelay = s->up_delay;
     417                 :         32 :     bond->downdelay = s->down_delay;
     418                 :            : 
     419         [ -  + ]:         32 :     if (bond->lacp_fallback_ab != s->lacp_fallback_ab_cfg) {
     420                 :          0 :         bond->lacp_fallback_ab = s->lacp_fallback_ab_cfg;
     421                 :          0 :         revalidate = true;
     422                 :            :     }
     423                 :            : 
     424         [ +  + ]:         32 :     if (bond->rebalance_interval != s->rebalance_interval) {
     425                 :         11 :         bond->rebalance_interval = s->rebalance_interval;
     426                 :         11 :         revalidate = true;
     427                 :            :     }
     428                 :            : 
     429         [ +  + ]:         32 :     if (bond->balance != s->balance) {
     430                 :          9 :         bond->balance = s->balance;
     431                 :          9 :         revalidate = true;
     432                 :            :     }
     433                 :            : 
     434         [ -  + ]:         32 :     if (bond->basis != s->basis) {
     435                 :          0 :         bond->basis = s->basis;
     436                 :          0 :         revalidate = true;
     437                 :            :     }
     438                 :            : 
     439         [ -  + ]:         32 :     if (bond->bond_revalidate) {
     440                 :          0 :         revalidate = true;
     441                 :          0 :         bond->bond_revalidate = false;
     442                 :            :     }
     443                 :            : 
     444         [ +  + ]:         32 :     if (bond->balance != BM_AB) {
     445         [ +  + ]:         18 :         if (!bond->recirc_id) {
     446                 :         18 :             bond->recirc_id = recirc_alloc_id(bond->ofproto);
     447                 :            :         }
     448         [ -  + ]:         14 :     } else if (bond->recirc_id) {
     449                 :          0 :         recirc_free_id(bond->recirc_id);
     450                 :          0 :         bond->recirc_id = 0;
     451                 :            :     }
     452                 :            : 
     453 [ +  + ][ +  + ]:         32 :     if (bond->balance == BM_AB || !bond->hash || revalidate) {
                 [ -  + ]
     454                 :         26 :         bond_entry_reset(bond);
     455                 :            :     }
     456                 :            : 
     457                 :         32 :     bond->active_slave_mac = s->active_slave_mac;
     458                 :         32 :     bond->active_slave_changed = false;
     459                 :            : 
     460                 :         32 :     ovs_rwlock_unlock(&rwlock);
     461                 :         32 :     return revalidate;
     462                 :            : }
     463                 :            : 
     464                 :            : static struct bond_slave *
     465                 :        418 : bond_find_slave_by_mac(const struct bond *bond, const struct eth_addr mac)
     466                 :            : {
     467                 :            :     struct bond_slave *slave;
     468                 :            : 
     469                 :            :     /* Find the last active slave */
     470 [ +  + ][ -  + ]:       1223 :     HMAP_FOR_EACH(slave, hmap_node, &bond->slaves) {
     471                 :            :         struct eth_addr slave_mac;
     472                 :            : 
     473         [ -  + ]:        823 :         if (netdev_get_etheraddr(slave->netdev, &slave_mac)) {
     474                 :          0 :             continue;
     475                 :            :         }
     476                 :            : 
     477         [ +  + ]:        823 :         if (eth_addr_equals(slave_mac, mac)) {
     478                 :        823 :             return slave;
     479                 :            :         }
     480                 :            :     }
     481                 :            : 
     482                 :        400 :     return NULL;
     483                 :            : }
     484                 :            : 
     485                 :            : static void
     486                 :         27 : bond_active_slave_changed(struct bond *bond)
     487                 :            : {
     488                 :            :     struct eth_addr mac;
     489                 :            : 
     490                 :         27 :     netdev_get_etheraddr(bond->active_slave->netdev, &mac);
     491                 :         27 :     bond->active_slave_mac = mac;
     492                 :         27 :     bond->active_slave_changed = true;
     493                 :         27 :     seq_change(connectivity_seq_get());
     494                 :         27 : }
     495                 :            : 
     496                 :            : static void
     497                 :        103 : bond_slave_set_netdev__(struct bond_slave *slave, struct netdev *netdev)
     498                 :            :     OVS_REQ_WRLOCK(rwlock)
     499                 :            : {
     500         [ +  + ]:        103 :     if (slave->netdev != netdev) {
     501                 :         41 :         slave->netdev = netdev;
     502                 :         41 :         slave->change_seq = 0;
     503                 :            :     }
     504                 :        103 : }
     505                 :            : 
     506                 :            : /* Registers 'slave_' as a slave of 'bond'.  The 'slave_' pointer is an
     507                 :            :  * arbitrary client-provided pointer that uniquely identifies a slave within a
     508                 :            :  * bond.  If 'slave_' already exists within 'bond' then this function
     509                 :            :  * reconfigures the existing slave.
     510                 :            :  *
     511                 :            :  * 'netdev' must be the network device that 'slave_' represents.  It is owned
     512                 :            :  * by the client, so the client must not close it before either unregistering
     513                 :            :  * 'slave_' or destroying 'bond'.
     514                 :            :  */
     515                 :            : void
     516                 :         67 : bond_slave_register(struct bond *bond, void *slave_,
     517                 :            :                     ofp_port_t ofport, struct netdev *netdev)
     518                 :            : {
     519                 :            :     struct bond_slave *slave;
     520                 :            : 
     521                 :         67 :     ovs_rwlock_wrlock(&rwlock);
     522                 :         67 :     slave = bond_slave_lookup(bond, slave_);
     523         [ +  + ]:         67 :     if (!slave) {
     524                 :         41 :         slave = xzalloc(sizeof *slave);
     525                 :            : 
     526                 :         41 :         hmap_insert(&bond->slaves, &slave->hmap_node, hash_pointer(slave_, 0));
     527                 :         41 :         slave->bond = bond;
     528                 :         41 :         slave->aux = slave_;
     529                 :         41 :         slave->ofp_port = ofport;
     530                 :         41 :         slave->delay_expires = LLONG_MAX;
     531                 :         41 :         slave->name = xstrdup(netdev_get_name(netdev));
     532                 :         41 :         bond->bond_revalidate = true;
     533                 :            : 
     534                 :         41 :         slave->enabled = false;
     535                 :         41 :         bond_enable_slave(slave, netdev_get_carrier(netdev));
     536                 :            :     }
     537                 :            : 
     538                 :         67 :     bond_slave_set_netdev__(slave, netdev);
     539                 :            : 
     540                 :         67 :     free(slave->name);
     541                 :         67 :     slave->name = xstrdup(netdev_get_name(netdev));
     542                 :         67 :     ovs_rwlock_unlock(&rwlock);
     543                 :         67 : }
     544                 :            : 
     545                 :            : /* Updates the network device to be used with 'slave_' to 'netdev'.
     546                 :            :  *
     547                 :            :  * This is useful if the caller closes and re-opens the network device
     548                 :            :  * registered with bond_slave_register() but doesn't need to change anything
     549                 :            :  * else. */
     550                 :            : void
     551                 :         36 : bond_slave_set_netdev(struct bond *bond, void *slave_, struct netdev *netdev)
     552                 :            : {
     553                 :            :     struct bond_slave *slave;
     554                 :            : 
     555                 :         36 :     ovs_rwlock_wrlock(&rwlock);
     556                 :         36 :     slave = bond_slave_lookup(bond, slave_);
     557         [ +  - ]:         36 :     if (slave) {
     558                 :         36 :         bond_slave_set_netdev__(slave, netdev);
     559                 :            :     }
     560                 :         36 :     ovs_rwlock_unlock(&rwlock);
     561                 :         36 : }
     562                 :            : 
     563                 :            : /* Unregisters 'slave_' from 'bond'.  If 'bond' does not contain such a slave
     564                 :            :  * then this function has no effect.
     565                 :            :  *
     566                 :            :  * Unregistering a slave invalidates all flows. */
     567                 :            : void
     568                 :         41 : bond_slave_unregister(struct bond *bond, const void *slave_)
     569                 :            : {
     570                 :            :     struct bond_slave *slave;
     571                 :            :     bool del_active;
     572                 :            : 
     573                 :         41 :     ovs_rwlock_wrlock(&rwlock);
     574                 :         41 :     slave = bond_slave_lookup(bond, slave_);
     575         [ -  + ]:         41 :     if (!slave) {
     576                 :          0 :         goto out;
     577                 :            :     }
     578                 :            : 
     579                 :         41 :     bond->bond_revalidate = true;
     580                 :         41 :     bond_enable_slave(slave, false);
     581                 :            : 
     582                 :         41 :     del_active = bond->active_slave == slave;
     583         [ +  + ]:         41 :     if (bond->hash) {
     584                 :            :         struct bond_entry *e;
     585         [ +  + ]:       6939 :         for (e = bond->hash; e <= &bond->hash[BOND_MASK]; e++) {
     586         [ +  + ]:       6912 :             if (e->slave == slave) {
     587                 :       1365 :                 e->slave = NULL;
     588                 :            :             }
     589                 :            :         }
     590                 :            :     }
     591                 :            : 
     592                 :         41 :     free(slave->name);
     593                 :            : 
     594                 :         41 :     hmap_remove(&bond->slaves, &slave->hmap_node);
     595                 :            :     /* Client owns 'slave->netdev'. */
     596                 :         41 :     free(slave);
     597                 :            : 
     598         [ +  + ]:         41 :     if (del_active) {
     599                 :         26 :         bond_choose_active_slave(bond);
     600                 :         26 :         bond->send_learning_packets = true;
     601                 :            :     }
     602                 :            : out:
     603                 :         41 :     ovs_rwlock_unlock(&rwlock);
     604                 :         41 : }
     605                 :            : 
     606                 :            : /* Should be called on each slave in 'bond' before bond_run() to indicate
     607                 :            :  * whether or not 'slave_' may be enabled. This function is intended to allow
     608                 :            :  * other protocols to have some impact on bonding decisions.  For example LACP
     609                 :            :  * or high level link monitoring protocols may decide that a given slave should
     610                 :            :  * not be able to send traffic. */
     611                 :            : void
     612                 :      14728 : bond_slave_set_may_enable(struct bond *bond, void *slave_, bool may_enable)
     613                 :            : {
     614                 :      14728 :     ovs_rwlock_wrlock(&rwlock);
     615                 :      14728 :     bond_slave_lookup(bond, slave_)->may_enable = may_enable;
     616                 :      14728 :     ovs_rwlock_unlock(&rwlock);
     617                 :      14728 : }
     618                 :            : 
     619                 :            : /* Performs periodic maintenance on 'bond'.
     620                 :            :  *
     621                 :            :  * Returns true if the caller should revalidate its flows.
     622                 :            :  *
     623                 :            :  * The caller should check bond_should_send_learning_packets() afterward. */
     624                 :            : bool
     625                 :       5410 : bond_run(struct bond *bond, enum lacp_status lacp_status)
     626                 :            : {
     627                 :            :     struct bond_slave *slave;
     628                 :            :     bool revalidate;
     629                 :            : 
     630                 :       5410 :     ovs_rwlock_wrlock(&rwlock);
     631         [ +  + ]:       5410 :     if (bond->lacp_status != lacp_status) {
     632                 :          7 :         bond->lacp_status = lacp_status;
     633                 :          7 :         bond->bond_revalidate = true;
     634                 :            :     }
     635                 :            : 
     636                 :            :     /* Enable slaves based on link status and LACP feedback. */
     637 [ +  + ][ -  + ]:      20138 :     HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
     638                 :      14728 :         bond_link_status_update(slave);
     639                 :      14728 :         slave->change_seq = seq_read(connectivity_seq_get());
     640                 :            :     }
     641 [ +  + ][ +  + ]:       5410 :     if (!bond->active_slave || !bond->active_slave->enabled) {
     642                 :        374 :         bond_choose_active_slave(bond);
     643                 :            :     }
     644                 :            : 
     645                 :       5410 :     revalidate = bond->bond_revalidate;
     646                 :       5410 :     bond->bond_revalidate = false;
     647                 :       5410 :     ovs_rwlock_unlock(&rwlock);
     648                 :            : 
     649                 :       5410 :     return revalidate;
     650                 :            : }
     651                 :            : 
     652                 :            : /* Causes poll_block() to wake up when 'bond' needs something to be done. */
     653                 :            : void
     654                 :       5397 : bond_wait(struct bond *bond)
     655                 :            : {
     656                 :            :     struct bond_slave *slave;
     657                 :            : 
     658                 :       5397 :     ovs_rwlock_rdlock(&rwlock);
     659 [ +  + ][ -  + ]:      20099 :     HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
     660         [ -  + ]:      14702 :         if (slave->delay_expires != LLONG_MAX) {
     661                 :          0 :             poll_timer_wait_until(slave->delay_expires);
     662                 :            :         }
     663                 :            : 
     664                 :      14702 :         seq_wait(connectivity_seq_get(), slave->change_seq);
     665                 :            :     }
     666                 :            : 
     667         [ -  + ]:       5397 :     if (bond->bond_revalidate) {
     668                 :          0 :         poll_immediate_wake();
     669                 :            :     }
     670                 :       5397 :     ovs_rwlock_unlock(&rwlock);
     671                 :            : 
     672                 :            :     /* We don't wait for bond->next_rebalance because rebalancing can only run
     673                 :            :      * at a flow account checkpoint.  ofproto does checkpointing on its own
     674                 :            :      * schedule and bond_rebalance() gets called afterward, so we'd just be
     675                 :            :      * waking up for no purpose. */
     676                 :       5397 : }
     677                 :            : 
     678                 :            : /* MAC learning table interaction. */
     679                 :            : 
     680                 :            : static bool
     681                 :         20 : may_send_learning_packets(const struct bond *bond)
     682                 :            : {
     683                 :         20 :     return ((bond->lacp_status == LACP_DISABLED
     684 [ +  + ][ -  + ]:         10 :         && (bond->balance == BM_SLB || bond->balance == BM_AB))
     685 [ -  + ][ #  # ]:         10 :         || (bond->lacp_fallback_ab && bond->lacp_status == LACP_CONFIGURED))
     686 [ +  + ][ +  - ]:         40 :         && bond->active_slave;
     687                 :            : }
     688                 :            : 
     689                 :            : /* Returns true if 'bond' needs the client to send out packets to assist with
     690                 :            :  * MAC learning on 'bond'.  If this function returns true, then the client
     691                 :            :  * should iterate through its MAC learning table for the bridge on which 'bond'
     692                 :            :  * is located.  For each MAC that has been learned on a port other than 'bond',
     693                 :            :  * it should call bond_compose_learning_packet().
     694                 :            :  *
     695                 :            :  * This function will only return true if 'bond' is in SLB or active-backup
     696                 :            :  * mode and LACP is not negotiated.  Otherwise sending learning packets isn't
     697                 :            :  * necessary.
     698                 :            :  *
     699                 :            :  * Calling this function resets the state that it checks. */
     700                 :            : bool
     701                 :       5410 : bond_should_send_learning_packets(struct bond *bond)
     702                 :            : {
     703                 :            :     bool send;
     704                 :            : 
     705                 :       5410 :     ovs_rwlock_wrlock(&rwlock);
     706 [ +  + ][ +  + ]:       5410 :     send = bond->send_learning_packets && may_send_learning_packets(bond);
     707                 :       5410 :     bond->send_learning_packets = false;
     708                 :       5410 :     ovs_rwlock_unlock(&rwlock);
     709                 :       5410 :     return send;
     710                 :            : }
     711                 :            : 
     712                 :            : /* Sends a gratuitous learning packet on 'bond' from 'eth_src' on 'vlan'.
     713                 :            :  *
     714                 :            :  * See bond_should_send_learning_packets() for description of usage. The
     715                 :            :  * caller should send the composed packet on the port associated with
     716                 :            :  * port_aux and takes ownership of the returned ofpbuf. */
     717                 :            : struct dp_packet *
     718                 :          2 : bond_compose_learning_packet(struct bond *bond, const struct eth_addr eth_src,
     719                 :            :                              uint16_t vlan, void **port_aux)
     720                 :            : {
     721                 :            :     struct bond_slave *slave;
     722                 :            :     struct dp_packet *packet;
     723                 :            :     struct flow flow;
     724                 :            : 
     725                 :          2 :     ovs_rwlock_rdlock(&rwlock);
     726         [ -  + ]:          2 :     ovs_assert(may_send_learning_packets(bond));
     727                 :          2 :     memset(&flow, 0, sizeof flow);
     728                 :          2 :     flow.dl_src = eth_src;
     729                 :          2 :     slave = choose_output_slave(bond, &flow, NULL, vlan);
     730                 :            : 
     731                 :          2 :     packet = dp_packet_new(0);
     732                 :          2 :     compose_rarp(packet, eth_src);
     733         [ -  + ]:          2 :     if (vlan) {
     734                 :          0 :         eth_push_vlan(packet, htons(ETH_TYPE_VLAN), htons(vlan));
     735                 :            :     }
     736                 :            : 
     737                 :          2 :     *port_aux = slave->aux;
     738                 :          2 :     ovs_rwlock_unlock(&rwlock);
     739                 :          2 :     return packet;
     740                 :            : }
     741                 :            : 
     742                 :            : /* Checks whether a packet that arrived on 'slave_' within 'bond', with an
     743                 :            :  * Ethernet destination address of 'eth_dst', should be admitted.
     744                 :            :  *
     745                 :            :  * The return value is one of the following:
     746                 :            :  *
     747                 :            :  *    - BV_ACCEPT: Admit the packet.
     748                 :            :  *
     749                 :            :  *    - BV_DROP: Drop the packet.
     750                 :            :  *
     751                 :            :  *    - BV_DROP_IF_MOVED: Consult the MAC learning table for the packet's
     752                 :            :  *      Ethernet source address and VLAN.  If there is none, or if the packet
     753                 :            :  *      is on the learned port, then admit the packet.  If a different port has
     754                 :            :  *      been learned, however, drop the packet (and do not use it for MAC
     755                 :            :  *      learning).
     756                 :            :  */
     757                 :            : enum bond_verdict
     758                 :      12363 : bond_check_admissibility(struct bond *bond, const void *slave_,
     759                 :            :                          const struct eth_addr eth_dst)
     760                 :            : {
     761                 :      12363 :     enum bond_verdict verdict = BV_DROP;
     762                 :            :     struct bond_slave *slave;
     763                 :            : 
     764                 :      12363 :     ovs_rwlock_rdlock(&rwlock);
     765                 :      12363 :     slave = bond_slave_lookup(bond, slave_);
     766         [ -  + ]:      12363 :     if (!slave) {
     767                 :          0 :         goto out;
     768                 :            :     }
     769                 :            : 
     770                 :            :     /* LACP bonds have very loose admissibility restrictions because we can
     771                 :            :      * assume the remote switch is aware of the bond and will "do the right
     772                 :            :      * thing".  However, as a precaution we drop packets on disabled slaves
     773                 :            :      * because no correctly implemented partner switch should be sending
     774                 :            :      * packets to them.
     775                 :            :      *
     776                 :            :      * If LACP is configured, but LACP negotiations have been unsuccessful, we
     777                 :            :      * drop all incoming traffic except if lacp_fallback_ab is enabled. */
     778   [ +  -  +  - ]:      12363 :     switch (bond->lacp_status) {
     779                 :            :     case LACP_NEGOTIATED:
     780         [ +  + ]:        312 :         verdict = slave->enabled ? BV_ACCEPT : BV_DROP;
     781                 :        312 :         goto out;
     782                 :            :     case LACP_CONFIGURED:
     783         [ #  # ]:          0 :         if (!bond->lacp_fallback_ab) {
     784                 :          0 :             goto out;
     785                 :            :         }
     786                 :            :     case LACP_DISABLED:
     787                 :      12051 :         break;
     788                 :            :     }
     789                 :            : 
     790                 :            :     /* Drop all multicast packets on inactive slaves. */
     791         [ +  + ]:      12051 :     if (eth_addr_is_multicast(eth_dst)) {
     792         [ +  - ]:         18 :         if (bond->active_slave != slave) {
     793                 :         18 :             goto out;
     794                 :            :         }
     795                 :            :     }
     796                 :            : 
     797   [ -  +  +  - ]:      12033 :     switch (bond->balance) {
     798                 :            :     case BM_TCP:
     799                 :            :         /* TCP balanced bonds require successful LACP negotiations. Based on the
     800                 :            :          * above check, LACP is off or lacp_fallback_ab is true on this bond.
     801                 :            :          * If lacp_fallback_ab is true fall through to BM_AB case else, we
     802                 :            :          * drop all incoming traffic. */
     803         [ #  # ]:          0 :         if (!bond->lacp_fallback_ab) {
     804                 :          0 :             goto out;
     805                 :            :         }
     806                 :            : 
     807                 :            :     case BM_AB:
     808                 :            :         /* Drop all packets which arrive on backup slaves.  This is similar to
     809                 :            :          * how Linux bonding handles active-backup bonds. */
     810         [ +  + ]:         19 :         if (bond->active_slave != slave) {
     811                 :            :             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     812                 :            : 
     813         [ -  + ]:         13 :             VLOG_DBG_RL(&rl, "active-backup bond received packet on backup"
     814                 :            :                         " slave (%s) destined for " ETH_ADDR_FMT,
     815                 :            :                         slave->name, ETH_ADDR_ARGS(eth_dst));
     816                 :         13 :             goto out;
     817                 :            :         }
     818                 :          6 :         verdict = BV_ACCEPT;
     819                 :          6 :         goto out;
     820                 :            : 
     821                 :            :     case BM_SLB:
     822                 :            :         /* Drop all packets for which we have learned a different input port,
     823                 :            :          * because we probably sent the packet on one slave and got it back on
     824                 :            :          * the other.  Gratuitous ARP packets are an exception to this rule:
     825                 :            :          * the host has moved to another switch.  The exception to the
     826                 :            :          * exception is if we locked the learning table to avoid reflections on
     827                 :            :          * bond slaves. */
     828                 :      12014 :         verdict = BV_DROP_IF_MOVED;
     829                 :      12014 :         goto out;
     830                 :            :     }
     831                 :            : 
     832                 :          0 :     OVS_NOT_REACHED();
     833                 :            : out:
     834                 :      12363 :     ovs_rwlock_unlock(&rwlock);
     835                 :      12363 :     return verdict;
     836                 :            : 
     837                 :            : }
     838                 :            : 
     839                 :            : /* Returns the slave (registered on 'bond' by bond_slave_register()) to which
     840                 :            :  * a packet with the given 'flow' and 'vlan' should be forwarded.  Returns
     841                 :            :  * NULL if the packet should be dropped because no slaves are enabled.
     842                 :            :  *
     843                 :            :  * 'vlan' is not necessarily the same as 'flow->vlan_tci'.  First, 'vlan'
     844                 :            :  * should be a VID only (i.e. excluding the PCP bits).  Second,
     845                 :            :  * 'flow->vlan_tci' is the VLAN TCI that appeared on the packet (so it will be
     846                 :            :  * nonzero only for trunk ports), whereas 'vlan' is the logical VLAN that the
     847                 :            :  * packet belongs to (so for an access port it will be the access port's VLAN).
     848                 :            :  *
     849                 :            :  * If 'wc' is non-NULL, bitwise-OR's 'wc' with the set of bits that were
     850                 :            :  * significant in the selection.  At some point earlier, 'wc' should
     851                 :            :  * have been initialized (e.g., by flow_wildcards_init_catchall()).
     852                 :            :  */
     853                 :            : void *
     854                 :       6420 : bond_choose_output_slave(struct bond *bond, const struct flow *flow,
     855                 :            :                          struct flow_wildcards *wc, uint16_t vlan)
     856                 :            : {
     857                 :            :     struct bond_slave *slave;
     858                 :            :     void *aux;
     859                 :            : 
     860                 :       6420 :     ovs_rwlock_rdlock(&rwlock);
     861                 :       6420 :     slave = choose_output_slave(bond, flow, wc, vlan);
     862         [ +  + ]:       6420 :     aux = slave ? slave->aux : NULL;
     863                 :       6420 :     ovs_rwlock_unlock(&rwlock);
     864                 :            : 
     865                 :       6420 :     return aux;
     866                 :            : }
     867                 :            : 
     868                 :            : /* Recirculation. */
     869                 :            : static void
     870                 :          0 : bond_entry_account(struct bond_entry *entry, uint64_t rule_tx_bytes)
     871                 :            :     OVS_REQ_WRLOCK(rwlock)
     872                 :            : {
     873         [ #  # ]:          0 :     if (entry->slave) {
     874                 :            :         uint64_t delta;
     875                 :            : 
     876                 :          0 :         delta = rule_tx_bytes - entry->pr_tx_bytes;
     877                 :          0 :         entry->tx_bytes += delta;
     878                 :          0 :         entry->pr_tx_bytes = rule_tx_bytes;
     879                 :            :     }
     880                 :          0 : }
     881                 :            : 
     882                 :            : /* Maintain bond stats using post recirculation rule byte counters.*/
     883                 :            : static void
     884                 :          6 : bond_recirculation_account(struct bond *bond)
     885                 :            :     OVS_REQ_WRLOCK(rwlock)
     886                 :            : {
     887                 :            :     int i;
     888                 :            : 
     889         [ +  + ]:       1542 :     for (i=0; i<=BOND_MASK; i++) {
     890                 :       1536 :         struct bond_entry *entry = &bond->hash[i];
     891                 :       1536 :         struct rule *rule = entry->pr_rule;
     892                 :            : 
     893         [ -  + ]:       1536 :         if (rule) {
     894                 :            :             uint64_t n_packets OVS_UNUSED;
     895                 :            :             long long int used OVS_UNUSED;
     896                 :            :             uint64_t n_bytes;
     897                 :            : 
     898                 :          0 :             rule->ofproto->ofproto_class->rule_get_stats(
     899                 :            :                 rule, &n_packets, &n_bytes, &used);
     900                 :          0 :             bond_entry_account(entry, n_bytes);
     901                 :            :         }
     902                 :            :     }
     903                 :          6 : }
     904                 :            : 
     905                 :            : bool
     906                 :       6444 : bond_may_recirc(const struct bond *bond, uint32_t *recirc_id,
     907                 :            :                 uint32_t *hash_bias)
     908                 :            : {
     909 [ +  + ][ +  - ]:       6444 :     if (bond->balance == BM_TCP && bond->recirc_id) {
     910         [ +  + ]:        327 :         if (recirc_id) {
     911                 :        321 :             *recirc_id = bond->recirc_id;
     912                 :            :         }
     913         [ +  + ]:        327 :         if (hash_bias) {
     914                 :        309 :             *hash_bias = bond->basis;
     915                 :            :         }
     916                 :        327 :         return true;
     917                 :            :     } else {
     918                 :       6117 :         return false;
     919                 :            :     }
     920                 :            : }
     921                 :            : 
     922                 :            : static void
     923                 :        309 : bond_update_post_recirc_rules__(struct bond* bond, const bool force)
     924                 :            :     OVS_REQ_WRLOCK(rwlock)
     925                 :            : {
     926                 :            :    struct bond_entry *e;
     927                 :        309 :    bool update_rules = force;  /* Always update rules if caller forces it. */
     928                 :            : 
     929                 :            :    /* Make sure all bond entries are populated */
     930         [ +  + ]:      79413 :    for (e = bond->hash; e <= &bond->hash[BOND_MASK]; e++) {
     931 [ +  + ][ +  + ]:      79104 :        if (!e->slave || !e->slave->enabled) {
     932                 :       7936 :             update_rules = true;
     933                 :       7936 :             e->slave = CONTAINER_OF(hmap_random_node(&bond->slaves),
     934                 :            :                                     struct bond_slave, hmap_node);
     935         [ +  + ]:       7936 :             if (!e->slave->enabled) {
     936                 :       6144 :                 e->slave = bond->active_slave;
     937                 :            :             }
     938                 :            :         }
     939                 :            :    }
     940                 :            : 
     941         [ +  + ]:        309 :    if (update_rules) {
     942                 :         31 :         update_recirc_rules(bond);
     943                 :            :    }
     944                 :        309 : }
     945                 :            : 
     946                 :            : void
     947                 :        309 : bond_update_post_recirc_rules(struct bond* bond, const bool force)
     948                 :            : {
     949                 :        309 :     ovs_rwlock_wrlock(&rwlock);
     950                 :        309 :     bond_update_post_recirc_rules__(bond, force);
     951                 :        309 :     ovs_rwlock_unlock(&rwlock);
     952                 :        309 : }
     953                 :            : 
     954                 :            : /* Rebalancing. */
     955                 :            : 
     956                 :            : static bool
     957                 :       1232 : bond_is_balanced(const struct bond *bond) OVS_REQ_RDLOCK(rwlock)
     958                 :            : {
     959                 :       1232 :     return bond->rebalance_interval
     960 [ +  + ][ +  + ]:       1232 :         && (bond->balance == BM_SLB || bond->balance == BM_TCP);
                 [ +  + ]
     961                 :            : }
     962                 :            : 
     963                 :            : /* Notifies 'bond' that 'n_bytes' bytes were sent in 'flow' within 'vlan'. */
     964                 :            : void
     965                 :        111 : bond_account(struct bond *bond, const struct flow *flow, uint16_t vlan,
     966                 :            :              uint64_t n_bytes)
     967                 :            : {
     968                 :        111 :     ovs_rwlock_wrlock(&rwlock);
     969         [ +  + ]:        111 :     if (bond_is_balanced(bond)) {
     970                 :        103 :         lookup_bond_entry(bond, flow, vlan)->tx_bytes += n_bytes;
     971                 :            :     }
     972                 :        111 :     ovs_rwlock_unlock(&rwlock);
     973                 :        111 : }
     974                 :            : 
     975                 :            : static struct bond_slave *
     976                 :          2 : bond_slave_from_bal_node(struct ovs_list *bal) OVS_REQ_RDLOCK(rwlock)
     977                 :            : {
     978                 :          2 :     return CONTAINER_OF(bal, struct bond_slave, bal_node);
     979                 :            : }
     980                 :            : 
     981                 :            : static void
     982                 :          6 : log_bals(struct bond *bond, const struct ovs_list *bals)
     983                 :            :     OVS_REQ_RDLOCK(rwlock)
     984                 :            : {
     985         [ -  + ]:          6 :     if (VLOG_IS_DBG_ENABLED()) {
     986                 :          0 :         struct ds ds = DS_EMPTY_INITIALIZER;
     987                 :            :         const struct bond_slave *slave;
     988                 :            : 
     989         [ #  # ]:          0 :         LIST_FOR_EACH (slave, bal_node, bals) {
     990         [ #  # ]:          0 :             if (ds.length) {
     991                 :          0 :                 ds_put_char(&ds, ',');
     992                 :            :             }
     993                 :          0 :             ds_put_format(&ds, " %s %"PRIu64"kB",
     994                 :          0 :                           slave->name, slave->tx_bytes / 1024);
     995                 :            : 
     996         [ #  # ]:          0 :             if (!slave->enabled) {
     997                 :          0 :                 ds_put_cstr(&ds, " (disabled)");
     998                 :            :             }
     999         [ #  # ]:          0 :             if (!ovs_list_is_empty(&slave->entries)) {
    1000                 :            :                 struct bond_entry *e;
    1001                 :            : 
    1002                 :          0 :                 ds_put_cstr(&ds, " (");
    1003         [ #  # ]:          0 :                 LIST_FOR_EACH (e, list_node, &slave->entries) {
    1004         [ #  # ]:          0 :                     if (&e->list_node != ovs_list_front(&slave->entries)) {
    1005                 :          0 :                         ds_put_cstr(&ds, " + ");
    1006                 :            :                     }
    1007                 :          0 :                     ds_put_format(&ds, "h%"PRIdPTR": %"PRIu64"kB",
    1008                 :          0 :                                   e - bond->hash, e->tx_bytes / 1024);
    1009                 :            :                 }
    1010                 :          0 :                 ds_put_cstr(&ds, ")");
    1011                 :            :             }
    1012                 :            :         }
    1013         [ #  # ]:          0 :         VLOG_DBG("bond %s:%s", bond->name, ds_cstr(&ds));
    1014                 :          0 :         ds_destroy(&ds);
    1015                 :            :     }
    1016                 :          6 : }
    1017                 :            : 
    1018                 :            : /* Shifts 'hash' from its current slave to 'to'. */
    1019                 :            : static void
    1020                 :          0 : bond_shift_load(struct bond_entry *hash, struct bond_slave *to)
    1021                 :            :     OVS_REQ_WRLOCK(rwlock)
    1022                 :            : {
    1023                 :          0 :     struct bond_slave *from = hash->slave;
    1024                 :          0 :     struct bond *bond = from->bond;
    1025                 :          0 :     uint64_t delta = hash->tx_bytes;
    1026                 :            : 
    1027         [ #  # ]:          0 :     VLOG_INFO("bond %s: shift %"PRIu64"kB of load (with hash %"PRIdPTR") "
    1028                 :            :               "from %s to %s (now carrying %"PRIu64"kB and "
    1029                 :            :               "%"PRIu64"kB load, respectively)",
    1030                 :            :               bond->name, delta / 1024, hash - bond->hash,
    1031                 :            :               from->name, to->name,
    1032                 :            :               (from->tx_bytes - delta) / 1024,
    1033                 :            :               (to->tx_bytes + delta) / 1024);
    1034                 :            : 
    1035                 :            :     /* Shift load away from 'from' to 'to'. */
    1036                 :          0 :     from->tx_bytes -= delta;
    1037                 :          0 :     to->tx_bytes += delta;
    1038                 :            : 
    1039                 :            :     /* Arrange for flows to be revalidated. */
    1040                 :          0 :     hash->slave = to;
    1041                 :          0 :     bond->bond_revalidate = true;
    1042                 :          0 : }
    1043                 :            : 
    1044                 :            : /* Picks and returns a bond_entry to migrate from 'from' (the most heavily
    1045                 :            :  * loaded bond slave) to a bond slave that has 'to_tx_bytes' bytes of load,
    1046                 :            :  * given that doing so must decrease the ratio of the load on the two slaves by
    1047                 :            :  * at least 0.1.  Returns NULL if there is no appropriate entry.
    1048                 :            :  *
    1049                 :            :  * The list of entries isn't sorted.  I don't know of a reason to prefer to
    1050                 :            :  * shift away small hashes or large hashes. */
    1051                 :            : static struct bond_entry *
    1052                 :          0 : choose_entry_to_migrate(const struct bond_slave *from, uint64_t to_tx_bytes)
    1053                 :            :     OVS_REQ_WRLOCK(rwlock)
    1054                 :            : {
    1055                 :            :     struct bond_entry *e;
    1056                 :            : 
    1057         [ #  # ]:          0 :     if (ovs_list_is_short(&from->entries)) {
    1058                 :            :         /* 'from' carries no more than one MAC hash, so shifting load away from
    1059                 :            :          * it would be pointless. */
    1060                 :          0 :         return NULL;
    1061                 :            :     }
    1062                 :            : 
    1063         [ #  # ]:          0 :     LIST_FOR_EACH (e, list_node, &from->entries) {
    1064                 :          0 :         uint64_t delta = e->tx_bytes;  /* The amount to rebalance.  */
    1065                 :          0 :         uint64_t ideal_tx_bytes = (from->tx_bytes + to_tx_bytes)/2;
    1066                 :            :                              /* Note, the ideal traffic is the mid point
    1067                 :            :                               * between 'from' and 'to'. This value does
    1068                 :            :                               * not change by rebalancing.  */
    1069                 :            :         uint64_t new_low;    /* The lower bandwidth between 'to' and 'from'
    1070                 :            :                                 after rebalancing. */
    1071                 :            : 
    1072                 :          0 :         new_low = MIN(from->tx_bytes - delta, to_tx_bytes + delta);
    1073                 :            : 
    1074 [ #  # ][ #  # ]:          0 :         if ((new_low > to_tx_bytes) &&
    1075                 :          0 :             (new_low - to_tx_bytes >= (ideal_tx_bytes - to_tx_bytes) / 10)) {
    1076                 :            :             /* Only rebalance if the new 'low' is closer to to the mid point,
    1077                 :            :              * and the improvement exceeds 10% of current traffic
    1078                 :            :              * deviation from the ideal split.
    1079                 :            :              *
    1080                 :            :              * The improvement on the 'high' side is always the same as the
    1081                 :            :              * 'low' side. Thus consider 'low' side is sufficient.  */
    1082                 :          0 :             return e;
    1083                 :            :         }
    1084                 :            :     }
    1085                 :            : 
    1086                 :          0 :     return NULL;
    1087                 :            : }
    1088                 :            : 
    1089                 :            : /* Inserts 'slave' into 'bals' so that descending order of 'tx_bytes' is
    1090                 :            :  * maintained. */
    1091                 :            : static void
    1092                 :          2 : insert_bal(struct ovs_list *bals, struct bond_slave *slave)
    1093                 :            : {
    1094                 :            :     struct bond_slave *pos;
    1095                 :            : 
    1096         [ +  + ]:          3 :     LIST_FOR_EACH (pos, bal_node, bals) {
    1097         [ -  + ]:          1 :         if (slave->tx_bytes > pos->tx_bytes) {
    1098                 :          0 :             break;
    1099                 :            :         }
    1100                 :            :     }
    1101                 :          2 :     ovs_list_insert(&pos->bal_node, &slave->bal_node);
    1102                 :          2 : }
    1103                 :            : 
    1104                 :            : /* Removes 'slave' from its current list and then inserts it into 'bals' so
    1105                 :            :  * that descending order of 'tx_bytes' is maintained. */
    1106                 :            : static void
    1107                 :          0 : reinsert_bal(struct ovs_list *bals, struct bond_slave *slave)
    1108                 :            : {
    1109                 :          0 :     ovs_list_remove(&slave->bal_node);
    1110                 :          0 :     insert_bal(bals, slave);
    1111                 :          0 : }
    1112                 :            : 
    1113                 :            : /* If 'bond' needs rebalancing, does so.
    1114                 :            :  *
    1115                 :            :  * The caller should have called bond_account() for each active flow, or in case
    1116                 :            :  * of recirculation is used, have called bond_recirculation_account(bond),
    1117                 :            :  * to ensure that flow data is consistently accounted at this point.
    1118                 :            :  */
    1119                 :            : void
    1120                 :       1063 : bond_rebalance(struct bond *bond)
    1121                 :            : {
    1122                 :            :     struct bond_slave *slave;
    1123                 :            :     struct bond_entry *e;
    1124                 :            :     struct ovs_list bals;
    1125                 :       1063 :     bool rebalanced = false;
    1126                 :            :     bool use_recirc;
    1127                 :            : 
    1128                 :       1063 :     ovs_rwlock_wrlock(&rwlock);
    1129 [ +  + ][ +  + ]:       1063 :     if (!bond_is_balanced(bond) || time_msec() < bond->next_rebalance) {
    1130                 :            :         goto done;
    1131                 :            :     }
    1132                 :          6 :     bond->next_rebalance = time_msec() + bond->rebalance_interval;
    1133                 :            : 
    1134   [ +  -  +  - ]:         12 :     use_recirc = ofproto_dpif_get_support(bond->ofproto)->odp.recirc &&
    1135                 :          6 :                  bond_may_recirc(bond, NULL, NULL);
    1136                 :            : 
    1137         [ +  - ]:          6 :     if (use_recirc) {
    1138                 :          6 :         bond_recirculation_account(bond);
    1139                 :            :     }
    1140                 :            : 
    1141                 :            :     /* Add each bond_entry to its slave's 'entries' list.
    1142                 :            :      * Compute each slave's tx_bytes as the sum of its entries' tx_bytes. */
    1143 [ +  + ][ -  + ]:         18 :     HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
    1144                 :         12 :         slave->tx_bytes = 0;
    1145                 :         12 :         ovs_list_init(&slave->entries);
    1146                 :            :     }
    1147         [ +  + ]:       1542 :     for (e = &bond->hash[0]; e <= &bond->hash[BOND_MASK]; e++) {
    1148 [ -  + ][ #  # ]:       1536 :         if (e->slave && e->tx_bytes) {
    1149                 :          0 :             e->slave->tx_bytes += e->tx_bytes;
    1150                 :          0 :             ovs_list_push_back(&e->slave->entries, &e->list_node);
    1151                 :            :         }
    1152                 :            :     }
    1153                 :            : 
    1154                 :            :     /* Add enabled slaves to 'bals' in descending order of tx_bytes.
    1155                 :            :      *
    1156                 :            :      * XXX This is O(n**2) in the number of slaves but it could be O(n lg n)
    1157                 :            :      * with a proper list sort algorithm. */
    1158                 :          6 :     ovs_list_init(&bals);
    1159 [ +  + ][ -  + ]:         18 :     HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
    1160         [ +  + ]:         12 :         if (slave->enabled) {
    1161                 :          2 :             insert_bal(&bals, slave);
    1162                 :            :         }
    1163                 :            :     }
    1164                 :          6 :     log_bals(bond, &bals);
    1165                 :            : 
    1166                 :            :     /* Shift load from the most-loaded slaves to the least-loaded slaves. */
    1167         [ +  + ]:          6 :     while (!ovs_list_is_short(&bals)) {
    1168                 :          1 :         struct bond_slave *from = bond_slave_from_bal_node(ovs_list_front(&bals));
    1169                 :          1 :         struct bond_slave *to = bond_slave_from_bal_node(ovs_list_back(&bals));
    1170                 :            :         uint64_t overload;
    1171                 :            : 
    1172                 :          1 :         overload = from->tx_bytes - to->tx_bytes;
    1173 [ +  - ][ -  + ]:          1 :         if (overload < to->tx_bytes >> 5 || overload < 100000) {
    1174                 :            :             /* The extra load on 'from' (and all less-loaded slaves), compared
    1175                 :            :              * to that of 'to' (the least-loaded slave), is less than ~3%, or
    1176                 :            :              * it is less than ~1Mbps.  No point in rebalancing. */
    1177                 :            :             break;
    1178                 :            :         }
    1179                 :            : 
    1180                 :            :         /* 'from' is carrying significantly more load than 'to'.  Pick a hash
    1181                 :            :          * to move from 'from' to 'to'. */
    1182                 :          0 :         e = choose_entry_to_migrate(from, to->tx_bytes);
    1183         [ #  # ]:          0 :         if (e) {
    1184                 :          0 :             bond_shift_load(e, to);
    1185                 :            : 
    1186                 :            :             /* Delete element from from->entries.
    1187                 :            :              *
    1188                 :            :              * We don't add the element to to->hashes.  That would only allow
    1189                 :            :              * 'e' to be migrated to another slave in this rebalancing run, and
    1190                 :            :              * there is no point in doing that. */
    1191                 :          0 :             ovs_list_remove(&e->list_node);
    1192                 :            : 
    1193                 :            :             /* Re-sort 'bals'. */
    1194                 :          0 :             reinsert_bal(&bals, from);
    1195                 :          0 :             reinsert_bal(&bals, to);
    1196                 :          0 :             rebalanced = true;
    1197                 :            :         } else {
    1198                 :            :             /* Can't usefully migrate anything away from 'from'.
    1199                 :            :              * Don't reconsider it. */
    1200                 :          0 :             ovs_list_remove(&from->bal_node);
    1201                 :            :         }
    1202                 :            :     }
    1203                 :            : 
    1204                 :            :     /* Implement exponentially weighted moving average.  A weight of 1/2 causes
    1205                 :            :      * historical data to decay to <1% in 7 rebalancing runs.  1,000,000 bytes
    1206                 :            :      * take 20 rebalancing runs to decay to 0 and get deleted entirely. */
    1207         [ +  + ]:       1542 :     for (e = &bond->hash[0]; e <= &bond->hash[BOND_MASK]; e++) {
    1208                 :       1536 :         e->tx_bytes /= 2;
    1209                 :            :     }
    1210                 :            : 
    1211 [ +  - ][ -  + ]:          6 :     if (use_recirc && rebalanced) {
    1212                 :          0 :         bond_update_post_recirc_rules__(bond,true);
    1213                 :            :     }
    1214                 :            : 
    1215                 :            : done:
    1216                 :       1063 :     ovs_rwlock_unlock(&rwlock);
    1217                 :       1063 : }
    1218                 :            : 
    1219                 :            : /* Bonding unixctl user interface functions. */
    1220                 :            : 
    1221                 :            : static struct bond *
    1222                 :        109 : bond_find(const char *name) OVS_REQ_RDLOCK(rwlock)
    1223                 :            : {
    1224                 :            :     struct bond *bond;
    1225                 :            : 
    1226 [ +  - ][ #  # ]:        109 :     HMAP_FOR_EACH_WITH_HASH (bond, hmap_node, hash_string(name, 0),
    1227                 :            :                              all_bonds) {
    1228         [ +  - ]:        109 :         if (!strcmp(bond->name, name)) {
    1229                 :        109 :             return bond;
    1230                 :            :         }
    1231                 :            :     }
    1232                 :          0 :     return NULL;
    1233                 :            : }
    1234                 :            : 
    1235                 :            : static struct bond_slave *
    1236                 :          0 : bond_lookup_slave(struct bond *bond, const char *slave_name)
    1237                 :            : {
    1238                 :            :     struct bond_slave *slave;
    1239                 :            : 
    1240 [ #  # ][ #  # ]:          0 :     HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
    1241         [ #  # ]:          0 :         if (!strcmp(slave->name, slave_name)) {
    1242                 :          0 :             return slave;
    1243                 :            :         }
    1244                 :            :     }
    1245                 :          0 :     return NULL;
    1246                 :            : }
    1247                 :            : 
    1248                 :            : static void
    1249                 :          0 : bond_unixctl_list(struct unixctl_conn *conn,
    1250                 :            :                   int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
    1251                 :            :                   void *aux OVS_UNUSED)
    1252                 :            : {
    1253                 :          0 :     struct ds ds = DS_EMPTY_INITIALIZER;
    1254                 :            :     const struct bond *bond;
    1255                 :            : 
    1256                 :          0 :     ds_put_cstr(&ds, "bond\ttype\trecircID\tslaves\n");
    1257                 :            : 
    1258                 :          0 :     ovs_rwlock_rdlock(&rwlock);
    1259 [ #  # ][ #  # ]:          0 :     HMAP_FOR_EACH (bond, hmap_node, all_bonds) {
    1260                 :            :         const struct bond_slave *slave;
    1261                 :            :         size_t i;
    1262                 :            : 
    1263                 :          0 :         ds_put_format(&ds, "%s\t%s\t%d\t", bond->name,
    1264                 :            :                       bond_mode_to_string(bond->balance), bond->recirc_id);
    1265                 :            : 
    1266                 :          0 :         i = 0;
    1267 [ #  # ][ #  # ]:          0 :         HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
    1268         [ #  # ]:          0 :             if (i++ > 0) {
    1269                 :          0 :                 ds_put_cstr(&ds, ", ");
    1270                 :            :             }
    1271                 :          0 :             ds_put_cstr(&ds, slave->name);
    1272                 :            :         }
    1273                 :          0 :         ds_put_char(&ds, '\n');
    1274                 :            :     }
    1275                 :          0 :     ovs_rwlock_unlock(&rwlock);
    1276                 :          0 :     unixctl_command_reply(conn, ds_cstr(&ds));
    1277                 :          0 :     ds_destroy(&ds);
    1278                 :          0 : }
    1279                 :            : 
    1280                 :            : static void
    1281                 :         18 : bond_print_details(struct ds *ds, const struct bond *bond)
    1282                 :            :     OVS_REQ_RDLOCK(rwlock)
    1283                 :            : {
    1284                 :         18 :     struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
    1285                 :         18 :     const struct shash_node **sorted_slaves = NULL;
    1286                 :            :     const struct bond_slave *slave;
    1287                 :            :     bool may_recirc;
    1288                 :            :     uint32_t recirc_id;
    1289                 :            :     int i;
    1290                 :            : 
    1291                 :         18 :     ds_put_format(ds, "---- %s ----\n", bond->name);
    1292                 :         18 :     ds_put_format(ds, "bond_mode: %s\n",
    1293                 :            :                   bond_mode_to_string(bond->balance));
    1294                 :            : 
    1295                 :         18 :     may_recirc = bond_may_recirc(bond, &recirc_id, NULL);
    1296 [ +  + ][ +  + ]:         18 :     ds_put_format(ds, "bond may use recirculation: %s, Recirc-ID : %d\n",
    1297                 :            :                   may_recirc ? "yes" : "no", may_recirc ? recirc_id: -1);
    1298                 :            : 
    1299                 :         18 :     ds_put_format(ds, "bond-hash-basis: %"PRIu32"\n", bond->basis);
    1300                 :            : 
    1301                 :         18 :     ds_put_format(ds, "updelay: %d ms\n", bond->updelay);
    1302                 :         18 :     ds_put_format(ds, "downdelay: %d ms\n", bond->downdelay);
    1303                 :            : 
    1304         [ -  + ]:         18 :     if (bond_is_balanced(bond)) {
    1305                 :          0 :         ds_put_format(ds, "next rebalance: %lld ms\n",
    1306                 :          0 :                       bond->next_rebalance - time_msec());
    1307                 :            :     }
    1308                 :            : 
    1309                 :         18 :     ds_put_cstr(ds, "lacp_status: ");
    1310   [ +  -  +  - ]:         18 :     switch (bond->lacp_status) {
    1311                 :            :     case LACP_NEGOTIATED:
    1312                 :         13 :         ds_put_cstr(ds, "negotiated\n");
    1313                 :         13 :         break;
    1314                 :            :     case LACP_CONFIGURED:
    1315                 :          0 :         ds_put_cstr(ds, "configured\n");
    1316                 :          0 :         break;
    1317                 :            :     case LACP_DISABLED:
    1318                 :          5 :         ds_put_cstr(ds, "off\n");
    1319                 :          5 :         break;
    1320                 :            :     default:
    1321                 :          0 :         ds_put_cstr(ds, "<unknown>\n");
    1322                 :          0 :         break;
    1323                 :            :     }
    1324                 :            : 
    1325                 :         18 :     ds_put_cstr(ds, "active slave mac: ");
    1326                 :         18 :     ds_put_format(ds, ETH_ADDR_FMT, ETH_ADDR_ARGS(bond->active_slave_mac));
    1327                 :         18 :     slave = bond_find_slave_by_mac(bond, bond->active_slave_mac);
    1328         [ +  + ]:         18 :     ds_put_format(ds,"(%s)\n", slave ? slave->name : "none");
    1329                 :            : 
    1330 [ +  + ][ -  + ]:         58 :     HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
    1331                 :         40 :         shash_add(&slave_shash, slave->name, slave);
    1332                 :            :     }
    1333                 :         18 :     sorted_slaves = shash_sort(&slave_shash);
    1334                 :            : 
    1335         [ +  + ]:         58 :     for (i = 0; i < shash_count(&slave_shash); i++) {
    1336                 :            :         struct bond_entry *be;
    1337                 :            : 
    1338                 :         40 :         slave = sorted_slaves[i]->data;
    1339                 :            : 
    1340                 :            :         /* Basic info. */
    1341         [ +  + ]:         40 :         ds_put_format(ds, "\nslave %s: %s\n",
    1342                 :         40 :                       slave->name, slave->enabled ? "enabled" : "disabled");
    1343         [ +  + ]:         40 :         if (slave == bond->active_slave) {
    1344                 :         17 :             ds_put_cstr(ds, "\tactive slave\n");
    1345                 :            :         }
    1346         [ -  + ]:         40 :         if (slave->delay_expires != LLONG_MAX) {
    1347         [ #  # ]:          0 :             ds_put_format(ds, "\t%s expires in %lld ms\n",
    1348                 :          0 :                           slave->enabled ? "downdelay" : "updelay",
    1349                 :          0 :                           slave->delay_expires - time_msec());
    1350                 :            :         }
    1351                 :            : 
    1352         [ +  + ]:         40 :         ds_put_format(ds, "\tmay_enable: %s\n",
    1353                 :         40 :                       slave->may_enable ? "true" : "false");
    1354                 :            : 
    1355         [ +  - ]:         40 :         if (!bond_is_balanced(bond)) {
    1356                 :         40 :             continue;
    1357                 :            :         }
    1358                 :            : 
    1359                 :            :         /* Hashes. */
    1360         [ #  # ]:          0 :         for (be = bond->hash; be <= &bond->hash[BOND_MASK]; be++) {
    1361                 :          0 :             int hash = be - bond->hash;
    1362                 :            :             uint64_t be_tx_k;
    1363                 :            : 
    1364         [ #  # ]:          0 :             if (be->slave != slave) {
    1365                 :          0 :                 continue;
    1366                 :            :             }
    1367                 :            : 
    1368                 :          0 :             be_tx_k = be->tx_bytes / 1024;
    1369         [ #  # ]:          0 :             if (be_tx_k) {
    1370                 :          0 :                 ds_put_format(ds, "\thash %d: %"PRIu64" kB load\n",
    1371                 :            :                           hash, be_tx_k);
    1372                 :            :             }
    1373                 :            : 
    1374                 :            :             /* XXX How can we list the MACs assigned to hashes of SLB bonds? */
    1375                 :            :         }
    1376                 :            :     }
    1377                 :         18 :     shash_destroy(&slave_shash);
    1378                 :         18 :     free(sorted_slaves);
    1379                 :         18 :     ds_put_cstr(ds, "\n");
    1380                 :         18 : }
    1381                 :            : 
    1382                 :            : static void
    1383                 :         14 : bond_unixctl_show(struct unixctl_conn *conn,
    1384                 :            :                   int argc, const char *argv[],
    1385                 :            :                   void *aux OVS_UNUSED)
    1386                 :            : {
    1387                 :         14 :     struct ds ds = DS_EMPTY_INITIALIZER;
    1388                 :            : 
    1389                 :         14 :     ovs_rwlock_rdlock(&rwlock);
    1390         [ +  + ]:         14 :     if (argc > 1) {
    1391                 :          7 :         const struct bond *bond = bond_find(argv[1]);
    1392                 :            : 
    1393         [ -  + ]:          7 :         if (!bond) {
    1394                 :          0 :             unixctl_command_reply_error(conn, "no such bond");
    1395                 :          0 :             goto out;
    1396                 :            :         }
    1397                 :          7 :         bond_print_details(&ds, bond);
    1398                 :            :     } else {
    1399                 :            :         const struct bond *bond;
    1400                 :            : 
    1401 [ +  + ][ -  + ]:         18 :         HMAP_FOR_EACH (bond, hmap_node, all_bonds) {
    1402                 :         11 :             bond_print_details(&ds, bond);
    1403                 :            :         }
    1404                 :            :     }
    1405                 :            : 
    1406                 :         14 :     unixctl_command_reply(conn, ds_cstr(&ds));
    1407                 :         14 :     ds_destroy(&ds);
    1408                 :            : 
    1409                 :            : out:
    1410                 :         14 :     ovs_rwlock_unlock(&rwlock);
    1411                 :         14 : }
    1412                 :            : 
    1413                 :            : static void
    1414                 :          0 : bond_unixctl_migrate(struct unixctl_conn *conn,
    1415                 :            :                      int argc OVS_UNUSED, const char *argv[],
    1416                 :            :                      void *aux OVS_UNUSED)
    1417                 :            : {
    1418                 :          0 :     const char *bond_s = argv[1];
    1419                 :          0 :     const char *hash_s = argv[2];
    1420                 :          0 :     const char *slave_s = argv[3];
    1421                 :            :     struct bond *bond;
    1422                 :            :     struct bond_slave *slave;
    1423                 :            :     struct bond_entry *entry;
    1424                 :            :     int hash;
    1425                 :            : 
    1426                 :          0 :     ovs_rwlock_wrlock(&rwlock);
    1427                 :          0 :     bond = bond_find(bond_s);
    1428         [ #  # ]:          0 :     if (!bond) {
    1429                 :          0 :         unixctl_command_reply_error(conn, "no such bond");
    1430                 :          0 :         goto out;
    1431                 :            :     }
    1432                 :            : 
    1433         [ #  # ]:          0 :     if (bond->balance != BM_SLB) {
    1434                 :          0 :         unixctl_command_reply_error(conn, "not an SLB bond");
    1435                 :          0 :         goto out;
    1436                 :            :     }
    1437                 :            : 
    1438         [ #  # ]:          0 :     if (strspn(hash_s, "0123456789") == strlen(hash_s)) {
    1439                 :          0 :         hash = atoi(hash_s) & BOND_MASK;
    1440                 :            :     } else {
    1441                 :          0 :         unixctl_command_reply_error(conn, "bad hash");
    1442                 :          0 :         goto out;
    1443                 :            :     }
    1444                 :            : 
    1445                 :          0 :     slave = bond_lookup_slave(bond, slave_s);
    1446         [ #  # ]:          0 :     if (!slave) {
    1447                 :          0 :         unixctl_command_reply_error(conn, "no such slave");
    1448                 :          0 :         goto out;
    1449                 :            :     }
    1450                 :            : 
    1451         [ #  # ]:          0 :     if (!slave->enabled) {
    1452                 :          0 :         unixctl_command_reply_error(conn, "cannot migrate to disabled slave");
    1453                 :          0 :         goto out;
    1454                 :            :     }
    1455                 :            : 
    1456                 :          0 :     entry = &bond->hash[hash];
    1457                 :          0 :     bond->bond_revalidate = true;
    1458                 :          0 :     entry->slave = slave;
    1459                 :          0 :     unixctl_command_reply(conn, "migrated");
    1460                 :            : 
    1461                 :            : out:
    1462                 :          0 :     ovs_rwlock_unlock(&rwlock);
    1463                 :          0 : }
    1464                 :            : 
    1465                 :            : static void
    1466                 :          0 : bond_unixctl_set_active_slave(struct unixctl_conn *conn,
    1467                 :            :                               int argc OVS_UNUSED, const char *argv[],
    1468                 :            :                               void *aux OVS_UNUSED)
    1469                 :            : {
    1470                 :          0 :     const char *bond_s = argv[1];
    1471                 :          0 :     const char *slave_s = argv[2];
    1472                 :            :     struct bond *bond;
    1473                 :            :     struct bond_slave *slave;
    1474                 :            : 
    1475                 :          0 :     ovs_rwlock_wrlock(&rwlock);
    1476                 :          0 :     bond = bond_find(bond_s);
    1477         [ #  # ]:          0 :     if (!bond) {
    1478                 :          0 :         unixctl_command_reply_error(conn, "no such bond");
    1479                 :          0 :         goto out;
    1480                 :            :     }
    1481                 :            : 
    1482                 :          0 :     slave = bond_lookup_slave(bond, slave_s);
    1483         [ #  # ]:          0 :     if (!slave) {
    1484                 :          0 :         unixctl_command_reply_error(conn, "no such slave");
    1485                 :          0 :         goto out;
    1486                 :            :     }
    1487                 :            : 
    1488         [ #  # ]:          0 :     if (!slave->enabled) {
    1489                 :          0 :         unixctl_command_reply_error(conn, "cannot make disabled slave active");
    1490                 :          0 :         goto out;
    1491                 :            :     }
    1492                 :            : 
    1493         [ #  # ]:          0 :     if (bond->active_slave != slave) {
    1494                 :          0 :         bond->bond_revalidate = true;
    1495                 :          0 :         bond->active_slave = slave;
    1496         [ #  # ]:          0 :         VLOG_INFO("bond %s: active interface is now %s",
    1497                 :            :                   bond->name, slave->name);
    1498                 :          0 :         bond->send_learning_packets = true;
    1499                 :          0 :         unixctl_command_reply(conn, "done");
    1500                 :          0 :         bond_active_slave_changed(bond);
    1501                 :            :     } else {
    1502                 :          0 :         unixctl_command_reply(conn, "no change");
    1503                 :            :     }
    1504                 :            : out:
    1505                 :          0 :     ovs_rwlock_unlock(&rwlock);
    1506                 :          0 : }
    1507                 :            : 
    1508                 :            : static void
    1509                 :          0 : enable_slave(struct unixctl_conn *conn, const char *argv[], bool enable)
    1510                 :            : {
    1511                 :          0 :     const char *bond_s = argv[1];
    1512                 :          0 :     const char *slave_s = argv[2];
    1513                 :            :     struct bond *bond;
    1514                 :            :     struct bond_slave *slave;
    1515                 :            : 
    1516                 :          0 :     ovs_rwlock_wrlock(&rwlock);
    1517                 :          0 :     bond = bond_find(bond_s);
    1518         [ #  # ]:          0 :     if (!bond) {
    1519                 :          0 :         unixctl_command_reply_error(conn, "no such bond");
    1520                 :          0 :         goto out;
    1521                 :            :     }
    1522                 :            : 
    1523                 :          0 :     slave = bond_lookup_slave(bond, slave_s);
    1524         [ #  # ]:          0 :     if (!slave) {
    1525                 :          0 :         unixctl_command_reply_error(conn, "no such slave");
    1526                 :          0 :         goto out;
    1527                 :            :     }
    1528                 :            : 
    1529                 :          0 :     bond_enable_slave(slave, enable);
    1530         [ #  # ]:          0 :     unixctl_command_reply(conn, enable ? "enabled" : "disabled");
    1531                 :            : 
    1532                 :            : out:
    1533                 :          0 :     ovs_rwlock_unlock(&rwlock);
    1534                 :          0 : }
    1535                 :            : 
    1536                 :            : static void
    1537                 :          0 : bond_unixctl_enable_slave(struct unixctl_conn *conn,
    1538                 :            :                           int argc OVS_UNUSED, const char *argv[],
    1539                 :            :                           void *aux OVS_UNUSED)
    1540                 :            : {
    1541                 :          0 :     enable_slave(conn, argv, true);
    1542                 :          0 : }
    1543                 :            : 
    1544                 :            : static void
    1545                 :          0 : bond_unixctl_disable_slave(struct unixctl_conn *conn,
    1546                 :            :                            int argc OVS_UNUSED, const char *argv[],
    1547                 :            :                            void *aux OVS_UNUSED)
    1548                 :            : {
    1549                 :          0 :     enable_slave(conn, argv, false);
    1550                 :          0 : }
    1551                 :            : 
    1552                 :            : static void
    1553                 :         12 : bond_unixctl_hash(struct unixctl_conn *conn, int argc, const char *argv[],
    1554                 :            :                   void *aux OVS_UNUSED)
    1555                 :            : {
    1556                 :         12 :     const char *mac_s = argv[1];
    1557         [ +  + ]:         12 :     const char *vlan_s = argc > 2 ? argv[2] : NULL;
    1558         [ +  + ]:         12 :     const char *basis_s = argc > 3 ? argv[3] : NULL;
    1559                 :            :     struct eth_addr mac;
    1560                 :            :     uint8_t hash;
    1561                 :            :     char *hash_cstr;
    1562                 :            :     unsigned int vlan;
    1563                 :            :     uint32_t basis;
    1564                 :            : 
    1565         [ +  + ]:         12 :     if (vlan_s) {
    1566         [ +  - ]:          8 :         if (!ovs_scan(vlan_s, "%u", &vlan)) {
    1567                 :          8 :             unixctl_command_reply_error(conn, "invalid vlan");
    1568                 :          8 :             return;
    1569                 :            :         }
    1570                 :            :     } else {
    1571                 :          4 :         vlan = 0;
    1572                 :            :     }
    1573                 :            : 
    1574         [ -  + ]:          4 :     if (basis_s) {
    1575         [ #  # ]:          0 :         if (!ovs_scan(basis_s, "%"SCNu32, &basis)) {
    1576                 :          0 :             unixctl_command_reply_error(conn, "invalid basis");
    1577                 :          0 :             return;
    1578                 :            :         }
    1579                 :            :     } else {
    1580                 :          4 :         basis = 0;
    1581                 :            :     }
    1582                 :            : 
    1583         [ -  + ]:          4 :     if (ovs_scan(mac_s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
    1584                 :          0 :         hash = bond_hash_src(mac, vlan, basis) & BOND_MASK;
    1585                 :            : 
    1586                 :          0 :         hash_cstr = xasprintf("%u", hash);
    1587                 :          0 :         unixctl_command_reply(conn, hash_cstr);
    1588                 :          0 :         free(hash_cstr);
    1589                 :            :     } else {
    1590                 :          4 :         unixctl_command_reply_error(conn, "invalid mac");
    1591                 :            :     }
    1592                 :            : }
    1593                 :            : 
    1594                 :            : void
    1595                 :        617 : bond_init(void)
    1596                 :            : {
    1597                 :        617 :     unixctl_command_register("bond/list", "", 0, 0, bond_unixctl_list, NULL);
    1598                 :        617 :     unixctl_command_register("bond/show", "[port]", 0, 1, bond_unixctl_show,
    1599                 :            :                              NULL);
    1600                 :        617 :     unixctl_command_register("bond/migrate", "port hash slave", 3, 3,
    1601                 :            :                              bond_unixctl_migrate, NULL);
    1602                 :        617 :     unixctl_command_register("bond/set-active-slave", "port slave", 2, 2,
    1603                 :            :                              bond_unixctl_set_active_slave, NULL);
    1604                 :        617 :     unixctl_command_register("bond/enable-slave", "port slave", 2, 2,
    1605                 :            :                              bond_unixctl_enable_slave, NULL);
    1606                 :        617 :     unixctl_command_register("bond/disable-slave", "port slave", 2, 2,
    1607                 :            :                              bond_unixctl_disable_slave, NULL);
    1608                 :        617 :     unixctl_command_register("bond/hash", "mac [vlan] [basis]", 1, 3,
    1609                 :            :                              bond_unixctl_hash, NULL);
    1610                 :        617 : }
    1611                 :            : 
    1612                 :            : static void
    1613                 :         26 : bond_entry_reset(struct bond *bond)
    1614                 :            : {
    1615         [ +  + ]:         26 :     if (bond->balance != BM_AB) {
    1616                 :         12 :         size_t hash_len = BOND_BUCKETS * sizeof *bond->hash;
    1617                 :            : 
    1618         [ +  - ]:         12 :         if (!bond->hash) {
    1619                 :         12 :             bond->hash = xmalloc(hash_len);
    1620                 :            :         }
    1621                 :         12 :         memset(bond->hash, 0, hash_len);
    1622                 :            : 
    1623                 :         12 :         bond->next_rebalance = time_msec() + bond->rebalance_interval;
    1624                 :            :     } else {
    1625                 :         14 :         free(bond->hash);
    1626                 :         14 :         bond->hash = NULL;
    1627                 :            :     }
    1628                 :         26 : }
    1629                 :            : 
    1630                 :            : static struct bond_slave *
    1631                 :      27235 : bond_slave_lookup(struct bond *bond, const void *slave_)
    1632                 :            : {
    1633                 :            :     struct bond_slave *slave;
    1634                 :            : 
    1635 [ +  + ][ -  + ]:      45813 :     HMAP_FOR_EACH_IN_BUCKET (slave, hmap_node, hash_pointer(slave_, 0),
    1636                 :            :                              &bond->slaves) {
    1637         [ +  + ]:      45772 :         if (slave->aux == slave_) {
    1638                 :      27194 :             return slave;
    1639                 :            :         }
    1640                 :            :     }
    1641                 :            : 
    1642                 :         41 :     return NULL;
    1643                 :            : }
    1644                 :            : 
    1645                 :            : static void
    1646                 :        138 : bond_enable_slave(struct bond_slave *slave, bool enable)
    1647                 :            : {
    1648                 :        138 :     slave->delay_expires = LLONG_MAX;
    1649         [ +  + ]:        138 :     if (enable != slave->enabled) {
    1650                 :        104 :         slave->bond->bond_revalidate = true;
    1651                 :        104 :         slave->enabled = enable;
    1652                 :            : 
    1653                 :        104 :         ovs_mutex_lock(&slave->bond->mutex);
    1654         [ +  + ]:        104 :         if (enable) {
    1655                 :         52 :             ovs_list_insert(&slave->bond->enabled_slaves, &slave->list_node);
    1656                 :            :         } else {
    1657                 :         52 :             ovs_list_remove(&slave->list_node);
    1658                 :            :         }
    1659                 :        104 :         ovs_mutex_unlock(&slave->bond->mutex);
    1660                 :            : 
    1661 [ +  - ][ +  + ]:        104 :         VLOG_INFO("interface %s: %s", slave->name,
    1662                 :            :                   slave->enabled ? "enabled" : "disabled");
    1663                 :            :     }
    1664                 :        138 : }
    1665                 :            : 
    1666                 :            : static void
    1667                 :      14728 : bond_link_status_update(struct bond_slave *slave)
    1668                 :            : {
    1669                 :      14728 :     struct bond *bond = slave->bond;
    1670                 :            :     bool up;
    1671                 :            : 
    1672 [ +  + ][ +  + ]:      14728 :     up = netdev_get_carrier(slave->netdev) && slave->may_enable;
    1673         [ +  + ]:      14728 :     if ((up == slave->enabled) != (slave->delay_expires == LLONG_MAX)) {
    1674                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
    1675 [ +  - ][ +  + ]:         56 :         VLOG_INFO_RL(&rl, "interface %s: link state %s",
    1676                 :            :                      slave->name, up ? "up" : "down");
    1677         [ -  + ]:         56 :         if (up == slave->enabled) {
    1678                 :          0 :             slave->delay_expires = LLONG_MAX;
    1679 [ #  # ][ #  # ]:          0 :             VLOG_INFO_RL(&rl, "interface %s: will not be %s",
    1680                 :            :                          slave->name, up ? "disabled" : "enabled");
    1681                 :            :         } else {
    1682                 :        112 :             int delay = (bond->lacp_status != LACP_DISABLED ? 0
    1683 [ +  + ][ +  + ]:         56 :                          : up ? bond->updelay : bond->downdelay);
    1684                 :         56 :             slave->delay_expires = time_msec() + delay;
    1685         [ -  + ]:         56 :             if (delay) {
    1686 [ #  # ][ #  # ]:          0 :                 VLOG_INFO_RL(&rl, "interface %s: will be %s if it stays %s "
                 [ #  # ]
    1687                 :            :                              "for %d ms",
    1688                 :            :                              slave->name,
    1689                 :            :                              up ? "enabled" : "disabled",
    1690                 :            :                              up ? "up" : "down",
    1691                 :            :                              delay);
    1692                 :            :             }
    1693                 :            :         }
    1694                 :            :     }
    1695                 :            : 
    1696         [ +  + ]:      14728 :     if (time_msec() >= slave->delay_expires) {
    1697                 :         56 :         bond_enable_slave(slave, up);
    1698                 :            :     }
    1699                 :      14728 : }
    1700                 :            : 
    1701                 :            : static unsigned int
    1702                 :       6190 : bond_hash_src(const struct eth_addr mac, uint16_t vlan, uint32_t basis)
    1703                 :            : {
    1704                 :       6190 :     return hash_mac(mac, vlan, basis);
    1705                 :            : }
    1706                 :            : 
    1707                 :            : static unsigned int
    1708                 :        309 : bond_hash_tcp(const struct flow *flow, uint16_t vlan, uint32_t basis)
    1709                 :            : {
    1710                 :        309 :     struct flow hash_flow = *flow;
    1711                 :        309 :     hash_flow.vlan_tci = htons(vlan);
    1712                 :            : 
    1713                 :            :     /* The symmetric quality of this hash function is not required, but
    1714                 :            :      * flow_hash_symmetric_l4 already exists, and is sufficient for our
    1715                 :            :      * purposes, so we use it out of convenience. */
    1716                 :        309 :     return flow_hash_symmetric_l4(&hash_flow, basis);
    1717                 :            : }
    1718                 :            : 
    1719                 :            : static unsigned int
    1720                 :       6499 : bond_hash(const struct bond *bond, const struct flow *flow, uint16_t vlan)
    1721                 :            : {
    1722 [ +  + ][ -  + ]:       6499 :     ovs_assert(bond->balance == BM_TCP || bond->balance == BM_SLB);
    1723                 :            : 
    1724                 :       6499 :     return (bond->balance == BM_TCP
    1725                 :        309 :             ? bond_hash_tcp(flow, vlan, bond->basis)
    1726         [ +  + ]:       6499 :             : bond_hash_src(flow->dl_src, vlan, bond->basis));
    1727                 :            : }
    1728                 :            : 
    1729                 :            : static struct bond_entry *
    1730                 :       6499 : lookup_bond_entry(const struct bond *bond, const struct flow *flow,
    1731                 :            :                   uint16_t vlan)
    1732                 :            : {
    1733                 :       6499 :     return &bond->hash[bond_hash(bond, flow, vlan) & BOND_MASK];
    1734                 :            : }
    1735                 :            : 
    1736                 :            : /* Selects and returns an enabled slave from the 'enabled_slaves' list
    1737                 :            :  * in a round-robin fashion.  If the 'enabled_slaves' list is empty,
    1738                 :            :  * returns NULL. */
    1739                 :            : static struct bond_slave *
    1740                 :        110 : get_enabled_slave(struct bond *bond)
    1741                 :            : {
    1742                 :            :     struct ovs_list *node;
    1743                 :            : 
    1744                 :        110 :     ovs_mutex_lock(&bond->mutex);
    1745         [ +  + ]:        110 :     if (ovs_list_is_empty(&bond->enabled_slaves)) {
    1746                 :         25 :         ovs_mutex_unlock(&bond->mutex);
    1747                 :         25 :         return NULL;
    1748                 :            :     }
    1749                 :            : 
    1750                 :         85 :     node = ovs_list_pop_front(&bond->enabled_slaves);
    1751                 :         85 :     ovs_list_push_back(&bond->enabled_slaves, node);
    1752                 :         85 :     ovs_mutex_unlock(&bond->mutex);
    1753                 :            : 
    1754                 :         85 :     return CONTAINER_OF(node, struct bond_slave, list_node);
    1755                 :            : }
    1756                 :            : 
    1757                 :            : static struct bond_slave *
    1758                 :       6422 : choose_output_slave(const struct bond *bond, const struct flow *flow,
    1759                 :            :                     struct flow_wildcards *wc, uint16_t vlan)
    1760                 :            : {
    1761                 :            :     struct bond_entry *e;
    1762                 :            :     int balance;
    1763                 :            : 
    1764                 :       6422 :     balance = bond->balance;
    1765         [ -  + ]:       6422 :     if (bond->lacp_status == LACP_CONFIGURED) {
    1766                 :            :         /* LACP has been configured on this bond but negotiations were
    1767                 :            :          * unsuccussful. If lacp_fallback_ab is enabled use active-
    1768                 :            :          * backup mode else drop all traffic. */
    1769         [ #  # ]:          0 :         if (!bond->lacp_fallback_ab) {
    1770                 :          0 :             return NULL;
    1771                 :            :         }
    1772                 :          0 :         balance = BM_AB;
    1773                 :            :     }
    1774                 :            : 
    1775   [ +  +  +  - ]:       6422 :     switch (balance) {
    1776                 :            :     case BM_AB:
    1777                 :         26 :         return bond->active_slave;
    1778                 :            : 
    1779                 :            :     case BM_TCP:
    1780         [ -  + ]:        309 :         if (bond->lacp_status != LACP_NEGOTIATED) {
    1781                 :            :             /* Must have LACP negotiations for TCP balanced bonds. */
    1782                 :          0 :             return NULL;
    1783                 :            :         }
    1784         [ -  + ]:        309 :         if (wc) {
    1785                 :          0 :             flow_mask_hash_fields(flow, wc, NX_HASH_FIELDS_SYMMETRIC_L4);
    1786                 :            :         }
    1787                 :            :         /* Fall Through. */
    1788                 :            :     case BM_SLB:
    1789         [ +  + ]:       6396 :         if (wc) {
    1790                 :       6087 :             flow_mask_hash_fields(flow, wc, NX_HASH_FIELDS_ETH_SRC);
    1791                 :            :         }
    1792                 :       6396 :         e = lookup_bond_entry(bond, flow, vlan);
    1793 [ +  + ][ +  + ]:       6396 :         if (!e->slave || !e->slave->enabled) {
    1794                 :        110 :             e->slave = get_enabled_slave(CONST_CAST(struct bond*, bond));
    1795                 :            :         }
    1796                 :       6396 :         return e->slave;
    1797                 :            : 
    1798                 :            :     default:
    1799                 :          0 :         OVS_NOT_REACHED();
    1800                 :            :     }
    1801                 :            : }
    1802                 :            : 
    1803                 :            : static struct bond_slave *
    1804                 :        400 : bond_choose_slave(const struct bond *bond)
    1805                 :            : {
    1806                 :            :     struct bond_slave *slave, *best;
    1807                 :            : 
    1808                 :            :     /* Find the last active slave. */
    1809                 :        400 :     slave = bond_find_slave_by_mac(bond, bond->active_slave_mac);
    1810 [ +  + ][ -  + ]:        400 :     if (slave && slave->enabled) {
    1811                 :          0 :         return slave;
    1812                 :            :     }
    1813                 :            : 
    1814                 :            :     /* Find an enabled slave. */
    1815 [ +  + ][ -  + ]:       1157 :     HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
    1816         [ +  + ]:        784 :         if (slave->enabled) {
    1817                 :         27 :             return slave;
    1818                 :            :         }
    1819                 :            :     }
    1820                 :            : 
    1821                 :            :     /* All interfaces are disabled.  Find an interface that will be enabled
    1822                 :            :      * after its updelay expires.  */
    1823                 :        373 :     best = NULL;
    1824 [ +  + ][ -  + ]:       1128 :     HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
    1825         [ -  + ]:        755 :         if (slave->delay_expires != LLONG_MAX
    1826         [ #  # ]:          0 :             && slave->may_enable
    1827 [ #  # ][ #  # ]:          0 :             && (!best || slave->delay_expires < best->delay_expires)) {
    1828                 :          0 :             best = slave;
    1829                 :            :         }
    1830                 :            :     }
    1831                 :        373 :     return best;
    1832                 :            : }
    1833                 :            : 
    1834                 :            : static void
    1835                 :        400 : bond_choose_active_slave(struct bond *bond)
    1836                 :            : {
    1837                 :            :     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
    1838                 :        400 :     struct bond_slave *old_active_slave = bond->active_slave;
    1839                 :            : 
    1840                 :        400 :     bond->active_slave = bond_choose_slave(bond);
    1841         [ +  + ]:        400 :     if (bond->active_slave) {
    1842         [ +  - ]:         27 :         if (bond->active_slave->enabled) {
    1843         [ +  - ]:         27 :             VLOG_INFO_RL(&rl, "bond %s: active interface is now %s",
    1844                 :            :                          bond->name, bond->active_slave->name);
    1845                 :            :         } else {
    1846         [ #  # ]:          0 :             VLOG_INFO_RL(&rl, "bond %s: active interface is now %s, skipping "
    1847                 :            :                          "remaining %lld ms updelay (since no interface was "
    1848                 :            :                          "enabled)", bond->name, bond->active_slave->name,
    1849                 :            :                          bond->active_slave->delay_expires - time_msec());
    1850                 :          0 :             bond_enable_slave(bond->active_slave, true);
    1851                 :            :         }
    1852                 :            : 
    1853                 :         27 :         bond->send_learning_packets = true;
    1854                 :            : 
    1855         [ +  - ]:         27 :         if (bond->active_slave != old_active_slave) {
    1856                 :         27 :             bond_active_slave_changed(bond);
    1857                 :            :         }
    1858         [ +  + ]:        373 :     } else if (old_active_slave) {
    1859         [ +  - ]:         17 :         VLOG_INFO_RL(&rl, "bond %s: all interfaces disabled", bond->name);
    1860                 :            :     }
    1861                 :        400 : }
    1862                 :            : 
    1863                 :            : /*
    1864                 :            :  * Return true if bond has unstored active slave change.
    1865                 :            :  * If return true, 'mac' will store the bond's current active slave's
    1866                 :            :  * MAC address.  */
    1867                 :            : bool
    1868                 :        102 : bond_get_changed_active_slave(const char *name, struct eth_addr *mac,
    1869                 :            :                               bool force)
    1870                 :            : {
    1871                 :            :     struct bond *bond;
    1872                 :            : 
    1873                 :        102 :     ovs_rwlock_wrlock(&rwlock);
    1874                 :        102 :     bond = bond_find(name);
    1875         [ +  - ]:        102 :     if (bond) {
    1876 [ +  + ][ +  + ]:        102 :         if (bond->active_slave_changed || force) {
    1877                 :         46 :             *mac = bond->active_slave_mac;
    1878                 :         46 :             bond->active_slave_changed = false;
    1879                 :         46 :             ovs_rwlock_unlock(&rwlock);
    1880                 :         46 :             return true;
    1881                 :            :         }
    1882                 :            :     }
    1883                 :         56 :     ovs_rwlock_unlock(&rwlock);
    1884                 :            : 
    1885                 :         56 :     return false;
    1886                 :            : }

Generated by: LCOV version 1.12