Line data Source code
1 : /*
2 : * Copyright (c) 2018 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 :
16 : #include <vnet/qos/qos_record.h>
17 : #include <vnet/ip/ip.h>
18 : #include <vnet/ip/ip6_to_ip4.h>
19 : #include <vnet/feature/feature.h>
20 : #include <vnet/qos/qos_types.h>
21 : #include <vnet/l2/l2_input.h>
22 : #include <vnet/l2/feat_bitmap.h>
23 :
24 : /**
25 : * Per-interface, per-protocol vector of feature on/off configurations
26 : */
27 : u8 *qos_record_configs[QOS_N_SOURCES];
28 : u32 l2_qos_input_next[QOS_N_SOURCES][32];
29 :
30 : static void
31 10 : qos_record_feature_config (u32 sw_if_index,
32 : qos_source_t input_source, u8 enable)
33 : {
34 10 : switch (input_source)
35 : {
36 6 : case QOS_SOURCE_IP:
37 6 : ip_feature_enable_disable (AF_IP6, N_SAFI, IP_FEATURE_INPUT,
38 : "ip6-qos-record",
39 : sw_if_index, enable, NULL, 0);
40 6 : ip_feature_enable_disable (AF_IP4, N_SAFI, IP_FEATURE_INPUT,
41 : "ip4-qos-record",
42 : sw_if_index, enable, NULL, 0);
43 6 : l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_L2_IP_QOS_RECORD,
44 : enable);
45 6 : break;
46 2 : case QOS_SOURCE_MPLS:
47 2 : vnet_feature_enable_disable ("mpls-input", "mpls-qos-record",
48 : sw_if_index, enable, NULL, 0);
49 2 : break;
50 2 : case QOS_SOURCE_VLAN:
51 2 : ip_feature_enable_disable (AF_IP6, N_SAFI, IP_FEATURE_INPUT,
52 : "vlan-ip6-qos-record",
53 : sw_if_index, enable, NULL, 0);
54 2 : ip_feature_enable_disable (AF_IP4, N_SAFI, IP_FEATURE_INPUT,
55 : "vlan-ip4-qos-record",
56 : sw_if_index, enable, NULL, 0);
57 2 : vnet_feature_enable_disable ("mpls-input", "vlan-mpls-qos-record",
58 : sw_if_index, enable, NULL, 0);
59 2 : break;
60 0 : case QOS_SOURCE_EXT:
61 : /* not a valid option for recording */
62 0 : break;
63 : }
64 10 : }
65 :
66 : int
67 5 : qos_record_enable (u32 sw_if_index, qos_source_t input_source)
68 : {
69 5 : vec_validate (qos_record_configs[input_source], sw_if_index);
70 :
71 5 : if (0 == qos_record_configs[input_source][sw_if_index])
72 : {
73 5 : qos_record_feature_config (sw_if_index, input_source, 1);
74 : }
75 :
76 5 : qos_record_configs[input_source][sw_if_index]++;
77 5 : return (0);
78 : }
79 :
80 : int
81 17009 : qos_record_disable (u32 sw_if_index, qos_source_t input_source)
82 : {
83 17009 : if (vec_len (qos_record_configs[input_source]) <= sw_if_index)
84 17004 : return VNET_API_ERROR_NO_MATCHING_INTERFACE;
85 :
86 5 : if (0 == qos_record_configs[input_source][sw_if_index])
87 0 : return VNET_API_ERROR_VALUE_EXIST;
88 :
89 5 : qos_record_configs[input_source][sw_if_index]--;
90 :
91 5 : if (0 == qos_record_configs[input_source][sw_if_index])
92 : {
93 5 : qos_record_feature_config (sw_if_index, input_source, 0);
94 : }
95 :
96 5 : return (0);
97 : }
98 :
99 : void
100 10 : qos_record_walk (qos_record_walk_cb_t fn, void *c)
101 : {
102 : qos_source_t qs;
103 :
104 50 : FOR_EACH_QOS_SOURCE (qs)
105 : {
106 : u32 sw_if_index;
107 :
108 108 : vec_foreach_index (sw_if_index, qos_record_configs[qs])
109 : {
110 68 : if (0 != qos_record_configs[qs][sw_if_index])
111 9 : fn (sw_if_index, qs, c);
112 : }
113 : }
114 10 : }
115 :
116 : /*
117 : * Disable recording feature for all protocols when the interface
118 : * is deleted
119 : */
120 : static clib_error_t *
121 11798 : qos_record_ip_interface_add_del (vnet_main_t * vnm,
122 : u32 sw_if_index, u32 is_add)
123 : {
124 11798 : if (!is_add)
125 : {
126 : qos_source_t qs;
127 :
128 21255 : FOR_EACH_QOS_SOURCE (qs)
129 : {
130 17004 : while (qos_record_disable (sw_if_index, qs) == 0);
131 : }
132 : }
133 :
134 11798 : return (NULL);
135 : }
136 :
137 3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (qos_record_ip_interface_add_del);
138 :
139 : clib_error_t *
140 575 : qos_record_init (vlib_main_t * vm)
141 : {
142 : qos_source_t qs;
143 575 : vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "l2-ip-qos-record");
144 :
145 : /* Initialize the feature next-node indexes */
146 2875 : FOR_EACH_QOS_SOURCE (qs)
147 2300 : feat_bitmap_init_next_nodes (vm,
148 : node->index,
149 : L2INPUT_N_FEAT,
150 : l2input_get_feat_names (),
151 2300 : l2_qos_input_next[qs]);
152 575 : return 0;
153 : }
154 :
155 88703 : VLIB_INIT_FUNCTION (qos_record_init);
156 :
157 : static clib_error_t *
158 0 : qos_record_cli (vlib_main_t * vm,
159 : unformat_input_t * input, vlib_cli_command_t * cmd)
160 : {
161 0 : vnet_main_t *vnm = vnet_get_main ();
162 : u32 sw_if_index, qs;
163 : u8 enable;
164 :
165 0 : qs = 0xff;
166 0 : enable = 1;
167 0 : sw_if_index = ~0;
168 :
169 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
170 : {
171 0 : if (unformat (input, "%U", unformat_vnet_sw_interface,
172 : vnm, &sw_if_index))
173 : ;
174 0 : else if (unformat (input, "%U", unformat_qos_source, &qs))
175 : ;
176 0 : else if (unformat (input, "enable"))
177 0 : enable = 1;
178 0 : else if (unformat (input, "disable"))
179 0 : enable = 0;
180 : else
181 0 : break;
182 : }
183 :
184 0 : if (~0 == sw_if_index)
185 0 : return clib_error_return (0, "interface must be specified");
186 0 : if (0xff == qs)
187 0 : return clib_error_return (0, "input location must be specified");
188 :
189 0 : if (enable)
190 0 : qos_record_enable (sw_if_index, qs);
191 : else
192 0 : qos_record_disable (sw_if_index, qs);
193 :
194 0 : return (NULL);
195 : }
196 :
197 : /*?
198 : * Enable QoS bit recording on an interface using the packet's input DSCP bits
199 : * Which input QoS bits to use are either; IP, MPLS or VLAN. If more than
200 : * one protocol is chosen (which is foolish) the higher layers override the
201 : * lower.
202 : *
203 : * @cliexpar
204 : * @cliexcmd{qos record ip GigEthernet0/1/0}
205 : ?*/
206 : /* *INDENT-OFF* */
207 285289 : VLIB_CLI_COMMAND (qos_record_command, static) = {
208 : .path = "qos record",
209 : .short_help = "qos record <record-source> <INTERFACE> [disable]",
210 : .function = qos_record_cli,
211 : .is_mp_safe = 1,
212 : };
213 : /* *INDENT-ON* */
214 :
215 : static void
216 2 : qos_record_show_one_interface (vlib_main_t * vm, u32 sw_if_index)
217 : {
218 2 : u8 n_cfgs[QOS_N_SOURCES] = { };
219 : qos_source_t qs;
220 : bool set;
221 :
222 2 : set = false;
223 :
224 10 : FOR_EACH_QOS_SOURCE (qs)
225 : {
226 8 : if (vec_len (qos_record_configs[qs]) <= sw_if_index)
227 6 : continue;
228 2 : if (0 != (n_cfgs[qs] = qos_record_configs[qs][sw_if_index]))
229 1 : set = true;
230 : }
231 :
232 2 : if (set)
233 : {
234 1 : vlib_cli_output (vm, " %U:", format_vnet_sw_if_index_name,
235 : vnet_get_main (), sw_if_index);
236 :
237 5 : FOR_EACH_QOS_SOURCE (qs)
238 : {
239 4 : if (n_cfgs[qs] != 0)
240 1 : vlib_cli_output (vm, " %U", format_qos_source, qs);
241 : }
242 : }
243 2 : }
244 :
245 : static clib_error_t *
246 1 : qos_record_show (vlib_main_t * vm,
247 : unformat_input_t * input, vlib_cli_command_t * cmd)
248 : {
249 1 : vnet_main_t *vnm = vnet_get_main ();
250 : qos_source_t qs;
251 : u32 sw_if_index;
252 :
253 1 : sw_if_index = ~0;
254 :
255 1 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
256 : {
257 0 : if (unformat (input, "%U", unformat_vnet_sw_interface,
258 : vnm, &sw_if_index))
259 : ;
260 : }
261 :
262 1 : if (~0 == sw_if_index)
263 : {
264 1 : u32 ii, n_ints = 0;
265 :
266 5 : FOR_EACH_QOS_SOURCE (qs)
267 : {
268 4 : n_ints = clib_max (n_ints, vec_len (qos_record_configs[qs]));
269 : }
270 :
271 3 : for (ii = 0; ii < n_ints; ii++)
272 : {
273 2 : qos_record_show_one_interface (vm, ii);
274 : }
275 : }
276 : else
277 0 : qos_record_show_one_interface (vm, sw_if_index);
278 :
279 1 : return (NULL);
280 : }
281 :
282 : /*?
283 : * Show Egress Qos Maps
284 : *
285 : * @cliexpar
286 : * @cliexcmd{show qos egress map}
287 : ?*/
288 : /* *INDENT-OFF* */
289 285289 : VLIB_CLI_COMMAND (qos_record_show_command, static) = {
290 : .path = "show qos record",
291 : .short_help = "show qos record [interface]",
292 : .function = qos_record_show,
293 : .is_mp_safe = 1,
294 : };
295 : /* *INDENT-ON* */
296 :
297 : /*
298 : * fd.io coding-style-patch-verification: ON
299 : *
300 : * Local Variables:
301 : * eval: (c-set-style "gnu")
302 : * End:
303 : */
|