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

« back to all changes in this revision

Viewing changes to ofproto/ofproto-dpif-mirror.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:
 
1
/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
 
2
 *
 
3
 * Licensed under the Apache License, Version 2.0 (the "License");
 
4
 * you may not use this file except in compliance with the License.
 
5
 * You may obtain a copy of the License at:
 
6
 *
 
7
 *     http://www.apache.org/licenses/LICENSE-2.0
 
8
 *
 
9
 * Unless required by applicable law or agreed to in writing, software
 
10
 * distributed under the License is distributed on an "AS IS" BASIS,
 
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
12
 * See the License for the specific language governing permissions and
 
13
 * limitations under the License. */
 
14
 
 
15
#include <config.h>
 
16
 
 
17
#include "ofproto-dpif-mirror.h"
 
18
 
 
19
#include <errno.h>
 
20
 
 
21
#include "hmap.h"
 
22
#include "hmapx.h"
 
23
#include "ofproto.h"
 
24
#include "vlan-bitmap.h"
 
25
#include "vlog.h"
 
26
 
 
27
VLOG_DEFINE_THIS_MODULE(ofproto_dpif_mirror);
 
28
 
 
29
#define MIRROR_MASK_C(X) UINT32_C(X)
 
30
BUILD_ASSERT_DECL(sizeof(mirror_mask_t) * CHAR_BIT >= MAX_MIRRORS);
 
31
 
 
32
struct mbridge {
 
33
    struct mirror *mirrors[MAX_MIRRORS];
 
34
    struct hmap mbundles;
 
35
 
 
36
    bool need_revalidate;
 
37
    bool has_mirrors;
 
38
 
 
39
    int ref_cnt;
 
40
};
 
41
 
 
42
struct mbundle {
 
43
    struct hmap_node hmap_node; /* In parent 'mbridge' map. */
 
44
    struct ofbundle *ofbundle;
 
45
 
 
46
    mirror_mask_t src_mirrors;  /* Mirrors triggered when packet received. */
 
47
    mirror_mask_t dst_mirrors;  /* Mirrors triggered when packet sent. */
 
48
    mirror_mask_t mirror_out;   /* Mirrors that output to this mbundle. */
 
49
};
 
50
 
 
51
struct mirror {
 
52
    struct mbridge *mbridge;    /* Owning ofproto. */
 
53
    size_t idx;                 /* In ofproto's "mirrors" array. */
 
54
    void *aux;                  /* Key supplied by ofproto's client. */
 
55
 
 
56
    /* Selection criteria. */
 
57
    struct hmapx srcs;          /* Contains "struct mbundle*"s. */
 
58
    struct hmapx dsts;          /* Contains "struct mbundle*"s. */
 
59
    unsigned long *vlans;       /* Bitmap of chosen VLANs, NULL selects all. */
 
60
 
 
61
    /* Output (exactly one of out == NULL and out_vlan == -1 is true). */
 
62
    struct mbundle *out;        /* Output port or NULL. */
 
63
    int out_vlan;               /* Output VLAN or -1. */
 
64
    mirror_mask_t dup_mirrors;  /* Bitmap of mirrors with the same output. */
 
65
 
 
66
    /* Counters. */
 
67
    int64_t packet_count;       /* Number of packets sent. */
 
68
    int64_t byte_count;         /* Number of bytes sent. */
 
69
};
 
70
 
 
71
static struct mirror *mirror_lookup(struct mbridge *, void *aux);
 
72
static struct mbundle *mbundle_lookup(const struct mbridge *,
 
73
                                      struct ofbundle *);
 
74
static void mbundle_lookup_multiple(const struct mbridge *, struct ofbundle **,
 
75
                                  size_t n_bundles, struct hmapx *mbundles);
 
76
static int mirror_scan(struct mbridge *);
 
77
static void mirror_update_dups(struct mbridge *);
 
78
static int mirror_mask_ffs(mirror_mask_t);
 
79
 
 
80
struct mbridge *
 
81
mbridge_create(void)
 
82
{
 
83
    struct mbridge *mbridge;
 
84
 
 
85
    mbridge = xzalloc(sizeof *mbridge);
 
86
    mbridge->ref_cnt = 1;
 
87
 
 
88
    hmap_init(&mbridge->mbundles);
 
89
    return mbridge;
 
90
}
 
