Line data Source code
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 : #include <vnet/ip/ip.h>
16 : #include <vnet/classify/vnet_classify.h>
17 : #include <vnet/classify/in_out_acl.h>
18 : #include <vnet/l2/l2_output.h>
19 : #include <vnet/l2/l2_input.h>
20 :
21 : in_out_acl_main_t in_out_acl_main;
22 :
23 : static int
24 510 : vnet_in_out_acl_feature_enable (in_out_acl_main_t *am, u32 sw_if_index,
25 : in_out_acl_table_id_t tid, int feature_enable,
26 : int is_output)
27 : {
28 : const char *arc_name, *feature_name;
29 : vnet_feature_config_main_t *fcm;
30 : u8 arc;
31 : int rv;
32 :
33 510 : switch (tid)
34 : {
35 0 : case IN_OUT_ACL_N_TABLES:
36 0 : return VNET_API_ERROR_NO_SUCH_TABLE;
37 158 : case IN_OUT_ACL_TABLE_L2:
38 158 : if (is_output)
39 6 : l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_ACL,
40 : feature_enable);
41 : else
42 152 : l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_ACL,
43 : feature_enable);
44 158 : return 0;
45 178 : case IN_OUT_ACL_TABLE_IP4:
46 178 : arc_name = is_output ? "ip4-output" : "ip4-unicast";
47 178 : feature_name = is_output ? "ip4-outacl" : "ip4-inacl";
48 178 : break;
49 168 : case IN_OUT_ACL_TABLE_IP6:
50 168 : arc_name = is_output ? "ip6-output" : "ip6-unicast";
51 168 : feature_name = is_output ? "ip6-outacl" : "ip6-inacl";
52 168 : break;
53 4 : case IN_OUT_ACL_TABLE_IP4_PUNT:
54 4 : if (sw_if_index != 0)
55 0 : return VNET_API_ERROR_INVALID_INTERFACE;
56 4 : arc_name = "ip4-punt";
57 4 : feature_name = "ip4-punt-acl";
58 4 : break;
59 2 : case IN_OUT_ACL_TABLE_IP6_PUNT:
60 2 : if (sw_if_index != 0)
61 0 : return VNET_API_ERROR_INVALID_INTERFACE;
62 2 : arc_name = "ip6-punt";
63 2 : feature_name = "ip6-punt-acl";
64 2 : break;
65 : }
66 :
67 352 : rv = vnet_feature_enable_disable (arc_name, feature_name, sw_if_index,
68 : feature_enable, 0, 0);
69 352 : if (rv)
70 0 : return rv;
71 :
72 352 : arc = vnet_get_feature_arc_index (arc_name);
73 352 : fcm = vnet_get_feature_arc_config_main (arc);
74 352 : am->vnet_config_main[is_output][tid] = &fcm->config_main;
75 :
76 352 : return 0;
77 : }
78 :
79 : int
80 370 : vnet_set_in_out_acl_intfc (vlib_main_t *vm, u32 sw_if_index,
81 : u32 ip4_table_index, u32 ip6_table_index,
82 : u32 l2_table_index, u32 ip4_punt_table_index,
83 : u32 ip6_punt_table_index, u32 is_add, u32 is_output)
84 : {
85 370 : in_out_acl_main_t *am = &in_out_acl_main;
86 370 : vnet_classify_main_t *vcm = am->vnet_classify_main;
87 370 : u32 acl[IN_OUT_ACL_N_TABLES] = {
88 : ip4_table_index, ip6_table_index, l2_table_index,
89 : ip4_punt_table_index, ip6_punt_table_index,
90 : };
91 : u32 ti;
92 : int rv;
93 :
94 : /* Assume that we've validated sw_if_index in the API layer */
95 :
96 2220 : for (ti = 0; ti < IN_OUT_ACL_N_TABLES; ti++)
97 : {
98 1850 : if (acl[ti] == ~0)
99 1340 : continue;
100 :
101 510 : if (pool_is_free_index (vcm->tables, acl[ti]))
102 0 : return VNET_API_ERROR_NO_SUCH_TABLE;
103 :
104 617 : vec_validate_init_empty
105 : (am->classify_table_index_by_sw_if_index[is_output][ti], sw_if_index,
106 : ~0);
107 :
108 : /* Reject any DEL operation with wrong sw_if_index */
109 510 : if (!is_add &&
110 255 : (acl[ti] !=
111 255 : am->classify_table_index_by_sw_if_index[is_output][ti]
112 255 : [sw_if_index]))
113 : {
114 0 : clib_warning
115 : ("Non-existent intf_idx=%d with table_index=%d for delete",
116 : sw_if_index, acl[ti]);
117 0 : return VNET_API_ERROR_NO_SUCH_TABLE;
118 : }
119 :
120 : /* Return ok on ADD operaton if feature is already enabled */
121 510 : if (is_add &&
122 255 : am->classify_table_index_by_sw_if_index[is_output][ti][sw_if_index]
123 : != ~0)
124 0 : return 0;
125 :
126 510 : rv = vnet_in_out_acl_feature_enable (am, sw_if_index, ti, is_add,
127 : is_output);
128 510 : if (rv)
129 0 : return rv;
130 :
131 510 : if (is_add)
132 255 : am->classify_table_index_by_sw_if_index[is_output][ti][sw_if_index] =
133 255 : acl[ti];
134 : else
135 255 : am->classify_table_index_by_sw_if_index[is_output][ti][sw_if_index] =
136 : ~0;
137 : }
138 :
139 370 : return 0;
140 : }
141 :
142 : int
143 210 : vnet_set_input_acl_intfc (vlib_main_t * vm, u32 sw_if_index,
144 : u32 ip4_table_index,
145 : u32 ip6_table_index, u32 l2_table_index, u32 is_add)
146 : {
147 210 : return vnet_set_in_out_acl_intfc (
148 : vm, sw_if_index, ip4_table_index, ip6_table_index, l2_table_index,
149 : ~0 /* ip4_punt_table_index */, ~0 /* ip6_punt_table_index */, is_add,
150 : IN_OUT_ACL_INPUT_TABLE_GROUP);
151 : }
152 :
153 : int
154 154 : vnet_set_output_acl_intfc (vlib_main_t * vm, u32 sw_if_index,
155 : u32 ip4_table_index,
156 : u32 ip6_table_index, u32 l2_table_index,
157 : u32 is_add)
158 : {
159 154 : return vnet_set_in_out_acl_intfc (
160 : vm, sw_if_index, ip4_table_index, ip6_table_index, l2_table_index,
161 : ~0 /* ip4_punt_table_index */, ~0 /* ip6_punt_table_index */, is_add,
162 : IN_OUT_ACL_OUTPUT_TABLE_GROUP);
163 : }
164 :
165 : static clib_error_t *
166 0 : set_in_out_acl_command_fn (vlib_main_t * vm,
167 : unformat_input_t * input, vlib_cli_command_t * cmd,
168 : u32 is_output)
169 : {
170 0 : vnet_main_t *vnm = vnet_get_main ();
171 0 : u32 sw_if_index = ~0;
172 0 : u32 ip4_table_index = ~0;
173 0 : u32 ip6_table_index = ~0;
174 0 : u32 ip4_punt_table_index = ~0;
175 0 : u32 ip6_punt_table_index = ~0;
176 0 : u32 l2_table_index = ~0;
177 0 : u32 is_add = 1;
178 0 : u32 idx_cnt = 0;
179 : int rv;
180 :
181 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
182 : {
183 0 : if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
184 : vnm, &sw_if_index))
185 : ;
186 0 : else if (unformat (input, "ip4-table %d", &ip4_table_index))
187 0 : idx_cnt++;
188 0 : else if (unformat (input, "ip6-table %d", &ip6_table_index))
189 0 : idx_cnt++;
190 0 : else if (unformat (input, "ip4-punt-table %d", &ip4_punt_table_index))
191 0 : idx_cnt++;
192 0 : else if (unformat (input, "ip6-punt-table %d", &ip6_punt_table_index))
193 0 : idx_cnt++;
194 0 : else if (unformat (input, "l2-table %d", &l2_table_index))
195 0 : idx_cnt++;
196 0 : else if (unformat (input, "del"))
197 0 : is_add = 0;
198 : else
199 0 : break;
200 : }
201 :
202 0 : if (sw_if_index == ~0)
203 0 : return clib_error_return (0, "Interface must be specified.");
204 :
205 0 : if (!idx_cnt)
206 0 : return clib_error_return (0, "Table index should be specified.");
207 :
208 0 : if (idx_cnt > 1)
209 0 : return clib_error_return (0, "Only one table index per API is allowed.");
210 :
211 0 : rv = vnet_set_in_out_acl_intfc (
212 : vm, sw_if_index, ip4_table_index, ip6_table_index, l2_table_index,
213 : ip4_punt_table_index, ip6_punt_table_index, is_add, is_output);
214 :
215 0 : switch (rv)
216 : {
217 0 : case 0:
218 0 : break;
219 :
220 0 : case VNET_API_ERROR_NO_MATCHING_INTERFACE:
221 0 : return clib_error_return (0, "No such interface");
222 :
223 0 : case VNET_API_ERROR_NO_SUCH_ENTRY:
224 0 : return clib_error_return (0, "No such classifier table");
225 :
226 0 : default:
227 0 : return clib_error_return (0, "Error: %d", rv);
228 : }
229 0 : return 0;
230 : }
231 :
232 : static clib_error_t *
233 0 : set_input_acl_command_fn (vlib_main_t * vm,
234 : unformat_input_t * input, vlib_cli_command_t * cmd)
235 : {
236 0 : return set_in_out_acl_command_fn (vm, input, cmd,
237 : IN_OUT_ACL_INPUT_TABLE_GROUP);
238 : }
239 :
240 : static clib_error_t *
241 0 : set_output_acl_command_fn (vlib_main_t * vm,
242 : unformat_input_t * input, vlib_cli_command_t * cmd)
243 : {
244 0 : return set_in_out_acl_command_fn (vm, input, cmd,
245 : IN_OUT_ACL_OUTPUT_TABLE_GROUP);
246 : }
247 :
248 : /*
249 : * Configure interface to enable/disble input/output ACL features:
250 : * intfc - interface name to be configured as input ACL
251 : * Ip4-table <index> [del] - enable/disable IP4 input ACL
252 : * Ip6-table <index> [del] - enable/disable IP6 input ACL
253 : * l2-table <index> [del] - enable/disable Layer2 input ACL
254 : *
255 : * Note: Only one table index per API call is allowed.
256 : *
257 : */
258 : /* *INDENT-OFF* */
259 285289 : VLIB_CLI_COMMAND (set_input_acl_command, static) = {
260 : .path = "set interface input acl",
261 : .short_help =
262 : "set interface input acl intfc <int> [ip4-table <index>]\n"
263 : " [ip6-table <index>] [l2-table <index>] [ip4-punt-table <index>]\n"
264 : " [ip6-punt-table <index> [del]",
265 : .function = set_input_acl_command_fn,
266 : };
267 285289 : VLIB_CLI_COMMAND (set_output_acl_command, static) = {
268 : .path = "set interface output acl",
269 : .short_help =
270 : "set interface output acl intfc <int> [ip4-table <index>]\n"
271 : " [ip6-table <index>] [l2-table <index>] [del]",
272 : .function = set_output_acl_command_fn,
273 : };
274 : /* *INDENT-ON* */
275 :
276 : clib_error_t *
277 575 : in_out_acl_init (vlib_main_t * vm)
278 : {
279 575 : in_out_acl_main_t *am = &in_out_acl_main;
280 :
281 575 : am->vlib_main = vm;
282 575 : am->vnet_main = vnet_get_main ();
283 575 : am->vnet_classify_main = &vnet_classify_main;
284 :
285 575 : return 0;
286 : }
287 : /* *INDENT-OFF* */
288 13823 : VLIB_INIT_FUNCTION (in_out_acl_init) =
289 : {
290 : .runs_after = VLIB_INITS("ip_in_out_acl_init"),
291 : };
292 : /* *INDENT-ON* */
293 :
294 : uword
295 64 : unformat_acl_type (unformat_input_t * input, va_list * args)
296 : {
297 64 : u32 *acl_type = va_arg (*args, u32 *);
298 64 : u32 tid = IN_OUT_ACL_N_TABLES;
299 :
300 128 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
301 : {
302 64 : if (unformat (input, "ip4"))
303 38 : tid = IN_OUT_ACL_TABLE_IP4;
304 26 : else if (unformat (input, "ip6"))
305 26 : tid = IN_OUT_ACL_TABLE_IP6;
306 0 : else if (unformat (input, "l2"))
307 0 : tid = IN_OUT_ACL_TABLE_L2;
308 : else
309 0 : break;
310 : }
311 :
312 64 : *acl_type = tid;
313 64 : return 1;
314 : }
315 :
316 : u8 *
317 63 : format_vnet_in_out_acl_info (u8 * s, va_list * va)
318 : {
319 63 : in_out_acl_main_t *am = va_arg (*va, in_out_acl_main_t *);
320 63 : int sw_if_idx = va_arg (*va, int);
321 63 : u32 tid = va_arg (*va, u32);
322 :
323 63 : if (tid == ~0)
324 : {
325 33 : s = format (s, "%10s%20s\t\t%s", "Intfc idx", "Classify table",
326 : "Interface name");
327 33 : return s;
328 : }
329 :
330 30 : s = format (s, "%10d%20d\t\t%U", sw_if_idx, tid,
331 : format_vnet_sw_if_index_name, am->vnet_main, sw_if_idx);
332 :
333 30 : return s;
334 : }
335 :
336 : static clib_error_t *
337 64 : show_in_out_acl_command_fn (vlib_main_t * vm,
338 : unformat_input_t * input,
339 : vlib_cli_command_t * cmd, u32 is_output)
340 : {
341 64 : in_out_acl_main_t *am = &in_out_acl_main;
342 64 : u32 type = IN_OUT_ACL_N_TABLES;
343 : int i;
344 : u32 *vec_tbl;
345 :
346 128 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
347 : {
348 64 : if (unformat (input, "type %U", unformat_acl_type, &type))
349 : ;
350 : else
351 0 : break;
352 : }
353 :
354 64 : if (type == IN_OUT_ACL_N_TABLES)
355 0 : return clib_error_return (0, is_output ? "Invalid output ACL table type."
356 : : "Invalid input ACL table type.");
357 :
358 64 : vec_tbl = am->classify_table_index_by_sw_if_index[is_output][type];
359 :
360 64 : if (vec_len (vec_tbl))
361 33 : vlib_cli_output (vm, "%U", format_vnet_in_out_acl_info, am, ~0 /* hdr */ ,
362 : ~0);
363 : else
364 31 : vlib_cli_output (vm, is_output ? "No output ACL tables configured"
365 : : "No input ACL tables configured");
366 :
367 130 : for (i = 0; i < vec_len (vec_tbl); i++)
368 : {
369 66 : if (vec_elt (vec_tbl, i) == ~0)
370 36 : continue;
371 :
372 30 : vlib_cli_output (vm, "%U", format_vnet_in_out_acl_info,
373 30 : am, i, vec_elt (vec_tbl, i));
374 : }
375 :
376 64 : return 0;
377 : }
378 :
379 : static clib_error_t *
380 32 : show_inacl_command_fn (vlib_main_t * vm,
381 : unformat_input_t * input, vlib_cli_command_t * cmd)
382 : {
383 32 : return show_in_out_acl_command_fn (vm, input, cmd,
384 : IN_OUT_ACL_INPUT_TABLE_GROUP);
385 : }
386 :
387 : static clib_error_t *
388 32 : show_outacl_command_fn (vlib_main_t * vm,
389 : unformat_input_t * input, vlib_cli_command_t * cmd)
390 : {
391 32 : return show_in_out_acl_command_fn (vm, input, cmd,
392 : IN_OUT_ACL_OUTPUT_TABLE_GROUP);
393 : }
394 :
395 : /* *INDENT-OFF* */
396 285289 : VLIB_CLI_COMMAND (show_inacl_command, static) = {
397 : .path = "show inacl",
398 : .short_help = "show inacl type [ip4|ip6|l2]",
399 : .function = show_inacl_command_fn,
400 : };
401 285289 : VLIB_CLI_COMMAND (show_outacl_command, static) = {
402 : .path = "show outacl",
403 : .short_help = "show outacl type [ip4|ip6|l2]",
404 : .function = show_outacl_command_fn,
405 : };
406 : /* *INDENT-ON* */
407 :
408 : /*
409 : * fd.io coding-style-patch-verification: ON
410 : *
411 : * Local Variables:
412 : * eval: (c-set-style "gnu")
413 : * End:
414 : */
|