1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2017 Nicira, Inc. 4 */ 5 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7 8#include <linux/if.h> 9#include <linux/skbuff.h> 10#include <linux/ip.h> 11#include <linux/kernel.h> 12#include <linux/openvswitch.h> 13#include <linux/netlink.h> 14#include <linux/rculist.h> 15#include <linux/swap.h> 16 17#include <net/netlink.h> 18#include <net/genetlink.h> 19 20#include "datapath.h" 21#include "meter.h" 22 23static const struct nla_policy meter_policy[OVS_METER_ATTR_MAX + 1] = { 24 [OVS_METER_ATTR_ID] = { .type = NLA_U32, }, 25 [OVS_METER_ATTR_KBPS] = { .type = NLA_FLAG }, 26 [OVS_METER_ATTR_STATS] = { .len = sizeof(struct ovs_flow_stats) }, 27 [OVS_METER_ATTR_BANDS] = { .type = NLA_NESTED }, 28 [OVS_METER_ATTR_USED] = { .type = NLA_U64 }, 29 [OVS_METER_ATTR_CLEAR] = { .type = NLA_FLAG }, 30 [OVS_METER_ATTR_MAX_METERS] = { .type = NLA_U32 }, 31 [OVS_METER_ATTR_MAX_BANDS] = { .type = NLA_U32 }, 32}; 33 34static const struct nla_policy band_policy[OVS_BAND_ATTR_MAX + 1] = { 35 [OVS_BAND_ATTR_TYPE] = { .type = NLA_U32, }, 36 [OVS_BAND_ATTR_RATE] = { .type = NLA_U32, }, 37 [OVS_BAND_ATTR_BURST] = { .type = NLA_U32, }, 38 [OVS_BAND_ATTR_STATS] = { .len = sizeof(struct ovs_flow_stats) }, 39}; 40 41static u32 meter_hash(struct dp_meter_instance *ti, u32 id) 42{ 43 return id % ti->n_meters; 44} 45 46static void ovs_meter_free(struct dp_meter *meter) 47{ 48 if (!meter) 49 return; 50 51 kfree_rcu(meter, rcu); 52} 53 54/* Call with ovs_mutex or RCU read lock. */ 55static struct dp_meter *lookup_meter(const struct dp_meter_table *tbl, 56 u32 meter_id) 57{ 58 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); 59 u32 hash = meter_hash(ti, meter_id); 60 struct dp_meter *meter; 61 62 meter = rcu_dereference_ovsl(ti->dp_meters[hash]); 63 if (meter && likely(meter->id == meter_id)) 64 return meter; 65 66 return NULL; 67} 68 69static struct dp_meter_instance *dp_meter_instance_alloc(const u32 size) 70{ 71 struct dp_meter_instance *ti; 72 73 ti = kvzalloc(sizeof(*ti) + 74 sizeof(struct dp_meter *) * size, 75 GFP_KERNEL); 76 if (!ti) 77 return NULL; 78 79 ti->n_meters = size; 80 81 return ti; 82} 83 84static void dp_meter_instance_free(struct dp_meter_instance *ti) 85{ 86 kvfree(ti); 87} 88 89static void dp_meter_instance_free_rcu(struct rcu_head *rcu) 90{ 91 struct dp_meter_instance *ti; 92 93 ti = container_of(rcu, struct dp_meter_instance, rcu); 94 kvfree(ti); 95} 96 97static int 98dp_meter_instance_realloc(struct dp_meter_table *tbl, u32 size) 99{ 100 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); 101 int n_meters = min(size, ti->n_meters); 102 struct dp_meter_instance *new_ti; 103 int i; 104 105 new_ti = dp_meter_instance_alloc(size); 106 if (!new_ti) 107 return -ENOMEM; 108 109 for (i = 0; i < n_meters; i++) 110 if (rcu_dereference_ovsl(ti->dp_meters[i])) 111 new_ti->dp_meters[i] = ti->dp_meters[i]; 112 113 rcu_assign_pointer(tbl->ti, new_ti); 114 call_rcu(&ti->rcu, dp_meter_instance_free_rcu); 115 116 return 0; 117} 118 119static void dp_meter_instance_insert(struct dp_meter_instance *ti, 120 struct dp_meter *meter) 121{ 122 u32 hash; 123 124 hash = meter_hash(ti, meter->id); 125 rcu_assign_pointer(ti->dp_meters[hash], meter); 126} 127 128static void dp_meter_instance_remove(struct dp_meter_instance *ti, 129 struct dp_meter *meter) 130{ 131 u32 hash; 132 133 hash = meter_hash(ti, meter->id); 134 RCU_INIT_POINTER(ti->dp_meters[hash], NULL); 135} 136 137static int attach_meter(struct dp_meter_table *tbl, struct dp_meter *meter) 138{ 139 struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); 140 u32 hash = meter_hash(ti, meter->id); 141 int err; 142 143 /* In generally, slots selected should be empty, because 144 * OvS uses id-pool to fetch a available id. 145 */ 146 if (unlikely(rcu_dereference_ovsl(ti->dp_meters[hash]))) 147 return -EBUSY; 148 149 dp_meter_instance_insert(ti, meter); 150 151 /* That function is thread-safe. */ 152 tbl->count++; 153 if (tbl->count >= tbl->max_meters_allowed) { 154 err = -EFBIG; 155 goto attach_err; 156 } 157 158 if (tbl->count >= ti->n_meters && 159 dp_meter_instance_realloc(tbl, ti->n_meters * 2)) { 160 err = -ENOMEM; 161 goto attach_err; 162 } 163 164 return 0; 165 166attach_err: 167 dp_meter_instance_remove(ti, meter); 168 tbl->count--; 169 return err; 170} 171 172static int detach_meter(struct dp_meter_table *tbl, struct dp_meter *meter) 173{ 174 struct dp_meter_instance *ti; 175 176 ASSERT_OVSL(); 177 if (!meter) 178 return 0; 179 180 ti = rcu_dereference_ovsl(tbl->ti); 181 dp_meter_instance_remove(ti, meter); 182 183 tbl->count--; 184 185 /* Shrink the meter array if necessary. */ 186 if (ti->n_meters > DP_METER_ARRAY_SIZE_MIN && 187 tbl->count <= (ti->n_meters / 4)) { 188 int half_size = ti->n_meters / 2; 189 int i; 190 191 /* Avoid hash collision, don't move slots to other place. 192 * Make sure there are no references of meters in array 193 * which will be released. 194 */ 195 for (i = half_size; i < ti->n_meters; i++) 196 if (rcu_dereference_ovsl(ti->dp_meters[i])) 197 goto out; 198 199 if (dp_meter_instance_realloc(tbl, half_size)) 200 goto shrink_err; 201 } 202 203out: 204 return 0; 205 206shrink_err: 207 dp_meter_instance_insert(ti, meter); 208 tbl->count++; 209 return -ENOMEM; 210} 211 212static struct sk_buff * 213ovs_meter_cmd_reply_start(struct genl_info *info, u8 cmd, 214 struct ovs_header **ovs_reply_header) 215{ 216 struct sk_buff *skb; 217 struct ovs_header *ovs_header = info->userhdr; 218 219 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 220 if (!skb) 221 return ERR_PTR(-ENOMEM); 222 223 *ovs_reply_header = genlmsg_put(skb, info->snd_portid, 224 info->snd_seq, 225 &dp_meter_genl_family, 0, cmd); 226 if (!*ovs_reply_header) { 227 nlmsg_free(skb); 228 return ERR_PTR(-EMSGSIZE); 229 } 230 (*ovs_reply_header)->dp_ifindex = ovs_header->dp_ifindex; 231 232 return skb; 233} 234 235static int ovs_meter_cmd_reply_stats(struct sk_buff *reply, u32 meter_id, 236 struct dp_meter *meter) 237{ 238 struct nlattr *nla; 239 struct dp_meter_band *band; 240 u16 i; 241 242 if (nla_put_u32(reply, OVS_METER_ATTR_ID, meter_id)) 243 goto error; 244 245 if (nla_put(reply, OVS_METER_ATTR_STATS, 246 sizeof(struct ovs_flow_stats), &meter->stats)) 247 goto error; 248 249 if (nla_put_u64_64bit(reply, OVS_METER_ATTR_USED, meter->used, 250 OVS_METER_ATTR_PAD)) 251 goto error; 252 253 nla = nla_nest_start_noflag(reply, OVS_METER_ATTR_BANDS); 254 if (!nla) 255 goto error; 256 257 band = meter->bands; 258 259 for (i = 0; i < meter->n_bands; ++i, ++band) { 260 struct nlattr *band_nla; 261 262 band_nla = nla_nest_start_noflag(reply, OVS_BAND_ATTR_UNSPEC); 263 if (!band_nla || nla_put(reply, OVS_BAND_ATTR_STATS, 264 sizeof(struct ovs_flow_stats), 265 &band->stats)) 266 goto error; 267 nla_nest_end(reply, band_nla); 268 } 269 nla_nest_end(reply, nla); 270 271 return 0; 272error: 273 return -EMSGSIZE; 274} 275 276static int ovs_meter_cmd_features(struct sk_buff *skb, struct genl_info *info) 277{ 278 struct ovs_header *ovs_header = info->userhdr; 279 struct ovs_header *ovs_reply_header; 280 struct nlattr *nla, *band_nla; 281 struct sk_buff *reply; 282 struct datapath *dp; 283 int err = -EMSGSIZE; 284 285 reply = ovs_meter_cmd_reply_start(info, OVS_METER_CMD_FEATURES, 286 &ovs_reply_header); 287 if (IS_ERR(reply)) 288 return PTR_ERR(reply); 289 290 ovs_lock(); 291 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 292 if (!dp) { 293 err = -ENODEV; 294 goto exit_unlock; 295 } 296 297 if (nla_put_u32(reply, OVS_METER_ATTR_MAX_METERS, 298 dp->meter_tbl.max_meters_allowed)) 299 goto exit_unlock; 300 301 ovs_unlock(); 302 303 if (nla_put_u32(reply, OVS_METER_ATTR_MAX_BANDS, DP_MAX_BANDS)) 304 goto nla_put_failure; 305 306 nla = nla_nest_start_noflag(reply, OVS_METER_ATTR_BANDS); 307 if (!nla) 308 goto nla_put_failure; 309 310 band_nla = nla_nest_start_noflag(reply, OVS_BAND_ATTR_UNSPEC); 311 if (!band_nla) 312 goto nla_put_failure; 313 /* Currently only DROP band type is supported. */ 314 if (nla_put_u32(reply, OVS_BAND_ATTR_TYPE, OVS_METER_BAND_TYPE_DROP)) 315 goto nla_put_failure; 316 nla_nest_end(reply, band_nla); 317 nla_nest_end(reply, nla); 318 319 genlmsg_end(reply, ovs_reply_header); 320 return genlmsg_reply(reply, info); 321 322exit_unlock: 323 ovs_unlock(); 324nla_put_failure: 325 nlmsg_free(reply); 326 return err; 327} 328 329static struct dp_meter *dp_meter_create(struct nlattr **a) 330{ 331 struct nlattr *nla; 332 int rem; 333 u16 n_bands = 0; 334 struct dp_meter *meter; 335 struct dp_meter_band *band; 336 int err; 337 338 /* Validate attributes, count the bands. */ 339 if (!a[OVS_METER_ATTR_BANDS]) 340 return ERR_PTR(-EINVAL); 341 342 nla_for_each_nested(nla, a[OVS_METER_ATTR_BANDS], rem) 343 if (++n_bands > DP_MAX_BANDS) 344 return ERR_PTR(-EINVAL); 345 346 /* Allocate and set up the meter before locking anything. */ 347 meter = kzalloc(struct_size(meter, bands, n_bands), GFP_KERNEL); 348 if (!meter) 349 return ERR_PTR(-ENOMEM); 350 351 meter->id = nla_get_u32(a[OVS_METER_ATTR_ID]); 352 meter->used = div_u64(ktime_get_ns(), 1000 * 1000); 353 meter->kbps = a[OVS_METER_ATTR_KBPS] ? 1 : 0; 354 meter->keep_stats = !a[OVS_METER_ATTR_CLEAR]; 355 spin_lock_init(&meter->lock); 356 if (meter->keep_stats && a[OVS_METER_ATTR_STATS]) { 357 meter->stats = *(struct ovs_flow_stats *) 358 nla_data(a[OVS_METER_ATTR_STATS]); 359 } 360 meter->n_bands = n_bands; 361 362 /* Set up meter bands. */ 363 band = meter->bands; 364 nla_for_each_nested(nla, a[OVS_METER_ATTR_BANDS], rem) { 365 struct nlattr *attr[OVS_BAND_ATTR_MAX + 1]; 366 u32 band_max_delta_t; 367 368 err = nla_parse_deprecated((struct nlattr **)&attr, 369 OVS_BAND_ATTR_MAX, nla_data(nla), 370 nla_len(nla), band_policy, NULL); 371 if (err) 372 goto exit_free_meter; 373 374 if (!attr[OVS_BAND_ATTR_TYPE] || 375 !attr[OVS_BAND_ATTR_RATE] || 376 !attr[OVS_BAND_ATTR_BURST]) { 377 err = -EINVAL; 378 goto exit_free_meter; 379 } 380 381 band->type = nla_get_u32(attr[OVS_BAND_ATTR_TYPE]); 382 band->rate = nla_get_u32(attr[OVS_BAND_ATTR_RATE]); 383 if (band->rate == 0) { 384 err = -EINVAL; 385 goto exit_free_meter; 386 } 387 388 band->burst_size = nla_get_u32(attr[OVS_BAND_ATTR_BURST]); 389 /* Figure out max delta_t that is enough to fill any bucket. 390 * Keep max_delta_t size to the bucket units: 391 * pkts => 1/1000 packets, kilobits => bits. 392 * 393 * Start with a full bucket. 394 */ 395 band->bucket = (band->burst_size + band->rate) * 1000ULL; 396 band_max_delta_t = div_u64(band->bucket, band->rate); 397 if (band_max_delta_t > meter->max_delta_t) 398 meter->max_delta_t = band_max_delta_t; 399 band++; 400 } 401 402 return meter; 403 404exit_free_meter: 405 kfree(meter); 406 return ERR_PTR(err); 407} 408 409static int ovs_meter_cmd_set(struct sk_buff *skb, struct genl_info *info) 410{ 411 struct nlattr **a = info->attrs; 412 struct dp_meter *meter, *old_meter; 413 struct sk_buff *reply; 414 struct ovs_header *ovs_reply_header; 415 struct ovs_header *ovs_header = info->userhdr; 416 struct dp_meter_table *meter_tbl; 417 struct datapath *dp; 418 int err; 419 u32 meter_id; 420 bool failed; 421 422 if (!a[OVS_METER_ATTR_ID]) 423 return -EINVAL; 424 425 meter = dp_meter_create(a); 426 if (IS_ERR_OR_NULL(meter)) 427 return PTR_ERR(meter); 428 429 reply = ovs_meter_cmd_reply_start(info, OVS_METER_CMD_SET, 430 &ovs_reply_header); 431 if (IS_ERR(reply)) { 432 err = PTR_ERR(reply); 433 goto exit_free_meter; 434 } 435 436 ovs_lock(); 437 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 438 if (!dp) { 439 err = -ENODEV; 440 goto exit_unlock; 441 } 442 443 meter_tbl = &dp->meter_tbl; 444 meter_id = nla_get_u32(a[OVS_METER_ATTR_ID]); 445 446 old_meter = lookup_meter(meter_tbl, meter_id); 447 err = detach_meter(meter_tbl, old_meter); 448 if (err) 449 goto exit_unlock; 450 451 err = attach_meter(meter_tbl, meter); 452 if (err) 453 goto exit_free_old_meter; 454 455 ovs_unlock(); 456 457 /* Build response with the meter_id and stats from 458 * the old meter, if any. 459 */ 460 failed = nla_put_u32(reply, OVS_METER_ATTR_ID, meter_id); 461 WARN_ON(failed); 462 if (old_meter) { 463 spin_lock_bh(&old_meter->lock); 464 if (old_meter->keep_stats) { 465 err = ovs_meter_cmd_reply_stats(reply, meter_id, 466 old_meter); 467 WARN_ON(err); 468 } 469 spin_unlock_bh(&old_meter->lock); 470 ovs_meter_free(old_meter); 471 } 472 473 genlmsg_end(reply, ovs_reply_header); 474 return genlmsg_reply(reply, info); 475 476exit_free_old_meter: 477 ovs_meter_free(old_meter); 478exit_unlock: 479 ovs_unlock(); 480 nlmsg_free(reply); 481exit_free_meter: 482 kfree(meter); 483 return err; 484} 485 486static int ovs_meter_cmd_get(struct sk_buff *skb, struct genl_info *info) 487{ 488 struct ovs_header *ovs_header = info->userhdr; 489 struct ovs_header *ovs_reply_header; 490 struct nlattr **a = info->attrs; 491 struct dp_meter *meter; 492 struct sk_buff *reply; 493 struct datapath *dp; 494 u32 meter_id; 495 int err; 496 497 if (!a[OVS_METER_ATTR_ID]) 498 return -EINVAL; 499 500 meter_id = nla_get_u32(a[OVS_METER_ATTR_ID]); 501 502 reply = ovs_meter_cmd_reply_start(info, OVS_METER_CMD_GET, 503 &ovs_reply_header); 504 if (IS_ERR(reply)) 505 return PTR_ERR(reply); 506 507 ovs_lock(); 508 509 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 510 if (!dp) { 511 err = -ENODEV; 512 goto exit_unlock; 513 } 514 515 /* Locate meter, copy stats. */ 516 meter = lookup_meter(&dp->meter_tbl, meter_id); 517 if (!meter) { 518 err = -ENOENT; 519 goto exit_unlock; 520 } 521 522 spin_lock_bh(&meter->lock); 523 err = ovs_meter_cmd_reply_stats(reply, meter_id, meter); 524 spin_unlock_bh(&meter->lock); 525 if (err) 526 goto exit_unlock; 527 528 ovs_unlock(); 529 530 genlmsg_end(reply, ovs_reply_header); 531 return genlmsg_reply(reply, info); 532 533exit_unlock: 534 ovs_unlock(); 535 nlmsg_free(reply); 536 return err; 537} 538 539static int ovs_meter_cmd_del(struct sk_buff *skb, struct genl_info *info) 540{ 541 struct ovs_header *ovs_header = info->userhdr; 542 struct ovs_header *ovs_reply_header; 543 struct nlattr **a = info->attrs; 544 struct dp_meter *old_meter; 545 struct sk_buff *reply; 546 struct datapath *dp; 547 u32 meter_id; 548 int err; 549 550 if (!a[OVS_METER_ATTR_ID]) 551 return -EINVAL; 552 553 reply = ovs_meter_cmd_reply_start(info, OVS_METER_CMD_DEL, 554 &ovs_reply_header); 555 if (IS_ERR(reply)) 556 return PTR_ERR(reply); 557 558 ovs_lock(); 559 560 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 561 if (!dp) { 562 err = -ENODEV; 563 goto exit_unlock; 564 } 565 566 meter_id = nla_get_u32(a[OVS_METER_ATTR_ID]); 567 old_meter = lookup_meter(&dp->meter_tbl, meter_id); 568 if (old_meter) { 569 spin_lock_bh(&old_meter->lock); 570 err = ovs_meter_cmd_reply_stats(reply, meter_id, old_meter); 571 WARN_ON(err); 572 spin_unlock_bh(&old_meter->lock); 573 574 err = detach_meter(&dp->meter_tbl, old_meter); 575 if (err) 576 goto exit_unlock; 577 } 578 579 ovs_unlock(); 580 ovs_meter_free(old_meter); 581 genlmsg_end(reply, ovs_reply_header); 582 return genlmsg_reply(reply, info); 583 584exit_unlock: 585 ovs_unlock(); 586 nlmsg_free(reply); 587 return err; 588} 589 590/* Meter action execution. 591 * 592 * Return true 'meter_id' drop band is triggered. The 'skb' should be 593 * dropped by the caller'. 594 */ 595bool ovs_meter_execute(struct datapath *dp, struct sk_buff *skb, 596 struct sw_flow_key *key, u32 meter_id) 597{ 598 long long int now_ms = div_u64(ktime_get_ns(), 1000 * 1000); 599 long long int long_delta_ms; 600 struct dp_meter_band *band; 601 struct dp_meter *meter; 602 int i, band_exceeded_max = -1; 603 u32 band_exceeded_rate = 0; 604 u32 delta_ms; 605 u32 cost; 606 607 meter = lookup_meter(&dp->meter_tbl, meter_id); 608 /* Do not drop the packet when there is no meter. */ 609 if (!meter) 610 return false; 611 612 /* Lock the meter while using it. */ 613 spin_lock(&meter->lock); 614 615 long_delta_ms = (now_ms - meter->used); /* ms */ 616 if (long_delta_ms < 0) { 617 /* This condition means that we have several threads fighting 618 * for a meter lock, and the one who received the packets a 619 * bit later wins. Assuming that all racing threads received 620 * packets at the same time to avoid overflow. 621 */ 622 long_delta_ms = 0; 623 } 624 625 /* Make sure delta_ms will not be too large, so that bucket will not 626 * wrap around below. 627 */ 628 delta_ms = (long_delta_ms > (long long int)meter->max_delta_t) 629 ? meter->max_delta_t : (u32)long_delta_ms; 630 631 /* Update meter statistics. 632 */ 633 meter->used = now_ms; 634 meter->stats.n_packets += 1; 635 meter->stats.n_bytes += skb->len; 636 637 /* Bucket rate is either in kilobits per second, or in packets per 638 * second. We maintain the bucket in the units of either bits or 639 * 1/1000th of a packet, correspondingly. 640 * Then, when rate is multiplied with milliseconds, we get the 641 * bucket units: 642 * msec * kbps = bits, and 643 * msec * packets/sec = 1/1000 packets. 644 * 645 * 'cost' is the number of bucket units in this packet. 646 */ 647 cost = (meter->kbps) ? skb->len * 8 : 1000; 648 649 /* Update all bands and find the one hit with the highest rate. */ 650 for (i = 0; i < meter->n_bands; ++i) { 651 long long int max_bucket_size; 652 653 band = &meter->bands[i]; 654 max_bucket_size = (band->burst_size + band->rate) * 1000LL; 655 656 band->bucket += delta_ms * band->rate; 657 if (band->bucket > max_bucket_size) 658 band->bucket = max_bucket_size; 659 660 if (band->bucket >= cost) { 661 band->bucket -= cost; 662 } else if (band->rate > band_exceeded_rate) { 663 band_exceeded_rate = band->rate; 664 band_exceeded_max = i; 665 } 666 } 667 668 if (band_exceeded_max >= 0) { 669 /* Update band statistics. */ 670 band = &meter->bands[band_exceeded_max]; 671 band->stats.n_packets += 1; 672 band->stats.n_bytes += skb->len; 673 674 /* Drop band triggered, let the caller drop the 'skb'. */ 675 if (band->type == OVS_METER_BAND_TYPE_DROP) { 676 spin_unlock(&meter->lock); 677 return true; 678 } 679 } 680 681 spin_unlock(&meter->lock); 682 return false; 683} 684 685static const struct genl_small_ops dp_meter_genl_ops[] = { 686 { .cmd = OVS_METER_CMD_FEATURES, 687 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 688 .flags = 0, /* OK for unprivileged users. */ 689 .doit = ovs_meter_cmd_features 690 }, 691 { .cmd = OVS_METER_CMD_SET, 692 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 693 .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN 694 * privilege. 695 */ 696 .doit = ovs_meter_cmd_set, 697 }, 698 { .cmd = OVS_METER_CMD_GET, 699 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 700 .flags = 0, /* OK for unprivileged users. */ 701 .doit = ovs_meter_cmd_get, 702 }, 703 { .cmd = OVS_METER_CMD_DEL, 704 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 705 .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN 706 * privilege. 707 */ 708 .doit = ovs_meter_cmd_del 709 }, 710}; 711 712static const struct genl_multicast_group ovs_meter_multicast_group = { 713 .name = OVS_METER_MCGROUP, 714}; 715 716struct genl_family dp_meter_genl_family __ro_after_init = { 717 .hdrsize = sizeof(struct ovs_header), 718 .name = OVS_METER_FAMILY, 719 .version = OVS_METER_VERSION, 720 .maxattr = OVS_METER_ATTR_MAX, 721 .policy = meter_policy, 722 .netnsok = true, 723 .parallel_ops = true, 724 .small_ops = dp_meter_genl_ops, 725 .n_small_ops = ARRAY_SIZE(dp_meter_genl_ops), 726 .mcgrps = &ovs_meter_multicast_group, 727 .n_mcgrps = 1, 728 .module = THIS_MODULE, 729}; 730 731int ovs_meters_init(struct datapath *dp) 732{ 733 struct dp_meter_table *tbl = &dp->meter_tbl; 734 struct dp_meter_instance *ti; 735 unsigned long free_mem_bytes; 736 737 ti = dp_meter_instance_alloc(DP_METER_ARRAY_SIZE_MIN); 738 if (!ti) 739 return -ENOMEM; 740 741 /* Allow meters in a datapath to use ~3.12% of physical memory. */ 742 free_mem_bytes = nr_free_buffer_pages() * (PAGE_SIZE >> 5); 743 tbl->max_meters_allowed = min(free_mem_bytes / sizeof(struct dp_meter), 744 DP_METER_NUM_MAX); 745 if (!tbl->max_meters_allowed) 746 goto out_err; 747 748 rcu_assign_pointer(tbl->ti, ti); 749 tbl->count = 0; 750 751 return 0; 752 753out_err: 754 dp_meter_instance_free(ti); 755 return -ENOMEM; 756} 757 758void ovs_meters_exit(struct datapath *dp) 759{ 760 struct dp_meter_table *tbl = &dp->meter_tbl; 761 struct dp_meter_instance *ti = rcu_dereference_raw(tbl->ti); 762 int i; 763 764 for (i = 0; i < ti->n_meters; i++) 765 ovs_meter_free(rcu_dereference_raw(ti->dp_meters[i])); 766 767 dp_meter_instance_free(ti); 768} 769