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

« back to all changes in this revision

Viewing changes to lib/lacp.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:
47
47
#define LACP_RX_MULTIPLIER 3    /* Multiply by TX rate to get RX rate. */
48
48
 
49
49
#define LACP_INFO_LEN 15
 
50
OVS_PACKED(
50
51
struct lacp_info {
51
52
    ovs_be16 sys_priority;            /* System priority. */
52
53
    uint8_t sys_id[ETH_ADDR_LEN];     /* System ID. */
54
55
    ovs_be16 port_priority;           /* Port priority. */
55
56
    ovs_be16 port_id;                 /* Port ID. */
56
57
    uint8_t state;                    /* State mask.  See LACP_STATE macros. */
57
 
} __attribute__((packed));
 
58
});
58
59
BUILD_ASSERT_DECL(LACP_INFO_LEN == sizeof(struct lacp_info));
59
60
 
60
61
#define LACP_PDU_LEN 110
 
62
OVS_PACKED(
61
63
struct lacp_pdu {
62
64
    uint8_t subtype;          /* Always 1. */
63
65
    uint8_t version;          /* Always 1. */
76
78
    uint8_t collector_len;    /* Always 16. */
77
79
    ovs_be16 collector_delay; /* Maximum collector delay. Set to UINT16_MAX. */
78
80
    uint8_t z3[64];           /* Combination of several fields.  Always 0. */
79
 
} __attribute__((packed));
 
81
});
80
82
BUILD_ASSERT_DECL(LACP_PDU_LEN == sizeof(struct lacp_pdu));
81
83
 
82
84
/* Implementation. */
100
102
    bool fast;               /* True if using fast probe interval. */
101
103
    bool negotiated;         /* True if LACP negotiations were successful. */
102
104
    bool update;             /* True if lacp_update() needs to be called. */
 
105
 
 
106
    atomic_int ref_cnt;
103
107
};
104
108
 
105
109
struct slave {
120
124
    struct timer rx;              /* Expected message receive timer. */
121
125
};
122
126
 
123
 
static struct list all_lacps = LIST_INITIALIZER(&all_lacps);
124
 
 
125
 
static void lacp_update_attached(struct lacp *);
126
 
 
127
 
static void slave_destroy(struct slave *);
128
 
static void slave_set_defaulted(struct slave *);
129
 
static void slave_set_expired(struct slave *);
130
 
static void slave_get_actor(struct slave *, struct lacp_info *actor);
131
 
static void slave_get_priority(struct slave *, struct lacp_info *priority);
132
 
static bool slave_may_tx(const struct slave *);
133
 
static struct slave *slave_lookup(const struct lacp *, const void *slave);
134
 
static bool info_tx_equal(struct lacp_info *, struct lacp_info *);
 
127
static struct ovs_mutex mutex;
 
128
static struct list all_lacps__ = LIST_INITIALIZER(&all_lacps__);
 
129
static struct list *const all_lacps OVS_GUARDED_BY(mutex) = &all_lacps__;
 
130
 
 
131
static void lacp_update_attached(struct lacp *) OVS_REQ_WRLOCK(mutex);
 
132
 
 
133
static void slave_destroy(struct slave *) OVS_REQ_WRLOCK(mutex);
 
134
static void slave_set_defaulted(struct slave *) OVS_REQ_WRLOCK(mutex);
 
135
static void slave_set_expired(struct slave *) OVS_REQ_WRLOCK(mutex);
 
136
static void slave_get_actor(struct slave *, struct lacp_info *actor)
 
137
    OVS_REQ_WRLOCK(mutex);
 
138
static void slave_get_priority(struct slave *, struct lacp_info *priority)
 
139
    OVS_REQ_WRLOCK(mutex);
 
140
static bool slave_may_tx(const struct slave *)
 
141
    OVS_REQ_WRLOCK(mutex);
 
142
static struct slave *slave_lookup(const struct lacp *, const void *slave)
 
143
    OVS_REQ_WRLOCK(mutex);
 
144
static bool info_tx_equal(struct lacp_info *, struct lacp_info *)
 
145
    OVS_REQ_WRLOCK(mutex);
135
146
 
136
147
static unixctl_cb_func lacp_unixctl_show;
137
148
 
190
201
 
191
202
/* Creates a LACP object. */
192
203
struct lacp *
193
 
