~james-page/ubuntu/saucy/openvswitch/1.12-snapshot

« back to all changes in this revision

Viewing changes to lib/bond.c

  • Committer: James Page
  • Date: 2013-08-21 10:16:57 UTC
  • mfrom: (1.1.20)
  • Revision ID: james.page@canonical.com-20130821101657-3o0z0qeiv5zkwlzi
New upstream snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
75
75
    struct list bal_node;       /* In bond_rebalance()'s 'bals' list. */
76
76
    struct list entries;        /* 'struct bond_entry's assigned here. */
77
77
    uint64_t tx_bytes;          /* Sum across 'tx_bytes' of entries. */
78
 
 
79
 
    /* BM_STABLE specific bonding info. */
80
 
    uint32_t stb_id;            /* ID used for 'stb_slaves' ordering. */
81
78
};
82
79
 
83
80
/* A bond, that is, a set of network devices grouped to improve performance or
104
101
    long long int next_rebalance; /* Next rebalancing time. */
105
102
    bool send_learning_packets;
106
103
 
107
 
    /* BM_STABLE specific bonding info. */
108
 
    tag_type stb_tag;               /* Tag associated with this bond. */
109
 
 
110
104
    /* Legacy compatibility. */
111
105
    long long int next_fake_iface_update; /* LLONG_MAX if disabled. */
112
106
 
114
108
     * where we can't otherwise provide revalidation feedback to the client.
115
109
     * That's only unixctl commands now; I hope no other cases will arise. */
116
110
    struct tag_set unixctl_tags;
 
111
 
 
112
    atomic_int ref_cnt;
117
113
};
118
114
 
119
 
static struct hmap all_bonds = HMAP_INITIALIZER(&all_bonds);
 
115
static struct ovs_rwlock rwlock = OVS_RWLOCK_INITIALIZER;
 
116
static struct hmap all_bonds__ = HMAP_INITIALIZER(&all_bonds__);
 
117
static struct hmap *const all_bonds OVS_GUARDED_BY(rwlock) = &all_bonds__;
120
118
 
121
 
static void bond_entry_reset(struct bond *);
122
 
static struct bond_slave *bond_slave_lookup(struct bond *, const void *slave_);
 
119
static void bond_entry_reset(struct bond *) OVS_REQ_WRLOCK(rwlock);
 
120
static struct bond_slave *bond_slave_lookup(struct bond *, const void *slave_)
 
121
    OVS_REQ_RDLOCK(rwlock);
123
122
static void bond_enable_slave(struct bond_slave *, bool enable,
124
 
                              struct tag_set *);
125
 
static void bond_link_status_update(struct bond_slave *, struct tag_set *);
126
 
static void bond_choose_active_slave(struct bond *, struct tag_set *);
 
123
                              struct tag_set *) OVS_REQ_WRLOCK(rwlock);
 
124
static void bond_link_status_update(struct bond_slave *, struct tag_set *)
 
125
    OVS_REQ_WRLOCK(rwlock);
 
126
static void bond_choose_active_slave(struct bond *, struct tag_set *)
 
127
    OVS_REQ_WRLOCK(rwlock);;
127
128
static unsigned int bond_hash_src(const uint8_t mac[ETH_ADDR_LEN],
128
129
                                  uint16_t vlan, uint32_t basis);
129
130
static unsigned int bond_hash_tcp(const struct flow *, uint16_t vlan,
130
131
                                  uint32_t basis);
131
132
static struct bond_entry *lookup_bond_entry(const struct bond *,
132
133
                                            const struct flow *,
133
 
                                            uint16_t vlan);
134
 
static tag_type bond_get_active_slave_tag(const struct bond *);
 
134
                                            uint16_t vlan)
 
135
    OVS_REQ_RDLOCK(rwlock);
 
136
static tag_type bond_get_active_slave_tag(const struct bond *)
 
137
    OVS_REQ_RDLOCK(rwlock);
135
138
static struct bond_slave *choose_output_slave(const struct bond *,
136
139
                                              const struct flow *,
137
 
                                              uint16_t vlan, tag_type *tags);
138
 
static void bond_update_fake_slave_stats(struct bond *);
 
140
                                              struct flow_wildcards *,
 
141
                                              uint16_t vlan, tag_type *tags)
 
142
    OVS_REQ_RDLOCK(rwlock);
 
143
static void bond_update_fake_slave_stats(struct bond *)
 
