From: Ethan Jackson Date: Thu, 20 Jun 2013 20:00:27 +0000 (-0700) Subject: ofproto-dpif: Modularize mirror code. X-Git-Tag: sliver-openvswitch-2.0.90-1~36^2~77 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=ec7ceaed4f3e03a3e59056a3a82a08886c328ce8;p=sliver-openvswitch.git ofproto-dpif: Modularize mirror code. This code modularizes ofproto-dpif's mirror code by moving it to ofproto-dpif-mirror. Not only does this shorten ofproto-dpif and hide complexity, but its also necessary for future patches which modularize ofproto-dpif-xlate in preparation for multi-threading. Signed-off-by: Ethan Jackson Acked-by: Ben Pfaff --- diff --git a/ofproto/automake.mk b/ofproto/automake.mk index b4d087688..af9a12a3e 100644 --- a/ofproto/automake.mk +++ b/ofproto/automake.mk @@ -26,6 +26,8 @@ ofproto_libofproto_a_SOURCES = \ ofproto/ofproto-dpif-governor.h \ ofproto/ofproto-dpif-ipfix.c \ ofproto/ofproto-dpif-ipfix.h \ + ofproto/ofproto-dpif-mirror.c \ + ofproto/ofproto-dpif-mirror.h \ ofproto/ofproto-dpif-sflow.c \ ofproto/ofproto-dpif-sflow.h \ ofproto/ofproto-dpif-xlate.c \ diff --git a/ofproto/ofproto-dpif-mirror.c b/ofproto/ofproto-dpif-mirror.c new file mode 100644 index 000000000..973471868 --- /dev/null +++ b/ofproto/ofproto-dpif-mirror.c @@ -0,0 +1,500 @@ +/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include + +#include "ofproto-dpif-mirror.h" + +#include + +#include "hmap.h" +#include "hmapx.h" +#include "ofproto.h" +#include "vlan-bitmap.h" +#include "vlog.h" + +VLOG_DEFINE_THIS_MODULE(ofproto_dpif_mirror); + +#define MIRROR_MASK_C(X) UINT32_C(X) +BUILD_ASSERT_DECL(sizeof(mirror_mask_t) * CHAR_BIT >= MAX_MIRRORS); + +struct mbridge { + struct mirror *mirrors[MAX_MIRRORS]; + struct hmap mbundles; + + bool need_revalidate; + bool has_mirrors; + + int ref_cnt; +}; + +struct mbundle { + struct hmap_node hmap_node; /* In parent 'mbridge' map. */ + struct ofbundle *ofbundle; + + mirror_mask_t src_mirrors; /* Mirrors triggered when packet received. */ + mirror_mask_t dst_mirrors; /* Mirrors triggered when packet sent. */ + mirror_mask_t mirror_out; /* Mirrors that output to this mbundle. */ +}; + +struct mirror { + struct mbridge *mbridge; /* Owning ofproto. */ + size_t idx; /* In ofproto's "mirrors" array. */ + void *aux; /* Key supplied by ofproto's client. */ + + /* Selection criteria. */ + struct hmapx srcs; /* Contains "struct mbundle*"s. */ + struct hmapx dsts; /* Contains "struct mbundle*"s. */ + unsigned long *vlans; /* Bitmap of chosen VLANs, NULL selects all. */ + + /* Output (exactly one of out == NULL and out_vlan == -1 is true). */ + struct mbundle *out; /* Output port or NULL. */ + int out_vlan; /* Output VLAN or -1. */ + mirror_mask_t dup_mirrors; /* Bitmap of mirrors with the same output. */ + + /* Counters. */ + int64_t packet_count; /* Number of packets sent. */ + int64_t byte_count; /* Number of bytes sent. */ +}; + +static struct mirror *mirror_lookup(struct mbridge *, void *aux); +static struct mbundle *mbundle_lookup(const struct mbridge *, + struct ofbundle *); +static void mbundle_lookup_multiple(const struct mbridge *, struct ofbundle **, + size_t n_bundles, struct hmapx *mbundles); +static int mirror_scan(struct mbridge *); +static void mirror_update_dups(struct mbridge *); +static int mirror_mask_ffs(mirror_mask_t); + +struct mbridge * +mbridge_create(void) +{ + struct mbridge *mbridge; + + mbridge = xzalloc(sizeof *mbridge); + mbridge->ref_cnt = 1; + + hmap_init(&mbridge->mbundles); + return mbridge; +} + +struct mbridge * +mbridge_ref(const struct mbridge *mbridge_) +{ + struct mbridge *mbridge = CONST_CAST(struct mbridge *, mbridge_); + if (mbridge) { + ovs_assert(mbridge->ref_cnt > 0); + mbridge->ref_cnt++; + } + return mbridge; +} + +void +mbridge_unref(struct mbridge *mbridge) +{ + struct mbundle *mbundle, *next; + size_t i; + + if (!mbridge) { + return; + } + + ovs_assert(mbridge->ref_cnt > 0); + if (--mbridge->ref_cnt) { + return; + } + + for (i = 0; i < MAX_MIRRORS; i++) { + if (mbridge->mirrors[i]) { + mirror_destroy(mbridge, mbridge->mirrors[i]->aux); + } + } + + HMAP_FOR_EACH_SAFE (mbundle, next, hmap_node, &mbridge->mbundles) { + mbridge_unregister_bundle(mbridge, mbundle->ofbundle); + } + + free(mbridge); +} + +bool +mbridge_has_mirrors(struct mbridge *mbridge) +{ + return mbridge ? mbridge->has_mirrors : false; +} + +/* Returns true if configurations changes in 'mbridge''s mirrors require + * revalidation. */ +bool +mbridge_need_revalidate(struct mbridge *mbridge) +{ + return mbridge->need_revalidate; +} + +void +mbridge_register_bundle(struct mbridge *mbridge, struct ofbundle *ofbundle) +{ + struct mbundle *mbundle; + + mbundle = xzalloc(sizeof *mbundle); + mbundle->ofbundle = ofbundle; + hmap_insert(&mbridge->mbundles, &mbundle->hmap_node, + hash_pointer(ofbundle, 0)); +} + +void +mbridge_unregister_bundle(struct mbridge *mbridge, struct ofbundle *ofbundle) +{ + struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle); + size_t i; + + if (!mbundle) { + return; + } + + for (i = 0; i < MAX_MIRRORS; i++) { + struct mirror *m = mbridge->mirrors[i]; + if (m) { + if (m->out == mbundle) { + mirror_destroy(mbridge, m->aux); + } else if (hmapx_find_and_delete(&m->srcs, mbundle) + || hmapx_find_and_delete(&m->dsts, mbundle)) { + mbridge->need_revalidate = true; + } + } + } + + hmap_remove(&mbridge->mbundles, &mbundle->hmap_node); + free(mbundle); +} + +mirror_mask_t +mirror_bundle_out(struct mbridge *mbridge, struct ofbundle *ofbundle) +{ + struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle); + return mbundle ? mbundle->mirror_out : 0; +} + +mirror_mask_t +mirror_bundle_src(struct mbridge *mbridge, struct ofbundle *ofbundle) +{ + struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle); + return mbundle ? mbundle->src_mirrors : 0; +} + +mirror_mask_t +mirror_bundle_dst(struct mbridge *mbridge, struct ofbundle *ofbundle) +{ + struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundle); + return mbundle ? mbundle->dst_mirrors : 0; +} + +int +mirror_set(struct mbridge *mbridge, void *aux, const char *name, + struct ofbundle **srcs, size_t n_srcs, + struct ofbundle **dsts, size_t n_dsts, + unsigned long *src_vlans, struct ofbundle *out_bundle, + uint16_t out_vlan) +{ + struct mbundle *mbundle, *out; + mirror_mask_t mirror_bit; + struct mirror *mirror; + struct hmapx srcs_map; /* Contains "struct ofbundle *"s. */ + struct hmapx dsts_map; /* Contains "struct ofbundle *"s. */ + + mirror = mirror_lookup(mbridge, aux); + if (!mirror) { + int idx; + + idx = mirror_scan(mbridge); + if (idx < 0) { + VLOG_WARN("maximum of %d port mirrors reached, cannot create %s", + MAX_MIRRORS, name); + return EFBIG; + } + + mirror = mbridge->mirrors[idx] = xzalloc(sizeof *mirror); + mirror->mbridge = mbridge; + mirror->idx = idx; + mirror->aux = aux; + mirror->out_vlan = -1; + } + + /* Get the new configuration. */ + if (out_bundle) { + out = mbundle_lookup(mbridge, out_bundle); + if (!out) { + mirror_destroy(mbridge, mirror->aux); + return EINVAL; + } + out_vlan = -1; + } else { + out = NULL; + } + mbundle_lookup_multiple(mbridge, srcs, n_srcs, &srcs_map); + mbundle_lookup_multiple(mbridge, dsts, n_dsts, &dsts_map); + + /* If the configuration has not changed, do nothing. */ + if (hmapx_equals(&srcs_map, &mirror->srcs) + && hmapx_equals(&dsts_map, &mirror->dsts) + && vlan_bitmap_equal(mirror->vlans, src_vlans) + && mirror->out == out + && mirror->out_vlan == out_vlan) + { + hmapx_destroy(&srcs_map); + hmapx_destroy(&dsts_map); + return 0; + } + + hmapx_swap(&srcs_map, &mirror->srcs); + hmapx_destroy(&srcs_map); + + hmapx_swap(&dsts_map, &mirror->dsts); + hmapx_destroy(&dsts_map); + + free(mirror->vlans); + mirror->vlans = vlan_bitmap_clone(src_vlans); + + mirror->out = out; + mirror->out_vlan = out_vlan; + + /* Update mbundles. */ + mirror_bit = MIRROR_MASK_C(1) << mirror->idx; + HMAP_FOR_EACH (mbundle, hmap_node, &mirror->mbridge->mbundles) { + if (hmapx_contains(&mirror->srcs, mbundle)) { + mbundle->src_mirrors |= mirror_bit; + } else { + mbundle->src_mirrors &= ~mirror_bit; + } + + if (hmapx_contains(&mirror->dsts, mbundle)) { + mbundle->dst_mirrors |= mirror_bit; + } else { + mbundle->dst_mirrors &= ~mirror_bit; + } + + if (mirror->out == mbundle) { + mbundle->mirror_out |= mirror_bit; + } else { + mbundle->mirror_out &= ~mirror_bit; + } + } + + mbridge->has_mirrors = true; + mirror_update_dups(mbridge); + + return 0; +} + +void +mirror_destroy(struct mbridge *mbridge, void *aux) +{ + struct mirror *mirror = mirror_lookup(mbridge, aux); + mirror_mask_t mirror_bit; + struct mbundle *mbundle; + int i; + + if (!mirror) { + return; + } + + mirror_bit = MIRROR_MASK_C(1) << mirror->idx; + HMAP_FOR_EACH (mbundle, hmap_node, &mbridge->mbundles) { + mbundle->src_mirrors &= ~mirror_bit; + mbundle->dst_mirrors &= ~mirror_bit; + mbundle->mirror_out &= ~mirror_bit; + } + + hmapx_destroy(&mirror->srcs); + hmapx_destroy(&mirror->dsts); + free(mirror->vlans); + + mbridge->mirrors[mirror->idx] = NULL; + free(mirror); + + mirror_update_dups(mbridge); + + mbridge->has_mirrors = false; + for (i = 0; i < MAX_MIRRORS; i++) { + if (mbridge->mirrors[i]) { + mbridge->has_mirrors = true; + break; + } + } +} + +int +mirror_get_stats(struct mbridge *mbridge, void *aux, uint64_t *packets, + uint64_t *bytes) +{ + struct mirror *mirror = mirror_lookup(mbridge, aux); + + if (!mirror) { + *packets = *bytes = UINT64_MAX; + return 0; + } + + *packets = mirror->packet_count; + *bytes = mirror->byte_count; + + return 0; +} + +void +mirror_update_stats(struct mbridge *mbridge, mirror_mask_t mirrors, + uint64_t packets, uint64_t bytes) +{ + if (!mbridge || !mirrors) { + return; + } + + for (; mirrors; mirrors = zero_rightmost_1bit(mirrors)) { + struct mirror *m; + + m = mbridge->mirrors[mirror_mask_ffs(mirrors) - 1]; + + if (!m) { + /* In normal circumstances 'm' will not be NULL. However, + * if mirrors are reconfigured, we can temporarily get out + * of sync in facet_revalidate(). We could "correct" the + * mirror list before reaching here, but doing that would + * not properly account the traffic stats we've currently + * accumulated for previous mirror configuration. */ + continue; + } + + m->packet_count += packets; + m->byte_count += bytes; + } +} + +/* Retrieves the mirror in 'mbridge' represented by the first bet set of + * 'mirrors'. Returns true if such a mirror exists, false otherwise. + * The caller takes ownership of, and is expected to deallocate, 'vlans' */ +bool +mirror_get(struct mbridge *mbridge, int index, unsigned long **vlans, + mirror_mask_t *dup_mirrors, struct ofbundle **out, int *out_vlan) +{ + struct mirror *mirror; + + if (!mbridge) { + return false; + } + + mirror = mbridge->mirrors[index]; + if (!mirror) { + return false; + } + + *vlans = vlan_bitmap_clone(mirror->vlans); + *dup_mirrors = mirror->dup_mirrors; + *out = mirror->out ? mirror->out->ofbundle : NULL; + *out_vlan = mirror->out_vlan; + return true; +} + +/* Helpers. */ + +static struct mbundle * +mbundle_lookup(const struct mbridge *mbridge, struct ofbundle *ofbundle) +{ + struct mbundle *mbundle; + + HMAP_FOR_EACH_IN_BUCKET (mbundle, hmap_node, hash_pointer(ofbundle, 0), + &mbridge->mbundles) { + if (mbundle->ofbundle == ofbundle) { + return mbundle; + } + } + return NULL; +} + +/* Looks up each of the 'n_ofbundlees' pointers in 'ofbundlees' as mbundles and + * adds the ones that are found to 'mbundles'. */ +static void +mbundle_lookup_multiple(const struct mbridge *mbridge, + struct ofbundle **ofbundles, size_t n_ofbundles, + struct hmapx *mbundles) +{ + size_t i; + + hmapx_init(mbundles); + for (i = 0; i < n_ofbundles; i++) { + struct mbundle *mbundle = mbundle_lookup(mbridge, ofbundles[i]); + if (mbundle) { + hmapx_add(mbundles, mbundle); + } + } +} + +static int +mirror_scan(struct mbridge *mbridge) +{ + int idx; + + for (idx = 0; idx < MAX_MIRRORS; idx++) { + if (!mbridge->mirrors[idx]) { + return idx; + } + } + return -1; +} + +static struct mirror * +mirror_lookup(struct mbridge *mbridge, void *aux) +{ + int i; + + for (i = 0; i < MAX_MIRRORS; i++) { + struct mirror *mirror = mbridge->mirrors[i]; + if (mirror && mirror->aux == aux) { + return mirror; + } + } + + return NULL; +} + +/* Update the 'dup_mirrors' member of each of the mirrors in 'ofproto'. */ +static void +mirror_update_dups(struct mbridge *mbridge) +{ + int i; + + for (i = 0; i < MAX_MIRRORS; i++) { + struct mirror *m = mbridge->mirrors[i]; + + if (m) { + m->dup_mirrors = MIRROR_MASK_C(1) << i; + } + } + + for (i = 0; i < MAX_MIRRORS; i++) { + struct mirror *m1 = mbridge->mirrors[i]; + int j; + + if (!m1) { + continue; + } + + for (j = i + 1; j < MAX_MIRRORS; j++) { + struct mirror *m2 = mbridge->mirrors[j]; + + if (m2 && m1->out == m2->out && m1->out_vlan == m2->out_vlan) { + m1->dup_mirrors |= MIRROR_MASK_C(1) << j; + m2->dup_mirrors |= m1->dup_mirrors; + } + } + } +} diff --git a/ofproto/ofproto-dpif-mirror.h b/ofproto/ofproto-dpif-mirror.h new file mode 100644 index 000000000..4a6f3cebd --- /dev/null +++ b/ofproto/ofproto-dpif-mirror.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2013 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#ifndef OFPROT_DPIF_MIRROR_H +#define OFPROT_DPIF_MIRROR_H 1 + +#include + +#include "util.h" + +#define MAX_MIRRORS 32 +typedef uint32_t mirror_mask_t; + +struct ofproto_dpif; +struct ofbundle; + +struct mbridge *mbridge_create(void); +struct mbridge *mbridge_ref(const struct mbridge *); +void mbridge_unref(struct mbridge *); +bool mbridge_has_mirrors(struct mbridge *); +bool mbridge_need_revalidate(struct mbridge *); + +void mbridge_register_bundle(struct mbridge *, struct ofbundle *); +void mbridge_unregister_bundle(struct mbridge *, struct ofbundle *); + +mirror_mask_t mirror_bundle_out(struct mbridge *, struct ofbundle *); +mirror_mask_t mirror_bundle_src(struct mbridge *, struct ofbundle *); +mirror_mask_t mirror_bundle_dst(struct mbridge *, struct ofbundle *); + +int mirror_set(struct mbridge *, void *aux, const char *name, + struct ofbundle **srcs, size_t n_srcs, + struct ofbundle **dsts, size_t n_dsts, + unsigned long *src_vlans, struct ofbundle *out_bundle, + uint16_t out_vlan); +void mirror_destroy(struct mbridge *, void *aux); +int mirror_get_stats(struct mbridge *, void *aux, uint64_t *packets, + uint64_t *bytes); +void mirror_update_stats(struct mbridge*, mirror_mask_t, uint64_t packets, + uint64_t bytes); +bool mirror_get(struct mbridge *, int index, unsigned long **vlans, + mirror_mask_t *dup_mirrors, struct ofbundle **out, + int *out_vlan); + +static inline int +mirror_mask_ffs(mirror_mask_t mask) +{ + BUILD_ASSERT_DECL(sizeof(unsigned int) >= sizeof(mask)); + return ffs(mask); +} +#endif /* ofproto-dpif-mirror.h */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 0203b98ff..2ba956015 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -38,6 +38,7 @@ #include "odp-execute.h" #include "ofp-actions.h" #include "ofproto/ofproto-dpif-ipfix.h" +#include "ofproto/ofproto-dpif-mirror.h" #include "ofproto/ofproto-dpif-sflow.h" #include "ofproto/ofproto-dpif.h" #include "tunnel.h" @@ -124,12 +125,6 @@ ofbundle_includes_vlan(const struct ofbundle *bundle, uint16_t vlan) return vlan == bundle->vlan || ofbundle_trunks_vlan(bundle, vlan); } -static bool -vlan_is_mirrored(const struct ofmirror *m, int vlan) -{ - return !m->vlans || bitmap_is_set(m->vlans, vlan); -} - static struct ofbundle * lookup_input_bundle(const struct ofproto_dpif *ofproto, ofp_port_t in_port, bool warn, struct ofport_dpif **in_ofportp) @@ -190,10 +185,10 @@ add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow) if (!in_bundle) { return; } - mirrors |= in_bundle->src_mirrors; + mirrors |= mirror_bundle_src(ctx->ofproto->mbridge, in_bundle); /* Drop frames on bundles reserved for mirroring. */ - if (in_bundle->mirror_out) { + if (mirror_bundle_out(ctx->ofproto->mbridge, in_bundle)) { if (ctx->xin->packet != NULL) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "bridge %s: dropping packet received on port " @@ -218,31 +213,40 @@ add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow) ctx->xin->flow = *orig_flow; while (mirrors) { - struct ofmirror *m; - - m = ofproto->mirrors[mirror_mask_ffs(mirrors) - 1]; - - if (m->vlans) { + mirror_mask_t dup_mirrors; + struct ofbundle *out; + unsigned long *vlans; + bool vlan_mirrored; + bool has_mirror; + int out_vlan; + + has_mirror = mirror_get(ofproto->mbridge, mirror_mask_ffs(mirrors) - 1, + &vlans, &dup_mirrors, &out, &out_vlan); + ovs_assert(has_mirror); + + if (vlans) { ctx->xout->wc.masks.vlan_tci |= htons(VLAN_CFI | VLAN_VID_MASK); } + vlan_mirrored = !vlans || bitmap_is_set(vlans, vlan); + free(vlans); - if (!vlan_is_mirrored(m, vlan)) { + if (!vlan_mirrored) { mirrors = zero_rightmost_1bit(mirrors); continue; } - mirrors &= ~m->dup_mirrors; - ctx->xout->mirrors |= m->dup_mirrors; - if (m->out) { - output_normal(ctx, m->out, vlan); - } else if (vlan != m->out_vlan + mirrors &= ~dup_mirrors; + ctx->xout->mirrors |= dup_mirrors; + if (out) { + output_normal(ctx, out, vlan); + } else if (vlan != out_vlan && !eth_addr_is_reserved(orig_flow->dl_dst)) { struct ofbundle *bundle; HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) { - if (ofbundle_includes_vlan(bundle, m->out_vlan) - && !bundle->mirror_out) { - output_normal(ctx, bundle, m->out_vlan); + if (ofbundle_includes_vlan(bundle, out_vlan) + && !mirror_bundle_out(bundle->ofproto->mbridge, bundle)) { + output_normal(ctx, bundle, out_vlan); } } } @@ -557,7 +561,7 @@ xlate_normal(struct xlate_ctx *ctx) } /* Drop frames on bundles reserved for mirroring. */ - if (in_bundle->mirror_out) { + if (mirror_bundle_out(ctx->ofproto->mbridge, in_bundle)) { if (ctx->xin->packet != NULL) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "bridge %s: dropping packet received on port " @@ -604,7 +608,7 @@ xlate_normal(struct xlate_ctx *ctx) if (bundle != in_bundle && ofbundle_includes_vlan(bundle, vlan) && bundle->floodable - && !bundle->mirror_out) { + && !mirror_bundle_out(bundle->ofproto->mbridge, bundle)) { output_normal(ctx, bundle, vlan); } } @@ -838,8 +842,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, return; } - if (ctx->ofproto->has_mirrors && ofport->bundle) { - ctx->xout->mirrors |= ofport->bundle->dst_mirrors; + if (mbridge_has_mirrors(ctx->ofproto->mbridge) && ofport->bundle) { + ctx->xout->mirrors |= + mirror_bundle_dst(ofport->bundle->ofproto->mbridge, + ofport->bundle); } if (ofport->peer) { @@ -1925,7 +1931,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack); - if (ctx.ofproto->has_mirrors || hit_resubmit_limit) { + if (mbridge_has_mirrors(ctx.ofproto->mbridge) || hit_resubmit_limit) { /* Do this conditionally because the copy is expensive enough that it * shows up in profiles. */ orig_flow = *flow; @@ -2002,7 +2008,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) && !actions_output_to_local_port(&ctx)) { compose_output_action(&ctx, OFPP_LOCAL); } - if (ctx.ofproto->has_mirrors) { + if (mbridge_has_mirrors(ctx.ofproto->mbridge)) { add_mirror_actions(&ctx, &orig_flow); } fix_sflow_action(&ctx); diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h index f5f0cd0fe..c82bc6420 100644 --- a/ofproto/ofproto-dpif-xlate.h +++ b/ofproto/ofproto-dpif-xlate.h @@ -19,6 +19,7 @@ #include "meta-flow.h" #include "odp-util.h" #include "ofpbuf.h" +#include "ofproto-dpif-mirror.h" #include "ofproto-dpif.h" #include "tag.h" diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 2d42c83b2..a45ad36f3 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -50,6 +50,7 @@ #include "ofp-print.h" #include "ofproto-dpif-governor.h" #include "ofproto-dpif-ipfix.h" +#include "ofproto-dpif-mirror.h" #include "ofproto-dpif-sflow.h" #include "ofproto-dpif-xlate.h" #include "poll-loop.h" @@ -81,11 +82,6 @@ static struct rule_dpif *rule_dpif_lookup(struct ofproto_dpif *, static void rule_get_stats(struct rule *, uint64_t *packets, uint64_t *bytes); static void rule_invalidate(const struct rule_dpif *); -static void mirror_destroy(struct ofmirror *); -static void update_mirror_stats(struct ofproto_dpif *ofproto, - mirror_mask_t mirrors, - uint64_t packets, uint64_t bytes); - static void bundle_remove(struct ofport *); static void bundle_update(struct ofbundle *); static void bundle_destroy(struct ofbundle *); @@ -1028,9 +1024,7 @@ construct(struct ofproto *ofproto_) ofproto->stp = NULL; hmap_init(&ofproto->bundles); ofproto->ml = mac_learning_create(MAC_ENTRY_DEFAULT_IDLE_TIME); - for (i = 0; i < MAX_MIRRORS; i++) { - ofproto->mirrors[i] = NULL; - } + ofproto->mbridge = mbridge_create(); ofproto->has_bonded_bundles = false; classifier_init(&ofproto->facets); @@ -1048,7 +1042,6 @@ construct(struct ofproto *ofproto_) ofproto_dpif_unixctl_init(); - ofproto->has_mirrors = false; hmap_init(&ofproto->vlandev_map); hmap_init(&ofproto->realdev_vid_map); @@ -1177,7 +1170,6 @@ destruct(struct ofproto *ofproto_) struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); struct rule_dpif *rule, *next_rule; struct oftable *table; - int i; ofproto->backer->need_revalidate = REV_RECONFIGURE; hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node); @@ -1192,9 +1184,7 @@ destruct(struct ofproto *ofproto_) } } - for (i = 0; i < MAX_MIRRORS; i++) { - mirror_destroy(ofproto->mirrors[i]); - } + mbridge_unref(ofproto->mbridge); netflow_destroy(ofproto->netflow); dpif_sflow_unref(ofproto->sflow); @@ -1244,6 +1234,11 @@ run(struct ofproto *ofproto_) complete_operations(ofproto); } + if (mbridge_need_revalidate(ofproto->mbridge)) { + ofproto->backer->need_revalidate = REV_RECONFIGURE; + mac_learning_flush(ofproto->ml, NULL); + } + /* Do not perform any periodic activity below required by 'ofproto' while * waiting for flow restore to complete. */ if (ofproto_get_flow_restore_wait()) { @@ -2131,24 +2126,6 @@ bundle_lookup(const struct ofproto_dpif *ofproto, void *aux) return NULL; } -/* Looks up each of the 'n_auxes' pointers in 'auxes' as bundles and adds the - * ones that are found to 'bundles'. */ -static void -bundle_lookup_multiple(struct ofproto_dpif *ofproto, - void **auxes, size_t n_auxes, - struct hmapx *bundles) -{ - size_t i; - - hmapx_init(bundles); - for (i = 0; i < n_auxes; i++) { - struct ofbundle *bundle = bundle_lookup(ofproto, auxes[i]); - if (bundle) { - hmapx_add(bundles, bundle); - } - } -} - static void bundle_update(struct ofbundle *bundle) { @@ -2221,24 +2198,13 @@ bundle_destroy(struct ofbundle *bundle) { struct ofproto_dpif *ofproto; struct ofport_dpif *port, *next_port; - int i; if (!bundle) { return; } ofproto = bundle->ofproto; - for (i = 0; i < MAX_MIRRORS; i++) { - struct ofmirror *m = ofproto->mirrors[i]; - if (m) { - if (m->out == bundle) { - mirror_destroy(m); - } else if (hmapx_find_and_delete(&m->srcs, bundle) - || hmapx_find_and_delete(&m->dsts, bundle)) { - ofproto->backer->need_revalidate = REV_RECONFIGURE; - } - } - } + mbridge_unregister_bundle(ofproto->mbridge, bundle->aux); LIST_FOR_EACH_SAFE (port, next_port, bundle_node, &bundle->ports) { bundle_del_port(port); @@ -2293,10 +2259,7 @@ bundle_set(struct ofproto *ofproto_, void *aux, bundle->bond = NULL; bundle->floodable = true; - - bundle->src_mirrors = 0; - bundle->dst_mirrors = 0; - bundle->mirror_out = 0; + mbridge_register_bundle(ofproto->mbridge, bundle); } if (!bundle->name || strcmp(s->name, bundle->name)) { @@ -2557,238 +2520,45 @@ bundle_wait(struct ofbundle *bundle) /* Mirrors. */ static int -mirror_scan(struct ofproto_dpif *ofproto) -{ - int idx; - - for (idx = 0; idx < MAX_MIRRORS; idx++) { - if (!ofproto->mirrors[idx]) { - return idx; - } - } - return -1; -} - -static struct ofmirror * -mirror_lookup(struct ofproto_dpif *ofproto, void *aux) -{ - int i; - - for (i = 0; i < MAX_MIRRORS; i++) { - struct ofmirror *mirror = ofproto->mirrors[i]; - if (mirror && mirror->aux == aux) { - return mirror; - } - } - - return NULL; -} - -/* Update the 'dup_mirrors' member of each of the ofmirrors in 'ofproto'. */ -static void -mirror_update_dups(struct ofproto_dpif *ofproto) -{ - int i; - - for (i = 0; i < MAX_MIRRORS; i++) { - struct ofmirror *m = ofproto->mirrors[i]; - - if (m) { - m->dup_mirrors = MIRROR_MASK_C(1) << i; - } - } - - for (i = 0; i < MAX_MIRRORS; i++) { - struct ofmirror *m1 = ofproto->mirrors[i]; - int j; - - if (!m1) { - continue; - } - - for (j = i + 1; j < MAX_MIRRORS; j++) { - struct ofmirror *m2 = ofproto->mirrors[j]; - - if (m2 && m1->out == m2->out && m1->out_vlan == m2->out_vlan) { - m1->dup_mirrors |= MIRROR_MASK_C(1) << j; - m2->dup_mirrors |= m1->dup_mirrors; - } - } - } -} - -static int -mirror_set(struct ofproto *ofproto_, void *aux, - const struct ofproto_mirror_settings *s) +mirror_set__(struct ofproto *ofproto_, void *aux, + const struct ofproto_mirror_settings *s) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - mirror_mask_t mirror_bit; - struct ofbundle *bundle; - struct ofmirror *mirror; - struct ofbundle *out; - struct hmapx srcs; /* Contains "struct ofbundle *"s. */ - struct hmapx dsts; /* Contains "struct ofbundle *"s. */ - int out_vlan; + struct ofbundle **srcs, **dsts; + int error; + size_t i; - mirror = mirror_lookup(ofproto, aux); if (!s) { - mirror_destroy(mirror); - return 0; - } - if (!mirror) { - int idx; - - idx = mirror_scan(ofproto); - if (idx < 0) { - VLOG_WARN("bridge %s: maximum of %d port mirrors reached, " - "cannot create %s", - ofproto->up.name, MAX_MIRRORS, s->name); - return EFBIG; - } - - mirror = ofproto->mirrors[idx] = xzalloc(sizeof *mirror); - mirror->ofproto = ofproto; - mirror->idx = idx; - mirror->aux = aux; - mirror->out_vlan = -1; - mirror->name = NULL; - } - - if (!mirror->name || strcmp(s->name, mirror->name)) { - free(mirror->name); - mirror->name = xstrdup(s->name); - } - - /* Get the new configuration. */ - if (s->out_bundle) { - out = bundle_lookup(ofproto, s->out_bundle); - if (!out) { - mirror_destroy(mirror); - return EINVAL; - } - out_vlan = -1; - } else { - out = NULL; - out_vlan = s->out_vlan; - } - bundle_lookup_multiple(ofproto, s->srcs, s->n_srcs, &srcs); - bundle_lookup_multiple(ofproto, s->dsts, s->n_dsts, &dsts); - - /* If the configuration has not changed, do nothing. */ - if (hmapx_equals(&srcs, &mirror->srcs) - && hmapx_equals(&dsts, &mirror->dsts) - && vlan_bitmap_equal(mirror->vlans, s->src_vlans) - && mirror->out == out - && mirror->out_vlan == out_vlan) - { - hmapx_destroy(&srcs); - hmapx_destroy(&dsts); + mirror_destroy(ofproto->mbridge, aux); return 0; } - hmapx_swap(&srcs, &mirror->srcs); - hmapx_destroy(&srcs); - - hmapx_swap(&dsts, &mirror->dsts); - hmapx_destroy(&dsts); - - free(mirror->vlans); - mirror->vlans = vlan_bitmap_clone(s->src_vlans); + srcs = xmalloc(s->n_srcs * sizeof *srcs); + dsts = xmalloc(s->n_dsts * sizeof *dsts); - mirror->out = out; - mirror->out_vlan = out_vlan; - - /* Update bundles. */ - mirror_bit = MIRROR_MASK_C(1) << mirror->idx; - HMAP_FOR_EACH (bundle, hmap_node, &mirror->ofproto->bundles) { - if (hmapx_contains(&mirror->srcs, bundle)) { - bundle->src_mirrors |= mirror_bit; - } else { - bundle->src_mirrors &= ~mirror_bit; - } - - if (hmapx_contains(&mirror->dsts, bundle)) { - bundle->dst_mirrors |= mirror_bit; - } else { - bundle->dst_mirrors &= ~mirror_bit; - } - - if (mirror->out == bundle) { - bundle->mirror_out |= mirror_bit; - } else { - bundle->mirror_out &= ~mirror_bit; - } + for (i = 0; i < s->n_srcs; i++) { + srcs[i] = bundle_lookup(ofproto, s->srcs[i]); } - ofproto->backer->need_revalidate = REV_RECONFIGURE; - ofproto->has_mirrors = true; - mac_learning_flush(ofproto->ml, - &ofproto->backer->revalidate_set); - mirror_update_dups(ofproto); - - return 0; -} - -static void -mirror_destroy(struct ofmirror *mirror) -{ - struct ofproto_dpif *ofproto; - mirror_mask_t mirror_bit; - struct ofbundle *bundle; - int i; - - if (!mirror) { - return; + for (i = 0; i < s->n_dsts; i++) { + dsts[i] = bundle_lookup(ofproto, s->dsts[i]); } - ofproto = mirror->ofproto; - ofproto->backer->need_revalidate = REV_RECONFIGURE; - mac_learning_flush(ofproto->ml, &ofproto->backer->revalidate_set); - - mirror_bit = MIRROR_MASK_C(1) << mirror->idx; - HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) { - bundle->src_mirrors &= ~mirror_bit; - bundle->dst_mirrors &= ~mirror_bit; - bundle->mirror_out &= ~mirror_bit; - } - - hmapx_destroy(&mirror->srcs); - hmapx_destroy(&mirror->dsts); - free(mirror->vlans); - - ofproto->mirrors[mirror->idx] = NULL; - free(mirror->name); - free(mirror); - - mirror_update_dups(ofproto); - - ofproto->has_mirrors = false; - for (i = 0; i < MAX_MIRRORS; i++) { - if (ofproto->mirrors[i]) { - ofproto->has_mirrors = true; - break; - } - } + error = mirror_set(ofproto->mbridge, aux, s->name, srcs, s->n_srcs, dsts, + s->n_dsts, s->src_vlans, + bundle_lookup(ofproto, s->out_bundle), s->out_vlan); + free(srcs); + free(dsts); + return error; } static int -mirror_get_stats(struct ofproto *ofproto_, void *aux, - uint64_t *packets, uint64_t *bytes) +mirror_get_stats__(struct ofproto *ofproto, void *aux, + uint64_t *packets, uint64_t *bytes) { - struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - struct ofmirror *mirror = mirror_lookup(ofproto, aux); - - if (!mirror) { - *packets = *bytes = UINT64_MAX; - return 0; - } - push_all_stats(); - - *packets = mirror->packet_count; - *bytes = mirror->byte_count; - - return 0; + return mirror_get_stats(ofproto_dpif_cast(ofproto)->mbridge, aux, packets, + bytes); } static int @@ -2806,7 +2576,7 @@ is_mirror_output_bundle(const struct ofproto *ofproto_, void *aux) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); struct ofbundle *bundle = bundle_lookup(ofproto, aux); - return bundle && bundle->mirror_out != 0; + return bundle && mirror_bundle_out(ofproto->mbridge, bundle) != 0; } static void @@ -4854,8 +4624,8 @@ facet_push_stats(struct facet *facet, bool may_learn) netflow_flow_update_time(ofproto->netflow, &facet->nf_flow, facet->used); netflow_flow_update_flags(&facet->nf_flow, facet->tcp_flags); - update_mirror_stats(ofproto, facet->xout.mirrors, stats.n_packets, - stats.n_bytes); + mirror_update_stats(ofproto->mbridge, facet->xout.mirrors, + stats.n_packets, stats.n_bytes); xlate_in_init(&xin, ofproto, &facet->flow, facet->rule, stats.tcp_flags, NULL); @@ -5482,35 +5252,6 @@ put_userspace_action(const struct ofproto_dpif *ofproto, return odp_put_userspace_action(pid, cookie, cookie_size, odp_actions); } - -static void -update_mirror_stats(struct ofproto_dpif *ofproto, mirror_mask_t mirrors, - uint64_t packets, uint64_t bytes) -{ - if (!mirrors) { - return; - } - - for (; mirrors; mirrors = zero_rightmost_1bit(mirrors)) { - struct ofmirror *m; - - m = ofproto->mirrors[mirror_mask_ffs(mirrors) - 1]; - - if (!m) { - /* In normal circumstances 'm' will not be NULL. However, - * if mirrors are reconfigured, we can temporarily get out - * of sync in facet_revalidate(). We could "correct" the - * mirror list before reaching here, but doing that would - * not properly account the traffic stats we've currently - * accumulated for previous mirror configuration. */ - continue; - } - - m->packet_count += packets; - m->byte_count += bytes; - } -} - tag_type calculate_flow_tag(struct ofproto_dpif *ofproto, const struct flow *flow, uint8_t table_id, struct rule_dpif *rule) @@ -6880,8 +6621,8 @@ const struct ofproto_class ofproto_dpif_class = { set_queues, bundle_set, bundle_remove, - mirror_set, - mirror_get_stats, + mirror_set__, + mirror_get_stats__, set_flood_vlans, is_mirror_output_bundle, forward_bpdu_changed, diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index 070429737..084f3c1c0 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -25,11 +25,6 @@ union user_action_cookie; -#define MAX_MIRRORS 32 -typedef uint32_t mirror_mask_t; -#define MIRROR_MASK_C(X) UINT32_C(X) -BUILD_ASSERT_DECL(sizeof(mirror_mask_t) * CHAR_BIT >= MAX_MIRRORS); - /* Number of implemented OpenFlow tables. */ enum { N_TABLES = 255 }; enum { TBL_INTERNAL = N_TABLES - 1 }; /* Used for internal hidden rules. */ @@ -86,9 +81,8 @@ struct ofproto_dpif { struct dpif_ipfix *ipfix; struct hmap bundles; /* Contains "struct ofbundle"s. */ struct mac_learning *ml; - struct ofmirror *mirrors[MAX_MIRRORS]; - bool has_mirrors; bool has_bonded_bundles; + struct mbridge *mbridge; /* Facets. */ struct classifier facets; /* Contains 'struct facet's. */ @@ -172,32 +166,6 @@ struct ofbundle { /* Status. */ bool floodable; /* True if no port has OFPUTIL_PC_NO_FLOOD set. */ - - /* Port mirroring info. */ - mirror_mask_t src_mirrors; /* Mirrors triggered when packet received. */ - mirror_mask_t dst_mirrors; /* Mirrors triggered when packet sent. */ - mirror_mask_t mirror_out; /* Mirrors that output to this bundle. */ -}; - -struct ofmirror { - struct ofproto_dpif *ofproto; /* Owning ofproto. */ - size_t idx; /* In ofproto's "mirrors" array. */ - void *aux; /* Key supplied by ofproto's client. */ - char *name; /* Identifier for log messages. */ - - /* Selection criteria. */ - struct hmapx srcs; /* Contains "struct ofbundle *"s. */ - struct hmapx dsts; /* Contains "struct ofbundle *"s. */ - unsigned long *vlans; /* Bitmap of chosen VLANs, NULL selects all. */ - - /* Output (exactly one of out == NULL and out_vlan == -1 is true). */ - struct ofbundle *out; /* Output port or NULL. */ - int out_vlan; /* Output VLAN or -1. */ - mirror_mask_t dup_mirrors; /* Bitmap of mirrors with the same output. */ - - /* Counters. */ - int64_t packet_count; /* Number of packets sent. */ - int64_t byte_count; /* Number of bytes sent. */ }; static inline struct rule_dpif *rule_dpif_cast(const struct rule *rule) @@ -219,13 +187,6 @@ ofbundle_get_a_port(const struct ofbundle *bundle) bundle_node); } -static inline int -mirror_mask_ffs(mirror_mask_t mask) -{ - BUILD_ASSERT_DECL(sizeof(unsigned int) >= sizeof(mask)); - return ffs(mask); -} - struct ofport_dpif *get_ofp_port(const struct ofproto_dpif *, ofp_port_t ofp_port);