[ovs-dev] [PATCH v4 4/4] dpif-netdev: Simple DROP meter implementation.
Jarno Rajahalme
jarno at ovn.org
Thu Feb 23 19:29:16 UTC 2017
I forgot to add advertised the changes to git before posting, so I just sent a v5.
Jarno
> On Feb 22, 2017, at 6:34 PM, Jarno Rajahalme <jarno at ovn.org> wrote:
>
> Meters may be used by any flow, so some kind of locking must be used.
> In this version we have an adaptive mutex for each meter, which may
> not be optimal for DPDK. However, this should serve as a basis for
> further improvement.
>
> A batch of packets is first tried as a whole, and only if some of the
> meter bands are hit, we need to process the packets individually.
>
> Signed-off-by: Jarno Rajahalme <jarno at ovn.org>
> Signed-off-by: Andy Zhou <azhou at ovn.org>
> ---
> lib/dpif-netdev.c | 362 ++++++++++++++++++++++++++++++++++++++++++++++++---
> tests/dpif-netdev.at | 106 +++++++++++++++
> 2 files changed, 450 insertions(+), 18 deletions(-)
>
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index 87beb01..4257f45 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -86,6 +86,8 @@ DEFINE_STATIC_PER_THREAD_DATA(uint32_t, recirc_depth, 0)
>
> /* Configuration parameters. */
> enum { MAX_FLOWS = 65536 }; /* Maximum number of flows in flow table. */
> +enum { MAX_METERS = 65536 }; /* Maximum number of meters. */
> +enum { MAX_BANDS = 8 }; /* Maximum number of bands / meter. */
>
> /* Protects against changes to 'dp_netdevs'. */
> static struct ovs_mutex dp_netdev_mutex = OVS_MUTEX_INITIALIZER;
> @@ -198,6 +200,31 @@ static bool dpcls_lookup(struct dpcls *cls,
> struct dpcls_rule **rules, size_t cnt,
> int *num_lookups_p);
>
> +/* Set of supported meter flags */
> +#define DP_SUPPORTED_METER_FLAGS_MASK \
> + (OFPMF13_STATS | OFPMF13_PKTPS | OFPMF13_KBPS | OFPMF13_BURST)
> +
> +/* Set of supported meter band types */
> +#define DP_SUPPORTED_METER_BAND_TYPES \
> + ( 1 << OFPMBT13_DROP )
> +
> +struct dp_meter_band {
> + struct ofputil_meter_band up; /* type, prec_level, pad, rate, burst_size */
> + uint32_t bucket; /* In 1/1000 packets (for PKTPS), or in bits (for KBPS) */
> + uint64_t packet_count;
> + uint64_t byte_count;
> +};
> +
> +struct dp_meter {
> + uint16_t flags;
> + uint16_t n_bands;
> + uint32_t max_delta_t;
> + uint64_t used;
> + uint64_t packet_count;
> + uint64_t byte_count;
> + struct dp_meter_band bands[];
> +};
> +
> /* Datapath based on the network device interface from netdev.h.
> *
> *
> @@ -228,6 +255,11 @@ struct dp_netdev {
> struct hmap ports;
> struct seq *port_seq; /* Incremented whenever a port changes. */
>
> + /* Meters. */
> + struct ovs_mutex meter_locks[MAX_METERS];
> + struct dp_meter *meters[MAX_METERS]; /* Meter bands. */
> + uint32_t meter_free; /* Next free meter. */
> +
> /* Protects access to ofproto-dpif-upcall interface during revalidator
> * thread synchronization. */
> struct fat_rwlock upcall_rwlock;
> @@ -1067,6 +1099,10 @@ create_dp_netdev(const char *name, const struct dpif_class *class,
> dp->reconfigure_seq = seq_create();
> dp->last_reconfigure_seq = seq_read(dp->reconfigure_seq);
>
> + for (int i = 0; i < MAX_METERS; ++i) {
> + ovs_mutex_init_adaptive(&dp->meter_locks[i]);
> + }
> +
> /* Disable upcalls by default. */
> dp_netdev_disable_upcall(dp);
> dp->upcall_aux = NULL;
> @@ -1146,6 +1182,16 @@ dp_netdev_destroy_upcall_lock(struct dp_netdev *dp)
> fat_rwlock_destroy(&dp->upcall_rwlock);
> }
>
> +static void
> +dp_delete_meter(struct dp_netdev *dp, uint32_t meter_id)
> + OVS_REQUIRES(dp->meter_locks[meter_id])
> +{
> + if (dp->meters[meter_id]) {
> + free(dp->meters[meter_id]);
> + dp->meters[meter_id] = NULL;
> + }
> +}
> +
> /* Requires dp_netdev_mutex so that we can't get a new reference to 'dp'
> * through the 'dp_netdevs' shash while freeing 'dp'. */
> static void
> @@ -1161,6 +1207,7 @@ dp_netdev_free(struct dp_netdev *dp)
> do_del_port(dp, port);
> }
> ovs_mutex_unlock(&dp->port_mutex);
> +
> dp_netdev_destroy_all_pmds(dp, true);
> cmap_destroy(&dp->poll_threads);
>
> @@ -1179,6 +1226,13 @@ dp_netdev_free(struct dp_netdev *dp)
> /* Upcalls must be disabled at this point */
> dp_netdev_destroy_upcall_lock(dp);
>
> + for (int i = 0; i < MAX_METERS; ++i) {
> + ovs_mutex_lock(&dp->meter_locks[i]);
> + dp_delete_meter(dp, i);
> + ovs_mutex_unlock(&dp->meter_locks[i]);
> + ovs_mutex_destroy(&dp->meter_locks[i]);
> + }
> +
> free(dp->pmd_cmask);
> free(CONST_CAST(char *, dp->name));
> free(dp);
> @@ -3657,37 +3711,304 @@ static void
> dpif_netdev_meter_get_features(const struct dpif * dpif OVS_UNUSED,
> struct ofputil_meter_features *features)
> {
> - features->max_meters = 0;
> - features->band_types = 0;
> - features->capabilities = 0;
> - features->max_bands = 0;
> + features->max_meters = MAX_METERS;
> + features->band_types = DP_SUPPORTED_METER_BAND_TYPES;
> + features->capabilities = DP_SUPPORTED_METER_FLAGS_MASK;
> + features->max_bands = MAX_BANDS;
> features->max_color = 0;
> }
>
> +/* Returns false when packet needs to be dropped. */
> +static void
> +dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
> + uint32_t meter_id, long long int now)
> +{
> + struct dp_meter *meter;
> + struct dp_meter_band *band;
> + long long int long_delta_t; /* msec */
> + uint32_t delta_t; /* msec */
> + int i;
> + int cnt = packets_->count;
> + uint32_t bytes, volume;
> + int exceeded_band[NETDEV_MAX_BURST];
> + uint32_t exceeded_rate[NETDEV_MAX_BURST];
> + int exceeded_pkt = cnt; /* First packet that exceeded a band rate. */
> +
> + if (meter_id >= MAX_METERS) {
> + return;
> + }
> +
> + ovs_mutex_lock(&dp->meter_locks[meter_id]);
> + meter = dp->meters[meter_id];
> + if (!meter) {
> + goto out;
> + }
> +
> + /* Initialize as negative values. */
> + memset(exceeded_band, 0xff, cnt * sizeof *exceeded_band);
> + /* Initialize as zeroes. */
> + memset(exceeded_rate, 0, cnt * sizeof *exceeded_rate);
> +
> + /* All packets will hit the meter at the same time. */
> + long_delta_t = (now - meter->used); /* msec */
> +
> + /* Make sure delta_t will not be too large, so that bucket will not
> + * wrap around below. */
> + delta_t = (long_delta_t > (long long int)meter->max_delta_t)
> + ? meter->max_delta_t : (uint32_t)long_delta_t;
> +
> + /* Update meter stats. */
> + meter->used = now;
> + meter->packet_count += cnt;
> + bytes = 0;
> + for (i = 0; i < cnt; i++) {
> + bytes += dp_packet_size(packets_->packets[i]);
> + }
> + meter->byte_count += bytes;
> +
> + /* Meters can operate in terms of packets per second or kilobits per
> + * second. */
> + if (meter->flags & OFPMF13_PKTPS) {
> + /* Rate in packets/second, bucket 1/1000 packets. */
> + /* msec * packets/sec = 1/1000 packets. */
> + volume = cnt * 1000; /* Take 'cnt' packets from the bucket. */
> + } else {
> + /* Rate in kbps, bucket in bits. */
> + /* msec * kbps = bits */
> + volume = bytes * 8;
> + }
> +
> + /* Update all bands and find the one hit with the highest rate for each
> + * packet (if any). */
> + for (int m = 0; m < meter->n_bands; ++m) {
> + band = &meter->bands[m];
> +
> + /* Update band's bucket. */
> + band->bucket += delta_t * band->up.rate;
> + if (band->bucket > band->up.burst_size) {
> + band->bucket = band->up.burst_size;
> + }
> +
> + /* Drain the bucket for all the packets, if possible. */
> + if (band->bucket >= volume) {
> + band->bucket -= volume;
> + } else {
> + int band_exceeded_pkt;
> +
> + /* Band limit hit, must process packet-by-packet. */
> + if (meter->flags & OFPMF13_PKTPS) {
> + band_exceeded_pkt = band->bucket / 1000;
> + band->bucket %= 1000; /* Remainder stays in bucket. */
> +
> + /* Update the exceeding band for each exceeding packet.
> + * (Only one band will be fired by a packet, and that
> + * can be different for each packet.) */
> + for (i = band_exceeded_pkt; i < cnt; i++) {
> + if (band->up.rate > exceeded_rate[i]) {
> + exceeded_rate[i] = band->up.rate;
> + exceeded_band[i] = m;
> + }
> + }
> + } else {
> + /* Packet sizes differ, must process one-by-one. */
> + band_exceeded_pkt = cnt;
> + for (i = 0; i < cnt; i++) {
> + uint32_t bits = dp_packet_size(packets_->packets[i]) * 8;
> +
> + if (band->bucket >= bits) {
> + band->bucket -= bits;
> + } else {
> + if (i < band_exceeded_pkt) {
> + band_exceeded_pkt = i;
> + }
> + /* Update the exceeding band for the exceeding packet.
> + * (Only one band will be fired by a packet, and that
> + * can be different for each packet.) */
> + if (band->up.rate > exceeded_rate[i]) {
> + exceeded_rate[i] = band->up.rate;
> + exceeded_band[i] = m;
> + }
> + }
> + }
> + }
> + /* Remember the first exceeding packet. */
> + if (exceeded_pkt > band_exceeded_pkt) {
> + exceeded_pkt = band_exceeded_pkt;
> + }
> + }
> + }
> +
> + /* Fire the highest rate band exceeded by each packet.
> + * Drop packets if needed, by swapping packet to the end that will be
> + * ignored. */
> + const size_t size = dp_packet_batch_size(packets_);
> + struct dp_packet *packet;
> + size_t j;
> + DP_PACKET_BATCH_REFILL_FOR_EACH (j, size, packet, packets_) {
> + if (exceeded_band[j] >= 0) {
> + /* Meter drop packet. */
> + band = &meter->bands[exceeded_band[j]];
> + band->packet_count += 1;
> + band->byte_count += dp_packet_size(packet);
> +
> + dp_packet_delete(packet);
> + } else {
> + /* Meter accepts packet. */
> + dp_packet_batch_refill(packets_, packet, j);
> + }
> + }
> + out:
> + ovs_mutex_unlock(&dp->meter_locks[meter_id]);
> +}
> +
> +/* Meter set/get/del processing is still single-threaded. */
> static int
> -dpif_netdev_meter_set(struct dpif *dpif OVS_UNUSED,
> - ofproto_meter_id *meter_id OVS_UNUSED,
> - struct ofputil_meter_config *config OVS_UNUSED)
> +dpif_netdev_meter_set(struct dpif *dpif, ofproto_meter_id *meter_id,
> + struct ofputil_meter_config *config)
> {
> - return EFBIG; /* meter_id out of range */
> + struct dp_netdev *dp = get_dp_netdev(dpif);
> + uint32_t mid = meter_id->uint32;
> + struct dp_meter *meter;
> + int i;
> +
> + if (mid == UINT32_MAX) {
> + mid = dp->meter_free;
> + }
> + if (mid >= MAX_METERS) {
> + return EFBIG; /* Meter_id out of range. */
> + }
> +
> + if (config->flags & ~DP_SUPPORTED_METER_FLAGS_MASK ||
> + !(config->flags & (OFPMF13_KBPS | OFPMF13_PKTPS))) {
> + return EBADF; /* Unsupported flags set */
> + }
> + /* Validate bands */
> + if (config->n_bands == 0 || config->n_bands > MAX_BANDS) {
> + return EINVAL; /* Too many bands */
> + }
> + for (i = 0; i < config->n_bands; ++i) {
> + switch (config->bands[i].type) {
> + case OFPMBT13_DROP:
> + break;
> + default:
> + return ENODEV; /* Unsupported band type */
> + }
> + }
> +
> + /* Allocate meter */
> + meter = xzalloc(sizeof *meter
> + + config->n_bands * sizeof(struct dp_meter_band));
> + if (meter) {
> + meter->flags = config->flags;
> + meter->n_bands = config->n_bands;
> + meter->max_delta_t = 0;
> + meter->used = time_msec();
> +
> + /* set up bands */
> + for (i = 0; i < config->n_bands; ++i) {
> + uint32_t band_max_delta_t;
> +
> + /* Set burst size to a workable value if none specified. */
> + if (config->bands[i].burst_size == 0) {
> + config->bands[i].burst_size = config->bands[i].rate;
> + }
> +
> + meter->bands[i].up = config->bands[i];
> + /* Convert burst size to the bucket units: */
> + /* pkts => 1/1000 packets, kilobits => bits. */
> + meter->bands[i].up.burst_size *= 1000;
> + /* Initialize bucket to empty. */
> + meter->bands[i].bucket = 0;
> +
> + /* Figure out max delta_t that is enough to fill any bucket. */
> + band_max_delta_t
> + = meter->bands[i].up.burst_size / meter->bands[i].up.rate;
> + if (band_max_delta_t > meter->max_delta_t) {
> + meter->max_delta_t = band_max_delta_t;
> + }
> + }
> +
> + ovs_mutex_lock(&dp->meter_locks[mid]);
> + dp_delete_meter(dp, mid); /* Free existing meter, if any */
> + dp->meters[mid] = meter;
> + ovs_mutex_unlock(&dp->meter_locks[mid]);
> +
> + meter_id->uint32 = mid; /* Store on success. */
> +
> + /* Find next free meter */
> + if (dp->meter_free == mid) { /* Now taken. */
> + do {
> + if (++mid >= MAX_METERS) { /* Wrap around */
> + mid = 0;
> + }
> + if (mid == dp->meter_free) { /* Full circle */
> + mid = MAX_METERS;
> + break;
> + }
> + } while (dp->meters[mid]);
> + dp->meter_free = mid; /* Next free meter or MAX_METERS */
> + }
> + return 0;
> + }
> + return ENOMEM;
> }
>
> static int
> -dpif_netdev_meter_get(const struct dpif *dpif OVS_UNUSED,
> - ofproto_meter_id meter_id OVS_UNUSED,
> - struct ofputil_meter_stats *stats OVS_UNUSED,
> - uint16_t n_bands OVS_UNUSED)
> +dpif_netdev_meter_get(const struct dpif *dpif,
> + ofproto_meter_id meter_id_,
> + struct ofputil_meter_stats *stats, uint16_t n_bands)
> {
> - return EFBIG; /* meter_id out of range */
> + const struct dp_netdev *dp = get_dp_netdev(dpif);
> + const struct dp_meter *meter;
> + uint32_t meter_id = meter_id_.uint32;
> +
> + if (meter_id >= MAX_METERS) {
> + return EFBIG;
> + }
> + meter = dp->meters[meter_id];
> + if (!meter) {
> + return ENOENT;
> + }
> + if (stats) {
> + int i = 0;
> +
> + ovs_mutex_lock(&dp->meter_locks[meter_id]);
> + stats->packet_in_count = meter->packet_count;
> + stats->byte_in_count = meter->byte_count;
> +
> + for (i = 0; i < n_bands && i < meter->n_bands; ++i) {
> + stats->bands[i].packet_count = meter->bands[i].packet_count;
> + stats->bands[i].byte_count = meter->bands[i].byte_count;
> + }
> + ovs_mutex_unlock(&dp->meter_locks[meter_id]);
> +
> + stats->n_bands = i;
> + }
> + return 0;
> }
>
> static int
> -dpif_netdev_meter_del(struct dpif *dpif OVS_UNUSED,
> - ofproto_meter_id meter_id OVS_UNUSED,
> - struct ofputil_meter_stats *stats OVS_UNUSED,
> - uint16_t n_bands OVS_UNUSED)
> +dpif_netdev_meter_del(struct dpif *dpif,
> + ofproto_meter_id meter_id_,
> + struct ofputil_meter_stats *stats, uint16_t n_bands)
> {
> - return EFBIG; /* meter_id out of range */
> + struct dp_netdev *dp = get_dp_netdev(dpif);
> + int error;
> +
> + error = dpif_netdev_meter_get(dpif, meter_id_, stats, n_bands);
> + if (!error) {
> + uint32_t meter_id = meter_id_.uint32;
> +
> + ovs_mutex_lock(&dp->meter_locks[meter_id]);
> + dp_delete_meter(dp, meter_id);
> + ovs_mutex_unlock(&dp->meter_locks[meter_id]);
> +
> + /* Keep free meter index as low as possible */
> + if (meter_id < dp->meter_free) {
> + dp->meter_free = meter_id;
> + }
> + }
> + return error;
> }
>
>
> @@ -4617,6 +4938,7 @@ dp_execute_userspace_action(struct dp_netdev_pmd_thread *pmd,
> static void
> dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
> const struct nlattr *a, bool may_steal)
> + OVS_NO_THREAD_SAFETY_ANALYSIS
> {
> struct dp_netdev_execute_aux *aux = aux_;
> uint32_t *depth = recirc_depth_get();
> @@ -4814,6 +5136,10 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
> }
>
> case OVS_ACTION_ATTR_METER:
> + dp_netdev_run_meter(pmd->dp, packets_, nl_attr_get_u32(a),
> + time_msec());
> + break;
> +
> case OVS_ACTION_ATTR_PUSH_VLAN:
> case OVS_ACTION_ATTR_POP_VLAN:
> case OVS_ACTION_ATTR_PUSH_MPLS:
> diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
> index fff0460..586a5b1 100644
> --- a/tests/dpif-netdev.at
> +++ b/tests/dpif-netdev.at
> @@ -4,6 +4,13 @@ m4_divert_push([PREPARE_TESTS])
> [
> # Strips out uninteresting parts of flow output, as well as parts
> # that vary from one run to another (e.g., timing and bond actions).
> +strip_timers () {
> + sed '
> + s/duration:[0-9]*\.[0-9]*/duration:0.0/
> + s/used:[0-9]*\.[0-9]*/used:0.0/
> +'
> +}
> +
> strip_xout () {
> sed '
> s/ufid:[-0-9a-f]* //
> @@ -160,3 +167,102 @@ skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label
>
> DPIF_NETDEV_MISS_FLOW_DUMP([dummy])
> DPIF_NETDEV_MISS_FLOW_DUMP([dummy-pmd])
> +
> +AT_SETUP([dpif-netdev - meters])
> +# Create br0 with interfaces p1 and p7
> +# and br1 with interfaces p2 and p8
> +# with p1 and p2 connected via unix domain socket
> +OVS_VSWITCHD_START(
> + [add-port br0 p1 -- set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p0.sock ofport_request=1 -- \
> + add-port br0 p7 -- set interface p7 ofport_request=7 type=dummy -- \
> + add-br br1 -- \
> + set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- \
> + set bridge br1 datapath-type=dummy other-config:datapath-id=1234 \
> + fail-mode=secure -- \
> + add-port br1 p2 -- set interface p2 type=dummy options:stream=unix:$OVS_RUNDIR/p0.sock ofport_request=2 -- \
> + add-port br1 p8 -- set interface p8 ofport_request=8 type=dummy --])
> +AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
> +
> +AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br0 'meter=1 pktps burst stats bands=type=drop rate=1 burst_size=1'])
> +AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br0 'meter=2 kbps burst stats bands=type=drop rate=1 burst_size=2'])
> +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 'in_port=1 action=meter:1,7'])
> +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 'in_port=7 action=meter:2,1'])
> +AT_CHECK([ovs-ofctl add-flow br1 'in_port=2 action=8'])
> +AT_CHECK([ovs-ofctl add-flow br1 'in_port=8 action=2'])
> +ovs-appctl time/stop
> +
> +AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0], [0], [dnl
> +OFPST_METER_CONFIG reply (OF1.3) (xid=0x2):
> +meter=1 pktps burst stats bands=
> +type=drop rate=1 burst_size=1
> +
> +meter=2 kbps burst stats bands=
> +type=drop rate=1 burst_size=2
> +])
> +
> +ovs-appctl time/warp 5000
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +sleep 1 # wait for forwarders process packets
> +
> +# Meter 1 is measuring packets, allowing one packet per second with
> +# bursts of one packet, so 4 out of 5 packets should hit the drop
> +# band.
> +# Meter 2 is measuring kbps, with burst size 2 (== 2000 bits). 4 packets
> +# (240 bytes == 1920 bits) pass, but the last packet should hit the drop band.
> +AT_CHECK([ovs-ofctl -O OpenFlow13 meter-stats br0 | strip_timers], [0], [dnl
> +OFPST_METER reply (OF1.3) (xid=0x2):
> +meter:1 flow_count:1 packet_in_count:5 byte_in_count:300 duration:0.0s bands:
> +0: packet_count:4 byte_count:240
> +
> +meter:2 flow_count:1 packet_in_count:5 byte_in_count:300 duration:0.0s bands:
> +0: packet_count:1 byte_count:60
> +])
> +
> +# Advance time by 1/2 second
> +ovs-appctl time/warp 500
> +
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' --len 60])
> +sleep 1 # wait for forwarders process packets
> +
> +# Meter 1 is measuring packets, allowing one packet per second with
> +# bursts of one packet, so all 5 of the new packets should hit the drop
> +# band.
> +# Meter 2 is measuring kbps, with burst size 2 (== 2000 bits). After 500ms
> +# there should be space for 80 + 500 bits, so one new 60 byte (480 bit) packet
> +# should pass, remaining 4 should hit the drop band.
> +AT_CHECK([ovs-ofctl -O OpenFlow13 meter-stats br0 | strip_timers], [0], [dnl
> +OFPST_METER reply (OF1.3) (xid=0x2):
> +meter:1 flow_count:1 packet_in_count:10 byte_in_count:600 duration:0.0s bands:
> +0: packet_count:9 byte_count:540
> +
> +meter:2 flow_count:1 packet_in_count:10 byte_in_count:600 duration:0.0s bands:
> +0: packet_count:5 byte_count:300
> +])
> +
> +AT_CHECK([cat ovs-vswitchd.log | filter_flow_install | strip_xout_keep_actions], [0], [dnl
> +recirc_id(0),in_port(1),eth_type(0x0800),ipv4(frag=no), actions:meter(0),7
> +recirc_id(0),in_port(2),eth_type(0x0800),ipv4(frag=no), actions:8
> +recirc_id(0),in_port(7),eth_type(0x0800),ipv4(frag=no), actions:meter(1),1
> +recirc_id(0),in_port(8),eth_type(0x0800),ipv4(frag=no), actions:2
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> --
> 2.1.4
>
More information about the dev
mailing list