Lines Matching +full:in +full:- +full:band

1 // SPDX-License-Identifier: GPL-2.0-only
42 return id % ti->n_meters; in meter_hash()
57 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); in lookup_meter()
61 meter = rcu_dereference_ovsl(ti->dp_meters[hash]); in lookup_meter()
62 if (meter && likely(meter->id == meter_id)) in lookup_meter()
78 ti->n_meters = size; in dp_meter_instance_alloc()
99 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); in dp_meter_instance_realloc()
100 int n_meters = min(size, ti->n_meters); in dp_meter_instance_realloc()
106 return -ENOMEM; in dp_meter_instance_realloc()
109 if (rcu_dereference_ovsl(ti->dp_meters[i])) in dp_meter_instance_realloc()
110 new_ti->dp_meters[i] = ti->dp_meters[i]; in dp_meter_instance_realloc()
112 rcu_assign_pointer(tbl->ti, new_ti); in dp_meter_instance_realloc()
113 call_rcu(&ti->rcu, dp_meter_instance_free_rcu); in dp_meter_instance_realloc()
123 hash = meter_hash(ti, meter->id); in dp_meter_instance_insert()
124 rcu_assign_pointer(ti->dp_meters[hash], meter); in dp_meter_instance_insert()
132 hash = meter_hash(ti, meter->id); in dp_meter_instance_remove()
133 RCU_INIT_POINTER(ti->dp_meters[hash], NULL); in dp_meter_instance_remove()
138 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); in attach_meter()
139 u32 hash = meter_hash(ti, meter->id); in attach_meter()
142 /* In generally, slots selected should be empty, because in attach_meter()
143 * OvS uses id-pool to fetch a available id. in attach_meter()
145 if (unlikely(rcu_dereference_ovsl(ti->dp_meters[hash]))) in attach_meter()
146 return -EBUSY; in attach_meter()
150 /* That function is thread-safe. */ in attach_meter()
151 tbl->count++; in attach_meter()
152 if (tbl->count >= tbl->max_meters_allowed) { in attach_meter()
153 err = -EFBIG; in attach_meter()
157 if (tbl->count >= ti->n_meters && in attach_meter()
158 dp_meter_instance_realloc(tbl, ti->n_meters * 2)) { in attach_meter()
159 err = -ENOMEM; in attach_meter()
167 tbl->count--; in attach_meter()
179 ti = rcu_dereference_ovsl(tbl->ti); in detach_meter()
182 tbl->count--; in detach_meter()
185 if (ti->n_meters > DP_METER_ARRAY_SIZE_MIN && in detach_meter()
186 tbl->count <= (ti->n_meters / 4)) { in detach_meter()
187 int half_size = ti->n_meters / 2; in detach_meter()
191 * Make sure there are no references of meters in array in detach_meter()
194 for (i = half_size; i < ti->n_meters; i++) in detach_meter()
195 if (rcu_dereference_ovsl(ti->dp_meters[i])) in detach_meter()
207 tbl->count++; in detach_meter()
208 return -ENOMEM; in detach_meter()
216 struct ovs_header *ovs_header = info->userhdr; in ovs_meter_cmd_reply_start()
220 return ERR_PTR(-ENOMEM); in ovs_meter_cmd_reply_start()
222 *ovs_reply_header = genlmsg_put(skb, info->snd_portid, in ovs_meter_cmd_reply_start()
223 info->snd_seq, in ovs_meter_cmd_reply_start()
227 return ERR_PTR(-EMSGSIZE); in ovs_meter_cmd_reply_start()
229 (*ovs_reply_header)->dp_ifindex = ovs_header->dp_ifindex; in ovs_meter_cmd_reply_start()
238 struct dp_meter_band *band; in ovs_meter_cmd_reply_stats() local
245 sizeof(struct ovs_flow_stats), &meter->stats)) in ovs_meter_cmd_reply_stats()
248 if (nla_put_u64_64bit(reply, OVS_METER_ATTR_USED, meter->used, in ovs_meter_cmd_reply_stats()
256 band = meter->bands; in ovs_meter_cmd_reply_stats()
258 for (i = 0; i < meter->n_bands; ++i, ++band) { in ovs_meter_cmd_reply_stats()
264 &band->stats)) in ovs_meter_cmd_reply_stats()
272 return -EMSGSIZE; in ovs_meter_cmd_reply_stats()
277 struct ovs_header *ovs_header = info->userhdr; in ovs_meter_cmd_features()
282 int err = -EMSGSIZE; in ovs_meter_cmd_features()
290 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); in ovs_meter_cmd_features()
292 err = -ENODEV; in ovs_meter_cmd_features()
297 dp->meter_tbl.max_meters_allowed)) in ovs_meter_cmd_features()
312 /* Currently only DROP band type is supported. */ in ovs_meter_cmd_features()
334 struct dp_meter_band *band; in dp_meter_create() local
339 return ERR_PTR(-EINVAL); in dp_meter_create()
343 return ERR_PTR(-EINVAL); in dp_meter_create()
348 return ERR_PTR(-ENOMEM); in dp_meter_create()
350 meter->id = nla_get_u32(a[OVS_METER_ATTR_ID]); in dp_meter_create()
351 meter->used = div_u64(ktime_get_ns(), 1000 * 1000); in dp_meter_create()
352 meter->kbps = a[OVS_METER_ATTR_KBPS] ? 1 : 0; in dp_meter_create()
353 meter->keep_stats = !a[OVS_METER_ATTR_CLEAR]; in dp_meter_create()
354 spin_lock_init(&meter->lock); in dp_meter_create()
355 if (meter->keep_stats && a[OVS_METER_ATTR_STATS]) { in dp_meter_create()
356 meter->stats = *(struct ovs_flow_stats *) in dp_meter_create()
359 meter->n_bands = n_bands; in dp_meter_create()
362 band = meter->bands; in dp_meter_create()
376 err = -EINVAL; in dp_meter_create()
380 band->type = nla_get_u32(attr[OVS_BAND_ATTR_TYPE]); in dp_meter_create()
381 band->rate = nla_get_u32(attr[OVS_BAND_ATTR_RATE]); in dp_meter_create()
382 if (band->rate == 0) { in dp_meter_create()
383 err = -EINVAL; in dp_meter_create()
387 band->burst_size = nla_get_u32(attr[OVS_BAND_ATTR_BURST]); in dp_meter_create()
394 band->bucket = band->burst_size * 1000ULL; in dp_meter_create()
395 band_max_delta_t = div_u64(band->bucket, band->rate); in dp_meter_create()
396 if (band_max_delta_t > meter->max_delta_t) in dp_meter_create()
397 meter->max_delta_t = band_max_delta_t; in dp_meter_create()
398 band++; in dp_meter_create()
410 struct nlattr **a = info->attrs; in ovs_meter_cmd_set()
414 struct ovs_header *ovs_header = info->userhdr; in ovs_meter_cmd_set()
422 return -EINVAL; in ovs_meter_cmd_set()
436 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); in ovs_meter_cmd_set()
438 err = -ENODEV; in ovs_meter_cmd_set()
442 meter_tbl = &dp->meter_tbl; in ovs_meter_cmd_set()
462 spin_lock_bh(&old_meter->lock); in ovs_meter_cmd_set()
463 if (old_meter->keep_stats) { in ovs_meter_cmd_set()
468 spin_unlock_bh(&old_meter->lock); in ovs_meter_cmd_set()
485 struct ovs_header *ovs_header = info->userhdr; in ovs_meter_cmd_get()
487 struct nlattr **a = info->attrs; in ovs_meter_cmd_get()
495 return -EINVAL; in ovs_meter_cmd_get()
506 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); in ovs_meter_cmd_get()
508 err = -ENODEV; in ovs_meter_cmd_get()
513 meter = lookup_meter(&dp->meter_tbl, meter_id); in ovs_meter_cmd_get()
515 err = -ENOENT; in ovs_meter_cmd_get()
519 spin_lock_bh(&meter->lock); in ovs_meter_cmd_get()
521 spin_unlock_bh(&meter->lock); in ovs_meter_cmd_get()
538 struct ovs_header *ovs_header = info->userhdr; in ovs_meter_cmd_del()
540 struct nlattr **a = info->attrs; in ovs_meter_cmd_del()
548 return -EINVAL; in ovs_meter_cmd_del()
557 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); in ovs_meter_cmd_del()
559 err = -ENODEV; in ovs_meter_cmd_del()
564 old_meter = lookup_meter(&dp->meter_tbl, meter_id); in ovs_meter_cmd_del()
566 spin_lock_bh(&old_meter->lock); in ovs_meter_cmd_del()
569 spin_unlock_bh(&old_meter->lock); in ovs_meter_cmd_del()
571 err = detach_meter(&dp->meter_tbl, old_meter); in ovs_meter_cmd_del()
589 * Return true 'meter_id' drop band is triggered. The 'skb' should be
597 struct dp_meter_band *band; in ovs_meter_execute() local
599 int i, band_exceeded_max = -1; in ovs_meter_execute()
604 meter = lookup_meter(&dp->meter_tbl, meter_id); in ovs_meter_execute()
610 spin_lock(&meter->lock); in ovs_meter_execute()
612 long_delta_ms = (now_ms - meter->used); /* ms */ in ovs_meter_execute()
625 delta_ms = (long_delta_ms > (long long int)meter->max_delta_t) in ovs_meter_execute()
626 ? meter->max_delta_t : (u32)long_delta_ms; in ovs_meter_execute()
630 meter->used = now_ms; in ovs_meter_execute()
631 meter->stats.n_packets += 1; in ovs_meter_execute()
632 meter->stats.n_bytes += skb->len; in ovs_meter_execute()
634 /* Bucket rate is either in kilobits per second, or in packets per in ovs_meter_execute()
635 * second. We maintain the bucket in the units of either bits or in ovs_meter_execute()
642 * 'cost' is the number of bucket units in this packet. in ovs_meter_execute()
644 cost = (meter->kbps) ? skb->len * 8 : 1000; in ovs_meter_execute()
647 for (i = 0; i < meter->n_bands; ++i) { in ovs_meter_execute()
650 band = &meter->bands[i]; in ovs_meter_execute()
651 max_bucket_size = band->burst_size * 1000LL; in ovs_meter_execute()
653 band->bucket += delta_ms * band->rate; in ovs_meter_execute()
654 if (band->bucket > max_bucket_size) in ovs_meter_execute()
655 band->bucket = max_bucket_size; in ovs_meter_execute()
657 if (band->bucket >= cost) { in ovs_meter_execute()
658 band->bucket -= cost; in ovs_meter_execute()
659 } else if (band->rate > band_exceeded_rate) { in ovs_meter_execute()
660 band_exceeded_rate = band->rate; in ovs_meter_execute()
666 /* Update band statistics. */ in ovs_meter_execute()
667 band = &meter->bands[band_exceeded_max]; in ovs_meter_execute()
668 band->stats.n_packets += 1; in ovs_meter_execute()
669 band->stats.n_bytes += skb->len; in ovs_meter_execute()
671 /* Drop band triggered, let the caller drop the 'skb'. */ in ovs_meter_execute()
672 if (band->type == OVS_METER_BAND_TYPE_DROP) { in ovs_meter_execute()
673 spin_unlock(&meter->lock); in ovs_meter_execute()
678 spin_unlock(&meter->lock); in ovs_meter_execute()
731 struct dp_meter_table *tbl = &dp->meter_tbl; in ovs_meters_init()
737 return -ENOMEM; in ovs_meters_init()
739 /* Allow meters in a datapath to use ~3.12% of physical memory. */ in ovs_meters_init()
741 tbl->max_meters_allowed = min(free_mem_bytes / sizeof(struct dp_meter), in ovs_meters_init()
743 if (!tbl->max_meters_allowed) in ovs_meters_init()
746 rcu_assign_pointer(tbl->ti, ti); in ovs_meters_init()
747 tbl->count = 0; in ovs_meters_init()
753 return -ENOMEM; in ovs_meters_init()
758 struct dp_meter_table *tbl = &dp->meter_tbl; in ovs_meters_exit()
759 struct dp_meter_instance *ti = rcu_dereference_raw(tbl->ti); in ovs_meters_exit()
762 for (i = 0; i < ti->n_meters; i++) in ovs_meters_exit()
763 ovs_meter_free(rcu_dereference_raw(ti->dp_meters[i])); in ovs_meters_exit()