]> git.proxmox.com Git - ovs.git/blob - ofproto/ofproto-dpif-mirror.c
tnl-neigh-cache: Purge learnt neighbors when port/bridge is deleted
[ovs.git] / ofproto / ofproto-dpif-mirror.c
1 /* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2015 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 "cmap.h"
22 #include "hmapx.h"
23 #include "ofproto.h"
24 #include "vlan-bitmap.h"
25 #include "openvswitch/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 cmap mbundles;
35
36 bool need_revalidate;
37 bool has_mirrors;
38
39 struct ovs_refcount ref_cnt;
40 };
41
42 struct mbundle {
43 struct cmap_node cmap_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
60 /* This is accessed by handler threads assuming RCU protection (see
61 * mirror_get()), but can be manipulated by mirror_set() without any
62 * explicit synchronization. */
63 OVSRCU_TYPE(unsigned long *) vlans; /* Bitmap of chosen VLANs, NULL
64 * selects all. */
65
66 /* Output (exactly one of out == NULL and out_vlan == -1 is true). */
67 struct mbundle *out; /* Output port or NULL. */
68 int out_vlan; /* Output VLAN or -1. */
69 uint16_t snaplen; /* Max per mirrored packet size in byte,
70 set to 0 equals 65535. */
71 mirror_mask_t dup_mirrors; /* Bitmap of mirrors with the same output. */
72
73 /* Counters. */
74 int64_t packet_count; /* Number of packets sent. */
75 int64_t byte_count; /* Number of bytes sent. */
76 };
77
78 static struct mirror *mirror_lookup(struct mbridge *, void *aux);
79 static struct mbundle *mbundle_lookup(const struct mbridge *,
80 struct ofbundle *);
81 static void mbundle_lookup_multiple(const struct mbridge *, struct ofbundle **,
82 size_t n_bundles, struct hmapx *mbundles);
83 static int mirror_scan(struct mbridge *);
84 static void mirror_update_dups(struct mbridge *);
85
86 struct mbridge *
87 mbridge_create(void)
88 {
89 struct mbridge *mbridge;
90
91 mbridge = xzalloc(sizeof *mbridge);
92 ovs_refcount_init(&mbridge->ref_cnt);
93
94 cmap_init(&mbridge->mbundles);
95 return mbridge;
96 }
97
98 struct mbridge *
99 mbridge_ref(const struct mbridge *mbridge_)
100 {
101 struct mbridge *mbridge = CONST_CAST(struct mbridge *, mbridge_);
102 if (mbridge) {
103 ovs_refcount_ref(&mbridge->ref_cnt);
104 }
105 return mbridge;
106 }
107
108 void
109 mbridge_unref(struct mbridge *mbridge)
110 {
111 struct mbundle *mbundle;
112 size_t i;
113
114 if (!mbridge) {
115 return;
116 }
117
118 if (ovs_refcount_unref(&mbridge->ref_cnt) == 1) {
119 for (i = 0; i < MAX_MIRRORS; i++) {
120 if (mbridge->mirrors[i]) {
121 mirror_destroy(mbridge, mbridge->mirrors[i]->aux);
122 }
123 }
124
125 CMAP_FOR_EACH (mbundle, cmap_node, &mbridge->mbundles) {
126 mbridge_unregister_bundle(mbridge, mbundle->ofbundle);
127 }
128
129 cmap_destroy(&mbridge->mbundles);
130 ovsrcu_postpone(free, mbridge);
131 }
132 }
133
134 bool
135 mbridge_has_mirrors(struct mbridge *mbridge)
136 {
137 return mbridge ? mbridge->has_mirrors : false;
138 }
139
140 /* Returns true if configurations changes in 'mbridge''s mirrors require
141 * revalidation, and resets the revalidation flag to false. */
142 bool
143 mbridge_need_revalidate(struct mbridge *mbridge)
144 {
145 bool need_revalidate = mbridge->need_revalidate;
146 mbridge->need_revalidate = false;
147 return need_revalidate;
148 }
149
150 void
151 mbridge_register_bundle(struct mbridge *mbridge, struct ofbundle *ofbundle)
152 {
153 struct mbundle *mbundle;
154
155 mbundle = xzalloc(sizeof *mbundle);
156 mbundle->ofbundle = ofbundle;
157 cmap_insert(&mbridge->mbundles, &mbundle->cmap_node,
158 hash_pointer(ofbundle, 0));
159 }
160
161 void
162 mbridge_unregister_bundle(struct mbridge *mbridge, struct ofbundle *ofbundle)
163 {
164 struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
165 size_t i;
166
167 if (!mbundle) {
168 return;
169 }
170
171 for (i = 0; i < MAX_MIRRORS; i++) {
172 struct mirror *m = mbridge->mirrors[i];
173 if (m) {
174 if (m->out == mbundle) {
175 mirror_destroy(mbridge, m->aux);
176 } else if (hmapx_find_and_delete(&m->srcs, mbundle)
177 || hmapx_find_and_delete(&m->dsts, mbundle)) {
178 mbridge->need_revalidate = true;
179 }
180 }
181 }
182
183 cmap_remove(&mbridge->mbundles, &mbundle->cmap_node,
184 hash_pointer(ofbundle, 0));
185 ovsrcu_postpone(free, mbundle);
186 }
187
188 mirror_mask_t
189 mirror_bundle_out(struct mbridge *mbridge, struct ofbundle *ofbundle)
190 {
191 struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
192 return mbundle ? mbundle->mirror_out : 0;
193 }
194
195 mirror_mask_t
196 mirror_bundle_src(struct mbridge *mbridge, struct ofbundle *ofbundle)
197 {
198 struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
199 return mbundle ? mbundle->src_mirrors : 0;
200 }
201
202 mirror_mask_t
203 mirror_bundle_dst(struct mbridge *mbridge, struct ofbundle *ofbundle)
204 {
205 struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
206 return mbundle ? mbundle->dst_mirrors : 0;
207 }
208
209 int
210 mirror_set(struct mbridge *mbridge, void *aux, const char *name,
211 struct ofbundle **srcs, size_t n_srcs,
212 struct ofbundle **dsts, size_t n_dsts,
213 unsigned long *src_vlans, struct ofbundle *out_bundle,
214 uint16_t snaplen,
215 uint16_t out_vlan)
216 {
217 struct mbundle *mbundle, *out;
218 mirror_mask_t mirror_bit;
219 struct mirror *mirror;
220 struct hmapx srcs_map; /* Contains "struct ofbundle *"s. */
221 struct hmapx dsts_map; /* Contains "struct ofbundle *"s. */
222
223 mirror = mirror_lookup(mbridge, aux);
224 if (!mirror) {
225 int idx;
226
227 idx = mirror_scan(mbridge);
228 if (idx < 0) {
229 VLOG_WARN("maximum of %d port mirrors reached, cannot create %s",
230 MAX_MIRRORS, name);
231 return EFBIG;
232 }
233
234 mirror = mbridge->mirrors[idx] = xzalloc(sizeof *mirror);
235 mirror->mbridge = mbridge;
236 mirror->idx = idx;
237 mirror->aux = aux;
238 mirror->out_vlan = -1;
239 mirror->snaplen = 0;
240 }
241
242 unsigned long *vlans = ovsrcu_get(unsigned long *, &mirror->vlans);
243
244 /* Get the new configuration. */
245 if (out_bundle) {
246 out = mbundle_lookup(mbridge, out_bundle);
247 if (!out) {
248 mirror_destroy(mbridge, mirror->aux);
249 return EINVAL;
250 }
251 out_vlan = -1;
252 } else {
253 out = NULL;
254 }
255 mbundle_lookup_multiple(mbridge, srcs, n_srcs, &srcs_map);
256 mbundle_lookup_multiple(mbridge, dsts, n_dsts, &dsts_map);
257
258 /* If the configuration has not changed, do nothing. */
259 if (hmapx_equals(&srcs_map, &mirror->srcs)
260 && hmapx_equals(&dsts_map, &mirror->dsts)
261 && vlan_bitmap_equal(vlans, src_vlans)
262 && mirror->out == out
263 && mirror->out_vlan == out_vlan
264 && mirror->snaplen == snaplen)
265 {
266 hmapx_destroy(&srcs_map);
267 hmapx_destroy(&dsts_map);
268 return 0;
269 }
270
271 /* XXX: Not sure if these need to be thread safe. */
272 hmapx_swap(&srcs_map, &mirror->srcs);
273 hmapx_destroy(&srcs_map);
274
275 hmapx_swap(&dsts_map, &mirror->dsts);
276 hmapx_destroy(&dsts_map);
277
278 if (vlans || src_vlans) {
279 ovsrcu_postpone(free, vlans);
280 vlans = vlan_bitmap_clone(src_vlans);
281 ovsrcu_set(&mirror->vlans, vlans);
282 }
283
284 mirror->out = out;
285 mirror->out_vlan = out_vlan;
286 mirror->snaplen = snaplen;
287
288 /* Update mbundles. */
289 mirror_bit = MIRROR_MASK_C(1) << mirror->idx;
290 CMAP_FOR_EACH (mbundle, cmap_node, &mirror->mbridge->mbundles) {
291 if (hmapx_contains(&mirror->srcs, mbundle)) {
292 mbundle->src_mirrors |= mirror_bit;
293 } else {
294 mbundle->src_mirrors &= ~mirror_bit;
295 }
296
297 if (hmapx_contains(&mirror->dsts, mbundle)) {
298 mbundle->dst_mirrors |= mirror_bit;
299 } else {
300 mbundle->dst_mirrors &= ~mirror_bit;
301 }
302
303 if (mirror->out == mbundle) {
304 mbundle->mirror_out |= mirror_bit;
305 } else {
306 mbundle->mirror_out &= ~mirror_bit;
307 }
308 }
309
310 mbridge->has_mirrors = true;
311 mirror_update_dups(mbridge);
312
313 return 0;
314 }
315
316 void
317 mirror_destroy(struct mbridge *mbridge, void *aux)
318 {
319 struct mirror *mirror = mirror_lookup(mbridge, aux);
320 mirror_mask_t mirror_bit;
321 struct mbundle *mbundle;
322 int i;
323
324 if (!mirror) {
325 return;
326 }
327
328 mirror_bit = MIRROR_MASK_C(1) << mirror->idx;
329 CMAP_FOR_EACH (mbundle, cmap_node, &mbridge->mbundles) {
330 mbundle->src_mirrors &= ~mirror_bit;
331 mbundle->dst_mirrors &= ~mirror_bit;
332 mbundle->mirror_out &= ~mirror_bit;
333 }
334
335 hmapx_destroy(&mirror->srcs);
336 hmapx_destroy(&mirror->dsts);
337
338 unsigned long *vlans = ovsrcu_get(unsigned long *, &mirror->vlans);
339 if (vlans) {
340 ovsrcu_postpone(free, vlans);
341 }
342
343 mbridge->mirrors[mirror->idx] = NULL;
344 /* mirror_get() might have just read the pointer, so we must postpone the
345 * free. */
346 ovsrcu_postpone(free, mirror);
347
348 mirror_update_dups(mbridge);
349
350 mbridge->has_mirrors = false;
351 for (i = 0; i < MAX_MIRRORS; i++) {
352 if (mbridge->mirrors[i]) {
353 mbridge->has_mirrors = true;
354 break;
355 }
356 }
357 }
358
359 int
360 mirror_get_stats(struct mbridge *mbridge, void *aux, uint64_t *packets,
361 uint64_t *bytes)
362 {
363 struct mirror *mirror = mirror_lookup(mbridge, aux);
364
365 if (!mirror) {
366 *packets = *bytes = UINT64_MAX;
367 return 0;
368 }
369
370 *packets = mirror->packet_count;
371 *bytes = mirror->byte_count;
372
373 return 0;
374 }
375
376 void
377 mirror_update_stats(struct mbridge *mbridge, mirror_mask_t mirrors,
378 uint64_t packets, uint64_t bytes)
379 {
380 if (!mbridge || !mirrors) {
381 return;
382 }
383
384 for (; mirrors; mirrors = zero_rightmost_1bit(mirrors)) {
385 struct mirror *m;
386
387 m = mbridge->mirrors[raw_ctz(mirrors)];
388
389 if (!m) {
390 /* In normal circumstances 'm' will not be NULL. However, if
391 * mirrors are reconfigured, we can temporarily get out of sync.
392 * We could "correct" the mirror list before reaching here, but
393 * doing that would not properly account the traffic stats we've
394 * currently accumulated for previous mirror configuration. */
395 continue;
396 }
397
398 /* XXX: This is not thread safe, yet we are calling these from the
399 * handler and revalidation threads. But then, maybe these stats do
400 * not need to be very accurate. */
401 m->packet_count += packets;
402 m->byte_count += bytes;
403 }
404 }
405
406 /* Retrieves the mirror numbered 'index' in 'mbridge'. Returns true if such a
407 * mirror exists, false otherwise.
408 *
409 * If successful, '*vlans' receives the mirror's VLAN membership information,
410 * either a null pointer if the mirror includes all VLANs or a 4096-bit bitmap
411 * in which a 1-bit indicates that the mirror includes a particular VLAN,
412 * '*dup_mirrors' receives a bitmap of mirrors whose output duplicates mirror
413 * 'index', '*out' receives the output ofbundle (if any), and '*out_vlan'
414 * receives the output VLAN (if any).
415 *
416 * Everything returned here is assumed to be RCU protected.
417 */
418 bool
419 mirror_get(struct mbridge *mbridge, int index, const unsigned long **vlans,
420 mirror_mask_t *dup_mirrors, struct ofbundle **out,
421 int *snaplen, int *out_vlan)
422 {
423 struct mirror *mirror;
424
425 if (!mbridge) {
426 return false;
427 }
428
429 mirror = mbridge->mirrors[index];
430 if (!mirror) {
431 return false;
432 }
433 /* Assume 'mirror' is RCU protected, i.e., it will not be freed until this
434 * thread quiesces. */
435
436 *vlans = ovsrcu_get(unsigned long *, &mirror->vlans);
437 *dup_mirrors = mirror->dup_mirrors;
438 *out = mirror->out ? mirror->out->ofbundle : NULL;
439 *out_vlan = mirror->out_vlan;
440 *snaplen = mirror->snaplen;
441 return true;
442 }
443 \f
444 /* Helpers. */
445
446 static struct mbundle *
447 mbundle_lookup(const struct mbridge *mbridge, struct ofbundle *ofbundle)
448 {
449 struct mbundle *mbundle;
450 uint32_t hash = hash_pointer(ofbundle, 0);
451
452 CMAP_FOR_EACH_WITH_HASH (mbundle, cmap_node, hash, &mbridge->mbundles) {
453 if (mbundle->ofbundle == ofbundle) {
454 return mbundle;
455 }
456 }
457 return NULL;
458 }
459
460 /* Looks up each of the 'n_ofbundles' pointers in 'ofbundles' as mbundles and
461 * adds the ones that are found to 'mbundles'. */
462 static void
463 mbundle_lookup_multiple(const struct mbridge *mbridge,
464 struct ofbundle **ofbundles, size_t n_ofbundles,
465 struct hmapx *mbundles)
466 {
467 size_t i;
468
469 hmapx_init(mbundles);
470 for (i = 0; i < n_ofbundles; i++) {
471 struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundles[i]);
472 if (mbundle) {
473 hmapx_add(mbundles, mbundle);
474 }
475 }
476 }
477
478 static int
479 mirror_scan(struct mbridge *mbridge)
480 {
481 int idx;
482
483 for (idx = 0; idx < MAX_MIRRORS; idx++) {
484 if (!mbridge->mirrors[idx]) {
485 return idx;
486 }
487 }
488 return -1;
489 }
490
491 static struct mirror *
492 mirror_lookup(struct mbridge *mbridge, void *aux)
493 {
494 int i;
495
496 for (i = 0; i < MAX_MIRRORS; i++) {
497 struct mirror *mirror = mbridge->mirrors[i];
498 if (mirror && mirror->aux == aux) {
499 return mirror;
500 }
501 }
502
503 return NULL;
504 }
505
506 /* Update the 'dup_mirrors' member of each of the mirrors in 'ofproto'. */
507 static void
508 mirror_update_dups(struct mbridge *mbridge)
509 {
510 int i;
511
512 for (i = 0; i < MAX_MIRRORS; i++) {
513 struct mirror *m = mbridge->mirrors[i];
514
515 if (m) {
516 m->dup_mirrors = MIRROR_MASK_C(1) << i;
517 }
518 }
519
520 for (i = 0; i < MAX_MIRRORS; i++) {
521 struct mirror *m1 = mbridge->mirrors[i];
522 int j;
523
524 if (!m1) {
525 continue;
526 }
527
528 for (j = i + 1; j < MAX_MIRRORS; j++) {
529 struct mirror *m2 = mbridge->mirrors[j];
530
531 if (m2 && m1->out == m2->out && m1->out_vlan == m2->out_vlan) {
532 m1->dup_mirrors |= MIRROR_MASK_C(1) << j;
533 m2->dup_mirrors |= m1->dup_mirrors;
534 }
535 }
536 }
537 }