144
    OVS_REQ_RDLOCK(rwlock);
139
145
 
140
146
/* Attempts to parse 's' as the name of a bond balancing mode.  If successful,
141
147
 * stores the mode in '*balance' and returns true.  Otherwise returns false
147
153
        *balance = BM_TCP;
148
154
    } else if (!strcmp(s, bond_mode_to_string(BM_SLB))) {
149
155
        *balance = BM_SLB;
150
 
    } else if (!strcmp(s, bond_mode_to_string(BM_STABLE))) {
151
 
        *balance = BM_STABLE;
152
156
    } else if (!strcmp(s, bond_mode_to_string(BM_AB))) {
153
157
        *balance = BM_AB;
154
158
    } else {
165
169
        return "balance-tcp";
166
170
    case BM_SLB:
167
171
        return "balance-slb";
168
 
    case BM_STABLE:
169
 
        return "stable";
170
172
    case BM_AB:
171
173
        return "active-backup";
172
174
    }
187
189
    bond = xzalloc(sizeof *bond);
188
190
    hmap_init(&bond->slaves);
189
191
    bond->no_slaves_tag = tag_create_random();
190
 
    bond->stb_tag = tag_create_random();
191
192
    bond->next_fake_iface_update = LLONG_MAX;
 
193
    atomic_init(&bond->ref_cnt, 1);
192
194
 
193
195
    bond_reconfigure(bond, s);
194
196
 
197
199
    return bond;
198
200
}
199
201
 
 
202
struct bond *
 
203
bond_ref(const struct bond *bond_)
 
204
{
 
205
    struct bond *bond = CONST_CAST(struct bond *, bond_);
 
206
 
 
207
    if (bond) {
 
208
        int orig;
 
209
        atomic_add(&bond->ref_cnt, 1, &orig);
 
210
        ovs_assert(orig > 0);
 
211
    }
 
212
    return bond;
 
213
}
 
214
 
200
215
/* Frees 'bond'. */
201
216
void
202
 
bond_destroy(struct bond *bond)
 
