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

« back to all changes in this revision

Viewing changes to lib/stp.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:
39
39
#define STP_TYPE_CONFIG 0x00
40
40
#define STP_TYPE_TCN 0x80
41
41
 
 
42
OVS_PACKED(
42
43
struct stp_bpdu_header {
43
44
    ovs_be16 protocol_id;       /* STP_PROTOCOL_ID. */
44
45
    uint8_t protocol_version;   /* STP_PROTOCOL_VERSION. */
45
46
    uint8_t bpdu_type;          /* One of STP_TYPE_*. */
46
 
} __attribute__((packed));
 
47
});
47
48
BUILD_ASSERT_DECL(sizeof(struct stp_bpdu_header) == 4);
48
49
 
49
50
enum stp_config_bpdu_flags {
51
52
    STP_CONFIG_TOPOLOGY_CHANGE = 0x01
52
53
};
53
54
 
 
55
OVS_PACKED(
54
56
struct stp_config_bpdu {
55
57
    struct stp_bpdu_header header; /* Type STP_TYPE_CONFIG. */
56
58
    uint8_t flags;                 /* STP_CONFIG_* flags. */
62
64
    ovs_be16 max_age;              /* 8.5.1.6: Timeout for received data. */
63
65
    ovs_be16 hello_time;           /* 8.5.1.7: Time between BPDU generation. */
64
66
    ovs_be16 forward_delay;        /* 8.5.1.8: State progression delay. */
65
 
} __attribute__((packed));
 
67
});
66
68
BUILD_ASSERT_DECL(sizeof(struct stp_config_bpdu) == 35);
67
69
 
 
70
OVS_PACKED(
68
71
struct stp_tcn_bpdu {
69
72
    struct stp_bpdu_header header; /* Type STP_TYPE_TCN. */
70
 
} __attribute__((packed));
 
73
});
71
74
BUILD_ASSERT_DECL(sizeof(struct stp_tcn_bpdu) == 4);
72
75
 
73
76
struct stp_timer {
137
140
    struct stp_port *first_changed_port;
138
141
    void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux);
139
142
    void *aux;
 
143
 
 
144
    atomic_int ref_cnt;
140
145
};
141
146
 
142
 
static struct list all_stps = LIST_INITIALIZER(&all_stps);
 
147
static struct ovs_mutex mutex;
 
148
static struct list all_stps__ = LIST_INITIALIZER(&all_stps__);
 
149
static struct list *const all_stps OVS_GUARDED_BY(&mutex) = &all_stps__;
143
150
 
144
151
#define FOR_EACH_ENABLED_PORT(PORT, STP)                        \
145
152
    for ((PORT) = stp_next_enabled_port((STP), (STP)->ports);   \
147
154
         (PORT) = stp_next_enabled_port((STP), (PORT) + 1))
148
155
static struct stp_port *
149
156
stp_next_enabled_port(const struct stp *stp, const struct stp_port *port)
 
157
    OVS_REQ_WRLOCK(mutex)
150
158
{
151
159
    for (; port < &stp->ports[ARRAY_SIZE(stp->ports)]; port++) {
152
160
        if (port->state != STP_DISABLED) {
158
166
 
159
167
#define MESSAGE_AGE_INCREMENT 1
160
168
 
161
 
static void stp_transmit_config(struct stp_port *);
 
169
static void stp_transmit_config(struct stp_port *) OVS_REQ_WRLOCK(mutex);
162
170
static bool stp_supersedes_port_info(const struct stp_port *,
163
 
                                     const struct stp_config_bpdu *);
 
171
                                     const struct stp_config_bpdu *)
 
172
    OVS_REQ_WRLOCK(mutex);
164
173
static void stp_record_config_information(struct stp_port *,
165
 
                                          const struct stp_config_bpdu *);
 
174
                                          const struct stp_config_bpdu *)
 
175
    OVS_REQ_WRLOCK(mutex);
166
176
static void stp_record_config_timeout_values(struct stp *,
167
 
                                             const struct stp_config_bpdu  *);
168
 
static bool stp_is_designated_port(const struct stp_port *);
169
 
static void stp_config_bpdu_generation(struct stp *);
170
 
static void stp_transmit_tcn(struct stp *);
171
 
static void stp_configuration_update(struct stp *);
 
177
                                             const struct stp_config_bpdu  *)
 
178
    OVS_REQ_WRLOCK(mutex);
 
179
static bool stp_is_designated_port(const struct stp_port *)
 
180
    OVS_REQ_WRLOCK(mutex);
 
181
static void stp_config_bpdu_generation(struct stp *) OVS_REQ_WRLOCK(mutex);
 
182
static void stp_transmit_tcn(struct stp *) OVS_REQ_WRLOCK(mutex);
 
183
static void stp_configuration_update(struct stp *) OVS_REQ_WRLOCK(mutex);
172
184
static bool stp_supersedes_root(const struct stp_port *root,
173
 
                                const struct stp_port *);
174
 
static void stp_root_selection(struct stp *);
175
 
static void stp_designated_port_selection(struct stp *);
176
 
static void stp_become_designated_port(struct stp_port *);
177
 
static void stp_port_state_selection(struct stp *);
178
 
static void stp_make_forwarding(struct stp_port *);
179
 
static void stp_make_blocking(struct stp_port *);
180
 
static void stp_set_port_state(struct stp_port *, enum stp_state);
181
 
static void stp_topology_change_detection(struct stp *);
182
 
static void stp_topology_change_acknowledged(struct stp *);
183
 
static void stp_acknowledge_topology_change(struct stp_port *);
 
185
                                const struct stp_port *) OVS_REQ_WRLOCK(mutex);
 
186
static void stp_root_selection(struct stp *) OVS_REQ_WRLOCK(mutex);
 
187
static void stp_designated_port_selection(struct stp *) OVS_REQ_WRLOCK(mutex);
 