91
 
 
92
struct mbridge *
 
93
mbridge_ref(const struct mbridge *mbridge_)
 
94
{
 
95
    struct mbridge *mbridge = CONST_CAST(struct mbridge *, mbridge_);
 
96
    if (mbridge) {
 
97
        ovs_assert(mbridge->ref_cnt > 0);
 
98
        mbridge->ref_cnt++;
 
99
    }
 
100
    return mbridge;
 
101
}
 
102
 
 
103
void
 
104
mbridge_unref(struct mbridge *mbridge)
 
105
{
 
106
    struct mbundle *mbundle, *next;
 
107
    size_t i;
 
108
 
 
109
    if (!mbridge) {
 
110
        return;
 
111
    }
 
112
 
 
113
    ovs_assert(mbridge->ref_cnt > 0);
 
114
    if (--mbridge->ref_cnt) {
 
115
        return;
 
116
    }
 
117
 
 
118
    for (i = 0; i < MAX_MIRRORS; i++) {
 
119
        if (mbridge->mirrors[i]) {
 
120
            mirror_destroy(mbridge, mbridge->mirrors[i]->aux);
 
121
        }
 
122
    }
 
123
 
 
124
    HMAP_FOR_EACH_SAFE (mbundle, next, hmap_node, &mbridge->mbundles) {
 
125
        mbridge_unregister_bundle(mbridge, mbundle->ofbundle);
 
126
    }
 
127
 
 
128
    free(mbridge);
 
129
}
 
130
 
 
131
bool
 
132
mbridge_has_mirrors(struct mbridge *mbridge)
 
133
{
 
134
    return mbridge ? mbridge->has_mirrors : false;
 
135
}
 
136
 
 
137
/* Returns true if configurations changes in 'mbridge''s mirrors require
 
138
 * revalidation. */
 
139
bool
 
140
mbridge_need_revalidate(struct mbridge *mbridge)
 
141
{
 
142
    return mbridge->need_revalidate;
 
143
}
 
144
 
 
145
void
 
146
mbridge_register_bundle(struct mbridge *mbridge, struct ofbundle *ofbundle)
 
147
{
 
148
    struct mbundle *mbundle;
 
149
 
 
150
    mbundle = xzalloc(sizeof *mbundle);
 
151
    mbundle->ofbundle = ofbundle;
 
152
    hmap_insert(&mbridge->mbundles, &mbundle->hmap_node,
 
153
                hash_pointer(ofbundle, 0));
 
154
}
 
155
 
 
156
void
 
157
mbridge_unregister_bundle(struct mbridge *mbridge, struct ofbundle *ofbundle)
 
158
{
 
159
    struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
 
160
    size_t i;
 
161
 
 
162
    if (!mbundle) {
 
163
        return;
 
164
    }
 
165
 
 
166
    for (i = 0; i < MAX_MIRRORS; i++) {
 
167
        struct mirror *m = mbridge->mirrors[i];
 
168
        if (m) {
 
169
            if (m->out == mbundle) {
 
170
                mirror_destroy(mbridge, m->aux);
 
171
            } else if (hmapx_find_and_delete(&m->srcs, mbundle)
 
172
                       || hmapx_find_and_delete(&m->dsts, mbundle)) {
 
173
                mbridge->need_revalidate = true;
 
174
            }
 
175
        }
 
176
    }
 
177
 
 
178
    hmap_remove(&mbridge->mbundles, &mbundle->hmap_node);
 
179
    free(mbundle);
 
180
}
 
181
 
 
182
mirror_mask_t
 
183
mirror_bundle_out(struct mbridge *mbridge, struct ofbundle *ofbundle)
 
184
{
 
185
    struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
 
186
    return mbundle ? mbundle->mirror_out : 0;
 
187
}
 
188
 
 
189
mirror_mask_t
 
190
mirror_bundle_src(struct mbridge *mbridge, struct ofbundle *ofbundle)
 
191
{
 
192
    struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
 
193
    return mbundle ? mbundle->src_mirrors : 0;
 
194
}
 
195
 
 
196
mirror_mask_t
 