217
bond_unref(struct bond *bond)
203
218
{
204
219
    struct bond_slave *slave, *next_slave;
 
220
    int orig;
205
221
 
206
222
    if (!bond) {
207
223
        return;
208
224
    }
209
225
 
210
 
    hmap_remove(&all_bonds, &bond->hmap_node);
 
226
    atomic_sub(&bond->ref_cnt, 1, &orig);
 
227
    ovs_assert(orig > 0);
 
228
    if (orig != 1) {
 
229
        return;
 
230
    }
 
231
 
 
232
    ovs_rwlock_wrlock(&rwlock);
 
233
    hmap_remove(all_bonds, &bond->hmap_node);
 
234
    ovs_rwlock_unlock(&rwlock);
211
235
 
212
236
    HMAP_FOR_EACH_SAFE (slave, next_slave, hmap_node, &bond->slaves) {
213
237
        hmap_remove(&bond->slaves, &slave->hmap_node);
236
260
{
237
261
    bool revalidate = false;
238
262
 
 
263
    ovs_rwlock_wrlock(&rwlock);
239
264
    if (!bond->name || strcmp(bond->name, s->name)) {
240
265
        if (bond->name) {
241
 
            hmap_remove(&all_bonds, &bond->hmap_node);
 
266
            hmap_remove(all_bonds, &bond->hmap_node);
242
267
            free(bond->name);
243
268
        }
244
269
        bond->name = xstrdup(s->name);
245
 
        hmap_insert(&all_bonds, &bond->hmap_node, hash_string(bond->name, 0));
 
270
        hmap_insert(all_bonds, &bond->hmap_node, hash_string(bond->name, 0));
246
271
    }
247
272
 
248
273
    bond->updelay = s->up_delay;
256
281
    if (bond->balance != s->balance) {
257
282
        bond->balance = s->balance;
258
283
        revalidate = true;
259
 
 
260
 
        if (bond->balance == BM_STABLE) {
261
 
            VLOG_WARN_ONCE("Stable bond mode is deprecated and may be removed"
262
 
                           " in February 2013. Please email"
263
 
                           " dev@openvswitch.org with concerns.");
264
 
        }
265
284
    }
266
285
 
267
286
    if (bond->basis != s->basis) {
286
305
        bond_entry_reset(bond);
287
306
    }
288
307
 
 
308
    ovs_rwlock_unlock(&rwlock);
289
309
    return revalidate;
290
310
}
291
311
 
292
312
static void
293
313
bond_slave_set_netdev__(struct bond_slave *slave, struct netdev *netdev)
 
314
    OVS_REQ_WRLOCK(rwlock)
294
315
{
295
316
    if (slave->netdev != netdev) {
296
317
        slave->netdev = netdev;
303
324
 * bond.  If 'slave_' already exists within 'bond' then this function
304
325
 * reconfigures the existing slave.
305
326
 *
306
 
 * 'stb_id' is used in BM_STABLE bonds to guarantee consistent slave choices
307
 
 * across restarts and distributed vswitch instances.  It should be unique per
308
 
 * slave, and preferably consistent across restarts and reconfigurations.
309
 
 *
310
327
 * 'netdev' must be the network device that 'slave_' represents.  It is owned
311
328
 * by the client, so the client must not close it before either unregistering
312
329
 * 'slave_' or destroying 'bond'.
313
330
 */
314
331
void
315
 
bond_slave_register(struct bond *bond, void *slave_, uint32_t stb_id,
316
 
                    struct netdev *netdev)
 
332
bond_slave_register(struct bond *bond, void *slave_, struct netdev *netdev)
317
333
{
318
 
    struct bond_slave *slave = bond_slave_lookup(bond, slave_);
 
334
    struct bond_slave *slave;
319
335
 
 
336
    ovs_rwlock_wrlock(&rwlock);
 
337
    slave = bond_slave_lookup(bond, slave_);
320
338
    if (!slave) {
321
339
        slave = xzalloc(sizeof *slave);
322
340
 
331
349
        bond_enable_slave(slave, netdev_get_carrier(netdev), NULL);
332
350
    }
333
351
 
334
 
    if (slave->stb_id != stb_id) {
335
 
        slave->stb_id = stb_id;
336
 
        bond->bond_revalidate = true;
337
 
    }
338
 
 
339
352
    bond_slave_set_netdev__(slave, netdev);
340
353
 
341
354
    free(slave->name);
342
355
    slave->name = xstrdup(netdev_get_name(netdev));
 
356
    ovs_rwlock_unlock(&rwlock);
343
357
}
344
358
 
345
359
/* Updates the network device to be used with 'slave_' to 'netdev'.
350
364
void
351
365
bond_slave_set_netdev(struct bond *bond, void *slave_, struct netdev *netdev)
352
366
{
353
 
    struct bond_slave *slave = bond_slave_lookup(bond, slave_);
 
367
    struct bond_slave *slave;
 
368
 
 
369
    ovs_rwlock_wrlock(&rwlock);
 
370
    slave = bond_slave_lookup(bond, slave_);
354
371
    if (slave) {
355
372
        bond_slave_set_netdev__(slave, netdev);
356
373
    }
 
374
    ovs_rwlock_unlock(&rwlock);
357
375
}
358
376
 
359
377
/* Unregisters 'slave_' from 'bond'.  If 'bond' does not contain such a slave
363
381
void
364
382
bond_slave_unregister(struct bond *bond, const void *slave_)
365
383
{
366
 
    struct bond_slave *slave = bond_slave_lookup(bond, slave_);
 
384
    struct bond_slave *slave;
367
385
    bool del_active;
368
386
 
 
387
    ovs_rwlock_wrlock(&rwlock);
 
388
    slave = bond_slave_lookup(bond, slave_);
369
389
    if (!slave) {
370
 
        return;
 
390
        goto out;
371
391
    }
372
392
 
373
393
    bond_enable_slave(slave, false, NULL);
395
415
        bond_choose_active_slave(bond, &tags);
396
416
        bond->send_learning_packets = true;
397
417
    }
 
418
out:
 
419
    ovs_rwlock_unlock(&rwlock);
398
420
}
399
421
 
400
422
/* Should be called on each slave in 'bond' before bond_run() to indicate
405
427
void
406
428
bond_slave_set_may_enable(struct bond *bond, void *slave_, bool may_enable)
407
429
{
 
430
    ovs_rwlock_wrlock(&rwlock);
408
431
    bond_slave_lookup(bond, slave_)->may_enable = may_enable;
 
432
    ovs_rwlock_unlock(&rwlock);
409
433
}
410
434
 
411
435
/* Performs periodic maintenance on 'bond'.  The caller must provide 'tags' to
417
441
{
418
442
    struct bond_slave *slave;
419
443
 
 
444
    ovs_rwlock_wrlock(&rwlock);
420
445
    if (bond->lacp_status != lacp_status) {
421
446
        bond->lacp_status = lacp_status;
422
447
        bond->bond_revalidate = true;
438
463
    }
439
464
 
440
465
    if (bond->bond_revalidate) {
 
466
        struct bond_slave *slave;
 
467
 
441
468
        bond->bond_revalidate = false;
442
 
 
443
469
        bond_entry_reset(bond);
444
 
        if (bond->balance != BM_STABLE) {
445
 
            struct bond_slave *slave;
446
 
 
447
 
            HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
448
 
                tag_set_add(tags, slave->tag);
449
 
            }
450
 
        } else {
451
 
            tag_set_add(tags, bond->stb_tag);
 
470
        HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
 
471
            tag_set_add(tags, slave->tag);
452
472
        }
453
473
        tag_set_add(tags, bond->no_slaves_tag);
454
474
    }
456
476
    /* Invalidate any tags required by  */
457
477
    tag_set_union(tags, &bond->unixctl_tags);
458
478
    tag_set_init(&bond->unixctl_tags);
 
479
    ovs_rwlock_unlock(&rwlock);
459
480
}
460
481
 
461
482
/* Causes poll_block() to wake up when 'bond' needs something to be done. */
464
485
{
465
486
    struct bond_slave *slave;
466
487
 
 
488
    ovs_rwlock_rdlock(&rwlock);
467
489
    HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
468
490
        if (slave->delay_expires != LLONG_MAX) {
469
491
            poll_timer_wait_until(slave->delay_expires);
482
504
    if (!tag_set_is_empty(&bond->unixctl_tags)) {
483
505
        poll_immediate_wake();
484
506
    }
 
507
    ovs_rwlock_unlock(&rwlock);
485
508
 
486
509
    /* We don't wait for bond->next_rebalance because rebalancing can only run
487
510
     * at a flow account checkpoint.  ofproto does checkpointing on its own
513
536
bool
514
537
bond_should_send_learning_packets(struct bond *bond)
515
538
{
516
 
    bool send = bond->send_learning_packets && may_send_learning_packets(bond);
 
539
    bool send;
 
540
 
 
541
    ovs_rwlock_wrlock(&rwlock);
 
542
    send = bond->send_learning_packets && may_send_learning_packets(bond);
517
543
    bond->send_learning_packets = false;
 
544
    ovs_rwlock_unlock(&rwlock);
518
545
    return send;
519
546
}
520
547
 
533
560
    tag_type tags = 0;
534
561
    struct flow flow;
535
562
 
 
563
    ovs_rwlock_rdlock(&rwlock);
536
564
    ovs_assert(may_send_learning_packets(bond));
537
 
 
538
565
    memset(&flow, 0, sizeof flow);
539
566
    memcpy(flow.dl_src, eth_src, ETH_ADDR_LEN);
540
 
    slave = choose_output_slave(bond, &flow, vlan, &tags);
 
567
    slave = choose_output_slave(bond, &flow, NULL, vlan, &tags);
541
568
 
542
569
    packet = ofpbuf_new(0);
543
570
    compose_rarp(packet, eth_src);
546
573
    }
547
574
 
548
575
    *port_aux = slave->aux;
 
576
    ovs_rwlock_unlock(&rwlock);
549
577
    return packet;
550
578
}
551
579
 
568
596
bond_check_admissibility(struct bond *bond, const void *slave_,
569
597
                         const uint8_t eth_dst[ETH_ADDR_LEN], tag_type *tags)
570
598
{
571
 
    struct bond_slave *slave = bond_slave_lookup(bond, slave_);
 
599
    enum bond_verdict verdict = BV_DROP;
 
600
    struct bond_slave *slave;
 
601
 
 
602
    ovs_rwlock_rdlock(&rwlock);
 
603
    slave = bond_slave_lookup(bond, slave_);
 
604
    if (!slave) {
 
605
        goto out;
 
606
    }
572
607
 
573
608
    /* LACP bonds have very loose admissibility restrictions because we can
574
609
     * assume the remote switch is aware of the bond and will "do the right
579
614
     * If LACP is configured, but LACP negotiations have been unsuccessful, we
580
615
     * drop all incoming traffic. */
581
616
    switch (bond->lacp_status) {
582
 
    case LACP_NEGOTIATED: return slave->enabled ? BV_ACCEPT : BV_DROP;
583
 
    case LACP_CONFIGURED: return BV_DROP;
584
 
    case LACP_DISABLED: break;
 
617
    case LACP_NEGOTIATED:
 
618
        verdict = slave->enabled ? BV_ACCEPT : BV_DROP;
 
619
        goto out;
 
620
    case LACP_CONFIGURED:
 
621
        goto out;
 
622
    case LACP_DISABLED:
 
623
        break;
585
624
    }
586
625
 
587
626
    /* Drop all multicast packets on inactive slaves. */
588
627
    if (eth_addr_is_multicast(eth_dst)) {
589
628
        *tags |= bond_get_active_slave_tag(bond);
590
 
        if (bond->active_slave != bond_slave_lookup(bond, slave_)) {
591
 
            return BV_DROP;
 
629
        if (bond->active_slave != slave) {
 
630
            goto out;
592
631
        }
593
632
    }
594
633
 
603
642
            VLOG_DBG_RL(&rl, "active-backup bond received packet on backup"
604
643
                        " slave (%s) destined for " ETH_ADDR_FMT,
605
644
                        slave->name, ETH_ADDR_ARGS(eth_dst));
606
 
            return BV_DROP;
 
645
            goto out;
607
646
        }
608
 
        return BV_ACCEPT;
 
647
        verdict = BV_ACCEPT;
 
648
        goto out;
609
649
 
610
650
    case BM_TCP:
611
651
        /* TCP balanced bonds require successful LACP negotiated. Based on the
612
652
         * above check, LACP is off on this bond.  Therfore, we drop all
613
653
         * incoming traffic. */
614
 
        return BV_DROP;
 
654
        goto out;
615
655
 
616
656
    case BM_SLB:
617
657
        /* Drop all packets for which we have learned a different input port,
620
660
         * the host has moved to another switch.  The exception to the
621
661
         * exception is if we locked the learning table to avoid reflections on
622
662
         * bond slaves. */
623
 
        return BV_DROP_IF_MOVED;
624
 
 
625
 
    case BM_STABLE:
626
 
        return BV_ACCEPT;
 
663
        verdict = BV_DROP_IF_MOVED;
 
664
        goto out;
627
665
    }
628
666
 
629
667
    NOT_REACHED();
 
668
out:
 
669
    ovs_rwlock_unlock(&rwlock);
 
670
    return verdict;
 
671
 
630
672
}
631
673
 
632
674
/* Returns the slave (registered on 'bond' by bond_slave_register()) to which
640
682
 * packet belongs to (so for an access port it will be the access port's VLAN).
641
683
 *
642
684
 * Adds a tag to '*tags' that associates the flow with the returned slave.
 
685
 *
 
686
 * If 'wc' is non-NULL, bitwise-OR's 'wc' with the set of bits that were
 
687
 * significant in the selection.  At some point earlier, 'wc' should
 
688
 * have been initialized (e.g., by flow_wildcards_init_catchall()).
643
689
 */
644
690
void *
645
691
bond_choose_output_slave(struct bond *bond, const struct flow *flow,
646
 
                         uint16_t vlan, tag_type *tags)
 
692
                         struct flow_wildcards *wc, uint16_t vlan,
 
693
                         tag_type *tags)
647
694
{
648
 
    struct bond_slave *slave = choose_output_slave(bond, flow, vlan, tags);
 
695
    struct bond_slave *slave;
 
696
    void *result = NULL;
 
697
 
 
698
    ovs_rwlock_rdlock(&rwlock);
 
699
    slave = choose_output_slave(bond, flow, wc, vlan, tags);
649
700
    if (slave) {
650
 
        *tags |= bond->balance == BM_STABLE ? bond->stb_tag : slave->tag;
651
 
        return slave->aux;
 
701
        *tags |= slave->tag;
 
702
        result = slave->aux;
652
703
    } else {
653
704
        *tags |= bond->no_slaves_tag;
654
 
        return NULL;
655
705
    }
 
706
    ovs_rwlock_unlock(&rwlock);
 
707
    return result;
656
708
}
657
709
 
658
710
/* Rebalancing. */
659
711
 
660
712
static bool
661
 
bond_is_balanced(const struct bond *bond)
 
713
bond_is_balanced(const struct bond *bond) OVS_REQ_RDLOCK(rwlock)
662
714
{
663
715
    return bond->rebalance_interval
664
716
        && (bond->balance == BM_SLB || bond->balance == BM_TCP);
669
721
bond_account(struct bond *bond, const struct flow *flow, uint16_t vlan,
670
722
             uint64_t n_bytes)
671
723
{
 
724
    ovs_rwlock_wrlock(&rwlock);
672
725
    if (bond_is_balanced(bond)) {
673
726
        lookup_bond_entry(bond, flow, vlan)->tx_bytes += n_bytes;
674
727
    }
 
728
    ovs_rwlock_unlock(&rwlock);
675
729
}
676
730
 
677
731
static struct bond_slave *
678
 
bond_slave_from_bal_node(struct list *bal)
 
732
bond_slave_from_bal_node(struct list *bal) OVS_REQ_RDLOCK(rwlock)
679
733
{
680
734
    return CONTAINER_OF(bal, struct bond_slave, bal_node);
681
735
}
821
875
    struct bond_entry *e;
822
876
    struct list bals;
823
877
 
 
878
    ovs_rwlock_wrlock(&rwlock);
824
879
    if (!bond_is_balanced(bond) || time_msec() < bond->next_rebalance) {
 
880
        ovs_rwlock_unlock(&rwlock);
825
881
        return;
826
882
    }
827
883
    bond->next_rebalance = time_msec() + bond->rebalance_interval;
897
953
            e->slave = NULL;
898
954
        }
899
955
    }
 
956
    ovs_rwlock_unlock(&rwlock);
900
957
}
901
958
 