188
static void stp_become_designated_port(struct stp_port *)
 
189
    OVS_REQ_WRLOCK(mutex);
 
190
static void stp_port_state_selection(struct stp *) OVS_REQ_WRLOCK(mutex);
 
191
static void stp_make_forwarding(struct stp_port *) OVS_REQ_WRLOCK(mutex);
 
192
static void stp_make_blocking(struct stp_port *) OVS_REQ_WRLOCK(mutex);
 
193
static void stp_set_port_state(struct stp_port *, enum stp_state)
 
194
    OVS_REQ_WRLOCK(mutex);
 
195
static void stp_topology_change_detection(struct stp *) OVS_REQ_WRLOCK(mutex);
 
196
static void stp_topology_change_acknowledged(struct stp *)
 
197
    OVS_REQ_WRLOCK(mutex);
 
198
static void stp_acknowledge_topology_change(struct stp_port *)
 
199
    OVS_REQ_WRLOCK(mutex);
184
200
static void stp_received_config_bpdu(struct stp *, struct stp_port *,
185
 
                                     const struct stp_config_bpdu *);
186
 
static void stp_received_tcn_bpdu(struct stp *, struct stp_port *);
187
 
static void stp_hello_timer_expiry(struct stp *);
188
 
static void stp_message_age_timer_expiry(struct stp_port *);
189
 
static bool stp_is_designated_for_some_port(const struct stp *);
190
 
static void stp_forward_delay_timer_expiry(struct stp_port *);
191
 
static void stp_tcn_timer_expiry(struct stp *);
192
 
static void stp_topology_change_timer_expiry(struct stp *);
193
 
static void stp_hold_timer_expiry(struct stp_port *);
194
 
static void stp_initialize_port(struct stp_port *, enum stp_state);
195
 
static void stp_become_root_bridge(struct stp *);
196
 
static void stp_update_bridge_timers(struct stp *);
 
201
                                     const struct stp_config_bpdu *)
 
202
    OVS_REQ_WRLOCK(mutex);
 
203
static void stp_received_tcn_bpdu(struct stp *, struct stp_port *)
 
204
    OVS_REQ_WRLOCK(mutex);
 
205
static void stp_hello_timer_expiry(struct stp *) OVS_REQ_WRLOCK(mutex);
 
206
static void stp_message_age_timer_expiry(struct stp_port *)
 
207
    OVS_REQ_WRLOCK(mutex);
 
208
static bool stp_is_designated_for_some_port(const struct stp *)
 
209
    OVS_REQ_WRLOCK(mutex);
 
210
static void stp_forward_delay_timer_expiry(struct stp_port *)
 
211
    OVS_REQ_WRLOCK(mutex);
 
212
static void stp_tcn_timer_expiry(struct stp *) OVS_REQ_WRLOCK(mutex);
 
213
static void stp_topology_change_timer_expiry(struct stp *)
 
214
    OVS_REQ_WRLOCK(mutex);
 
215
static void stp_hold_timer_expiry(struct stp_port *) OVS_REQ_WRLOCK(mutex);
 
216
static void stp_initialize_port(struct stp_port *, enum stp_state)
 
217
    OVS_REQ_WRLOCK(mutex);
 
218
static void stp_become_root_bridge(struct stp *) OVS_REQ_WRLOCK(mutex);
 
219
static void stp_update_bridge_timers(struct stp *) OVS_REQ_WRLOCK(mutex);
197
220
 
198
221
static int clamp(int x, int min, int max);
199
222
static int ms_to_timer(int ms);
202
225
static void stp_stop_timer(struct stp_timer *);
203
226
static bool stp_timer_expired(struct stp_timer *, int elapsed, int timeout);
204
227
 
205
 
static void stp_send_bpdu(struct stp_port *, const void *, size_t);
 
228
static void stp_send_bpdu(struct stp_port *, const void *, size_t)
 
229
    OVS_REQ_WRLOCK(mutex);
206
230
static void stp_unixctl_tcn(struct unixctl_conn *, int argc,
207
231
                            const char *argv[], void *aux);
208
232
 
231
255
           void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux),
232
256
           void *aux)
233
257
{
 
258
    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
234
259
    struct stp *stp;
235
260
    struct stp_port *p;
236
261
 
 
262
    if (ovsthread_once_start(&once)) {
 
263
        /* We need a recursive mutex because stp_send_bpdu() could loop back
 
264
         * into the stp module through a patch port.  This happens
 
265
         * intentionally as part of the unit tests.  Ideally we'd ditch
 
266
         * the call back function, but for now this is what we have. */
 
267
        ovs_mutex_init(&mutex,  PTHREAD_MUTEX_RECURSIVE);
 
268
        ovsthread_once_done(&once);
 
269
    }
 
270
 
 
271
    ovs_mutex_lock(&mutex);
237
272
    stp = xzalloc(sizeof *stp);
238
273
    stp->name = xstrdup(name);
239
274
    stp->bridge_id = bridge_id;
269
304
        p->path_cost = 19;      /* Recommended default for 100 Mb/s link. */
270
305
        stp_initialize_port(p, STP_DISABLED);
271
306
    }
272
 
    list_push_back(&all_stps, &stp->node);
 
307
    atomic_init(&stp->ref_cnt, 1);
 
308
 
 
309
    list_push_back(all_stps, &stp->node);
 
310
    ovs_mutex_unlock(&mutex);
 
311
    return stp;
 
312
}
 
313
 
 
314
struct stp *
 
315
stp_ref(const struct stp *stp_)
 
316
{
 
317
    struct stp *stp = CONST_CAST(struct stp *, stp_);
 
318
    if (stp) {
 
319
        int orig;
 
320
        atomic_add(&stp->ref_cnt, 1, &orig);
 
321
        ovs_assert(orig > 0);
 
322
    }
273
323
    return stp;
274
324
}
275
325
 