197
mirror_bundle_dst(struct mbridge *mbridge, struct ofbundle *ofbundle)
 
198
{
 
199
    struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
 
200
    return mbundle ? mbundle->dst_mirrors : 0;
 
201
}
 
202
 
 
203
int
 
204
mirror_set(struct mbridge *mbridge, void *aux, const char *name,
 
205
           struct ofbundle **srcs, size_t n_srcs,
 
206
           struct ofbundle **dsts, size_t n_dsts,
 
207
           unsigned long *src_vlans, struct ofbundle *out_bundle,
 
208
           uint16_t out_vlan)
 
209
{
 
210
    struct mbundle *mbundle, *out;
 
211
    mirror_mask_t mirror_bit;
 
212
    struct mirror *mirror;
 
213
    struct hmapx srcs_map;          /* Contains "struct ofbundle *"s. */
 
214
    struct hmapx dsts_map;          /* Contains "struct ofbundle *"s. */
 
215
 
 
216
    mirror = mirror_lookup(mbridge, aux);
 
217
    if (!mirror) {
 
218
        int idx;
 
219
 
 
220
        idx = mirror_scan(mbridge);
 
221
        if (idx < 0) {
 
222
            VLOG_WARN("maximum of %d port mirrors reached, cannot create %s",
 
223
                      MAX_MIRRORS, name);
 
224
            return EFBIG;
 
225
        }
 
226
 
 
227
        mirror = mbridge->mirrors[idx] = xzalloc(sizeof *mirror);
 
228
        mirror->mbridge = mbridge;
 
229
        mirror->idx = idx;
 
230
        mirror->aux = aux;
 
231
        mirror->out_vlan = -1;
 
232
    }
 
233
 
 
234
    /* Get the new configuration. */
 
235
    if (out_bundle) {
 
236
        out = mbundle_lookup(mbridge, out_bundle);
 
237
        if (!out) {
 
238
            mirror_destroy(mbridge, mirror->aux);
 
239
            return EINVAL;
 
240
        }
 
241
        out_vlan = -1;
 
242
    } else {
 
243
        out = NULL;
 
244
    }
 
245
    mbundle_lookup_multiple(mbridge, srcs, n_srcs, &srcs_map);
 
246
    mbundle_lookup_multiple(mbridge, dsts, n_dsts, &dsts_map);
 
247
 
 
248
    /* If the configuration has not changed, do nothing. */
 
249
    if (hmapx_equals(&srcs_map, &mirror->srcs)
 
250
        && hmapx_equals(&dsts_map, &mirror->dsts)
 
251
        && vlan_bitmap_equal(mirror->vlans, src_vlans)
 
252
        && mirror->out == out
 
253
        && mirror->out_vlan == out_vlan)
 
254
    {
 
255
        hmapx_destroy(&srcs_map);
 
256
        hmapx_destroy(&dsts_map);
 
257
        return 0;
 
258
    }
 
259
 
 
260
    hmapx_swap(&srcs_map, &mirror->srcs);
 
261
    hmapx_destroy(&srcs_map);
 
262
 
 
263
    hmapx_swap(&dsts_map, &mirror->dsts);
 
264
    hmapx_destroy(&dsts_map);
 
265
 
 
266
    free(mirror->vlans);
 
267
    mirror->vlans = vlan_bitmap_clone(src_vlans);
 
268
 
 
269
    mirror->out = out;
 
270
    mirror->out_vlan = out_vlan;
 
271
 
 
272
    /* Update mbundles. */
 
273
    mirror_bit = MIRROR_MASK_C(1) << mirror->idx;
 
274
    HMAP_FOR_EACH (mbundle, hmap_node, &mirror->mbridge->mbundles) {
 
275
        if (hmapx_contains(&mirror->srcs, mbundle)) {
 
276
            mbundle->src_mirrors |= mirror_bit;
 
277
        } else {
 
278
            mbundle->src_mirrors &= ~mirror_bit;
 
279
        }
 
280
 
 
281
        if (hmapx_contains(&mirror->dsts, mbundle)) {
 
282
            mbundle->dst_mirrors |= mirror_bit;
 
283
        } else {
 
284
            mbundle->dst_mirrors &= ~mirror_bit;
 
285
        }
 
286
 
 
287
        if (mirror->out == mbundle) {
 
288
            mbundle->mirror_out |= mirror_bit;
 
289
        } else {
 
290
            mbundle->mirror_out &= ~mirror_bit;
 
291
        }
 
292
    }
 
293
 
 
294
    mbridge->has_mirrors = true;
 
295
    mirror_update_dups(mbridge);
 
296
 
 
297
    return 0;
 
298
}
 