902
959
/* Bonding unixctl user interface functions. */
903
960
 
904
961
static struct bond *
905
 
bond_find(const char *name)
 
962
bond_find(const char *name) OVS_REQ_RDLOCK(rwlock)
906
963
{
907
964
    struct bond *bond;
908
965
 
909
966
    HMAP_FOR_EACH_WITH_HASH (bond, hmap_node, hash_string(name, 0),
910
 
                             &all_bonds) {
 
967
                             all_bonds) {
911
968
        if (!strcmp(bond->name, name)) {
912
969
            return bond;
913
970
        }
938
995
 
939
996
    ds_put_cstr(&ds, "bond\ttype\tslaves\n");
940
997
 
941
 
    HMAP_FOR_EACH (bond, hmap_node, &all_bonds) {
 
998
    ovs_rwlock_rdlock(&rwlock);
 
999
    HMAP_FOR_EACH (bond, hmap_node, all_bonds) {
942
1000
        const struct bond_slave *slave;
943
1001
        size_t i;
944
1002
 
954
1012
        }
955
1013
        ds_put_char(&ds, '\n');
956
1014
    }
 
1015
    ovs_rwlock_unlock(&rwlock);
957
1016
    unixctl_command_reply(conn, ds_cstr(&ds));
958
1017
    ds_destroy(&ds);
959
1018
}
960
1019
 
961
1020
static void
962
1021
bond_print_details(struct ds *ds, const struct bond *bond)
 
1022
    OVS_REQ_RDLOCK(rwlock)
963
1023
{
964
1024
    struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
965
1025
    const struct shash_node **sorted_slaves = NULL;
1051
1111
{
1052
1112
    struct ds ds = DS_EMPTY_INITIALIZER;
1053
1113
 
 
1114
    ovs_rwlock_rdlock(&rwlock);
1054
1115
    if (argc > 1) {
1055
1116
        const struct bond *bond = bond_find(argv[1]);
1056
1117
 
1057
1118
        if (!bond) {
1058
1119
            unixctl_command_reply_error(conn, "no such bond");
1059
 
            return;
 
1120
            goto out;
1060
1121
        }
1061
1122
        bond_print_details(&ds, bond);
1062
1123
    } else {
1063
1124
        const struct bond *bond;
1064
1125
 
1065
 
        HMAP_FOR_EACH (bond, hmap_node, &all_bonds) {
 
1126
        HMAP_FOR_EACH (bond, hmap_node, all_bonds) {
1066
1127
            bond_print_details(&ds, bond);
1067
1128
        }
1068
1129
    }
1069
1130
 
1070
1131
    unixctl_command_reply(conn, ds_cstr(&ds));
1071
1132
    ds_destroy(&ds);
 
1133
 
 
1134
out:
 
1135
    ovs_rwlock_unlock(&rwlock);
1072
1136
}
1073
1137
 
1074
1138
static void
1084
1148
    struct bond_entry *entry;
1085
1149
    int hash;
1086
1150
 
 
1151
    ovs_rwlock_wrlock(&rwlock);
1087
1152
    bond = bond_find(bond_s);
1088
1153
    if (!bond) {
1089
1154
        unixctl_command_reply_error(conn, "no such bond");
1090
 
        return;
 
1155
        goto out;
1091
1156
    }
1092
1157
 
1093
1158
    if (bond->balance != BM_SLB) {
1094
1159
        unixctl_command_reply_error(conn, "not an SLB bond");
1095
 
        return;
 
1160
        goto out;
1096
1161
    }
1097
1162
 
1098
1163
    if (strspn(hash_s, "0123456789") == strlen(hash_s)) {
1099
1164
        hash = atoi(hash_s) & BOND_MASK;
1100
1165
    } else {
1101
1166
        unixctl_command_reply_error(conn, "bad hash");
1102
 
        return;
 
1167
        goto out;
1103
1168
    }
1104
1169
 
1105
1170
    slave = bond_lookup_slave(bond, slave_s);
1106
1171
    if (!slave) {
1107
1172
        unixctl_command_reply_error(conn, "no such slave");
1108
 
        return;
 
1173
        goto out;
1109
1174
    }
1110
1175
 
1111
1176
    if (!slave->enabled) {
1112
1177
        unixctl_command_reply_error(conn, "cannot migrate to disabled slave");
1113
 
        return;
 
1178
        goto out;
1114
1179
    }
1115
1180
 
1116
1181
    entry = &bond->hash[hash];
1118
1183
    entry->slave = slave;
1119
1184
    entry->tag = tag_create_random();
1120
1185
    unixctl_command_reply(conn, "migrated");
 
1186
 
 
1187
out:
 
1188
    ovs_rwlock_unlock(&rwlock);
1121
1189
}
1122
1190
 
1123
1191
static void
1130
1198
    struct bond *bond;
1131
1199
    struct bond_slave *slave;
1132
1200
 
 
1201
    ovs_rwlock_wrlock(&rwlock);
1133
1202
    bond = bond_find(bond_s);
1134
1203
    if (!bond) {
1135
1204
        unixctl_command_reply_error(conn, "no such bond");
1136
 
        return;
 
1205
        goto out;
1137
1206
    }
1138
1207
 
1139
1208
    slave = bond_lookup_slave(bond, slave_s);
1140
1209
    if (!slave) {
1141
1210
        unixctl_command_reply_error(conn, "no such slave");
1142
 
        return;
 
1211
        goto out;
1143
1212
    }
1144
1213
 
1145
1214
    if (!slave->enabled) {
1146
1215
        unixctl_command_reply_error(conn, "cannot make disabled slave active");
1147
 
        return;
 
1216
        goto out;
1148
1217
    }
1149
1218
 
1150
1219
    if (bond->active_slave != slave) {
1158
1227
    } else {
1159
1228
        unixctl_command_reply(conn, "no change");
1160
1229
    }
 
1230
out:
 
1231
    ovs_rwlock_unlock(&rwlock);
1161
1232
}
1162
1233
 
1163
1234
static void
1168
1239
    struct bond *bond;
1169
1240
    struct bond_slave *slave;
1170
1241
 
 
1242
    ovs_rwlock_wrlock(&rwlock);
1171
1243
    bond = bond_find(bond_s);
1172
1244
    if (!bond) {
1173
1245
        unixctl_command_reply_error(conn, "no such bond");
1174
 
        return;
 
1246
        goto out;
1175
1247
    }
1176
1248
 
1177
1249
    slave = bond_lookup_slave(bond, slave_s);
1178
1250
    if (!slave) {
1179
1251
        unixctl_command_reply_error(conn, "no such slave");
1180
 
        return;
 
1252
        goto out;
1181
1253
    }
1182
1254
 
1183
1255
    bond_enable_slave(slave, enable, &bond->unixctl_tags);
1184
1256
    unixctl_command_reply(conn, enable ? "enabled" : "disabled");
 
1257
 
 
1258
out:
 
1259
    ovs_rwlock_unlock(&rwlock);
1185
1260
}
1186
1261
 
