Branch data Line data Source code
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 "openvswitch/hmap.h"
22 : : #include "hmapx.h"
23 : : #include "ofproto.h"
24 : : #include "vlan-bitmap.h"
25 : : #include "openvswitch/vlog.h"
26 : :
27 : 1288 : 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 : : struct ovs_refcount 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 : : uint16_t snaplen; /* Max per mirrored packet size in byte,
65 : : set to 0 equals 65535. */
66 : : mirror_mask_t dup_mirrors; /* Bitmap of mirrors with the same output. */
67 : :
68 : : /* Counters. */
69 : : int64_t packet_count; /* Number of packets sent. */
70 : : int64_t byte_count; /* Number of bytes sent. */
71 : : };
72 : :
73 : : static struct mirror *mirror_lookup(struct mbridge *, void *aux);
74 : : static struct mbundle *mbundle_lookup(const struct mbridge *,
75 : : struct ofbundle *);
76 : : static void mbundle_lookup_multiple(const struct mbridge *, struct ofbundle **,
77 : : size_t n_bundles, struct hmapx *mbundles);
78 : : static int mirror_scan(struct mbridge *);
79 : : static void mirror_update_dups(struct mbridge *);
80 : :
81 : : struct mbridge *
82 : 749 : mbridge_create(void)
83 : : {
84 : : struct mbridge *mbridge;
85 : :
86 : 749 : mbridge = xzalloc(sizeof *mbridge);
87 : 749 : ovs_refcount_init(&mbridge->ref_cnt);
88 : :
89 : 749 : hmap_init(&mbridge->mbundles);
90 : 749 : return mbridge;
91 : : }
92 : :
93 : : struct mbridge *
94 : 41779 : mbridge_ref(const struct mbridge *mbridge_)
95 : : {
96 : 41779 : struct mbridge *mbridge = CONST_CAST(struct mbridge *, mbridge_);
97 [ + - ]: 41779 : if (mbridge) {
98 : 41779 : ovs_refcount_ref(&mbridge->ref_cnt);
99 : : }
100 : 41779 : return mbridge;
101 : : }
102 : :
103 : : void
104 : 84302 : mbridge_unref(struct mbridge *mbridge)
105 : : {
106 : : struct mbundle *mbundle, *next;
107 : : size_t i;
108 : :
109 [ + + ]: 84302 : if (!mbridge) {
110 : 41774 : return;
111 : : }
112 : :
113 [ + + ]: 42528 : if (ovs_refcount_unref(&mbridge->ref_cnt) == 1) {
114 [ + + ]: 24717 : for (i = 0; i < MAX_MIRRORS; i++) {
115 [ - + ]: 23968 : if (mbridge->mirrors[i]) {
116 : 0 : mirror_destroy(mbridge, mbridge->mirrors[i]->aux);
117 : : }
118 : : }
119 : :
120 [ + - ][ - + ]: 749 : HMAP_FOR_EACH_SAFE (mbundle, next, hmap_node, &mbridge->mbundles) {
[ - + ]
121 : 0 : mbridge_unregister_bundle(mbridge, mbundle->ofbundle);
122 : : }
123 : :
124 : 749 : hmap_destroy(&mbridge->mbundles);
125 : 749 : free(mbridge);
126 : : }
127 : : }
128 : :
129 : : bool
130 : 173720 : mbridge_has_mirrors(struct mbridge *mbridge)
131 : : {
132 [ + - ][ + + ]: 173720 : return mbridge ? mbridge->has_mirrors : false;
133 : : }
134 : :
135 : : /* Returns true if configurations changes in 'mbridge''s mirrors require
136 : : * revalidation, and resets the revalidation flag to false. */
137 : : bool
138 : 157605 : mbridge_need_revalidate(struct mbridge *mbridge)
139 : : {
140 : 157605 : bool need_revalidate = mbridge->need_revalidate;
141 : 157605 : mbridge->need_revalidate = false;
142 : 157605 : return need_revalidate;
143 : : }
144 : :
145 : : void
146 : 2667 : mbridge_register_bundle(struct mbridge *mbridge, struct ofbundle *ofbundle)
147 : : {
148 : : struct mbundle *mbundle;
149 : :
150 : 2667 : mbundle = xzalloc(sizeof *mbundle);
151 : 2667 : mbundle->ofbundle = ofbundle;
152 : 2667 : hmap_insert(&mbridge->mbundles, &mbundle->hmap_node,
153 : : hash_pointer(ofbundle, 0));
154 : 2667 : }
155 : :
156 : : void
157 : 2667 : mbridge_unregister_bundle(struct mbridge *mbridge, struct ofbundle *ofbundle)
158 : : {
159 : 2667 : struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
160 : : size_t i;
161 : :
162 [ - + ]: 2667 : if (!mbundle) {
163 : 0 : return;
164 : : }
165 : :
166 [ + + ]: 88011 : for (i = 0; i < MAX_MIRRORS; i++) {
167 : 85344 : struct mirror *m = mbridge->mirrors[i];
168 [ + + ]: 85344 : if (m) {
169 [ + + ]: 54 : if (m->out == mbundle) {
170 : 16 : mirror_destroy(mbridge, m->aux);
171 [ + + ]: 38 : } else if (hmapx_find_and_delete(&m->srcs, mbundle)
172 [ + + ]: 7 : || hmapx_find_and_delete(&m->dsts, mbundle)) {
173 : 35 : mbridge->need_revalidate = true;
174 : : }
175 : : }
176 : : }
177 : :
178 : 2667 : hmap_remove(&mbridge->mbundles, &mbundle->hmap_node);
179 : 2667 : free(mbundle);
180 : : }
181 : :
182 : : mirror_mask_t
183 : 148933 : mirror_bundle_out(struct mbridge *mbridge, struct ofbundle *ofbundle)
184 : : {
185 : 148933 : struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
186 [ + - ]: 148933 : return mbundle ? mbundle->mirror_out : 0;
187 : : }
188 : :
189 : : mirror_mask_t
190 : 55 : mirror_bundle_src(struct mbridge *mbridge, struct ofbundle *ofbundle)
191 : : {
192 : 55 : struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
193 [ + - ]: 55 : return mbundle ? mbundle->src_mirrors : 0;
194 : : }
195 : :
196 : : mirror_mask_t
197 : 101 : mirror_bundle_dst(struct mbridge *mbridge, struct ofbundle *ofbundle)
198 : : {
199 : 101 : struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle);
200 [ + - ]: 101 : return mbundle ? mbundle->dst_mirrors : 0;
201 : : }
202 : :
203 : : int
204 : 22 : 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 snaplen,
209 : : uint16_t out_vlan)
210 : : {
211 : : struct mbundle *mbundle, *out;
212 : : mirror_mask_t mirror_bit;
213 : : struct mirror *mirror;
214 : : struct hmapx srcs_map; /* Contains "struct ofbundle *"s. */
215 : : struct hmapx dsts_map; /* Contains "struct ofbundle *"s. */
216 : :
217 : 22 : mirror = mirror_lookup(mbridge, aux);
218 [ + - ]: 22 : if (!mirror) {
219 : : int idx;
220 : :
221 : 22 : idx = mirror_scan(mbridge);
222 [ - + ]: 22 : if (idx < 0) {
223 [ # # ]: 0 : VLOG_WARN("maximum of %d port mirrors reached, cannot create %s",
224 : : MAX_MIRRORS, name);
225 : 0 : return EFBIG;
226 : : }
227 : :
228 : 22 : mirror = mbridge->mirrors[idx] = xzalloc(sizeof *mirror);
229 : 22 : mirror->mbridge = mbridge;
230 : 22 : mirror->idx = idx;
231 : 22 : mirror->aux = aux;
232 : 22 : mirror->out_vlan = -1;
233 : 22 : mirror->snaplen = 0;
234 : : }
235 : :
236 : : /* Get the new configuration. */
237 [ + + ]: 22 : if (out_bundle) {
238 : 16 : out = mbundle_lookup(mbridge, out_bundle);
239 [ - + ]: 16 : if (!out) {
240 : 0 : mirror_destroy(mbridge, mirror->aux);
241 : 0 : return EINVAL;
242 : : }
243 : 16 : out_vlan = -1;
244 : : } else {
245 : 6 : out = NULL;
246 : : }
247 : 22 : mbundle_lookup_multiple(mbridge, srcs, n_srcs, &srcs_map);
248 : 22 : mbundle_lookup_multiple(mbridge, dsts, n_dsts, &dsts_map);
249 : :
250 : : /* If the configuration has not changed, do nothing. */
251 [ + + ]: 22 : if (hmapx_equals(&srcs_map, &mirror->srcs)
252 [ - + ]: 3 : && hmapx_equals(&dsts_map, &mirror->dsts)
253 [ # # ]: 0 : && vlan_bitmap_equal(mirror->vlans, src_vlans)
254 [ # # ]: 0 : && mirror->out == out
255 [ # # ]: 0 : && mirror->out_vlan == out_vlan)
256 : : {
257 : 0 : hmapx_destroy(&srcs_map);
258 : 0 : hmapx_destroy(&dsts_map);
259 : 0 : return 0;
260 : : }
261 : :
262 : 22 : hmapx_swap(&srcs_map, &mirror->srcs);
263 : 22 : hmapx_destroy(&srcs_map);
264 : :
265 : 22 : hmapx_swap(&dsts_map, &mirror->dsts);
266 : 22 : hmapx_destroy(&dsts_map);
267 : :
268 : 22 : free(mirror->vlans);
269 : 22 : mirror->vlans = vlan_bitmap_clone(src_vlans);
270 : :
271 : 22 : mirror->out = out;
272 : 22 : mirror->out_vlan = out_vlan;
273 : 22 : mirror->snaplen = snaplen;
274 : :
275 : : /* Update mbundles. */
276 : 22 : mirror_bit = MIRROR_MASK_C(1) << mirror->idx;
277 [ + + ][ - + ]: 109 : HMAP_FOR_EACH (mbundle, hmap_node, &mirror->mbridge->mbundles) {
278 [ + + ]: 87 : if (hmapx_contains(&mirror->srcs, mbundle)) {
279 : 67 : mbundle->src_mirrors |= mirror_bit;
280 : : } else {
281 : 20 : mbundle->src_mirrors &= ~mirror_bit;
282 : : }
283 : :
284 [ + + ]: 87 : if (hmapx_contains(&mirror->dsts, mbundle)) {
285 : 70 : mbundle->dst_mirrors |= mirror_bit;
286 : : } else {
287 : 17 : mbundle->dst_mirrors &= ~mirror_bit;
288 : : }
289 : :
290 [ + + ]: 87 : if (mirror->out == mbundle) {
291 : 16 : mbundle->mirror_out |= mirror_bit;
292 : : } else {
293 : 71 : mbundle->mirror_out &= ~mirror_bit;
294 : : }
295 : : }
296 : :
297 : 22 : mbridge->has_mirrors = true;
298 : 22 : mirror_update_dups(mbridge);
299 : :
300 : 22 : return 0;
301 : : }
302 : :
303 : : void
304 : 38 : mirror_destroy(struct mbridge *mbridge, void *aux)
305 : : {
306 : 38 : struct mirror *mirror = mirror_lookup(mbridge, aux);
307 : : mirror_mask_t mirror_bit;
308 : : struct mbundle *mbundle;
309 : : int i;
310 : :
311 [ + + ]: 38 : if (!mirror) {
312 : 16 : return;
313 : : }
314 : :
315 : 22 : mirror_bit = MIRROR_MASK_C(1) << mirror->idx;
316 [ + + ][ - + ]: 71 : HMAP_FOR_EACH (mbundle, hmap_node, &mbridge->mbundles) {
317 : 49 : mbundle->src_mirrors &= ~mirror_bit;
318 : 49 : mbundle->dst_mirrors &= ~mirror_bit;
319 : 49 : mbundle->mirror_out &= ~mirror_bit;
320 : : }
321 : :
322 : 22 : hmapx_destroy(&mirror->srcs);
323 : 22 : hmapx_destroy(&mirror->dsts);
324 : 22 : free(mirror->vlans);
325 : :
326 : 22 : mbridge->mirrors[mirror->idx] = NULL;
327 : 22 : free(mirror);
328 : :
329 : 22 : mirror_update_dups(mbridge);
330 : :
331 : 22 : mbridge->has_mirrors = false;
332 [ + + ]: 663 : for (i = 0; i < MAX_MIRRORS; i++) {
333 [ + + ]: 643 : if (mbridge->mirrors[i]) {
334 : 2 : mbridge->has_mirrors = true;
335 : 2 : break;
336 : : }
337 : : }
338 : : }
339 : :
340 : : int
341 : 0 : mirror_get_stats(struct mbridge *mbridge, void *aux, uint64_t *packets,
342 : : uint64_t *bytes)
343 : : {
344 : 0 : struct mirror *mirror = mirror_lookup(mbridge, aux);
345 : :
346 [ # # ]: 0 : if (!mirror) {
347 : 0 : *packets = *bytes = UINT64_MAX;
348 : 0 : return 0;
349 : : }
350 : :
351 : 0 : *packets = mirror->packet_count;
352 : 0 : *bytes = mirror->byte_count;
353 : :
354 : 0 : return 0;
355 : : }
356 : :
357 : : void
358 : 6 : mirror_update_stats(struct mbridge *mbridge, mirror_mask_t mirrors,
359 : : uint64_t packets, uint64_t bytes)
360 : : {
361 [ + - ][ - + ]: 6 : if (!mbridge || !mirrors) {
362 : 0 : return;
363 : : }
364 : :
365 [ + + ]: 12 : for (; mirrors; mirrors = zero_rightmost_1bit(mirrors)) {
366 : : struct mirror *m;
367 : :
368 : 6 : m = mbridge->mirrors[raw_ctz(mirrors)];
369 : :
370 [ + + ]: 6 : if (!m) {
371 : : /* In normal circumstances 'm' will not be NULL. However,
372 : : * if mirrors are reconfigured, we can temporarily get out
373 : : * of sync in facet_revalidate(). We could "correct" the
374 : : * mirror list before reaching here, but doing that would
375 : : * not properly account the traffic stats we've currently
376 : : * accumulated for previous mirror configuration. */
377 : 1 : continue;
378 : : }
379 : :
380 : 5 : m->packet_count += packets;
381 : 5 : m->byte_count += bytes;
382 : : }
383 : : }
384 : :
385 : : /* Retrieves the mirror numbered 'index' in 'mbridge'. Returns true if such a
386 : : * mirror exists, false otherwise.
387 : : *
388 : : * If successful, '*vlans' receives the mirror's VLAN membership information,
389 : : * either a null pointer if the mirror includes all VLANs or a 4096-bit bitmap
390 : : * in which a 1-bit indicates that the mirror includes a particular VLAN,
391 : : * '*dup_mirrors' receives a bitmap of mirrors whose output duplicates mirror
392 : : * 'index', '*out' receives the output ofbundle (if any), and '*out_vlan'
393 : : * receives the output VLAN (if any). */
394 : : bool
395 : 46 : mirror_get(struct mbridge *mbridge, int index, const unsigned long **vlans,
396 : : mirror_mask_t *dup_mirrors, struct ofbundle **out,
397 : : int *snaplen, int *out_vlan)
398 : : {
399 : : struct mirror *mirror;
400 : :
401 [ - + ]: 46 : if (!mbridge) {
402 : 0 : return false;
403 : : }
404 : :
405 : 46 : mirror = mbridge->mirrors[index];
406 [ - + ]: 46 : if (!mirror) {
407 : 0 : return false;
408 : : }
409 : :
410 : 46 : *vlans = mirror->vlans;
411 : 46 : *dup_mirrors = mirror->dup_mirrors;
412 [ + + ]: 46 : *out = mirror->out ? mirror->out->ofbundle : NULL;
413 : 46 : *out_vlan = mirror->out_vlan;
414 : 46 : *snaplen = mirror->snaplen;
415 : 46 : return true;
416 : : }
417 : :
418 : : /* Helpers. */
419 : :
420 : : static struct mbundle *
421 : 151909 : mbundle_lookup(const struct mbridge *mbridge, struct ofbundle *ofbundle)
422 : : {
423 : : struct mbundle *mbundle;
424 : :
425 [ + - ][ # # ]: 174537 : HMAP_FOR_EACH_IN_BUCKET (mbundle, hmap_node, hash_pointer(ofbundle, 0),
426 : : &mbridge->mbundles) {
427 [ + + ]: 174537 : if (mbundle->ofbundle == ofbundle) {
428 : 151909 : return mbundle;
429 : : }
430 : : }
431 : 0 : return NULL;
432 : : }
433 : :
434 : : /* Looks up each of the 'n_ofbundlees' pointers in 'ofbundlees' as mbundles and
435 : : * adds the ones that are found to 'mbundles'. */
436 : : static void
437 : 44 : mbundle_lookup_multiple(const struct mbridge *mbridge,
438 : : struct ofbundle **ofbundles, size_t n_ofbundles,
439 : : struct hmapx *mbundles)
440 : : {
441 : : size_t i;
442 : :
443 : 44 : hmapx_init(mbundles);
444 [ + + ]: 181 : for (i = 0; i < n_ofbundles; i++) {
445 : 137 : struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundles[i]);
446 [ + - ]: 137 : if (mbundle) {
447 : 137 : hmapx_add(mbundles, mbundle);
448 : : }
449 : : }
450 : 44 : }
451 : :
452 : : static int
453 : 22 : mirror_scan(struct mbridge *mbridge)
454 : : {
455 : : int idx;
456 : :
457 [ + - ]: 24 : for (idx = 0; idx < MAX_MIRRORS; idx++) {
458 [ + + ]: 24 : if (!mbridge->mirrors[idx]) {
459 : 22 : return idx;
460 : : }
461 : : }
462 : 0 : return -1;
463 : : }
464 : :
465 : : static struct mirror *
466 : 60 : mirror_lookup(struct mbridge *mbridge, void *aux)
467 : : {
468 : : int i;
469 : :
470 [ + + ]: 1278 : for (i = 0; i < MAX_MIRRORS; i++) {
471 : 1240 : struct mirror *mirror = mbridge->mirrors[i];
472 [ + + ][ + + ]: 1240 : if (mirror && mirror->aux == aux) {
473 : 22 : return mirror;
474 : : }
475 : : }
476 : :
477 : 38 : return NULL;
478 : : }
479 : :
480 : : /* Update the 'dup_mirrors' member of each of the mirrors in 'ofproto'. */
481 : : static void
482 : 44 : mirror_update_dups(struct mbridge *mbridge)
483 : : {
484 : : int i;
485 : :
486 [ + + ]: 1452 : for (i = 0; i < MAX_MIRRORS; i++) {
487 : 1408 : struct mirror *m = mbridge->mirrors[i];
488 : :
489 [ + + ]: 1408 : if (m) {
490 : 26 : m->dup_mirrors = MIRROR_MASK_C(1) << i;
491 : : }
492 : : }
493 : :
494 [ + + ]: 1452 : for (i = 0; i < MAX_MIRRORS; i++) {
495 : 1408 : struct mirror *m1 = mbridge->mirrors[i];
496 : : int j;
497 : :
498 [ + + ]: 1408 : if (!m1) {
499 : 1382 : continue;
500 : : }
501 : :
502 [ + + ]: 829 : for (j = i + 1; j < MAX_MIRRORS; j++) {
503 : 803 : struct mirror *m2 = mbridge->mirrors[j];
504 : :
505 [ + + ][ + - ]: 803 : if (m2 && m1->out == m2->out && m1->out_vlan == m2->out_vlan) {
[ - + ]
506 : 0 : m1->dup_mirrors |= MIRROR_MASK_C(1) << j;
507 : 0 : m2->dup_mirrors |= m1->dup_mirrors;
508 : : }
509 : : }
510 : : }
511 : 44 : }
|