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