1187
1262
static void
1297
1372
static void
1298
1373
bond_enable_slave(struct bond_slave *slave, bool enable, struct tag_set *tags)
1299
1374
{
1300
 
    struct bond *bond = slave->bond;
1301
1375
    slave->delay_expires = LLONG_MAX;
1302
1376
    if (enable != slave->enabled) {
1303
1377
        slave->enabled = enable;
1304
1378
        if (!slave->enabled) {
1305
 
            VLOG_WARN("interface %s: disabled", slave->name);
 
1379
            VLOG_INFO("interface %s: disabled", slave->name);
1306
1380
            if (tags) {
1307
1381
                tag_set_add(tags, slave->tag);
1308
1382
            }
1309
1383
        } else {
1310
 
            VLOG_WARN("interface %s: enabled", slave->name);
 
1384
            VLOG_INFO("interface %s: enabled", slave->name);
1311
1385
            slave->tag = tag_create_random();
1312
1386
        }
1313
 
 
1314
 
        if (bond->balance == BM_STABLE) {
1315
 
            bond->bond_revalidate = true;
1316
 
        }
1317
1387
    }
1318
1388
}
1319
1389
 
1387
1457
    return &bond->hash[bond_hash(bond, flow, vlan) & BOND_MASK];
1388
1458
}
1389
1459
 