276
326
/* Destroys 'stp'. */
277
327
void
278
 
stp_destroy(struct stp *stp)
 
328
stp_unref(struct stp *stp)
279
329
{
280
 
    if (stp) {
 
330
    int orig;
 
331
 
 
332
    if (!stp) {
 
333
        return;
 
334
    }
 
335
 
 
336
    atomic_sub(&stp->ref_cnt, 1, &orig);
 
337
    ovs_assert(orig > 0);
 
338
    if (orig == 1) {
 
339
        ovs_mutex_lock(&mutex);
281
340
        list_remove(&stp->node);
 
341
        ovs_mutex_unlock(&mutex);
282
342
        free(stp->name);
283
343
        free(stp);
284
344
    }
291
351
    struct stp_port *p;
292
352
    int elapsed;
293
353
 
 
354
    ovs_mutex_lock(&mutex);
294
355
    /* Convert 'ms' to STP timer ticks.  Preserve any leftover milliseconds
295
356
     * from previous stp_tick() calls so that we don't lose STP ticks when we
296
357
     * are called too frequently. */
298
359
    elapsed = ms_to_timer(ms);
299
360
    stp->elapsed_remainder = ms - timer_to_ms(elapsed);
300
361
    if (!elapsed) {
301
 
        return;
 
362
        goto out;
302
363
    }
303
364
 
304
365
    if (stp_timer_expired(&stp->hello_timer, elapsed, stp->hello_time)) {
325
386
            stp_hold_timer_expiry(p);
326
387
        }
327
388
    }
 
389
 
 
390
out:
 
391
    ovs_mutex_unlock(&mutex);
328
392
}
329
393
 
330
394
static void
331
395
set_bridge_id(struct stp *stp, stp_identifier new_bridge_id)
 
396
    OVS_REQ_WRLOCK(mutex)
