summaryrefslogtreecommitdiffstats
path: root/src/vnet/policer/policer.h
blob: f5b6c0d3b311cfe5136dba9eacb718db408fdd5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
 * Copyright (c) 2015 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __included_policer_h__
#define __included_policer_h__

#include <stdbool.h>

#include <vlib/vlib.h>
#include <vnet/vnet.h>

#include <vnet/policer/xlate.h>
#include <vnet/policer/police.h>

typedef struct
{
  /* policer pool, aligned */
  policer_t *policers;

  /* config + template h/w policer instance parallel pools */
  qos_pol_cfg_params_st *configs;
  policer_t *policer_templates;

  /* Config by name hash */
  uword *policer_config_by_name;

  /* Policer by name hash */
  uword *policer_index_by_name;

  /* Policer by sw_if_index vector */
  u32 *policer_index_by_sw_if_index[VLIB_N_RX_TX];

  /* convenience */
  vlib_main_t *vlib_main;
  vnet_main_t *vnet_main;

  vlib_log_class_t log_class;

  /* frame queue for thread handoff */
  u32 fq_index[VLIB_N_RX_TX];

  u16 msg_id_base;
} vnet_policer_main_t;

extern vnet_policer_main_t vnet_policer_main;

extern vlib_combined_counter_main_t policer_counters[];

extern vlib_node_registration_t policer_input_node;
extern vlib_node_registration_t policer_output_node;

typedef enum
{
  VNET_POLICER_NEXT_DROP,
  VNET_POLICER_NEXT_HANDOFF,
  VNET_POLICER_N_NEXT,
} vnet_policer_next_t;

u8 *format_policer_instance (u8 * s, va_list * va);
clib_error_t *policer_add_del (vlib_main_t *vm, u8 *name,
			       qos_pol_cfg_params_st *cfg, u32 *policer_index,
			       u8 is_add);
int policer_bind_worker (u8 *name, u32 worker, bool bind);
int policer_input (u8 *name, u32 sw_if_index, vlib_dir_t dir, bool apply);

#endif /* __included_policer_h__ */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */
roughly one CPU clock cycle. // This is shifted to create a larger period, with a goal to be around 50usec. // The period time will vary based on CPU clock speed. // CPU speeds of 1Ghz to 8Ghz are targetted. // The shift amount is a constant 17 bits, resulting in a period between // 16usec (8Ghz CPU) and 131usec (1Ghz CPU). // The token_per_period computation takes into account the clock speed. // // The 32-bit bucket/limit supports about 850ms of burst on a 40GE port, // or 340ms on a 100GE port. If a larger burst is configured, then the // programmed value is simply capped at 2^32-1. If we needed to support // more than that, the bucket and limit fields could be expanded. // // tokens_per_period should be > 1000 to support 0.1% granularity. // To support lower rates (which would not meet this requirement), the packet // length, bucket, and limit values can be scaled. The scale is a power of 2 // so the multiplication can be implemented as a shift. The control plane // computes the shift amount be the largest possible that still supports the // burst size. This makes the rate accuracy as high as possible. // // The 64-bit last_update_time supports a 4Ghz CPU without rollover for 100 // years // // The lock field should be used for a spin-lock on the struct. Alternatively, // a thread index field is provided so that policed packets may be handed // off to a single worker thread. #define POLICER_TICKS_PER_PERIOD_SHIFT 17 #define POLICER_TICKS_PER_PERIOD (1 << POLICER_TICKS_PER_PERIOD_SHIFT) typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); u32 lock; // for exclusive access to the struct u32 single_rate; // 1 = single rate policer, 0 = two rate policer u32 color_aware; // for hierarchical policing u32 scale; // power-of-2 shift amount for lower rates qos_action_type_en action[3]; ip_dscp_t mark_dscp[3]; u8 pad[2]; // Fields are marked as 2R if they are only used for a 2-rate policer, // and MOD if they are modified as part of the update operation. // 1 token = 1 byte. u32 cir_tokens_per_period; // # of tokens for each period u32 pir_tokens_per_period; // 2R u32 current_limit; u32 current_bucket; // MOD u32 extended_limit; u32 extended_bucket; // MOD u64 last_update_time; // MOD u32 thread_index; // Tie policer to a thread, rather than lock u32 pad32; } policer_t; STATIC_ASSERT_SIZEOF (policer_t, CLIB_CACHE_LINE_BYTES); static inline policer_result_e vnet_police_packet (policer_t *policer, u32 packet_length, policer_result_e packet_color, u64 time) { u64 n_periods; u64 current_tokens, extended_tokens; policer_result_e result; // Scale packet length to support a wide range of speeds packet_length = packet_length << policer->scale; // Compute the number of policer periods that have passed since the last // operation. n_periods = time - policer->last_update_time; policer->last_update_time = time; // Since there is no background last-update-time adjustment, n_periods // could grow large if the policer is idle for a long time. This could // cause a 64-bit overflow when computing tokens_per_period * num_periods. // It will overflow if log2(n_periods) + log2(tokens_per_period) > 64. // // To mitigate this, the policer configuration algorithm insures that // tokens_per_period is less than 2^22, i.e. this is a 22 bit value not // a 32-bit value. Thus overflow will only occur if n_periods > 64-22 or // 42. 2^42 min-sized periods is 16us * 2^42, or 2 years. So this can // rarely occur. If overflow does happen, the only effect will be that // fewer tokens than the max burst will be added to the bucket for this // packet. This constraint on tokens_per_period lets the ucode omit // code to dynamically check for or prevent the overflow. if (policer->single_rate) { // Compute number of tokens for this time period current_tokens = policer->current_bucket + n_periods * policer->cir_tokens_per_period; if (current_tokens > policer->current_limit) { current_tokens = policer->current_limit; } extended_tokens = policer->extended_bucket + n_periods * policer->cir_tokens_per_period; if (extended_tokens > policer->extended_limit) { extended_tokens = policer->extended_limit; } // Determine color if ((!policer->color_aware || (packet_color == POLICE_CONFORM)) && (current_tokens >= packet_length)) { policer->current_bucket = current_tokens - packet_length; policer->extended_bucket = extended_tokens - packet_length; result = POLICE_CONFORM; } else if ((!policer->color_aware || (packet_color != POLICE_VIOLATE)) && (extended_tokens >= packet_length)) { policer->current_bucket = current_tokens; policer->extended_bucket = extended_tokens - packet_length; result = POLICE_EXCEED; } else { policer->current_bucket = current_tokens; policer->extended_bucket = extended_tokens; result = POLICE_VIOLATE; } } else { // Two-rate policer // Compute number of tokens for this time period current_tokens = policer->current_bucket + n_periods * policer->cir_tokens_per_period; extended_tokens = policer->extended_bucket + n_periods * policer->pir_tokens_per_period; if (current_tokens > policer->current_limit) { current_tokens = policer->current_limit; } if (extended_tokens > policer->extended_limit) { extended_tokens = policer->extended_limit; } // Determine color if ((policer->color_aware && (packet_color == POLICE_VIOLATE)) || (extended_tokens < packet_length)) { policer->current_bucket = current_tokens; policer->extended_bucket = extended_tokens; result = POLICE_VIOLATE; } else if ((policer->color_aware && (packet_color == POLICE_EXCEED)) || (current_tokens < packet_length)) { policer->current_bucket = current_tokens; policer->extended_bucket = extended_tokens - packet_length; result = POLICE_EXCEED; } else { policer->current_bucket = current_tokens - packet_length; policer->extended_bucket = extended_tokens - packet_length; result = POLICE_CONFORM; } } return result; } #endif // __POLICE_H__ /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */