/* In generally, slots selected should be empty, because * OvS uses id-pool to fetch a available id.
*/ if (unlikely(rcu_dereference_ovsl(ti->dp_meters[hash]))) return -EBUSY;
dp_meter_instance_insert(ti, meter);
/* That function is thread-safe. */
tbl->count++; if (tbl->count >= tbl->max_meters_allowed) {
err = -EFBIG; goto attach_err;
}
ti = rcu_dereference_ovsl(tbl->ti);
dp_meter_instance_remove(ti, meter);
tbl->count--;
/* Shrink the meter array if necessary. */ if (ti->n_meters > DP_METER_ARRAY_SIZE_MIN &&
tbl->count <= (ti->n_meters / 4)) { int half_size = ti->n_meters / 2; int i;
/* Avoid hash collision, don't move slots to other place. * Make sure there are no references of meters in array * which will be released.
*/ for (i = half_size; i < ti->n_meters; i++) if (rcu_dereference_ovsl(ti->dp_meters[i])) goto out;
if (dp_meter_instance_realloc(tbl, half_size)) goto shrink_err;
}
if (nla_put_u32(reply, OVS_METER_ATTR_MAX_METERS,
dp->meter_tbl.max_meters_allowed)) goto exit_unlock;
ovs_unlock();
if (nla_put_u32(reply, OVS_METER_ATTR_MAX_BANDS, DP_MAX_BANDS)) goto nla_put_failure;
nla = nla_nest_start_noflag(reply, OVS_METER_ATTR_BANDS); if (!nla) goto nla_put_failure;
band_nla = nla_nest_start_noflag(reply, OVS_BAND_ATTR_UNSPEC); if (!band_nla) goto nla_put_failure; /* Currently only DROP band type is supported. */ if (nla_put_u32(reply, OVS_BAND_ATTR_TYPE, OVS_METER_BAND_TYPE_DROP)) goto nla_put_failure;
nla_nest_end(reply, band_nla);
nla_nest_end(reply, nla);
/* Validate attributes, count the bands. */ if (!a[OVS_METER_ATTR_BANDS]) return ERR_PTR(-EINVAL);
nla_for_each_nested(nla, a[OVS_METER_ATTR_BANDS], rem) if (++n_bands > DP_MAX_BANDS) return ERR_PTR(-EINVAL);
/* Allocate and set up the meter before locking anything. */
meter = kzalloc(struct_size(meter, bands, n_bands), GFP_KERNEL_ACCOUNT); if (!meter) return ERR_PTR(-ENOMEM);
/* Set up meter bands. */
band = meter->bands;
nla_for_each_nested(nla, a[OVS_METER_ATTR_BANDS], rem) { struct nlattr *attr[OVS_BAND_ATTR_MAX + 1];
u32 band_max_delta_t;
band->burst_size = nla_get_u32(attr[OVS_BAND_ATTR_BURST]); /* Figure out max delta_t that is enough to fill any bucket. * Keep max_delta_t size to the bucket units: * pkts => 1/1000 packets, kilobits => bits. * * Start with a full bucket.
*/
band->bucket = band->burst_size * 1000ULL;
band_max_delta_t = div_u64(band->bucket, band->rate); if (band_max_delta_t > meter->max_delta_t)
meter->max_delta_t = band_max_delta_t;
band++;
}
err = attach_meter(meter_tbl, meter); if (err) goto exit_free_old_meter;
ovs_unlock();
/* Build response with the meter_id and stats from * the old meter, if any.
*/
failed = nla_put_u32(reply, OVS_METER_ATTR_ID, meter_id);
WARN_ON(failed); if (old_meter) {
spin_lock_bh(&old_meter->lock); if (old_meter->keep_stats) {
err = ovs_meter_cmd_reply_stats(reply, meter_id,
old_meter);
WARN_ON(err);
}
spin_unlock_bh(&old_meter->lock);
ovs_meter_free(old_meter);
}
/* Meter action execution. * * Return true 'meter_id' drop band is triggered. The 'skb' should be * dropped by the caller'.
*/ bool ovs_meter_execute(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, u32 meter_id)
{ longlongint now_ms = div_u64(ktime_get_ns(), 1000 * 1000); longlongint long_delta_ms; struct dp_meter_band *band; struct dp_meter *meter; int i, band_exceeded_max = -1;
u32 band_exceeded_rate = 0;
u32 delta_ms;
u32 cost;
meter = lookup_meter(&dp->meter_tbl, meter_id); /* Do not drop the packet when there is no meter. */ if (!meter) returnfalse;
/* Lock the meter while using it. */
spin_lock(&meter->lock);
long_delta_ms = (now_ms - meter->used); /* ms */ if (long_delta_ms < 0) { /* This condition means that we have several threads fighting * for a meter lock, and the one who received the packets a * bit later wins. Assuming that all racing threads received * packets at the same time to avoid overflow.
*/
long_delta_ms = 0;
}
/* Make sure delta_ms will not be too large, so that bucket will not * wrap around below.
*/
delta_ms = (long_delta_ms > (longlongint)meter->max_delta_t)
? meter->max_delta_t : (u32)long_delta_ms;
/* Bucket rate is either in kilobits per second, or in packets per * second. We maintain the bucket in the units of either bits or * 1/1000th of a packet, correspondingly. * Then, when rate is multiplied with milliseconds, we get the * bucket units: * msec * kbps = bits, and * msec * packets/sec = 1/1000 packets. * * 'cost' is the number of bucket units in this packet.
*/
cost = (meter->kbps) ? skb->len * 8 : 1000;
/* Update all bands and find the one hit with the highest rate. */ for (i = 0; i < meter->n_bands; ++i) { longlongint max_bucket_size;
band = &meter->bands[i];
max_bucket_size = band->burst_size * 1000LL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.