332
397
{
333
398
    if (new_bridge_id != stp->bridge_id) {
334
399
        bool root;
354
419
{
355
420
    const uint64_t mac_bits = (UINT64_C(1) << 48) - 1;
356
421
    const uint64_t pri_bits = ~mac_bits;
 
422
    ovs_mutex_lock(&mutex);
357
423
    set_bridge_id(stp, (stp->bridge_id & pri_bits) | (bridge_id & mac_bits));
 
424
    ovs_mutex_unlock(&mutex);
358
425
}
359
426
 
360
427
void
361
428
stp_set_bridge_priority(struct stp *stp, uint16_t new_priority)
362
429
{
363
430
    const uint64_t mac_bits = (UINT64_C(1) << 48) - 1;
 
431
    ovs_mutex_lock(&mutex);
364
432
    set_bridge_id(stp, ((stp->bridge_id & mac_bits)
365
433
                        | ((uint64_t) new_priority << 48)));
 
434
    ovs_mutex_unlock(&mutex);
366
435
}
367
436
 
368
437
/* Sets the desired hello time for 'stp' to 'ms', in milliseconds.  The actual
372
441
void
373
442
stp_set_hello_time(struct stp *stp, int ms)
374
443
{
 
444
    ovs_mutex_lock(&mutex);
375
445
    stp->rq_hello_time = ms;
376
446
    stp_update_bridge_timers(stp);
 
447
    ovs_mutex_unlock(&mutex);
377
448
}
378
449
 
379
450
/* Sets the desired max age for 'stp' to 'ms', in milliseconds.  The actual max
384
455
void
385
456
stp_set_max_age(struct stp *stp, int ms)
386
457
{
 
458
    ovs_mutex_lock(&mutex);
387
459
    stp->rq_max_age = ms;
388
460
    stp_update_bridge_timers(stp);
 
461
    ovs_mutex_unlock(&mutex);
389
462
}
390
463
 
391
464
/* Sets the desired forward delay for 'stp' to 'ms', in milliseconds.  The
395
468
void
396
469
stp_set_forward_delay(struct stp *stp, int ms)
397
470
{
 
471
    ovs_mutex_lock(&mutex);
398
472
    stp->rq_forward_delay = ms;
399
473
    stp_update_bridge_timers(stp);
 
474
    ovs_mutex_unlock(&mutex);
400
475
}
401
476
 
402
477
/* Returns the name given to 'stp' in the call to stp_create(). */
403
478
const char *
404
479
stp_get_name(const struct stp *stp)
405
480
{
406
 
    return stp->name;
 
481
    char *name;
 
482
 
 
483
    ovs_mutex_lock(&mutex);
 
484
    name = stp->name;
 
485
    ovs_mutex_unlock(&mutex);
 
486
    return name;
407
487
}
408
488
 
409
489
/* Returns the bridge ID for 'stp'. */
410
490
stp_identifier
411
491
stp_get_bridge_id(const struct stp *stp)
412
492
{
413
 
    return stp->bridge_id;
 
493
    stp_identifier bridge_id;
 
494
 
 
495
    ovs_mutex_lock(&mutex);
 
496
    bridge_id = stp->bridge_id;
 
497
    ovs_mutex_unlock(&mutex);
 
498
    return bridge_id;
414
499
}
415
500
 
416
501
/* Returns the bridge ID of the bridge currently believed to be the root. */
417
502
stp_identifier
418
503
stp_get_designated_root(const struct stp *stp)
419
504
{
420
 
    return stp->designated_root;
 
505
    stp_identifier designated_root;
 
506
 
 
507
    ovs_mutex_lock(&mutex);
 
508
    designated_root = stp->designated_root;
 
509
    ovs_mutex_unlock(&mutex);
 
510
    return designated_root;
421
511
}
422
512
 
423
513
/* Returns true if 'stp' believes itself to the be root of the spanning tree,
425
515
bool
426
516
stp_is_root_bridge(const struct stp *stp)
427
517
{
428
 
    return stp->bridge_id == stp->designated_root;
 
518
    bool is_root;
 
519
 
 
520
    ovs_mutex_lock(&mutex);
 
521
    is_root = stp->bridge_id == stp->designated_root;
 
522
    ovs_mutex_unlock(&mutex);
 
523
    return is_root;
429
524
}
430
525
 
431
526
/* Returns the cost of the path from 'stp' to the root of the spanning tree. */
432
527
int
433
528
stp_get_root_path_cost(const struct stp *stp)
434
529
{
435
 
    return stp->root_path_cost;
 
530
    int cost;
 
531
 
 
532
    ovs_mutex_lock(&mutex);
 
533
    cost = stp->root_path_cost;
 
534
    ovs_mutex_unlock(&mutex);
 
535
    return cost;
436
536
}
437
537
 
438
538
/* Returns the bridge hello time, in ms.  The returned value is not necessarily
441
541
int
442
542
stp_get_hello_time(const struct stp *stp)
443
543
{
444
 
    return timer_to_ms(stp->bridge_hello_time);
 
544
    int time;
 
545
 
 
546
    ovs_mutex_lock(&mutex);
 
547
    time = timer_to_ms(stp->bridge_hello_time);
 
548
    ovs_mutex_unlock(&mutex);
 
549
    return time;
445
550
}
446
551
 
447
552
/* Returns the bridge max age, in ms.  The returned value is not necessarily
451
556
int
452
557
stp_get_max_age(const struct stp *stp)
453
558
{
454
 
    return timer_to_ms(stp->bridge_max_age);
 
559
    int time;
 
560
 
 
561
    ovs_mutex_lock(&mutex);
 
562
    time = timer_to_ms(stp->bridge_max_age);
 
563
    ovs_mutex_unlock(&mutex);
 
564
    return time;
455
565
}
456
566
 
457
567
/* Returns the bridge forward delay, in ms.  The returned value is not
461
571
int
462
572
stp_get_forward_delay(const struct stp *stp)
463
573
{
464
 
    return timer_to_ms(stp->bridge_forward_delay);
 
574
    int time;
 
575
 
 
576
    ovs_mutex_lock(&mutex);
 
577
    time = timer_to_ms(stp->bridge_forward_delay);
 
578
    ovs_mutex_unlock(&mutex);
 
579
    return time;
465
580
}
466
581
 
467
582
/* Returns true if something has happened to 'stp' which necessitates flushing
470
585
bool
471
586
stp_check_and_reset_fdb_flush(struct stp *stp)
472
587
{
473
 
    bool needs_flush = stp->fdb_needs_flush;
 
588
    bool needs_flush;
 
589
 
 
590
    ovs_mutex_lock(&mutex);
 
591
    needs_flush = stp->fdb_needs_flush;
474
592
    stp->fdb_needs_flush = false;
 
593
    ovs_mutex_unlock(&mutex);
475
594
    return needs_flush;
476
595
}
477
596
 
480
599
struct stp_port *
481
600
stp_get_port(struct stp *stp, int port_no)
482
601
{
 
602
    struct stp_port *port;
 
603
 
 
604
    ovs_mutex_lock(&mutex);
483
605
    ovs_assert(port_no >= 0 && port_no < ARRAY_SIZE(stp->ports));
484
 
    return &stp->ports[port_no];
 
606
    port = &stp->ports[port_no];
 
607
    ovs_mutex_unlock(&mutex);
 
608
    return port;
485
609
}
486
610
 
487
611
/* Returns the port connecting 'stp' to the root bridge, or a null pointer if
489
613
struct stp_port *
490
614
stp_get_root_port(struct stp *stp)
491
615
{
492
 
    return stp->root_port;
 
616
    struct stp_port *port;
 
617
 
 
618
    ovs_mutex_lock(&mutex);
 
619
    port = stp->root_port;
 
620
    ovs_mutex_unlock(&mutex);
 
621
    return port;
493
622
}
494
623
 
495
624
/* Finds a port whose state has changed.  If successful, stores the port whose
498
627
bool
499
628
stp_get_changed_port(struct stp *stp, struct stp_port **portp)
500
629
{
501
 
    struct stp_port *end = &stp->ports[ARRAY_SIZE(stp->ports)];
502
 
    struct stp_port *p;
 
630
    struct stp_port *end, *p;
 
631
    bool changed = false;
503
632
 
 
633
    ovs_mutex_lock(&mutex);
 
634
    end = &stp->ports[ARRAY_SIZE(stp->ports)];
504
635
    for (p = stp->first_changed_port; p < end; p++) {
505
636
        if (p->state_changed) {
506
637
            p->state_changed = false;
507
638
            stp->first_changed_port = p + 1;
508
639
            *portp = p;
509
 
            return true;
 
640
            changed = true;
 
641
            goto out;
510
642
        }
511
643
    }
512
644
    stp->first_changed_port = end;
513
645
    *portp = NULL;
514
 
    return false;
 
646
 
 
647
out:
 
648
    ovs_mutex_unlock(&mutex);
 
649
    return changed;
515
650
}
516
651
 
517
652
/* Returns the name for the given 'state' (for use in debugging and log
586
721
    struct stp *stp = p->stp;
587
722
    const struct stp_bpdu_header *header;
588
723
 
 
724
    ovs_mutex_lock(&mutex);
589
725
    if (p->state == STP_DISABLED) {
590
 
        return;
 
726
        goto out;
591
727
    }
592
728
 
593
729
    if (bpdu_size < sizeof(struct stp_bpdu_header)) {
594
730
        VLOG_WARN("%s: received runt %zu-byte BPDU", stp->name, bpdu_size);
595
731
        p->error_count++;
596
 
        return;
 
732
        goto out;
597
733
    }
598
734
 
599
735
    header = bpdu;
601
737
        VLOG_WARN("%s: received BPDU with unexpected protocol ID %"PRIu16,
602
738
                  stp->name, ntohs(header->protocol_id));
603
739
        p->error_count++;
604
 
        return;
 
740
        goto out;
605
741
    }
606
742
    if (header->protocol_version != STP_PROTOCOL_VERSION) {
607
743
        VLOG_DBG("%s: received BPDU with unexpected protocol version %"PRIu8,
614
750
            VLOG_WARN("%s: received config BPDU with invalid size %zu",
615
751
                      stp->name, bpdu_size);
616
752
            p->error_count++;
617
 
            return;
 
753
            goto out;
618
754
        }
619
755
        stp_received_config_bpdu(stp, p, bpdu);
620
756
        break;
624
760
            VLOG_WARN("%s: received TCN BPDU with invalid size %zu",
625
761
                      stp->name, bpdu_size);
626
762
            p->error_count++;
627
 
            return;
 
763
            goto out;
628
764
        }
629
765
        stp_received_tcn_bpdu(stp, p);
630
766
        break;
633
769
        VLOG_WARN("%s: received BPDU of unexpected type %"PRIu8,
634
770
                  stp->name, header->bpdu_type);
635
771
        p->error_count++;
636
 
        return;
 
772
        goto out;
637
773
    }
638
774
    p->rx_count++;
 
775
 
 
776
out:
 
777
    ovs_mutex_unlock(&mutex);
639
778
}
640
779
 
641
780
/* Returns the STP entity in which 'p' is nested. */
642
781
struct stp *
643
782
stp_port_get_stp(struct stp_port *p)
644
783
{
645
 
    return p->stp;
 
784
    struct stp *stp;
 
785
 
 
786
    ovs_mutex_lock(&mutex);
 
787
    stp = p->stp;
 
788
    ovs_mutex_unlock(&mutex);
 
789
    return stp;
646
790
}
647
791
 
648
792
/* Sets the 'aux' member of 'p'.
653
797
void
654
798
stp_port_set_aux(struct stp_port *p, void *aux)
655
799
{
 
800
    ovs_mutex_lock(&mutex);
656
801
    p->aux = aux;
 
802
    ovs_mutex_unlock(&mutex);
657
803
}
658
804
 
659
805
/* Returns the 'aux' member of 'p'. */
660
806
void *
661
807
stp_port_get_aux(struct stp_port *p)
662
808
{
663
 
    return p->aux;
 
809
    void *aux;
 
810
 
 
811
    ovs_mutex_lock(&mutex);
 
812
    aux = p->aux;
 
813
    ovs_mutex_unlock(&mutex);
 
814
    return aux;
664
815
}
665
816
 
666
817
/* Returns the index of port 'p' within its bridge. */
667
818
int
668
819
stp_port_no(const struct stp_port *p)
669
820
{
670
 
    struct stp *stp = p->stp;
 
821
    struct stp *stp;
 
822
    int index;
 
823
 
 
824
    ovs_mutex_lock(&mutex);
 
825
    stp = p->stp;
671
826
    ovs_assert(p >= stp->ports && p < &stp->ports[ARRAY_SIZE(stp->ports)]);
672
 
    return p - stp->ports;
 
827
    index = p - p->stp->ports;
 
828
    ovs_mutex_unlock(&mutex);
 
829
    return index;
673
830
}
674
831
 
675
832
/* Returns the port ID for 'p'. */
676
833
int
677
834
stp_port_get_id(const struct stp_port *p)
678
835
{
679
 
    return p->port_id;
 
836
    int port_id;
 
837
 
 
838
    ovs_mutex_lock(&mutex);
 
839
    port_id = p->port_id;
 
840
    ovs_mutex_unlock(&mutex);
 
841
    return port_id;
680
842
}
681
843
 
682
844
/* Returns the state of port 'p'. */
683
845
enum stp_state
684
846
stp_port_get_state(const struct stp_port *p)
685
847
{
686
 
    return p->state;
 
848
    enum stp_state state;
 
849
 
 
850
    ovs_mutex_lock(&mutex);
 
851
    state = p->state;
 
852
    ovs_mutex_unlock(&mutex);
 
853
    return state;
687
854
}
688
855
 
689
856
/* Returns the role of port 'p'. */
690
857
enum stp_role
691
858
stp_port_get_role(const struct stp_port *p)
692
859
{
693
 
    struct stp_port *root_port = stp_get_root_port(p->stp);
 
860
    struct stp_port *root_port;
 
861
    enum stp_role role;
694
862
 
 
863
    ovs_mutex_lock(&mutex);
 
864
    root_port = p->stp->root_port;
695
865
    if (root_port && root_port->port_id == p->port_id) {
696
 
        return STP_ROLE_ROOT;
 
866
        role = STP_ROLE_ROOT;
697
867
    } else if (stp_is_designated_port(p)) {
698
 
        return STP_ROLE_DESIGNATED;
 
868
        role = STP_ROLE_DESIGNATED;
699
869
    } else if (p->state == STP_DISABLED) {
700
 
        return STP_ROLE_DISABLED;
 
870
        role = STP_ROLE_DISABLED;
701
871
    } else {
702
 
        return STP_ROLE_ALTERNATE;
 
872
        role = STP_ROLE_ALTERNATE;
703
873
    }
 
874
    ovs_mutex_unlock(&mutex);
 
875
    return role;
704
876
}
705
877
 
706
878
/* Retrieves BPDU transmit and receive counts for 'p'. */
707
 
void stp_port_get_counts(const struct stp_port *p,
708
 
                         int *tx_count, int *rx_count, int *error_count)
 
879
void
 
880
stp_port_get_counts(const struct stp_port *p,
 
881
                    int *tx_count, int *rx_count, int *error_count)
709
882
{
 
883
    ovs_mutex_lock(&mutex);
710
884
    *tx_count = p->tx_count;
711
885
    *rx_count = p->rx_count;
712
886
    *error_count = p->error_count;
 
887
    ovs_mutex_unlock(&mutex);
713
888
}
714
889
 
715
890
/* Disables STP on port 'p'. */
716
891
void
717
892
stp_port_disable(struct stp_port *p)
718
893
{
719
 
    struct stp *stp = p->stp;
 
894
    struct stp *stp;
 
895
 
 
896
    ovs_mutex_lock(&mutex);
 
897
    stp = p->stp;
720
898
    if (p->state != STP_DISABLED) {
721
899
        bool root = stp_is_root_bridge(stp);
722
900
        stp_become_designated_port(p);
732
910
        }
733
911
        p->aux = NULL;
734
912
    }
 
913
    ovs_mutex_unlock(&mutex);
735
914
}
736
915
 
737
916
/* Enables STP on port 'p'.  The port will initially be in "blocking" state. */
738
917
void
739
918
stp_port_enable(struct stp_port *p)
740
919
{
 
920
    ovs_mutex_lock(&mutex);
741
921
    if (p->state == STP_DISABLED) {
742
922
        stp_initialize_port(p, STP_BLOCKING);
743
923
        stp_port_state_selection(p->stp);
744
924
    }
 
925
    ovs_mutex_unlock(&mutex);
745
926
}
746
927
 
747
928
/* Sets the priority of port 'p' to 'new_priority'.  Lower numerical values
749
930
void
750
931
stp_port_set_priority(struct stp_port *p, uint8_t new_priority)
751
932
{
752
 
    uint16_t new_port_id = (p->port_id & 0xff) | (new_priority << 8);
 
933
    uint16_t new_port_id;
 
934
 
 
935
    ovs_mutex_lock(&mutex);
 
936
    new_port_id  = (p->port_id & 0xff) | (new_priority << 8);
753
937
    if (p->port_id != new_port_id) {
754
938
        struct stp *stp = p->stp;
755
939
        if (stp_is_designated_port(p)) {
762
946
            stp_port_state_selection(stp);
763
947
        }
764
948
    }
 
949
    ovs_mutex_unlock(&mutex);
765
950
}
766
951
 
767
952
/* Convert 'speed' (measured in Mb/s) into the path cost. */
768
953
uint16_t
769
954
stp_convert_speed_to_cost(unsigned int speed)
770
955
{
771
 
    return speed >= 10000 ? 2  /* 10 Gb/s. */
772
 
           : speed >= 1000 ? 4 /* 1 Gb/s. */
773
 
           : speed >= 100 ? 19 /* 100 Mb/s. */
774
 
           : speed >= 16 ? 62  /* 16 Mb/s. */
775
 
           : speed >= 10 ? 100 /* 10 Mb/s. */
776
 
           : speed >= 4 ? 250  /* 4 Mb/s. */
777
 
           : 19;             /* 100 Mb/s (guess). */
 
956
    uint16_t ret;
 
957
 
 
958
    ovs_mutex_lock(&mutex);
 
959
    ret = speed >= 10000 ? 2  /* 10 Gb/s. */
 
960
        : speed >= 1000 ? 4 /* 1 Gb/s. */
 
961
        : speed >= 100 ? 19 /* 100 Mb/s. */
 
962
        : speed >= 16 ? 62  /* 16 Mb/s. */
 
963
        : speed >= 10 ? 100 /* 10 Mb/s. */
 
964
        : speed >= 4 ? 250  /* 4 Mb/s. */
 
965
        : 19;             /* 100 Mb/s (guess). */
 
966
    ovs_mutex_unlock(&mutex);
 
967
    return ret;
778
968
}
779
969
 
780
970
/* Sets the path cost of port 'p' to 'path_cost'.  Lower values are generally
783
973
void
784
974
stp_port_set_path_cost(struct stp_port *p, uint16_t path_cost)
785
975
{
 
976
    ovs_mutex_lock(&mutex);
786
977
    if (p->path_cost != path_cost) {
787
978
        struct stp *stp = p->stp;
788
979
        p->path_cost = path_cost;
789
980
        stp_configuration_update(stp);
790
981
        stp_port_state_selection(stp);
791
982
    }
 
983
    ovs_mutex_unlock(&mutex);
792
984
}
793
985
 
794
986
/* Sets the path cost of port 'p' based on 'speed' (measured in Mb/s). */
813
1005
}
814
1006
 
