tests: Add MPLS + VLAN tests.
[sliver-openvswitch.git] / ofproto / ofproto-dpif-mirror.c
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
79 struct mbridge *
80 mbridge_create(void)
81 {
82     struct mbridge *mbridge;
83
84     mbridge = xzalloc(sizeof *mbridge);
85     mbridge->ref_cnt = 1;
86
87     hmap_init(&mbridge->mbundles);
88     return mbridge;
89 }
90
91 struct mbridge *
92 mbridge_ref(const struct mbridge *mbridge_)
93 {
94     struct mbridge *mbridge = CONST_CAST(struct mbridge *, mbridge_);
95     if (mbridge) {
96         ovs_assert(mbridge->ref_cnt > 0);
97         mbridge->ref_cnt++;
98     }
99     return mbridge;
100 }
101
102 void
103 mbridge_unref(struct mbridge *mbridge)
104 {
105     struct mbundle *mbundle, *next;
106     size_t i;
107
108     if (!mbridge) {
109         return;
110     }
111
112     ovs_assert(mbridge->ref_cnt > 0);
113     if (--mbridge->ref_cnt) {
114         return;
115     }
116
117     for (i = 0; i < MAX_MIRRORS; i++) {
118         if (mbridge->mirrors[i]) {
119             mirror_destroy(mbridge, mbridge->mirrors[i]->aux);
120         }
121     }
122
123     HMAP_FOR_EACH_SAFE (mbundle, next, hmap_node, &mbridge->mbundles) {
124         mbridge_unregister_bundle(mbridge, mbundle->ofbundle);
125     }
126
127     hmap_destroy(&mbridge->mbundles);
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[raw_ctz(mirrors)];
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 \f
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 }