Lines Matching +full:out +full:- +full:of +full:- +full:band
1 // SPDX-License-Identifier: GPL-2.0-only
43 return id % ti->n_meters; in meter_hash()
58 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); in lookup_meter()
62 meter = rcu_dereference_ovsl(ti->dp_meters[hash]); in lookup_meter()
63 if (meter && likely(meter->id == meter_id)) in lookup_meter()
79 ti->n_meters = size; in dp_meter_instance_alloc()
100 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); in dp_meter_instance_realloc()
101 int n_meters = min(size, ti->n_meters); in dp_meter_instance_realloc()
107 return -ENOMEM; in dp_meter_instance_realloc()
110 if (rcu_dereference_ovsl(ti->dp_meters[i])) in dp_meter_instance_realloc()
111 new_ti->dp_meters[i] = ti->dp_meters[i]; in dp_meter_instance_realloc()
113 rcu_assign_pointer(tbl->ti, new_ti); in dp_meter_instance_realloc()
114 call_rcu(&ti->rcu, dp_meter_instance_free_rcu); in dp_meter_instance_realloc()
124 hash = meter_hash(ti, meter->id); in dp_meter_instance_insert()
125 rcu_assign_pointer(ti->dp_meters[hash], meter); in dp_meter_instance_insert()
133 hash = meter_hash(ti, meter->id); in dp_meter_instance_remove()
134 RCU_INIT_POINTER(ti->dp_meters[hash], NULL); in dp_meter_instance_remove()
139 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); in attach_meter()
140 u32 hash = meter_hash(ti, meter->id); in attach_meter()
144 * OvS uses id-pool to fetch a available id. in attach_meter()
146 if (unlikely(rcu_dereference_ovsl(ti->dp_meters[hash]))) in attach_meter()
147 return -EBUSY; in attach_meter()
151 /* That function is thread-safe. */ in attach_meter()
152 tbl->count++; in attach_meter()
153 if (tbl->count >= tbl->max_meters_allowed) { in attach_meter()
154 err = -EFBIG; in attach_meter()
158 if (tbl->count >= ti->n_meters && in attach_meter()
159 dp_meter_instance_realloc(tbl, ti->n_meters * 2)) { in attach_meter()
160 err = -ENOMEM; in attach_meter()
168 tbl->count--; in attach_meter()
180 ti = rcu_dereference_ovsl(tbl->ti); in detach_meter()
183 tbl->count--; in detach_meter()
186 if (ti->n_meters > DP_METER_ARRAY_SIZE_MIN && in detach_meter()
187 tbl->count <= (ti->n_meters / 4)) { in detach_meter()
188 int half_size = ti->n_meters / 2; in detach_meter()
192 * Make sure there are no references of meters in array in detach_meter()
195 for (i = half_size; i < ti->n_meters; i++) in detach_meter()
196 if (rcu_dereference_ovsl(ti->dp_meters[i])) in detach_meter()
197 goto out; in detach_meter()
203 out: in detach_meter()
208 tbl->count++; in detach_meter()
209 return -ENOMEM; in detach_meter()
217 struct ovs_header *ovs_header = info->userhdr; in ovs_meter_cmd_reply_start()
221 return ERR_PTR(-ENOMEM); in ovs_meter_cmd_reply_start()
223 *ovs_reply_header = genlmsg_put(skb, info->snd_portid, in ovs_meter_cmd_reply_start()
224 info->snd_seq, in ovs_meter_cmd_reply_start()
228 return ERR_PTR(-EMSGSIZE); in ovs_meter_cmd_reply_start()
230 (*ovs_reply_header)->dp_ifindex = ovs_header->dp_ifindex; in ovs_meter_cmd_reply_start()
239 struct dp_meter_band *band; in ovs_meter_cmd_reply_stats() local
246 sizeof(struct ovs_flow_stats), &meter->stats)) in ovs_meter_cmd_reply_stats()
249 if (nla_put_u64_64bit(reply, OVS_METER_ATTR_USED, meter->used, in ovs_meter_cmd_reply_stats()
257 band = meter->bands; in ovs_meter_cmd_reply_stats()
259 for (i = 0; i < meter->n_bands; ++i, ++band) { in ovs_meter_cmd_reply_stats()
265 &band->stats)) in ovs_meter_cmd_reply_stats()
273 return -EMSGSIZE; in ovs_meter_cmd_reply_stats()
278 struct ovs_header *ovs_header = info->userhdr; in ovs_meter_cmd_features()
283 int err = -EMSGSIZE; in ovs_meter_cmd_features()
291 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); in ovs_meter_cmd_features()
293 err = -ENODEV; in ovs_meter_cmd_features()
298 dp->meter_tbl.max_meters_allowed)) in ovs_meter_cmd_features()
313 /* Currently only DROP band type is supported. */ in ovs_meter_cmd_features()
335 struct dp_meter_band *band; in dp_meter_create() local
340 return ERR_PTR(-EINVAL); in dp_meter_create()
344 return ERR_PTR(-EINVAL); in dp_meter_create()
349 return ERR_PTR(-ENOMEM); in dp_meter_create()
351 meter->id = nla_get_u32(a[OVS_METER_ATTR_ID]); in dp_meter_create()
352 meter->used = div_u64(ktime_get_ns(), 1000 * 1000); in dp_meter_create()
353 meter->kbps = a[OVS_METER_ATTR_KBPS] ? 1 : 0; in dp_meter_create()
354 meter->keep_stats = !a[OVS_METER_ATTR_CLEAR]; in dp_meter_create()
355 spin_lock_init(&meter->lock); in dp_meter_create()
356 if (meter->keep_stats && a[OVS_METER_ATTR_STATS]) { in dp_meter_create()
357 meter->stats = *(struct ovs_flow_stats *) in dp_meter_create()
360 meter->n_bands = n_bands; in dp_meter_create()
363 band = meter->bands; in dp_meter_create()
377 err = -EINVAL; in dp_meter_create()
381 band->type = nla_get_u32(attr[OVS_BAND_ATTR_TYPE]); in dp_meter_create()
382 band->rate = nla_get_u32(attr[OVS_BAND_ATTR_RATE]); in dp_meter_create()
383 if (band->rate == 0) { in dp_meter_create()
384 err = -EINVAL; in dp_meter_create()
388 band->burst_size = nla_get_u32(attr[OVS_BAND_ATTR_BURST]); in dp_meter_create()
389 /* Figure out max delta_t that is enough to fill any bucket. in dp_meter_create()
395 band->bucket = (band->burst_size + band->rate) * 1000ULL; in dp_meter_create()
396 band_max_delta_t = div_u64(band->bucket, band->rate); in dp_meter_create()
397 if (band_max_delta_t > meter->max_delta_t) in dp_meter_create()
398 meter->max_delta_t = band_max_delta_t; in dp_meter_create()
399 band++; in dp_meter_create()
411 struct nlattr **a = info->attrs; in ovs_meter_cmd_set()
415 struct ovs_header *ovs_header = info->userhdr; in ovs_meter_cmd_set()
423 return -EINVAL; in ovs_meter_cmd_set()
437 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); in ovs_meter_cmd_set()
439 err = -ENODEV; in ovs_meter_cmd_set()
443 meter_tbl = &dp->meter_tbl; in ovs_meter_cmd_set()
463 spin_lock_bh(&old_meter->lock); in ovs_meter_cmd_set()
464 if (old_meter->keep_stats) { in ovs_meter_cmd_set()
469 spin_unlock_bh(&old_meter->lock); in ovs_meter_cmd_set()
486 struct ovs_header *ovs_header = info->userhdr; in ovs_meter_cmd_get()
488 struct nlattr **a = info->attrs; in ovs_meter_cmd_get()
496 return -EINVAL; in ovs_meter_cmd_get()
507 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); in ovs_meter_cmd_get()
509 err = -ENODEV; in ovs_meter_cmd_get()
514 meter = lookup_meter(&dp->meter_tbl, meter_id); in ovs_meter_cmd_get()
516 err = -ENOENT; in ovs_meter_cmd_get()
520 spin_lock_bh(&meter->lock); in ovs_meter_cmd_get()
522 spin_unlock_bh(&meter->lock); in ovs_meter_cmd_get()
539 struct ovs_header *ovs_header = info->userhdr; in ovs_meter_cmd_del()
541 struct nlattr **a = info->attrs; in ovs_meter_cmd_del()
549 return -EINVAL; in ovs_meter_cmd_del()
558 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); in ovs_meter_cmd_del()
560 err = -ENODEV; in ovs_meter_cmd_del()
565 old_meter = lookup_meter(&dp->meter_tbl, meter_id); in ovs_meter_cmd_del()
567 spin_lock_bh(&old_meter->lock); in ovs_meter_cmd_del()
570 spin_unlock_bh(&old_meter->lock); in ovs_meter_cmd_del()
572 err = detach_meter(&dp->meter_tbl, old_meter); in ovs_meter_cmd_del()
590 * Return true 'meter_id' drop band is triggered. The 'skb' should be
598 struct dp_meter_band *band; in ovs_meter_execute() local
600 int i, band_exceeded_max = -1; in ovs_meter_execute()
605 meter = lookup_meter(&dp->meter_tbl, meter_id); in ovs_meter_execute()
611 spin_lock(&meter->lock); in ovs_meter_execute()
613 long_delta_ms = (now_ms - meter->used); /* ms */ in ovs_meter_execute()
618 delta_ms = (long_delta_ms > (long long int)meter->max_delta_t) in ovs_meter_execute()
619 ? meter->max_delta_t : (u32)long_delta_ms; in ovs_meter_execute()
623 meter->used = now_ms; in ovs_meter_execute()
624 meter->stats.n_packets += 1; in ovs_meter_execute()
625 meter->stats.n_bytes += skb->len; in ovs_meter_execute()
628 * second. We maintain the bucket in the units of either bits or in ovs_meter_execute()
629 * 1/1000th of a packet, correspondingly. in ovs_meter_execute()
635 * 'cost' is the number of bucket units in this packet. in ovs_meter_execute()
637 cost = (meter->kbps) ? skb->len * 8 : 1000; in ovs_meter_execute()
640 for (i = 0; i < meter->n_bands; ++i) { in ovs_meter_execute()
643 band = &meter->bands[i]; in ovs_meter_execute()
644 max_bucket_size = (band->burst_size + band->rate) * 1000LL; in ovs_meter_execute()
646 band->bucket += delta_ms * band->rate; in ovs_meter_execute()
647 if (band->bucket > max_bucket_size) in ovs_meter_execute()
648 band->bucket = max_bucket_size; in ovs_meter_execute()
650 if (band->bucket >= cost) { in ovs_meter_execute()
651 band->bucket -= cost; in ovs_meter_execute()
652 } else if (band->rate > band_exceeded_rate) { in ovs_meter_execute()
653 band_exceeded_rate = band->rate; in ovs_meter_execute()
659 /* Update band statistics. */ in ovs_meter_execute()
660 band = &meter->bands[band_exceeded_max]; in ovs_meter_execute()
661 band->stats.n_packets += 1; in ovs_meter_execute()
662 band->stats.n_bytes += skb->len; in ovs_meter_execute()
664 /* Drop band triggered, let the caller drop the 'skb'. */ in ovs_meter_execute()
665 if (band->type == OVS_METER_BAND_TYPE_DROP) { in ovs_meter_execute()
666 spin_unlock(&meter->lock); in ovs_meter_execute()
671 spin_unlock(&meter->lock); in ovs_meter_execute()
723 struct dp_meter_table *tbl = &dp->meter_tbl; in ovs_meters_init()
729 return -ENOMEM; in ovs_meters_init()
731 /* Allow meters in a datapath to use ~3.12% of physical memory. */ in ovs_meters_init()
733 tbl->max_meters_allowed = min(free_mem_bytes / sizeof(struct dp_meter), in ovs_meters_init()
735 if (!tbl->max_meters_allowed) in ovs_meters_init()
738 rcu_assign_pointer(tbl->ti, ti); in ovs_meters_init()
739 tbl->count = 0; in ovs_meters_init()
745 return -ENOMEM; in ovs_meters_init()
750 struct dp_meter_table *tbl = &dp->meter_tbl; in ovs_meters_exit()
751 struct dp_meter_instance *ti = rcu_dereference_raw(tbl->ti); in ovs_meters_exit()
754 for (i = 0; i < ti->n_meters; i++) in ovs_meters_exit()
755 ovs_meter_free(rcu_dereference_raw(ti->dp_meters[i])); in ovs_meters_exit()