[ovs-dev] [mirror 04/13] ofproto-dpif: Improve RSPAN translation performance from O(n**2) to O(n).
Justin Pettit
jpettit at nicira.com
Mon Nov 14 00:28:27 UTC 2011
Looks good.
--Justin
On Oct 26, 2011, at 10:09 AM, Ben Pfaff wrote:
> This code previously checked whether each individual mirror output was
> already in the set of destinations. This is O(n**2) in the number of
> ports in a bridge.
>
> The new code uses a smarter algorithm to eliminate duplicates, one that is
> O(n) in the number of ports in a bridge.
> ---
> ofproto/ofproto-dpif.c | 116 +++++++++++++++++++++++++++++------------------
> 1 files changed, 71 insertions(+), 45 deletions(-)
>
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index af94d54..74407c9 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -121,9 +121,10 @@ struct ofmirror {
> struct hmapx dsts; /* Contains "struct ofbundle *"s. */
> unsigned long *vlans; /* Bitmap of chosen VLANs, NULL selects all. */
>
> - /* Output (mutually exclusive). */
> + /* 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. */
> };
>
> static void mirror_destroy(struct ofmirror *);
> @@ -1657,6 +1658,39 @@ mirror_lookup(struct ofproto_dpif *ofproto, void *aux)
> 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 (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)
> @@ -1762,6 +1796,7 @@ mirror_set(struct ofproto *ofproto_, void *aux,
>
> ofproto->need_revalidate = true;
> mac_learning_flush(ofproto->ml);
> + mirror_update_dups(ofproto);
>
> return 0;
> }
> @@ -1795,6 +1830,8 @@ mirror_destroy(struct ofmirror *mirror)
> ofproto->mirrors[mirror->idx] = NULL;
> free(mirror->name);
> free(mirror);
> +
> + mirror_update_dups(ofproto);
> }
>
> static int
> @@ -4528,19 +4565,6 @@ dst_set_free(struct dst_set *set)
> }
>
> static bool
> -dst_is_duplicate(const struct dst_set *set, const struct dst *test)
> -{
> - size_t i;
> - for (i = 0; i < set->n; i++) {
> - if (set->dsts[i].vid == test->vid
> - && set->dsts[i].port == test->port) {
> - return true;
> - }
> - }
> - return false;
> -}
> -
> -static bool
> ofbundle_trunks_vlan(const struct ofbundle *bundle, uint16_t vlan)
> {
> return (bundle->vlan_mode != PORT_VLAN_ACCESS
> @@ -4654,38 +4678,40 @@ compose_mirror_dsts(struct action_xlate_ctx *ctx,
> }
>
> flow_vid = vlan_tci_to_vid(ctx->flow.vlan_tci);
> - for (; mirrors; mirrors &= mirrors - 1) {
> - struct ofmirror *m = ofproto->mirrors[mirror_mask_ffs(mirrors) - 1];
> - if (vlan_is_mirrored(m, vlan)) {
> - struct dst dst;
> -
> - if (m->out) {
> - if (set_dst(ctx, &dst, in_bundle, m->out)
> - && !dst_is_duplicate(set, &dst)) {
> - dst_set_add(set, &dst);
> - }
> - } else if (eth_dst_may_rspan(ctx->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
> - && set_dst(ctx, &dst, in_bundle, bundle))
> - {
> - /* set_dst() got dst->vid from the input packet's VLAN,
> - * not from m->out_vlan, so recompute it. */
> - dst.vid = output_vlan_to_vid(bundle, m->out_vlan);
> -
> - if (dst_is_duplicate(set, &dst)) {
> - continue;
> - }
> -
> - if (bundle == in_bundle && dst.vid == flow_vid) {
> - /* Don't send out input port on same VLAN. */
> - continue;
> - }
> - dst_set_add(set, &dst);
> + while (mirrors) {
> + struct ofmirror *m;
> + struct dst dst;
> +
> + m = ofproto->mirrors[mirror_mask_ffs(mirrors) - 1];
> +
> + if (!vlan_is_mirrored(m, vlan)) {
> + mirrors &= mirrors - 1;
> + continue;
> + }
> +
> + mirrors &= ~m->dup_mirrors;
> + if (m->out) {
> + if (set_dst(ctx, &dst, in_bundle, m->out)) {
> + dst_set_add(set, &dst);
> + }
> + } else if (eth_dst_may_rspan(ctx->flow.dl_dst)
> + && vlan != m->out_vlan) {
> + struct ofbundle *bundle;
> +
> + HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) {
> + if (ofbundle_includes_vlan(bundle, m->out_vlan)
> + && !bundle->mirror_out
> + && set_dst(ctx, &dst, in_bundle, bundle))
> + {
> + /* set_dst() got dst->vid from the input packet's VLAN,
> + * not from m->out_vlan, so recompute it. */
> + dst.vid = output_vlan_to_vid(bundle, m->out_vlan);
> +
> + if (bundle == in_bundle && dst.vid == flow_vid) {
> + /* Don't send out input port on same VLAN. */
> + continue;
> }
> + dst_set_add(set, &dst);
> }
> }
> }
> --
> 1.7.2.5
>
More information about the dev
mailing list