1390
 
/* This function uses Highest Random Weight hashing to choose an output slave.
1391
 
 * This approach only reassigns a minimal number of flows when slaves are
1392
 
 * enabled or disabled.  Unfortunately, it has O(n) performance against the
1393
 
 * number of slaves.  There exist algorithms which are O(1), but have slightly
1394
 
 * more complex implementations and require the use of memory.  This may need
1395
 
 * to be reimplemented if it becomes a performance bottleneck. */
1396
 
static struct bond_slave *
1397
 
choose_stb_slave(const struct bond *bond, uint32_t flow_hash)
1398
 
{
1399
 
    struct bond_slave *best, *slave;
1400
 
    uint32_t best_hash;
1401
 
 
1402
 
    best = NULL;
1403
 
    best_hash = 0;
1404
 
    HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
1405
 
        if (slave->enabled) {
1406
 
            uint32_t hash;
1407
 
 
1408
 
            hash = hash_2words(flow_hash, slave->stb_id);
1409
 
            if (!best || hash > best_hash) {
1410
 
                best = slave;
1411
 
                best_hash = hash;
1412
 
            }
1413
 
        }
1414
 
    }
1415
 
 
1416
 
    return best;
1417
 
}
1418
 
 
1419
1460
static struct bond_slave *
1420
1461
choose_output_slave(const struct bond *bond, const struct flow *flow,
1421
 
                    uint16_t vlan, tag_type *tags)
 
