mirror of
https://github.com/openvswitch/ovs
synced 2025-09-07 09:46:20 +00:00
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 <ethan@nicira.com> Acked-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
@@ -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 \
|
||||
|
500
ofproto/ofproto-dpif-mirror.c
Normal file
500
ofproto/ofproto-dpif-mirror.c
Normal file
@@ -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 <config.h>
|
||||
|
||||
#include "ofproto-dpif-mirror.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
61
ofproto/ofproto-dpif-mirror.h
Normal file
61
ofproto/ofproto-dpif-mirror.h
Normal file
@@ -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 <stdint.h>
|
||||
|
||||
#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 */
|
@@ -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;
|
||||
mirror_mask_t dup_mirrors;
|
||||
struct ofbundle *out;
|
||||
unsigned long *vlans;
|
||||
bool vlan_mirrored;
|
||||
bool has_mirror;
|
||||
int out_vlan;
|
||||
|
||||
m = ofproto->mirrors[mirror_mask_ffs(mirrors) - 1];
|
||||
has_mirror = mirror_get(ofproto->mbridge, mirror_mask_ffs(mirrors) - 1,
|
||||
&vlans, &dup_mirrors, &out, &out_vlan);
|
||||
ovs_assert(has_mirror);
|
||||
|
||||
if (m->vlans) {
|
||||
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);
|
||||
|
@@ -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"
|
||||
|
||||
|
@@ -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);
|
||||
srcs = xmalloc(s->n_srcs * sizeof *srcs);
|
||||
dsts = xmalloc(s->n_dsts * sizeof *dsts);
|
||||
|
||||
hmapx_swap(&dsts, &mirror->dsts);
|
||||
hmapx_destroy(&dsts);
|
||||
|
||||
free(mirror->vlans);
|
||||
mirror->vlans = vlan_bitmap_clone(s->src_vlans);
|
||||
|
||||
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,
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user