299
 
 
300
void
 
301
mirror_destroy(struct mbridge *mbridge, void *aux)
 
302
{
 
303
    struct mirror *mirror = mirror_lookup(mbridge, aux);
 
304
    mirror_mask_t mirror_bit;
 
305
    struct mbundle *mbundle;
 
306
    int i;
 
307
 
 
308
    if (!mirror) {
 
309
        return;
 
310
    }
 
311
 
 
312
    mirror_bit = MIRROR_MASK_C(1) << mirror->idx;
 
313
    HMAP_FOR_EACH (mbundle, hmap_node, &mbridge->mbundles) {
 
314
        mbundle->src_mirrors &= ~mirror_bit;
 
315
        mbundle->dst_mirrors &= ~mirror_bit;
 
316
        mbundle->mirror_out &= ~mirror_bit;
 
317
    }
 
318
 
 
319
    hmapx_destroy(&mirror->srcs);
 
320
    hmapx_destroy(&mirror->dsts);
 
321
    free(mirror->vlans);
 
322
 
 
323
    mbridge->mirrors[mirror->idx] = NULL;
 
324
    free(mirror);
 
325
 
 
326
    mirror_update_dups(mbridge);
 
327
 
 
328
    mbridge->has_mirrors = false;
 
329
    for (i = 0; i < MAX_MIRRORS; i++) {
 
330
        if (mbridge->mirrors[i]) {
 
331
            mbridge->has_mirrors = true;
 
332
            break;
 
333
        }
 
334
    }
 
335
}
 
336
 
 
337
int
 
338
mirror_get_stats(struct mbridge *mbridge, void *aux, uint64_t *packets,
 
339
                 uint64_t *bytes)
 
340
{
 
341
    struct mirror *mirror = mirror_lookup(mbridge, aux);
 
342
 
 
343
    if (!mirror) {
 
344
        *packets = *bytes = UINT64_MAX;
 
345
        return 0;
 
346
    }
 
347
 
 
348
    *packets = mirror->packet_count;
 
349
    *bytes = mirror->byte_count;
 
350
 
 
351
    return 0;
 
352
}
 
353
 
 
354
void
 
355
mirror_update_stats(struct mbridge *mbridge, mirror_mask_t mirrors,
 
356
                    uint64_t packets, uint64_t bytes)
 
357
{
 
358
    if (!mbridge || !mirrors) {
 
359
        return;
 
360
    }
 
361
 
 
362
    for (; mirrors; mirrors = zero_rightmost_1bit(mirrors)) {
 
363
        struct mirror *m;
 
364
 
 
365
        m = mbridge->mirrors[mirror_mask_ffs(mirrors) - 1];
 
366
 
 
367
        if (!m) {
 
368
            /* In normal circumstances 'm' will not be NULL.  However,
 
369
             * if mirrors are reconfigured, we can temporarily get out
 
370
             * of sync in facet_revalidate().  We could "correct" the
 
371
             * mirror list before reaching here, but doing that would
 
372
             * not properly account the traffic stats we've currently
 
373
             * accumulated for previous mirror configuration. */
 
374
            continue;
 
375
        }
 
376
 
 
377
        m->packet_count += packets;
 
378
        m->byte_count += bytes;
 
379
    }
 
380
}
 
381
 
 
382
/* Retrieves the mirror in 'mbridge' represented by the first bet set of
 
383
 * 'mirrors'.  Returns true if such a mirror exists, false otherwise.
 
384
 * The caller takes ownership of, and is expected to deallocate, 'vlans' */
 
385
bool
 
386
mirror_get(struct mbridge *mbridge, int index, unsigned long **vlans,
 
387
           mirror_mask_t *dup_mirrors, struct ofbundle **out, int *out_vlan)
 
