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/ip/ip.h>
17 : #include <vnet/feature/feature.h>
18 : #include <vnet/qos/qos_egress_map.h>
19 : #include <vnet/qos/qos_mark.h>
20 :
21 : /**
22 : * per-interface vector of which MAP is used by which interface
23 : * for each output source
24 : */
25 : index_t *qos_mark_configs[QOS_N_SOURCES];
26 :
27 : void
28 12 : qos_mark_ip_enable_disable (u32 sw_if_index, u8 enable)
29 : {
30 12 : vnet_feature_enable_disable ("ip6-output", "ip6-qos-mark",
31 : sw_if_index, enable, NULL, 0);
32 12 : vnet_feature_enable_disable ("ip4-output", "ip4-qos-mark",
33 : sw_if_index, enable, NULL, 0);
34 12 : }
35 :
36 : void
37 4 : qos_mark_vlan_enable_disable (u32 sw_if_index, u8 enable)
38 : {
39 : /*
40 : * one cannot run a feature on a sub-interface, so we need
41 : * to enable a feature on all the L3 output paths
42 : */
43 4 : vnet_feature_enable_disable ("ip6-output", "vlan-ip6-qos-mark",
44 : sw_if_index, enable, NULL, 0);
45 4 : vnet_feature_enable_disable ("ip4-output", "vlan-ip4-qos-mark",
46 : sw_if_index, enable, NULL, 0);
47 4 : vnet_feature_enable_disable ("mpls-output", "vlan-mpls-qos-mark",
48 : sw_if_index, enable, NULL, 0);
49 4 : }
50 :
51 : void
52 2 : qos_mark_mpls_enable_disable (u32 sw_if_index, u8 enable)
53 : {
54 2 : vnet_feature_enable_disable ("mpls-output", "mpls-qos-mark",
55 : sw_if_index, enable, NULL, 0);
56 2 : }
57 :
58 : static void
59 18 : qos_egress_map_feature_config (u32 sw_if_index, qos_source_t qs, u8 enable)
60 : {
61 18 : switch (qs)
62 : {
63 0 : case QOS_SOURCE_EXT:
64 0 : ASSERT (0);
65 0 : break;
66 4 : case QOS_SOURCE_VLAN:
67 4 : qos_mark_vlan_enable_disable (sw_if_index, enable);
68 4 : break;
69 2 : case QOS_SOURCE_MPLS:
70 2 : qos_mark_mpls_enable_disable (sw_if_index, enable);
71 2 : break;
72 12 : case QOS_SOURCE_IP:
73 12 : qos_mark_ip_enable_disable (sw_if_index, enable);
74 12 : break;
75 : }
76 18 : }
77 :
78 : int
79 9 : qos_mark_enable (u32 sw_if_index,
80 : qos_source_t output_source, qos_egress_map_id_t mid)
81 : {
82 : index_t qemi;
83 :
84 33 : vec_validate_init_empty (qos_mark_configs[output_source],
85 : sw_if_index, INDEX_INVALID);
86 :
87 9 : qemi = qos_egress_map_find (mid);
88 :
89 9 : if (INDEX_INVALID == qemi)
90 0 : return VNET_API_ERROR_NO_SUCH_TABLE;
91 :
92 9 : if (INDEX_INVALID == qos_mark_configs[output_source][sw_if_index])
93 : {
94 9 : qos_egress_map_feature_config (sw_if_index, output_source, 1);
95 : }
96 :
97 9 : qos_mark_configs[output_source][sw_if_index] = qemi;
98 :
99 9 : return (0);
100 : }
101 :
102 : int
103 9 : qos_mark_disable (u32 sw_if_index, qos_source_t output_source)
104 : {
105 9 : if (vec_len (qos_mark_configs[output_source]) <= sw_if_index)
106 0 : return VNET_API_ERROR_NO_MATCHING_INTERFACE;
107 9 : if (INDEX_INVALID == qos_mark_configs[output_source][sw_if_index])
108 0 : return VNET_API_ERROR_VALUE_EXIST;
109 :
110 9 : if (INDEX_INVALID != qos_mark_configs[output_source][sw_if_index])
111 : {
112 9 : qos_egress_map_feature_config (sw_if_index, output_source, 0);
113 : }
114 :
115 9 : qos_mark_configs[output_source][sw_if_index] = INDEX_INVALID;
116 :
117 9 : return (0);
118 : }
119 :
120 : void
121 16 : qos_mark_walk (qos_mark_walk_cb_t fn, void *c)
122 : {
123 : qos_source_t qs;
124 :
125 80 : FOR_EACH_QOS_SOURCE (qs)
126 : {
127 : u32 sw_if_index;
128 :
129 216 : vec_foreach_index (sw_if_index, qos_mark_configs[qs])
130 : {
131 152 : if (INDEX_INVALID != qos_mark_configs[qs][sw_if_index])
132 15 : fn (sw_if_index,
133 15 : qos_egress_map_get_id (qos_mark_configs[qs][sw_if_index]), qs, c);
134 : }
135 : }
136 16 : }
137 :
138 : static clib_error_t *
139 0 : qos_mark_cli (vlib_main_t * vm,
140 : unformat_input_t * input, vlib_cli_command_t * cmd)
141 : {
142 : qos_egress_map_id_t map_id;
143 : u32 sw_if_index, qs;
144 : vnet_main_t *vnm;
145 : int rv, enable;
146 :
147 0 : vnm = vnet_get_main ();
148 0 : map_id = ~0;
149 0 : qs = 0xff;
150 0 : enable = 1;
151 :
152 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
153 : {
154 0 : if (unformat (input, "id %d", &map_id))
155 : ;
156 0 : else if (unformat (input, "disable"))
157 0 : enable = 0;
158 0 : else if (unformat (input, "%U", unformat_qos_source, &qs))
159 : ;
160 0 : else if (unformat (input, "%U",
161 : unformat_vnet_sw_interface, vnm, &sw_if_index))
162 : ;
163 : else
164 0 : break;
165 : }
166 :
167 0 : if (~0 == sw_if_index)
168 0 : return clib_error_return (0, "interface must be specified");
169 0 : if (0xff == qs)
170 0 : return clib_error_return (0, "output location must be specified");
171 :
172 0 : if (enable)
173 0 : rv = qos_mark_enable (sw_if_index, qs, map_id);
174 : else
175 0 : rv = qos_mark_disable (sw_if_index, qs);
176 :
177 0 : if (0 == rv)
178 0 : return (NULL);
179 :
180 0 : return clib_error_return (0, "Failed to map interface");
181 : }
182 :
183 : /*?
184 : * Apply a QoS egress mapping table to an interface for QoS marking packets
185 : * at the given output protocol.
186 : *
187 : * @cliexpar
188 : * @cliexcmd{qos egress interface GigEthernet0/9/0 id 0 output ip}
189 : ?*/
190 : /* *INDENT-OFF* */
191 272887 : VLIB_CLI_COMMAND (qos_egress_map_interface_command, static) = {
192 : .path = "qos mark",
193 : .short_help = "qos mark <SOURCE> <INTERFACE> id <MAP>",
194 : .function = qos_mark_cli,
195 : .is_mp_safe = 1,
196 : };
197 : /* *INDENT-ON* */
198 :
199 : static void
200 12 : qos_mark_show_one_interface (vlib_main_t * vm, u32 sw_if_index)
201 : {
202 : index_t qemis[QOS_N_SOURCES];
203 : qos_source_t qs;
204 : bool set;
205 :
206 12 : set = false;
207 12 : clib_memset_u32 (qemis, INDEX_INVALID, QOS_N_SOURCES);
208 :
209 60 : FOR_EACH_QOS_SOURCE (qs)
210 : {
211 48 : if (vec_len (qos_mark_configs[qs]) <= sw_if_index)
212 36 : continue;
213 12 : if (INDEX_INVALID != (qemis[qs] = qos_mark_configs[qs][sw_if_index]))
214 6 : set = true;
215 : }
216 :
217 12 : if (set)
218 : {
219 6 : vlib_cli_output (vm, " %U:", format_vnet_sw_if_index_name,
220 : vnet_get_main (), sw_if_index);
221 :
222 30 : FOR_EACH_QOS_SOURCE (qs)
223 : {
224 24 : if (qemis[qs] != INDEX_INVALID)
225 6 : vlib_cli_output (vm, " %U: map:%d", format_qos_source, qs,
226 : qemis[qs]);
227 : }
228 : }
229 12 : }
230 :
231 : static clib_error_t *
232 2 : qos_mark_show (vlib_main_t * vm,
233 : unformat_input_t * input, vlib_cli_command_t * cmd)
234 : {
235 2 : vnet_main_t *vnm = vnet_get_main ();
236 : qos_source_t qs;
237 : u32 sw_if_index;
238 :
239 2 : sw_if_index = ~0;
240 :
241 2 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
242 : {
243 0 : if (unformat (input, "%U", unformat_vnet_sw_interface,
244 : vnm, &sw_if_index))
245 : ;
246 : }
247 :
248 2 : if (~0 == sw_if_index)
249 : {
250 2 : u32 ii, n_ints = 0;
251 :
252 10 : FOR_EACH_QOS_SOURCE (qs)
253 : {
254 8 : n_ints = clib_max (n_ints, vec_len (qos_mark_configs[qs]));
255 : }
256 :
257 14 : for (ii = 0; ii < n_ints; ii++)
258 : {
259 12 : qos_mark_show_one_interface (vm, ii);
260 : }
261 : }
262 : else
263 0 : qos_mark_show_one_interface (vm, sw_if_index);
264 :
265 2 : return (NULL);
266 : }
267 :
268 : /*?
269 : * Show Egress Qos Maps
270 : *
271 : * @cliexpar
272 : * @cliexcmd{show qos egress map}
273 : ?*/
274 : /* *INDENT-OFF* */
275 272887 : VLIB_CLI_COMMAND (qos_mark_show_command, static) = {
276 : .path = "show qos mark",
277 : .short_help = "show qos mark [interface]",
278 : .function = qos_mark_show,
279 : .is_mp_safe = 1,
280 : };
281 : /* *INDENT-ON* */
282 :
283 : /*
284 : * fd.io coding-style-patch-verification: ON
285 : *
286 : * Local Variables:
287 : * eval: (c-set-style "gnu")
288 : * End:
289 : *
290 : */
|