Skip to content

Commit

Permalink
ofproto-dpif: Add 'meter_ids' to backer
Browse files Browse the repository at this point in the history
Add 'meter_ids', an id-pool object to manage datapath meter id, i.e.
provider_meter_id.

Currently, only userspace datapath supports meter, and it implements
the provider_meter_id management. Moving this function to 'backer'
allows other datapath implementation to share the same logic.

Signed-off-by: Andy Zhou <[email protected]>
Acked-by: Jarno Rajahalme <[email protected]>
  • Loading branch information
azhou-nicira committed Apr 28, 2017
1 parent ba8cff3 commit 333ad77
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 27 deletions.
24 changes: 0 additions & 24 deletions lib/dpif-netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ struct dp_netdev {
/* Meters. */
struct ovs_mutex meter_locks[N_METER_LOCKS];
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. */
Expand Down Expand Up @@ -3896,9 +3895,6 @@ dpif_netdev_meter_set(struct dpif *dpif, ofproto_meter_id *meter_id,
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. */
}
Expand Down Expand Up @@ -3958,21 +3954,6 @@ dpif_netdev_meter_set(struct dpif *dpif, ofproto_meter_id *meter_id,
dp->meters[mid] = meter;
meter_unlock(dp, 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;
Expand Down Expand Up @@ -4027,11 +4008,6 @@ dpif_netdev_meter_del(struct dpif *dpif,
meter_lock(dp, meter_id);
dp_delete_meter(dp, meter_id);
meter_unlock(dp, meter_id);

/* Keep free meter index as low as possible */
if (meter_id < dp->meter_free) {
dp->meter_free = meter_id;
}
}
return error;
}
Expand Down
51 changes: 48 additions & 3 deletions ofproto/ofproto-dpif.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ close_dpif_backer(struct dpif_backer *backer)
free(backer->type);
free(backer->dp_version_string);
dpif_close(backer->dpif);
id_pool_destroy(backer->meter_ids);
free(backer);
}

Expand Down Expand Up @@ -787,6 +788,15 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
= check_variable_length_userdata(backer);
backer->dp_version_string = dpif_get_dp_version(backer->dpif);

/* Manage Datapath meter IDs if supported. */
struct ofputil_meter_features features;
dpif_meter_get_features(backer->dpif, &features);
if (features.max_meters) {
backer->meter_ids = id_pool_create(0, features.max_meters);
} else {
backer->meter_ids = NULL;
}

return error;
}

Expand Down Expand Up @@ -5502,6 +5512,17 @@ meter_set(struct ofproto *ofproto_, ofproto_meter_id *meter_id,
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);

/* Provider ID unknown. Use backer to allocate a new DP meter */
if (meter_id->uint32 == UINT32_MAX) {
if (!ofproto->backer->meter_ids) {
return EFBIG; /* Datapath does not support meter. */
}

if(!id_pool_alloc_id(ofproto->backer->meter_ids, &meter_id->uint32)) {
return ENOMEM; /* Can't allocate a DP meter. */
}
}

switch (dpif_meter_set(ofproto->backer->dpif, meter_id, config)) {
case 0:
return 0;
Expand Down Expand Up @@ -5531,12 +5552,36 @@ meter_get(const struct ofproto *ofproto_, ofproto_meter_id meter_id,
return OFPERR_OFPMMFC_UNKNOWN_METER;
}

struct free_meter_id_args {
struct ofproto_dpif *ofproto;
ofproto_meter_id meter_id;
};

static void
free_meter_id(struct free_meter_id_args *args)
{
struct ofproto_dpif *ofproto = args->ofproto;

dpif_meter_del(ofproto->backer->dpif, args->meter_id, NULL, 0);
id_pool_free_id(ofproto->backer->meter_ids, args->meter_id.uint32);
free(args);
}

static void
meter_del(struct ofproto *ofproto_, ofproto_meter_id meter_id)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);

dpif_meter_del(ofproto->backer->dpif, meter_id, NULL, 0);
struct free_meter_id_args *arg = xmalloc(sizeof *arg);

/* Before a meter can be deleted, Openflow spec requires all rules
* referring to the meter to be (automatically) removed before the
* meter is deleted. However, since vswitchd is multi-threaded,
* those rules and their actions remain accessible by other threads,
* especially by the handler and revalidator threads.
* Postpone meter deletion after RCU grace period, so that ongoing
* upcall translation or flow revalidation can complete. */
arg->ofproto = ofproto_dpif_cast(ofproto_);
arg->meter_id = meter_id;
ovsrcu_postpone(free_meter_id, arg);
}

const struct ofproto_class ofproto_dpif_class = {
Expand Down
4 changes: 4 additions & 0 deletions ofproto/ofproto-dpif.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "hmapx.h"
#include "odp-util.h"
#include "openvswitch/ofp-util.h"
#include "id-pool.h"
#include "ovs-thread.h"
#include "ofproto-provider.h"
#include "util.h"
Expand Down Expand Up @@ -224,6 +225,9 @@ struct dpif_backer {

bool recv_set_enable; /* Enables or disables receiving packets. */

/* Meter. */
struct id_pool *meter_ids; /* Datapath meter allocation. */

/* Version string of the datapath stored in OVSDB. */
char *dp_version_string;

Expand Down

0 comments on commit 333ad77

Please sign in to comment.