388
{
 
389
    struct mirror *mirror;
 
390
 
 
391
    if (!mbridge) {
 
392
        return false;
 
393
    }
 
394
 
 
395
    mirror = mbridge->mirrors[index];
 
396
    if (!mirror) {
 
397
        return false;
 
398
    }
 
399
 
 
400
    *vlans = vlan_bitmap_clone(mirror->vlans);
 
401
    *dup_mirrors = mirror->dup_mirrors;
 
402
    *out = mirror->out ? mirror->out->ofbundle : NULL;
 
403
    *out_vlan = mirror->out_vlan;
 
404
    return true;
 
405
}
 
406
 
 
407
/* Helpers. */
 
408
 
 
409
static struct mbundle *
 
410
mbundle_lookup(const struct mbridge *mbridge, struct ofbundle *ofbundle)
 
411
{
 
412
    struct mbundle *mbundle;
 
413
 
 
414
    HMAP_FOR_EACH_IN_BUCKET (mbundle, hmap_node, hash_pointer(ofbundle, 0),
 
415
                             &mbridge->mbundles) {
 
416
        if (mbundle->ofbundle == ofbundle) {
 
417
            return mbundle;
 
418
        }
 
419
    }
 
420
    return NULL;
 
421
}
 
422
 
 
423
/* Looks up each of the 'n_ofbundlees' pointers in 'ofbundlees' as mbundles and
 
424
 * adds the ones that are found to 'mbundles'. */
 
425
static void
 
426
mbundle_lookup_multiple(const struct mbridge *mbridge,
 
427
                        struct ofbundle **ofbundles, size_t n_ofbundles,
 
428
                        struct hmapx *mbundles)
 
429
{
 
430
    size_t i;
 
431
 
 
432
    hmapx_init(mbundles);
 
433
    for (i = 0; i < n_ofbundles; i++) {
 
434
        struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundles[i]);
 
435
        if (mbundle) {
 
436
            hmapx_add(mbundles, mbundle);
 
437
        }
 
438
    }
 
439
}
 
440
 
 
441
static int
 
442
mirror_scan(struct mbridge *mbridge)
 
443
{
 
444
    int idx;
 
445
 
 
446
    for (idx = 0; idx < MAX_MIRRORS; idx++) {
 
447
        if (!mbridge->mirrors[idx]) {
 
448
            return idx;
 
449
        }
 
450
    }
 
451
    return -1;
 
452
}
 
453
 
 
454
static struct mirror *
 
455
mirror_lookup(struct mbridge *mbridge, void *aux)
 
456
{
 
457
    int i;
 
458
 
 
459
    for (i = 0; i < MAX_MIRRORS; i++) {
 
460
        struct mirror *mirror = mbridge->mirrors[i];
 
461
        if (mirror && mirror->aux == aux) {
 
462
            return mirror;
 
463
        }
 
464
    }
 
465
 
 
466
    return NULL;
 
467
}
 
468
 
 
469
/* Update the 'dup_mirrors' member of each of the mirrors in 'ofproto'. */
 
470
static void
 
471
mirror_update_dups(struct mbridge *mbridge)
 
472
{
 
473
    int i;
 
474
 
 
475
    for (i = 0; i < MAX_MIRRORS; i++) {
 
476
        struct mirror *m = mbridge->mirrors[i];
 
477
 
 
478
        if (m) {
 
479
            m->dup_mirrors = MIRROR_MASK_C(1) << i;
 
480
        }
 
481
    }
 
482
 
 
483
    for (i = 0; i < MAX_MIRRORS; i++) {
 
484
        struct mirror *m1 = mbridge->mirrors[i];
 
485
        int j;
 
486
 
 
487
        if (!m1) {
 
488
            continue;
 
489
        }
 
490
 
 
491
        for (j = i + 1; j < MAX_MIRRORS; j++) {
 
492
            struct mirror *m2 = mbridge->mirrors[j];
 
493
 
 
494
            if (m2 && m1->out == m2->out && m1->out_vlan == m2->out_vlan) {
 
495
                m1->dup_mirrors |= MIRROR_MASK_C(1) << j;
 
496
                m2->dup_mirrors |= m1->dup_mirrors;
 
497
            }
 
498
        }
 
499
    }
 
500
}