lacp_create(void)
 
204
lacp_create(void) OVS_EXCLUDED(mutex)
194
205
{
 
206
    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
195
207
    struct lacp *lacp;
196
208
 
 
209
    if (ovsthread_once_start(&once)) {
 
210
        ovs_mutex_init(&mutex, PTHREAD_MUTEX_RECURSIVE);
 
211
        ovsthread_once_done(&once);
 
212
    }
 
213
 
197
214
    lacp = xzalloc(sizeof *lacp);
198
215
    hmap_init(&lacp->slaves);
199
 
    list_push_back(&all_lacps, &lacp->node);
 
216
    atomic_init(&lacp->ref_cnt, 1);
 
217
 
 
218
    ovs_mutex_lock(&mutex);
 
219
    list_push_back(all_lacps, &lacp->node);
 
220
    ovs_mutex_unlock(&mutex);
 
221
    return lacp;
 
222
}
 
223
 
 
224
struct lacp *
 
225
lacp_ref(const struct lacp *lacp_)
 
226
{
 
227
    struct lacp *lacp = CONST_CAST(struct lacp *, lacp_);
 
228
    if (lacp) {
 
229
        int orig;
 
230
        atomic_add(&lacp->ref_cnt, 1, &orig);
 
231
        ovs_assert(orig > 0);
 
232
    }
200
233
    return lacp;
201
234
}
202
235
 
203
236
/* Destroys 'lacp' and its slaves. Does nothing if 'lacp' is NULL. */
204
237
void
205
 
lacp_destroy(struct lacp *lacp)
 