815
1007
static void
816
 
stp_transmit_config(struct stp_port *p)
 
1008
stp_transmit_config(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
817
1009
{
818
1010
    struct stp *stp = p->stp;
819
1011
    bool root = stp_is_root_bridge(stp);
860
1052
static bool
861
1053
stp_supersedes_port_info(const struct stp_port *p,
862
1054
                         const struct stp_config_bpdu *config)
 
1055
     OVS_REQ_WRLOCK(mutex)
863
1056
{
864
1057
    if (ntohll(config->root_id) != p->designated_root) {
865
1058
        return ntohll(config->root_id) < p->designated_root;
876
1069
static void
877
1070
stp_record_config_information(struct stp_port *p,
878
1071
                              const struct stp_config_bpdu *config)
 
1072
     OVS_REQ_WRLOCK(mutex)
879
1073
{
880
1074
    p->designated_root = ntohll(config->root_id);
881
1075
    p->designated_cost = ntohl(config->root_path_cost);
887
1081
static void
888
1082
stp_record_config_timeout_values(struct stp *stp,
889
1083
                                 const struct stp_config_bpdu  *config)
 
1084
     OVS_REQ_WRLOCK(mutex)
890
1085
{
891
1086
    stp->max_age = ntohs(config->max_age);
892
1087
    stp->hello_time = ntohs(config->hello_time);
895
1090
}
896
1091
 
897
1092
static bool
898
 
stp_is_designated_port(const struct stp_port *p)
 
1093
stp_is_designated_port(const struct stp_port *p) OVS_REQ_WRLOCK(mutex)
899
1094
{
900
1095
    return (p->designated_bridge == p->stp->bridge_id
901
1096
            && p->designated_port == p->port_id);
902
1097
}
903
1098
 
904
1099
static void
905
 
stp_config_bpdu_generation(struct stp *stp)
 
1100
stp_config_bpdu_generation(struct stp *stp) OVS_REQ_WRLOCK(mutex)
906
1101
{
907
1102
    struct stp_port *p;
908
1103
 
914
1109
}
915
1110
 
916
1111
static void
917
 
stp_transmit_tcn(struct stp *stp)
 
1112
stp_transmit_tcn(struct stp *stp) OVS_REQ_WRLOCK(mutex)
918
1113
{
919
1114
    struct stp_port *p = stp->root_port;
920
1115
    struct stp_tcn_bpdu tcn_bpdu;
928
1123
}
929
1124
 
930
1125
static void
931
 
stp_configuration_update(struct stp *stp)
 
1126
stp_configuration_update(struct stp *stp) OVS_REQ_WRLOCK(mutex)
932
1127
{
933
1128
    stp_root_selection(stp);
934
1129
    stp_designated_port_selection(stp);
936
1131
 
937
1132
static bool
938
1133
stp_supersedes_root(const struct stp_port *root, const struct stp_port *p)
 
1134
    OVS_REQ_WRLOCK(mutex)
939
1135
{
940
1136
    int p_cost = p->designated_cost + p->path_cost;
941
1137
    int root_cost = root->designated_cost + root->path_cost;
954
1150
}
955
1151
 
956
1152
static void
957
 
stp_root_selection(struct stp *stp)
 
1153
stp_root_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
958
1154
{
959
1155
    struct stp_port *p, *root;
960
1156
 
980
1176
}
981
1177
 
982
1178
static void
983
 
stp_designated_port_selection(struct stp *stp)
 
1179
stp_designated_port_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
984
1180
{
985
1181
    struct stp_port *p;
986
1182
 
999
1195
}
1000
1196
 
1001
1197
static void
1002
 
stp_become_designated_port(struct stp_port *p)
 
1198
stp_become_designated_port(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
1003
1199
{
1004
1200
    struct stp *stp = p->stp;
1005
1201
    p->designated_root = stp->designated_root;
1009
1205
}
1010
1206
 
1011
1207
static void
1012
 
stp_port_state_selection(struct stp *stp)
 
1208
stp_port_state_selection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
1013
1209
{
1014
1210
    struct stp_port *p;
1015
1211
 
1030
1226
}
1031
1227
 
1032
1228
static void
1033
 
stp_make_forwarding(struct stp_port *p)
 
1229
stp_make_forwarding(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
1034
1230
{
1035
1231
    if (p->state == STP_BLOCKING) {
1036
1232
        stp_set_port_state(p, STP_LISTENING);
1039
1235
}
1040
1236
 
1041
1237
static void
1042
 
stp_make_blocking(struct stp_port *p)
 
1238
stp_make_blocking(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
1043
1239
{
1044
1240
    if (!(p->state & (STP_DISABLED | STP_BLOCKING))) {
1045
1241
        if (p->state & (STP_FORWARDING | STP_LEARNING)) {
1054
1250
 
1055
1251
static void
1056
1252
stp_set_port_state(struct stp_port *p, enum stp_state state)
 
1253
    OVS_REQ_WRLOCK(mutex)
1057
1254
{
1058
1255
    if (state != p->state && !p->state_changed) {
1059
1256
        p->state_changed = true;
1065
1262
}
1066
1263
 
1067
1264
static void
1068
 
stp_topology_change_detection(struct stp *stp)
 
1265
stp_topology_change_detection(struct stp *stp) OVS_REQ_WRLOCK(mutex)
1069
1266
{
1070
1267
    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
1071
1268
 
1082
1279
}
1083
1280
 
1084
1281
static void
1085
 
stp_topology_change_acknowledged(struct stp *stp)
 
1282
stp_topology_change_acknowledged(struct stp *stp) OVS_REQ_WRLOCK(mutex)
1086
1283
{
1087
1284
    stp->topology_change_detected = false;
1088
1285
    stp_stop_timer(&stp->tcn_timer);
1089
1286
}
1090
1287
 
1091
1288
static void
1092
 
stp_acknowledge_topology_change(struct stp_port *p)
 
1289
stp_acknowledge_topology_change(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
1093
1290
{
1094
1291
    p->topology_change_ack = true;
1095
1292
    stp_transmit_config(p);
1098
1295
static void
1099
1296
stp_received_config_bpdu(struct stp *stp, struct stp_port *p,
1100
1297
                         const struct stp_config_bpdu *config)
 
1298
    OVS_REQ_WRLOCK(mutex)
1101
1299
{
1102
1300
    if (ntohs(config->message_age) >= ntohs(config->max_age)) {
1103
1301
        VLOG_WARN("%s: received config BPDU with message age (%u) greater "
1138
1336
 
1139
1337
static void
1140
1338
stp_received_tcn_bpdu(struct stp *stp, struct stp_port *p)
 
1339
    OVS_REQ_WRLOCK(mutex)
1141
1340
{
1142
1341
    if (p->state != STP_DISABLED) {
1143
1342
        if (stp_is_designated_port(p)) {
1148
1347
}
1149
1348
 
1150
1349
static void
1151
 
stp_hello_timer_expiry(struct stp *stp)
 
1350
stp_hello_timer_expiry(struct stp *stp) OVS_REQ_WRLOCK(mutex)
1152
1351
{
1153
1352
    stp_config_bpdu_generation(stp);
1154
1353
    stp_start_timer(&stp->hello_timer, 0);
1155
1354
}
1156
1355
 
1157
1356
static void
1158
 
stp_message_age_timer_expiry(struct stp_port *p)
 
1357
stp_message_age_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
1159
1358
{
1160
1359
    struct stp *stp = p->stp;
1161
1360
    bool root = stp_is_root_bridge(stp);
1174
1373
}
1175
1374
 
1176
1375
static bool
1177
 
stp_is_designated_for_some_port(const struct stp *stp)
 
1376
stp_is_designated_for_some_port(const struct stp *stp) OVS_REQ_WRLOCK(mutex)
1178
1377
{
1179
1378
    const struct stp_port *p;
1180
1379
 
1187
1386
}
1188
1387
 
1189
1388
static void
1190
 
stp_forward_delay_timer_expiry(struct stp_port *p)
 
1389
stp_forward_delay_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
1191
1390
{
1192
1391
    if (p->state == STP_LISTENING) {
1193
1392
        stp_set_port_state(p, STP_LEARNING);
1203
1402
}
1204
1403
 
1205
1404
static void
1206
 
stp_tcn_timer_expiry(struct stp *stp)
 
1405
stp_tcn_timer_expiry(struct stp *stp) OVS_REQ_WRLOCK(mutex)
1207
1406
{
1208
1407
    stp_transmit_tcn(stp);
1209
1408
    stp_start_timer(&stp->tcn_timer, 0);
1210
1409
}
1211
1410
 
1212
1411
static void
1213
 
stp_topology_change_timer_expiry(struct stp *stp)
 
1412
stp_topology_change_timer_expiry(struct stp *stp) OVS_REQ_WRLOCK(mutex)
1214
1413
{
1215
1414
    stp->topology_change_detected = false;
1216
1415
    stp->topology_change = false;
1217
1416
}
1218
1417
 
1219
1418
static void
1220
 
stp_hold_timer_expiry(struct stp_port *p)
 
1419
stp_hold_timer_expiry(struct stp_port *p) OVS_REQ_WRLOCK(mutex)
1221
1420
{
1222
1421
    if (p->config_pending) {
1223
1422
        stp_transmit_config(p);
1226
1425
 
1227
1426
static void
1228
1427
stp_initialize_port(struct stp_port *p, enum stp_state state)
 
1428
    OVS_REQ_WRLOCK(mutex)
1229
1429
{
1230
1430
    ovs_assert(state & (STP_DISABLED | STP_BLOCKING));
1231
1431
    stp_become_designated_port(p);
1241
1441
}
1242
1442
 
1243
1443
static void
1244
 
stp_become_root_bridge(struct stp *stp)
 
1444
stp_become_root_bridge(struct stp *stp) OVS_REQ_WRLOCK(mutex)
1245
1445
{
1246
1446
    stp->max_age = stp->bridge_max_age;
1247
1447
    stp->hello_time = stp->bridge_hello_time;
1253
1453
}
1254
1454
 
1255
1455
static void
1256
 
stp_start_timer(struct stp_timer *timer, int value)
 
1456
stp_start_timer(struct stp_timer *timer, int value) OVS_REQ_WRLOCK(mutex)
1257
1457
{
1258
1458
    timer->value = value;
1259
1459
    timer->active = true;
1260
1460
}
1261
1461
 
1262
1462
static void
1263
 
stp_stop_timer(struct stp_timer *timer)
 
1463
stp_stop_timer(struct stp_timer *timer) OVS_REQ_WRLOCK(mutex)
1264
1464
{
1265
1465
    timer->active = false;
1266
1466
}
1267
1467
 
1268
1468
static bool
1269
1469
stp_timer_expired(struct stp_timer *timer, int elapsed, int timeout)
 
1470
    OVS_REQ_WRLOCK(mutex)
1270
1471
{
1271
1472
    if (timer->active) {
1272
1473
        timer->value += elapsed;
1301
1502
}
1302
1503
 
1303
1504
static void
1304
 
stp_update_bridge_timers(struct stp *stp)
 
1505
stp_update_bridge_timers(struct stp *stp) OVS_REQ_WRLOCK(mutex)
1305
1506
{
1306
1507
    int ht, ma, fd;
1307
1508
 
1322
1523
 
1323
1524
static void
1324
1525
stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
 
1526
    OVS_REQ_WRLOCK(mutex)
1325
1527
{
1326
1528
    struct eth_header *eth;
1327
1529
    struct llc_header *llc;
1350
1552
/* Unixctl. */
1351
1553
 
1352
1554
static struct stp *
1353
 
stp_find(const char *name)
 
1555
stp_find(const char *name) OVS_REQ_WRLOCK(mutex)
1354
1556
{
1355
1557
    struct stp *stp;
1356
1558
 
1357
 
    LIST_FOR_EACH (stp, node, &all_stps) {
 
1559
    LIST_FOR_EACH (stp, node, all_stps) {
1358
1560
        if (!strcmp(stp->name, name)) {
1359
1561
            return stp;
1360
1562
        }
1366
1568
stp_unixctl_tcn(struct unixctl_conn *conn, int argc,
1367
1569
                const char *argv[], void *aux OVS_UNUSED)
1368
1570
{
 
1571
    ovs_mutex_lock(&mutex);
1369
1572
    if (argc > 1) {
1370
1573
        struct stp *stp = stp_find(argv[1]);
1371
1574
 
1372
1575
        if (!stp) {
1373
1576
            unixctl_command_reply_error(conn, "no such stp object");
1374
 
            return;
 
1577
            goto out;
1375
1578
        }
1376
1579
        stp_topology_change_detection(stp);
1377
1580
    } else {
1378
1581
        struct stp *stp;
1379
1582
 
1380
 
        LIST_FOR_EACH (stp, node, &all_stps) {
 
1583
        LIST_FOR_EACH (stp, node, all_stps) {
1381
1584
            stp_topology_change_detection(stp);
1382
1585
        }
1383
1586
    }
1384
1587
 
1385
1588
    unixctl_command_reply(conn, "OK");
 
1589
 
 
1590
out:
 
1591
    ovs_mutex_unlock(&mutex);
1386
1592
}