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()
76 ti->n_meters = size; in dp_meter_instance_alloc()
97 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); in dp_meter_instance_realloc()
98 int n_meters = min(size, ti->n_meters); in dp_meter_instance_realloc()
104 return -ENOMEM; in dp_meter_instance_realloc()
107 if (rcu_dereference_ovsl(ti->dp_meters[i])) in dp_meter_instance_realloc()
108 new_ti->dp_meters[i] = ti->dp_meters[i]; in dp_meter_instance_realloc()
110 rcu_assign_pointer(tbl->ti, new_ti); in dp_meter_instance_realloc()
111 call_rcu(&ti->rcu, dp_meter_instance_free_rcu); in dp_meter_instance_realloc()
121 hash = meter_hash(ti, meter->id); in dp_meter_instance_insert()
122 rcu_assign_pointer(ti->dp_meters[hash], meter); in dp_meter_instance_insert()
130 hash = meter_hash(ti, meter->id); in dp_meter_instance_remove()
131 RCU_INIT_POINTER(ti->dp_meters[hash], NULL); in dp_meter_instance_remove()
136 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); in attach_meter()
137 u32 hash = meter_hash(ti, meter->id); in attach_meter()
140 /* In generally, slots selected should be empty, because in attach_meter()
141 * OvS uses id-pool to fetch a available id. in attach_meter()
143 if (unlikely(rcu_dereference_ovsl(ti->dp_meters[hash]))) in attach_meter()
144 return -EBUSY; in attach_meter()
148 /* That function is thread-safe. */ in attach_meter()
149 tbl->count++; in attach_meter()
150 if (tbl->count >= tbl->max_meters_allowed) { in attach_meter()
151 err = -EFBIG; in attach_meter()
155 if (tbl->count >= ti->n_meters && in attach_meter()
156 dp_meter_instance_realloc(tbl, ti->n_meters * 2)) { in attach_meter()
157 err = -ENOMEM; in attach_meter()
165 tbl->count--; in attach_meter()
177 ti = rcu_dereference_ovsl(tbl->ti); in detach_meter()
180 tbl->count--; in detach_meter()
183 if (ti->n_meters > DP_METER_ARRAY_SIZE_MIN && in detach_meter()
184 tbl->count <= (ti->n_meters / 4)) { in detach_meter()
185 int half_size = ti->n_meters / 2; in detach_meter()
189 * Make sure there are no references of meters in array in detach_meter()
192 for (i = half_size; i < ti->n_meters; i++) in detach_meter()
193 if (rcu_dereference_ovsl(ti->dp_meters[i])) in detach_meter()
205 tbl->count++; in detach_meter()
206 return -ENOMEM; in detach_meter()
218 return ERR_PTR(-ENOMEM); in ovs_meter_cmd_reply_start()
220 *ovs_reply_header = genlmsg_put(skb, info->snd_portid, in ovs_meter_cmd_reply_start()
221 info->snd_seq, in ovs_meter_cmd_reply_start()
225 return ERR_PTR(-EMSGSIZE); in ovs_meter_cmd_reply_start()
227 (*ovs_reply_header)->dp_ifindex = ovs_header->dp_ifindex; in ovs_meter_cmd_reply_start()
236 struct dp_meter_band *band; in ovs_meter_cmd_reply_stats() local
243 sizeof(struct ovs_flow_stats), &meter->stats)) in ovs_meter_cmd_reply_stats()
246 if (nla_put_u64_64bit(reply, OVS_METER_ATTR_USED, meter->used, in ovs_meter_cmd_reply_stats()
254 band = meter->bands; in ovs_meter_cmd_reply_stats()
256 for (i = 0; i < meter->n_bands; ++i, ++band) { in ovs_meter_cmd_reply_stats()
262 &band->stats)) in ovs_meter_cmd_reply_stats()
270 return -EMSGSIZE; in ovs_meter_cmd_reply_stats()
280 int err = -EMSGSIZE; in ovs_meter_cmd_features()
288 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); in ovs_meter_cmd_features()
290 err = -ENODEV; in ovs_meter_cmd_features()
295 dp->meter_tbl.max_meters_allowed)) in ovs_meter_cmd_features()
310 /* Currently only DROP band type is supported. */ in ovs_meter_cmd_features()
332 struct dp_meter_band *band; in dp_meter_create() local
337 return ERR_PTR(-EINVAL); in dp_meter_create()
341 return ERR_PTR(-EINVAL); in dp_meter_create()
346 return ERR_PTR(-ENOMEM); in dp_meter_create()
348 meter->id = nla_get_u32(a[OVS_METER_ATTR_ID]); in dp_meter_create()
349 meter->used = div_u64(ktime_get_ns(), 1000 * 1000); in dp_meter_create()
350 meter->kbps = a[OVS_METER_ATTR_KBPS] ? 1 : 0; in dp_meter_create()
351 meter->keep_stats = !a[OVS_METER_ATTR_CLEAR]; in dp_meter_create()
352 spin_lock_init(&meter->lock); in dp_meter_create()
353 if (meter->keep_stats && a[OVS_METER_ATTR_STATS]) { in dp_meter_create()
354 meter->stats = *(struct ovs_flow_stats *) in dp_meter_create()
357 meter->n_bands = n_bands; in dp_meter_create()
360 band = meter->bands; in dp_meter_create()
374 err = -EINVAL; in dp_meter_create()
378 band->type = nla_get_u32(attr[OVS_BAND_ATTR_TYPE]); in dp_meter_create()
379 band->rate = nla_get_u32(attr[OVS_BAND_ATTR_RATE]); in dp_meter_create()
380 if (band->rate == 0) { in dp_meter_create()
381 err = -EINVAL; in dp_meter_create()
385 band->burst_size = nla_get_u32(attr[OVS_BAND_ATTR_BURST]); in dp_meter_create()
392 band->bucket = band->burst_size * 1000ULL; in dp_meter_create()
393 band_max_delta_t = div_u64(band->bucket, band->rate); in dp_meter_create()
394 if (band_max_delta_t > meter->max_delta_t) in dp_meter_create()
395 meter->max_delta_t = band_max_delta_t; in dp_meter_create()
396 band++; in dp_meter_create()
408 struct nlattr **a = info->attrs; in ovs_meter_cmd_set()
420 return -EINVAL; in ovs_meter_cmd_set()
434 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); in ovs_meter_cmd_set()
436 err = -ENODEV; in ovs_meter_cmd_set()
440 meter_tbl = &dp->meter_tbl; in ovs_meter_cmd_set()
460 spin_lock_bh(&old_meter->lock); in ovs_meter_cmd_set()
461 if (old_meter->keep_stats) { in ovs_meter_cmd_set()
466 spin_unlock_bh(&old_meter->lock); in ovs_meter_cmd_set()
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()
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()