238
lacp_unref(struct lacp *lacp) OVS_EXCLUDED(mutex)
206
239
{
207
 
    if (lacp) {
 
240
    int orig;
 
241
 
 
242
    if (!lacp) {
 
243
        return;
 
244
    }
 
245
 
 
246
    atomic_sub(&lacp->ref_cnt, 1, &orig);
 
247
    ovs_assert(orig > 0);
 
248
    if (orig == 1) {
208
249
        struct slave *slave, *next;
209
250
 
 
251
        ovs_mutex_lock(&mutex);
210
252
        HMAP_FOR_EACH_SAFE (slave, next, node, &lacp->slaves) {
211
253
            slave_destroy(slave);
212
254
        }
215
257
        list_remove(&lacp->node);
216
258
        free(lacp->name);
217
259
        free(lacp);
 
260
        ovs_mutex_unlock(&mutex);
218
261
    }
219
262
}
220
263
 
221
264
/* Configures 'lacp' with settings from 's'. */
222
265
void
223
266
lacp_configure(struct lacp *lacp, const struct lacp_settings *s)
 
267
    OVS_EXCLUDED(mutex)
224
268
{
225
269
    ovs_assert(!eth_addr_is_zero(s->id));
226
270
 
 
271
    ovs_mutex_lock(&mutex);
227
272
    if (!lacp->name || strcmp(s->name, lacp->name)) {
228
273
        free(lacp->name);
229
274
        lacp->name = xstrdup(s->name);
238
283
 
239
284
    lacp->active = s->active;
240
285
    lacp->fast = s->fast;
 
286
    ovs_mutex_unlock(&mutex);
241
287
}
242
288
 
243
289
/* Returns true if 'lacp' is configured in active mode, false if 'lacp' is
244
290
 * configured for passive mode. */
245
291
bool
246
 
lacp_is_active(const struct lacp *lacp)
 
292
lacp_is_active(const struct lacp *lacp) OVS_EXCLUDED(mutex)
247
293
{
248
 
    return lacp->active;
 
294
    bool ret;
 
295
    ovs_mutex_lock(&mutex);
 
296
    ret = lacp->active;
 
297
    ovs_mutex_unlock(&mutex);
 
298
    return ret;
249
299
}
250
300
 
251
301
/* Processes 'packet' which was received on 'slave_'.  This function should be
254
304
void
255
305
lacp_process_packet(struct lacp *lacp, const void *slave_,
256
306
                    const struct ofpbuf *packet)
 
307
    OVS_EXCLUDED(mutex)
257
308
{
258
309
    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
259
 
    struct slave *slave = slave_lookup(lacp, slave_);
260
310
    const struct lacp_pdu *pdu;
261
311
    long long int tx_rate;
 
312
    struct slave *slave;
 
313
 
 
314
    ovs_mutex_lock(&mutex);
 
315
    slave = slave_lookup(lacp, slave_);
 
316
    if (!slave) {
 
317
        goto out;
 
318
    }
262
319
 
263
320
    pdu = parse_lacp_packet(packet);
264
321
    if (!pdu) {
265
322
        VLOG_WARN_RL(&rl, "%s: received an unparsable LACP PDU.", lacp->name);
266
 
        return;
 
323
        goto out;
267
324
    }
268
325
 
269
326
    slave->status = LACP_CURRENT;
279
336
        lacp->update = true;
280
337
        slave->partner = pdu->actor;
281
338
    }
 
339
 
 
340
out:
 
341
    ovs_mutex_unlock(&mutex);
282
342
}
283
343
 
284
344
/* Returns the lacp_status of the given 'lacp' object (which may be NULL). */
285
345
enum lacp_status
286
 
lacp_status(const struct lacp *lacp)
 
346
lacp_status(const struct lacp *lacp) OVS_EXCLUDED(mutex)
287
347
{
 
348
    enum lacp_status ret;
 
349
 
 
350
    ovs_mutex_lock(&mutex);
288
351
    if (!lacp) {
289
 
        return LACP_DISABLED;
 
352
        ret = LACP_DISABLED;
290
353
    } else if (lacp->negotiated) {
291
 
        return LACP_NEGOTIATED;
 
354
        ret = LACP_NEGOTIATED;
292
355
    } else {
293
 
        return LACP_CONFIGURED;
 
356
        ret = LACP_CONFIGURED;
294
357
    }
 
358
    ovs_mutex_unlock(&mutex);
 
359
    return ret;
295
360
}
296
361
 
297
362
/* Registers 'slave_' as subordinate to 'lacp'.  This should be called at least
300
365
void
301
366
lacp_slave_register(struct lacp *lacp, void *slave_,
302
367
                    const struct lacp_slave_settings *s)
 
368
    OVS_EXCLUDED(mutex)
303
369
{
304
 
    struct slave *slave = slave_lookup(lacp, slave_);
 
370
    struct slave *slave;
305
371
 
 
372
    ovs_mutex_lock(&mutex);
 
373
    slave = slave_lookup(lacp, slave_);
306
374
    if (!slave) {
307
375
        slave = xzalloc(sizeof *slave);
308
376
        slave->lacp = lacp;
333
401
            slave_set_expired(slave);
334
402
        }
335
403
    }
 
404
    ovs_mutex_unlock(&mutex);
336
405
}
337
406
 
338
407
/* Unregisters 'slave_' with 'lacp'.  */
339
408
void
340
409
lacp_slave_unregister(struct lacp *lacp, const void *slave_)
 
410
    OVS_EXCLUDED(mutex)
341
411
{
342
 
    struct slave *slave = slave_lookup(lacp, slave_);
 
412
    struct slave *slave;
343
413
 
 
414
    ovs_mutex_lock(&mutex);
 
415
    slave = slave_lookup(lacp, slave_);
344
416
    if (slave) {
345
417
        slave_destroy(slave);
346
418
        lacp->update = true;
347
419
    }
 
420
    ovs_mutex_unlock(&mutex);
348
421
}
349
422
 
350
423
/* This function should be called whenever the carrier status of 'slave_' has
351
424
 * changed.  If 'lacp' is null, this function has no effect.*/
352
425
void
353
426
lacp_slave_carrier_changed(const struct lacp *lacp, const void *slave_)
 
427
    OVS_EXCLUDED(mutex)
354
428
{
355
 
    if (lacp) {
356
 
        struct slave *slave = slave_lookup(lacp, slave_);
357
 
 
358
 
        if (slave->status == LACP_CURRENT || slave->lacp->active) {
359
 
            slave_set_expired(slave);
360
 
        }
361
 
    }
 
429
    struct slave *slave;
 
430
    if (!lacp) {
 
431
        return;
 
432
    }
 
433
 
 
434
    ovs_mutex_lock(&mutex);
 
435
    slave = slave_lookup(lacp, slave_);
 
436
    if (!slave) {
 
437
        goto out;
 
438
    }
 
439
 
 
440
    if (slave->status == LACP_CURRENT || slave->lacp->active) {
 
441
        slave_set_expired(slave);
 
442
    }
 
443
 
 
444
out:
 
445
    ovs_mutex_unlock(&mutex);
362
446
}
363
447
 
364
448
static bool
365
 
slave_may_enable__(struct slave *slave)
 
449
slave_may_enable__(struct slave *slave) OVS_REQ_WRLOCK(mutex)
366
450
{
367
451
    /* The slave may be enabled if it's attached to an aggregator and its
368
452
     * partner is synchronized.*/
374
458
 * convenience, returns true if 'lacp' is NULL. */
375
459
bool
376
460
lacp_slave_may_enable(const struct lacp *lacp, const void *slave_)
 
461
    OVS_EXCLUDED(mutex)
377
462
{
378
463
    if (lacp) {
379
 
        return slave_may_enable__(slave_lookup(lacp, slave_));
 
464
        struct slave *slave;
 
465
        bool ret;
 
466
 
 
467
        ovs_mutex_lock(&mutex);
 
468
        slave = slave_lookup(lacp, slave_);
 
469
        ret = slave ? slave_may_enable__(slave) : false;
 
470
        ovs_mutex_unlock(&mutex);
 
471
        return ret;
380
472
    } else {
381
473
        return true;
382
474
    }
383
475
}
384
476
 
385
 
/* Returns the port ID used for 'slave_' in LACP communications. */
386
 
uint16_t
387
 
lacp_slave_get_port_id(const struct lacp *lacp, const void *slave_)
388
 
{
389
 
    struct slave *slave = slave_lookup(lacp, slave_);
390
 
    return slave->port_id;
391
 
}
392
 
 
393
477
/* Returns true if partner information on 'slave_' is up to date.  'slave_'
394
478
 * not being current, generally indicates a connectivity problem, or a
395
479
 * misconfigured (or broken) partner. */
396
480
bool
397
481
lacp_slave_is_current(const struct lacp *lacp, const void *slave_)
 
482
    OVS_EXCLUDED(mutex)
398
483
{
399
 
    return slave_lookup(lacp, slave_)->status != LACP_DEFAULTED;
 
484
    struct slave *slave;
 
485
    bool ret;
 
486
 
 
487
    ovs_mutex_lock(&mutex);
 
488
    slave = slave_lookup(lacp, slave_);
 
489
    ret = slave ? slave->status != LACP_DEFAULTED : false;
 
490
    ovs_mutex_unlock(&mutex);
 
491
    return ret;
400
492
}
401
493
 
402
494
/* This function should be called periodically to update 'lacp'. */
403
495
void
404
 
lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu)
 
496
lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)
405
497
{
406
498
    struct slave *slave;
407
499
 
 
500
    ovs_mutex_lock(&mutex);
408
501
    HMAP_FOR_EACH (slave, node, &lacp->slaves) {
409
502
        if (timer_expired(&slave->rx)) {
410
503
            if (slave->status == LACP_CURRENT) {
444
537
            timer_set_duration(&slave->tx, duration);
445
538
        }
446
539
    }
 
540
    ovs_mutex_unlock(&mutex);
447
541
}
448
542
 
449
543
/* Causes poll_block() to wake up when lacp_run() needs to be called again. */
450
544
void
451
 
lacp_wait(struct lacp *lacp)
 
545
lacp_wait(struct lacp *lacp) OVS_EXCLUDED(mutex)
452
546
{
453
547
    struct slave *slave;
454
548
 
 
549
    ovs_mutex_lock(&mutex);
455
550
    HMAP_FOR_EACH (slave, node, &lacp->slaves) {
456
551
        if (slave_may_tx(slave)) {
457
552
            timer_wait(&slave->tx);
461
556
            timer_wait(&slave->rx);
462
557
        }
463
558
    }
 
559
    ovs_mutex_unlock(&mutex);
464
560
}
465
561
 
466
562
/* Static Helpers. */
468
564
/* Updates the attached status of all slaves controlled by 'lacp' and sets its
469
565
 * negotiated parameter to true if any slaves are attachable. */
470
566
static void
471
 
lacp_update_attached(struct lacp *lacp)
 
567
lacp_update_attached(struct lacp *lacp) OVS_REQ_WRLOCK(mutex)
472
568
{
473
569
    struct slave *lead, *slave;
474
570
    struct lacp_info lead_pri;
517
613
}
518
614
 
519
615
static void
520
 
slave_destroy(struct slave *slave)
 
616
slave_destroy(struct slave *slave) OVS_REQ_WRLOCK(mutex)
521
617
{
522
618
    if (slave) {
523
619
        struct lacp *lacp = slave->lacp;
541
637
}
542
638
 
543
639
static void
544
 
slave_set_defaulted(struct slave *slave)
 
640
slave_set_defaulted(struct slave *slave) OVS_REQ_WRLOCK(mutex)
545
641
{
546
642
    memset(&slave->partner, 0, sizeof slave->partner);
547
643
 
550
646
}
551
647
 
552
648
static void
553
 
slave_set_expired(struct slave *slave)
 
649
slave_set_expired(struct slave *slave) OVS_REQ_WRLOCK(mutex)
554
650
{
555
651
    slave->status = LACP_EXPIRED;
556
652
    slave->partner.state |= LACP_STATE_TIME;
561
657
 
562
658
static void
563
659
slave_get_actor(struct slave *slave, struct lacp_info *actor)
 
660
    OVS_REQ_WRLOCK(mutex)
564
661
{
565
662
    struct lacp *lacp = slave->lacp;
566
663
    uint16_t key;
613
710
 * link. */
614
711
static void
615
712
slave_get_priority(struct slave *slave, struct lacp_info *priority)
 
713
    OVS_REQ_WRLOCK(mutex)
616
714
{
617
715
    uint16_t partner_priority, actor_priority;
618
716
 
637
735
}
638
736
 
639
737
static bool
640
 
slave_may_tx(const struct slave *slave)
 
738
slave_may_tx(const struct slave *slave) OVS_REQ_WRLOCK(mutex)
641
739
{
642
740
    return slave->lacp->active || slave->status != LACP_DEFAULTED;
643
741
}
644
742
 
645
743
static struct slave *
646
 
slave_lookup(const struct lacp *lacp, const void *slave_)
 
744
slave_lookup(const struct lacp *lacp, const void *slave_) OVS_REQ_WRLOCK(mutex)
647
745
{
648
746
    struct slave *slave;
649
747
 
680
778
}
681
779
 
682
780
static struct lacp *
683
 
lacp_find(const char *name)
 
781
lacp_find(const char *name) OVS_REQ_WRLOCK(&mutex)
684
782
{
685
783
    struct lacp *lacp;
686
784
 
687
 
    LIST_FOR_EACH (lacp, node, &all_lacps) {
 
785
    LIST_FOR_EACH (lacp, node, all_lacps) {
688
786
        if (!strcmp(lacp->name, name)) {
689
787
            return lacp;
690
788
        }
730
828
}
731
829
 
732
830
static void
733
 
lacp_print_details(struct ds *ds, struct lacp *lacp)
 
831
lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQ_WRLOCK(&mutex)
734
832
{
735
833
    struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
736
834
    const struct shash_node **sorted_slaves = NULL;
831
929
 
832
930
static void
833
931
lacp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],
834
 
                  void *aux OVS_UNUSED)
 
932
                  void *aux OVS_UNUSED) OVS_EXCLUDED(mutex)
835
933
{
836
934
    struct ds ds = DS_EMPTY_INITIALIZER;
837
935
    struct lacp *lacp;
838
936
 
 
937
    ovs_mutex_lock(&mutex);
839
938
    if (argc > 1) {
840
939
        lacp = lacp_find(argv[1]);
841
940
        if (!lacp) {
842
941
            unixctl_command_reply_error(conn, "no such lacp object");
843
 
            return;
 
942
            goto out;
844
943
        }
845
944
        lacp_print_details(&ds, lacp);
846
945
    } else {
847
 
        LIST_FOR_EACH (lacp, node, &all_lacps) {
 
946
        LIST_FOR_EACH (lacp, node, all_lacps) {
848
947
            lacp_print_details(&ds, lacp);
849
948
        }
850
949
    }
851
950
 
852
951
    unixctl_command_reply(conn, ds_cstr(&ds));
853
952
    ds_destroy(&ds);
 
953
 
 
954
out:
 
955
    ovs_mutex_unlock(&mutex);
854
956
}