policer: add counters
[vpp.git] / src / vnet / policer / police.h
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef __POLICE_H__
16 #define __POLICE_H__
17
18 typedef enum
19 {
20   POLICE_CONFORM = 0,
21   POLICE_EXCEED = 1,
22   POLICE_VIOLATE = 2,
23 } policer_result_e;
24
25 #define NUM_POLICE_RESULTS 3
26
27 // This is the hardware representation of the policer.
28 // To be multithread-safe, the policer is accessed through a spin-lock
29 // on the lock field. (For a policer update operation, 24B needs to be
30 // modified and this would be a challenge to do with atomic instructions.)
31 // The structure is padded so that no other data is put into the same
32 // 64B cache-line. This reduces cache-thrashing between threads.
33 //
34 // A note on scale:
35 // The HW TSC tick is roughly one CPU clock cycle.
36 // This is shifted to create a larger period, with a goal to be around 50usec.
37 // The period time will vary based on CPU clock speed.
38 // CPU speeds of 1Ghz to 8Ghz are targetted.
39 // The shift amount is a constant 17 bits, resulting in a period between
40 // 16usec (8Ghz CPU) and 131usec (1Ghz CPU).
41 // The token_per_period computation takes into account the clock speed.
42 //
43 // The 32-bit bucket/limit supports about 850ms of burst on a 40GE port,
44 // or 340ms on a 100GE port. If a larger burst is configured, then the
45 // programmed value is simply capped at 2^32-1. If we needed to support
46 // more than that, the bucket and limit fields could be expanded.
47 //
48 // tokens_per_period should be > 1000 to support 0.1% granularity.
49 // To support lower rates (which would not meet this requirement), the packet
50 // length, bucket, and limit values can be scaled. The scale is a power of 2
51 // so the multiplication can be implemented as a shift. The control plane
52 // computes the shift amount be the largest possible that still supports the
53 // burst size. This makes the rate accuracy as high as possible.
54 //
55 // The 64-bit last_update_time supports a 4Ghz CPU without rollover for 100
56 // years
57 //
58 // The lock field should be used for a spin-lock on the struct. Alternatively,
59 // a thread index field is provided so that policed packets may be handed
60 // off to a single worker thread.
61
62 #define POLICER_TICKS_PER_PERIOD_SHIFT 17
63 #define POLICER_TICKS_PER_PERIOD       (1 << POLICER_TICKS_PER_PERIOD_SHIFT)
64
65 typedef struct
66 {
67
68   u32 lock;                     // for exclusive access to the struct
69
70   u32 single_rate;              // 1 = single rate policer, 0 = two rate policer
71   u32 color_aware;              // for hierarchical policing
72   u32 scale;                    // power-of-2 shift amount for lower rates
73   u8 action[3];
74   u8 mark_dscp[3];
75   u8 pad[2];
76
77   // Fields are marked as 2R if they are only used for a 2-rate policer,
78   // and MOD if they are modified as part of the update operation.
79   // 1 token = 1 byte.
80
81   u32 cir_tokens_per_period;    // # of tokens for each period
82   u32 pir_tokens_per_period;    // 2R
83
84   u32 current_limit;
85   u32 current_bucket;           // MOD
86   u32 extended_limit;
87   u32 extended_bucket;          // MOD
88
89   u64 last_update_time;         // MOD
90   u32 thread_index;             // Tie policer to a thread, rather than lock
91   u32 pad32;
92
93 } policer_read_response_type_st;
94
95 static inline policer_result_e
96 vnet_police_packet (policer_read_response_type_st * policer,
97                     u32 packet_length,
98                     policer_result_e packet_color, u64 time)
99 {
100   u64 n_periods;
101   u64 current_tokens, extended_tokens;
102   policer_result_e result;
103
104   // Scale packet length to support a wide range of speeds
105   packet_length = packet_length << policer->scale;
106
107   // Compute the number of policer periods that have passed since the last
108   // operation.
109   n_periods = time - policer->last_update_time;
110   policer->last_update_time = time;
111
112   // Since there is no background last-update-time adjustment, n_periods
113   // could grow large if the policer is idle for a long time. This could
114   // cause a 64-bit overflow when computing tokens_per_period * num_periods.
115   // It will overflow if log2(n_periods) + log2(tokens_per_period) > 64.
116   //
117   // To mitigate this, the policer configuration algorithm insures that
118   // tokens_per_period is less than 2^22, i.e. this is a 22 bit value not
119   // a 32-bit value. Thus overflow will only occur if n_periods > 64-22 or
120   // 42. 2^42 min-sized periods is 16us * 2^42, or 2 years. So this can
121   // rarely occur. If overflow does happen, the only effect will be that
122   // fewer tokens than the max burst will be added to the bucket for this
123   // packet. This constraint on tokens_per_period lets the ucode omit
124   // code to dynamically check for or prevent the overflow.
125
126   if (policer->single_rate)
127     {
128
129       // Compute number of tokens for this time period
130       current_tokens =
131         policer->current_bucket + n_periods * policer->cir_tokens_per_period;
132       if (current_tokens > policer->current_limit)
133         {
134           current_tokens = policer->current_limit;
135         }
136
137       extended_tokens =
138         policer->extended_bucket + n_periods * policer->cir_tokens_per_period;
139       if (extended_tokens > policer->extended_limit)
140         {
141           extended_tokens = policer->extended_limit;
142         }
143
144       // Determine color
145
146       if ((!policer->color_aware || (packet_color == POLICE_CONFORM))
147           && (current_tokens >= packet_length))
148         {
149           policer->current_bucket = current_tokens - packet_length;
150           policer->extended_bucket = extended_tokens - packet_length;
151           result = POLICE_CONFORM;
152         }
153       else if ((!policer->color_aware || (packet_color != POLICE_VIOLATE))
154                && (extended_tokens >= packet_length))
155         {
156           policer->current_bucket = current_tokens;
157           policer->extended_bucket = extended_tokens - packet_length;
158           result = POLICE_EXCEED;
159         }
160       else
161         {
162           policer->current_bucket = current_tokens;
163           policer->extended_bucket = extended_tokens;
164           result = POLICE_VIOLATE;
165         }
166
167     }
168   else
169     {
170       // Two-rate policer
171
172       // Compute number of tokens for this time period
173       current_tokens =
174         policer->current_bucket + n_periods * policer->cir_tokens_per_period;
175       extended_tokens =
176         policer->extended_bucket + n_periods * policer->pir_tokens_per_period;
177       if (current_tokens > policer->current_limit)
178         {
179           current_tokens = policer->current_limit;
180         }
181       if (extended_tokens > policer->extended_limit)
182         {
183           extended_tokens = policer->extended_limit;
184         }
185
186       // Determine color
187
188       if ((policer->color_aware && (packet_color == POLICE_VIOLATE))
189           || (extended_tokens < packet_length))
190         {
191           policer->current_bucket = current_tokens;
192           policer->extended_bucket = extended_tokens;
193           result = POLICE_VIOLATE;
194         }
195       else if ((policer->color_aware && (packet_color == POLICE_EXCEED))
196                || (current_tokens < packet_length))
197         {
198           policer->current_bucket = current_tokens;
199           policer->extended_bucket = extended_tokens - packet_length;
200           result = POLICE_EXCEED;
201         }
202       else
203         {
204           policer->current_bucket = current_tokens - packet_length;
205           policer->extended_bucket = extended_tokens - packet_length;
206           result = POLICE_CONFORM;
207         }
208     }
209   return result;
210 }
211
212 #endif // __POLICE_H__
213
214 /*
215  * fd.io coding-style-patch-verification: ON
216  *
217  * Local Variables:
218  * eval: (c-set-style "gnu")
219  * End:
220  */