1462
                    struct flow_wildcards *wc, uint16_t vlan, tag_type *tags)
1422
1463
{
1423
1464
    struct bond_entry *e;
1424
1465
 
1432
1473
    case BM_AB:
1433
1474
        return bond->active_slave;
1434
1475
 
1435
 
    case BM_STABLE:
1436
 
        return choose_stb_slave(bond, bond_hash_tcp(flow, vlan, bond->basis));
1437
 
 
1438
1476
    case BM_TCP:
1439
1477
        if (bond->lacp_status != LACP_NEGOTIATED) {
1440
1478
            /* Must have LACP negotiations for TCP balanced bonds. */
1441
1479
            return NULL;
1442
1480
        }
 
1481
        if (wc) {
 
1482
            flow_mask_hash_fields(flow, wc, NX_HASH_FIELDS_SYMMETRIC_L4);
 
1483
        }
1443
1484
        /* Fall Through. */
1444
1485
    case BM_SLB:
1445
 
        if (!bond_is_balanced(bond)) {
1446
 
            return choose_stb_slave(bond, bond_hash(bond, flow, vlan));
 
1486
        if (wc) {
 
1487
            flow_mask_hash_fields(flow, wc, NX_HASH_FIELDS_ETH_SRC);
1447
1488
        }
1448
1489
        e = lookup_bond_entry(bond, flow, vlan);
1449
1490
        if (!e->slave || !e->slave->enabled) {
1512
1553
 
1513
1554
        bond->send_learning_packets = true;
1514
1555
    } else if (old_active_slave) {
1515
 
        VLOG_WARN_RL(&rl, "bond %s: all interfaces disabled", bond->name);
 
1556
        VLOG_INFO_RL(&rl, "bond %s: all interfaces disabled", bond->name);
1516
1557
    }
1517
1558
}
1518
1559