blob: bfd1dcb9280caa458d364f2e31791bf5be80a555 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * l2_vtr.c : layer 2 vlan tag rewrite configuration
3 *
4 * Copyright (c) 2013 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <vlib/vlib.h>
19#include <vnet/vnet.h>
20#include <vnet/ethernet/ethernet.h>
21#include <vnet/ethernet/packet.h>
22#include <vnet/l2/l2_input.h>
23#include <vnet/l2/l2_output.h>
24#include <vnet/l2/feat_bitmap.h>
25#include <vnet/l2/l2_vtr.h>
26#include <vnet/l2/l2_input_vtr.h>
27#include <vnet/l2/l2_output.h>
28
29#include <vppinfra/error.h>
30#include <vlib/cli.h>
31
Billy McFall22aa3e92016-09-09 08:46:40 -040032/**
33 * @file
34 * @brief Ethernet VLAN Tag Rewrite.
35 *
36 * VLAN tag rewrite provides the ability to change the VLAN tags on a packet.
37 * Existing tags can be popped, new tags can be pushed, and existing tags can
38 * be swapped with new tags. The rewrite feature is attached to a subinterface
39 * as input and output operations. The input operation is explicitly configured.
40 * The output operation is the symmetric opposite and is automatically derived
41 * from the input operation.
42 */
Ed Warnickecb9cada2015-12-08 15:45:58 -070043
Chris Luke16bcf7d2016-09-01 14:31:46 -040044/** Just a placeholder; ensures file is not eliminated by linker. */
Dave Barach97d8dc22016-08-15 15:31:15 -040045clib_error_t *
46l2_vtr_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -070047{
48 return 0;
49}
50
Dave Barach97d8dc22016-08-15 15:31:15 -040051VLIB_INIT_FUNCTION (l2_vtr_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -070052
Pavel Kotucek95300d12016-08-26 16:11:36 +020053u32
54l2pbb_configure (vlib_main_t * vlib_main,
55 vnet_main_t * vnet_main, u32 sw_if_index, u32 vtr_op,
56 u8 * b_dmac, u8 * b_smac,
57 u16 b_vlanid, u32 i_sid, u16 vlan_outer_tag)
58{
59 u32 error = 0;
60 u32 enable = 0;
61
62 l2_output_config_t *config = 0;
63 vnet_hw_interface_t *hi;
Dave Barach3940de32019-07-23 16:28:36 -040064 hi = vnet_get_sup_hw_interface_api_visible_or_null (vnet_main, sw_if_index);
Pavel Kotucek95300d12016-08-26 16:11:36 +020065
66 if (!hi)
67 {
68 error = VNET_API_ERROR_INVALID_INTERFACE;
69 goto done;
70 }
71
72 // Config for this interface should be already initialized
73 ptr_config_t *in_config;
74 ptr_config_t *out_config;
75 config = vec_elt_at_index (l2output_main.configs, sw_if_index);
76 in_config = &(config->input_pbb_vtr);
77 out_config = &(config->output_pbb_vtr);
78
79 in_config->pop_bytes = 0;
80 in_config->push_bytes = 0;
81 out_config->pop_bytes = 0;
82 out_config->push_bytes = 0;
83 enable = (vtr_op != L2_VTR_DISABLED);
84
85 if (!enable)
86 goto done;
87
88 if (vtr_op == L2_VTR_POP_2)
89 {
90 in_config->pop_bytes = sizeof (ethernet_pbb_header_packed_t);
91 }
92 else if (vtr_op == L2_VTR_PUSH_2)
93 {
Dave Barach178cf492018-11-13 16:34:13 -050094 clib_memcpy_fast (in_config->macs_tags.b_dst_address, b_dmac,
95 sizeof (in_config->macs_tags.b_dst_address));
96 clib_memcpy_fast (in_config->macs_tags.b_src_address, b_smac,
97 sizeof (in_config->macs_tags.b_src_address));
Pavel Kotucek95300d12016-08-26 16:11:36 +020098 in_config->macs_tags.b_type =
99 clib_net_to_host_u16 (ETHERNET_TYPE_DOT1AD);
100 in_config->macs_tags.priority_dei_id =
101 clib_net_to_host_u16 (b_vlanid & 0xFFF);
102 in_config->macs_tags.i_type =
103 clib_net_to_host_u16 (ETHERNET_TYPE_DOT1AH);
104 in_config->macs_tags.priority_dei_uca_res_sid =
105 clib_net_to_host_u32 (i_sid & 0xFFFFF);
106 in_config->push_bytes = sizeof (ethernet_pbb_header_packed_t);
107 }
108 else if (vtr_op == L2_VTR_TRANSLATE_2_2)
109 {
110 /* TODO after PoC */
111 }
112
113 /*
114 * Construct the output tag-rewrite config
115 *
116 * The push/pop values are always reversed
117 */
118 out_config->raw_data = in_config->raw_data;
119 out_config->pop_bytes = in_config->push_bytes;
120 out_config->push_bytes = in_config->pop_bytes;
121
122done:
123 l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
124 if (config)
125 config->out_vtr_flag = (u8) enable;
126
127 /* output vtr enable is checked explicitly in l2_output */
128 return error;
129}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130
Dave Barach97d8dc22016-08-15 15:31:15 -0400131/**
132 * Configure vtag tag rewrite on the given interface.
133 * Return 1 if there is an error, 0 if ok
134 */
135u32
136l2vtr_configure (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index, u32 vtr_op, u32 push_dot1q, /* ethertype of first pushed tag is dot1q/dot1ad */
137 u32 vtr_tag1, /* first pushed tag */
138 u32 vtr_tag2) /* second pushed tag */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139{
Dave Barach97d8dc22016-08-15 15:31:15 -0400140 vnet_hw_interface_t *hi;
141 vnet_sw_interface_t *si;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142 u32 hw_no_tags;
143 u32 error = 0;
Pavel Kotucek95300d12016-08-26 16:11:36 +0200144 l2_output_config_t *config;
Dave Barach97d8dc22016-08-15 15:31:15 -0400145 vtr_config_t *in_config;
146 vtr_config_t *out_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147 u32 enable;
148 u32 push_inner_et;
149 u32 push_outer_et;
150 u32 cfg_tags;
151
Dave Barach3940de32019-07-23 16:28:36 -0400152 hi = vnet_get_sup_hw_interface_api_visible_or_null (vnet_main, sw_if_index);
Dave Barach97d8dc22016-08-15 15:31:15 -0400153 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
154 {
155 error = VNET_API_ERROR_INVALID_INTERFACE; /* non-ethernet interface */
156 goto done;
157 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158
Dave Barach97d8dc22016-08-15 15:31:15 -0400159 /* Init the config for this interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160 vec_validate (l2output_main.configs, sw_if_index);
Pavel Kotucek95300d12016-08-26 16:11:36 +0200161 config = vec_elt_at_index (l2output_main.configs, sw_if_index);
162 in_config = &(config->input_vtr);
163 out_config = &(config->output_vtr);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164 in_config->raw_tags = 0;
165 out_config->raw_tags = 0;
166
Dave Barach97d8dc22016-08-15 15:31:15 -0400167 /* Get the configured tags for the interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168 si = vnet_get_sw_interface (vnet_main, sw_if_index);
169 hw_no_tags = (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
170
Dave Barach97d8dc22016-08-15 15:31:15 -0400171 /* Construct the input tag-rewrite config */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700172
Dave Barach97d8dc22016-08-15 15:31:15 -0400173 push_outer_et =
174 clib_net_to_host_u16 (push_dot1q ? ETHERNET_TYPE_VLAN :
175 ETHERNET_TYPE_DOT1AD);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176 push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN);
177 vtr_tag1 = clib_net_to_host_u16 (vtr_tag1);
178 vtr_tag2 = clib_net_to_host_u16 (vtr_tag2);
179
Paul Vinciguerrabdc0e6b2018-09-22 05:32:50 -0700180 /* Determine number of vlan tags with explicitly configured values */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181 cfg_tags = 0;
Dave Barach97d8dc22016-08-15 15:31:15 -0400182 if (hw_no_tags || si->sub.eth.flags.no_tags)
183 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184 cfg_tags = 0;
185 }
Dave Barach97d8dc22016-08-15 15:31:15 -0400186 else if (si->sub.eth.flags.one_tag)
187 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188 cfg_tags = 1;
Dave Barach97d8dc22016-08-15 15:31:15 -0400189 if (si->sub.eth.flags.outer_vlan_id_any)
190 {
191 cfg_tags = 0;
192 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193 }
Dave Barach97d8dc22016-08-15 15:31:15 -0400194 else if (si->sub.eth.flags.two_tags)
195 {
196 cfg_tags = 2;
197 if (si->sub.eth.flags.inner_vlan_id_any)
198 {
199 cfg_tags = 1;
200 }
201 if (si->sub.eth.flags.outer_vlan_id_any)
202 {
203 cfg_tags = 0;
204 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206
Dave Barach97d8dc22016-08-15 15:31:15 -0400207 switch (vtr_op)
208 {
209 case L2_VTR_DISABLED:
210 in_config->push_and_pop_bytes = 0;
211 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212
Dave Barach97d8dc22016-08-15 15:31:15 -0400213 case L2_VTR_POP_1:
214 if (cfg_tags < 1)
215 {
216 /* Need one or two tags */
217 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;
218 goto done;
219 }
220 in_config->pop_bytes = 4;
221 in_config->push_bytes = 0;
222 break;
223
224 case L2_VTR_POP_2:
225 if (cfg_tags < 2)
226 {
227 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
228 goto done;
229 }
230 in_config->pop_bytes = 8;
231 in_config->push_bytes = 0;
Dave Barach97d8dc22016-08-15 15:31:15 -0400232 break;
233
234 case L2_VTR_PUSH_1:
235 in_config->pop_bytes = 0;
236 in_config->push_bytes = 4;
237 in_config->tags[1].priority_cfi_and_id = vtr_tag1;
238 in_config->tags[1].type = push_outer_et;
239 break;
240
241 case L2_VTR_PUSH_2:
242 in_config->pop_bytes = 0;
243 in_config->push_bytes = 8;
244 in_config->tags[0].priority_cfi_and_id = vtr_tag1;
245 in_config->tags[0].type = push_outer_et;
246 in_config->tags[1].priority_cfi_and_id = vtr_tag2;
247 in_config->tags[1].type = push_inner_et;
248 break;
249
250 case L2_VTR_TRANSLATE_1_1:
251 if (cfg_tags < 1)
252 {
253 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */
254 goto done;
255 }
256 in_config->pop_bytes = 4;
257 in_config->push_bytes = 4;
258 in_config->tags[1].priority_cfi_and_id = vtr_tag1;
259 in_config->tags[1].type = push_outer_et;
260 break;
261
262 case L2_VTR_TRANSLATE_1_2:
263 if (cfg_tags < 1)
264 {
265 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */
266 goto done;
267 }
268 in_config->pop_bytes = 4;
269 in_config->push_bytes = 8;
270 in_config->tags[0].priority_cfi_and_id = vtr_tag1;
271 in_config->tags[0].type = push_outer_et;
272 in_config->tags[1].priority_cfi_and_id = vtr_tag2;
273 in_config->tags[1].type = push_inner_et;
274 break;
275
276 case L2_VTR_TRANSLATE_2_1:
277 if (cfg_tags < 2)
278 {
279 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
280 goto done;
281 }
282 in_config->pop_bytes = 8;
283 in_config->push_bytes = 4;
284 in_config->tags[1].priority_cfi_and_id = vtr_tag1;
285 in_config->tags[1].type = push_outer_et;
286 break;
287
288 case L2_VTR_TRANSLATE_2_2:
289 if (cfg_tags < 2)
290 {
291 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
292 goto done;
293 }
294 in_config->pop_bytes = 8;
295 in_config->push_bytes = 8;
296 in_config->tags[0].priority_cfi_and_id = vtr_tag1;
297 in_config->tags[0].type = push_outer_et;
298 in_config->tags[1].priority_cfi_and_id = vtr_tag2;
299 in_config->tags[1].type = push_inner_et;
300 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700301 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302
Dave Barach97d8dc22016-08-15 15:31:15 -0400303 /*
304 * Construct the output tag-rewrite config
305 *
306 * The push/pop values are always reversed
307 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700308 out_config->push_bytes = in_config->pop_bytes;
309 out_config->pop_bytes = in_config->push_bytes;
310
Dave Barach97d8dc22016-08-15 15:31:15 -0400311 /* Any pushed tags are derived from the subinterface config */
312 push_outer_et =
313 clib_net_to_host_u16 (si->sub.eth.flags.dot1ad ? ETHERNET_TYPE_DOT1AD :
314 ETHERNET_TYPE_VLAN);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315 push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN);
316 vtr_tag1 = clib_net_to_host_u16 (si->sub.eth.outer_vlan_id);
317 vtr_tag2 = clib_net_to_host_u16 (si->sub.eth.inner_vlan_id);
318
Dave Barach97d8dc22016-08-15 15:31:15 -0400319 if (out_config->push_bytes == 4)
320 {
321 out_config->tags[1].priority_cfi_and_id = vtr_tag1;
322 out_config->tags[1].type = push_outer_et;
323 }
324 else if (out_config->push_bytes == 8)
325 {
326 out_config->tags[0].priority_cfi_and_id = vtr_tag1;
327 out_config->tags[0].type = push_outer_et;
328 out_config->tags[1].priority_cfi_and_id = vtr_tag2;
329 out_config->tags[1].type = push_inner_et;
330 }
331
332 /* set the interface enable flags */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333 enable = (vtr_op != L2_VTR_DISABLED);
Pavel Kotucek95300d12016-08-26 16:11:36 +0200334 config->out_vtr_flag = (u8) enable;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335 l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
Dave Barach97d8dc22016-08-15 15:31:15 -0400336 /* output vtr enable is checked explicitly in l2_output */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700337
Dave Barach97d8dc22016-08-15 15:31:15 -0400338done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339 return error;
340}
341
Dave Barach97d8dc22016-08-15 15:31:15 -0400342/**
Chris Luke16bcf7d2016-09-01 14:31:46 -0400343 * Get vtag tag rewrite on the given interface.
Dave Barach97d8dc22016-08-15 15:31:15 -0400344 * Return 1 if there is an error, 0 if ok
345 */
346u32
347l2vtr_get (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index, u32 * vtr_op, u32 * push_dot1q, /* ethertype of first pushed tag is dot1q/dot1ad */
348 u32 * vtr_tag1, /* first pushed tag */
349 u32 * vtr_tag2) /* second pushed tag */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350{
Dave Barach97d8dc22016-08-15 15:31:15 -0400351 vnet_hw_interface_t *hi;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352 u32 error = 0;
Dave Barach97d8dc22016-08-15 15:31:15 -0400353 vtr_config_t *in_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354
Dave Barach97d8dc22016-08-15 15:31:15 -0400355 if (!vtr_op || !push_dot1q || !vtr_tag1 || !vtr_tag2)
356 {
357 clib_warning ("invalid arguments");
358 error = VNET_API_ERROR_INVALID_ARGUMENT;
359 goto done;
360 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361
362 *vtr_op = L2_VTR_DISABLED;
363 *vtr_tag1 = 0;
364 *vtr_tag2 = 0;
365 *push_dot1q = 0;
366
Dave Barach3940de32019-07-23 16:28:36 -0400367 hi = vnet_get_sup_hw_interface_api_visible_or_null (vnet_main, sw_if_index);
Dave Barach97d8dc22016-08-15 15:31:15 -0400368 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
369 {
370 /* non-ethernet interface */
371 goto done;
372 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700373
Dave Barach97d8dc22016-08-15 15:31:15 -0400374 if (sw_if_index >= vec_len (l2output_main.configs))
375 {
376 /* no specific config (return disabled) */
377 goto done;
378 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700379
Dave Barach97d8dc22016-08-15 15:31:15 -0400380 /* Get the config for this interface */
381 in_config =
382 &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_vtr);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700383
Dave Barach97d8dc22016-08-15 15:31:15 -0400384 /* DISABLED */
385 if (in_config->push_and_pop_bytes == 0)
386 {
387 goto done;
388 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700389
Dave Barach97d8dc22016-08-15 15:31:15 -0400390 /* find out vtr_op */
391 switch (in_config->pop_bytes)
392 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393 case 0:
Dave Barach97d8dc22016-08-15 15:31:15 -0400394 switch (in_config->push_bytes)
395 {
396 case 0:
397 /* DISABLED */
398 goto done;
399 case 4:
400 *vtr_op = L2_VTR_PUSH_1;
401 *vtr_tag1 =
402 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
403 *push_dot1q =
404 (ETHERNET_TYPE_VLAN ==
405 clib_host_to_net_u16 (in_config->tags[1].type));
406 break;
407 case 8:
408 *vtr_op = L2_VTR_PUSH_2;
409 *vtr_tag1 =
410 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
411 *vtr_tag2 =
412 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
413 *push_dot1q =
414 (ETHERNET_TYPE_VLAN ==
415 clib_host_to_net_u16 (in_config->tags[0].type));
416 break;
417 default:
418 clib_warning ("invalid push_bytes count: %d",
419 in_config->push_bytes);
420 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
421 goto done;
422 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700423 break;
424
425 case 4:
Dave Barach97d8dc22016-08-15 15:31:15 -0400426 switch (in_config->push_bytes)
427 {
428 case 0:
429 *vtr_op = L2_VTR_POP_1;
430 break;
431 case 4:
432 *vtr_op = L2_VTR_TRANSLATE_1_1;
433 *vtr_tag1 =
434 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
435 *push_dot1q =
436 (ETHERNET_TYPE_VLAN ==
437 clib_host_to_net_u16 (in_config->tags[1].type));
438 break;
439 case 8:
440 *vtr_op = L2_VTR_TRANSLATE_1_2;
441 *vtr_tag1 =
442 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
443 *vtr_tag2 =
444 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
445 *push_dot1q =
446 (ETHERNET_TYPE_VLAN ==
447 clib_host_to_net_u16 (in_config->tags[0].type));
448 break;
449 default:
450 clib_warning ("invalid push_bytes count: %d",
451 in_config->push_bytes);
452 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
453 goto done;
454 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700455 break;
456
457 case 8:
Dave Barach97d8dc22016-08-15 15:31:15 -0400458 switch (in_config->push_bytes)
459 {
460 case 0:
461 *vtr_op = L2_VTR_POP_2;
462 break;
463 case 4:
464 *vtr_op = L2_VTR_TRANSLATE_2_1;
465 *vtr_tag1 =
466 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
467 *push_dot1q =
468 (ETHERNET_TYPE_VLAN ==
469 clib_host_to_net_u16 (in_config->tags[1].type));
470 break;
471 case 8:
472 *vtr_op = L2_VTR_TRANSLATE_2_2;
473 *vtr_tag1 =
474 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
475 *vtr_tag2 =
476 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
477 *push_dot1q =
478 (ETHERNET_TYPE_VLAN ==
479 clib_host_to_net_u16 (in_config->tags[0].type));
480 break;
481 default:
482 clib_warning ("invalid push_bytes count: %d",
483 in_config->push_bytes);
484 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
485 goto done;
486 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700487 break;
488
489 default:
490 clib_warning ("invalid pop_bytes count: %d", in_config->pop_bytes);
491 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
492 goto done;
Dave Barach97d8dc22016-08-15 15:31:15 -0400493 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494
Dave Barach97d8dc22016-08-15 15:31:15 -0400495done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700496 return error;
497}
498
Dave Barach97d8dc22016-08-15 15:31:15 -0400499/**
Chris Luke16bcf7d2016-09-01 14:31:46 -0400500 * Set subinterface vtr enable/disable.
Dave Barach97d8dc22016-08-15 15:31:15 -0400501 * The CLI format is:
502 * set interface l2 tag-rewrite <interface> [disable | pop 1 | pop 2 | push {dot1q|dot1ad} <tag> [<tag>]]
503 *
504 * "push" can also be replaced by "translate-{1|2}-{1|2}"
505 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506static clib_error_t *
507int_l2_vtr (vlib_main_t * vm,
Dave Barach97d8dc22016-08-15 15:31:15 -0400508 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700509{
Dave Barach97d8dc22016-08-15 15:31:15 -0400510 vnet_main_t *vnm = vnet_get_main ();
511 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700512 u32 sw_if_index;
513 u32 vtr_op;
514 u32 push_dot1q = 0;
515 u32 tag1 = 0, tag2 = 0;
516
Dave Barach97d8dc22016-08-15 15:31:15 -0400517 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518 {
519 error = clib_error_return (0, "unknown interface `%U'",
Dave Barach97d8dc22016-08-15 15:31:15 -0400520 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521 goto done;
522 }
523
524 vtr_op = L2_VTR_DISABLED;
525
Dave Barach97d8dc22016-08-15 15:31:15 -0400526 if (unformat (input, "disable"))
527 {
528 vtr_op = L2_VTR_DISABLED;
529 }
530 else if (unformat (input, "pop 1"))
531 {
532 vtr_op = L2_VTR_POP_1;
533 }
534 else if (unformat (input, "pop 2"))
535 {
536 vtr_op = L2_VTR_POP_2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537
Dave Barach97d8dc22016-08-15 15:31:15 -0400538 }
539 else if (unformat (input, "push dot1q %d %d", &tag1, &tag2))
540 {
541 vtr_op = L2_VTR_PUSH_2;
542 push_dot1q = 1;
543 }
544 else if (unformat (input, "push dot1ad %d %d", &tag1, &tag2))
545 {
546 vtr_op = L2_VTR_PUSH_2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547
Dave Barach97d8dc22016-08-15 15:31:15 -0400548 }
549 else if (unformat (input, "push dot1q %d", &tag1))
550 {
551 vtr_op = L2_VTR_PUSH_1;
552 push_dot1q = 1;
553 }
554 else if (unformat (input, "push dot1ad %d", &tag1))
555 {
556 vtr_op = L2_VTR_PUSH_1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700557
Dave Barach97d8dc22016-08-15 15:31:15 -0400558 }
559 else if (unformat (input, "translate 1-1 dot1q %d", &tag1))
560 {
561 vtr_op = L2_VTR_TRANSLATE_1_1;
562 push_dot1q = 1;
563 }
564 else if (unformat (input, "translate 1-1 dot1ad %d", &tag1))
565 {
566 vtr_op = L2_VTR_TRANSLATE_1_1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700567
Dave Barach97d8dc22016-08-15 15:31:15 -0400568 }
569 else if (unformat (input, "translate 2-1 dot1q %d", &tag1))
570 {
571 vtr_op = L2_VTR_TRANSLATE_2_1;
572 push_dot1q = 1;
573 }
574 else if (unformat (input, "translate 2-1 dot1ad %d", &tag1))
575 {
576 vtr_op = L2_VTR_TRANSLATE_2_1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700577
Dave Barach97d8dc22016-08-15 15:31:15 -0400578 }
579 else if (unformat (input, "translate 2-2 dot1q %d %d", &tag1, &tag2))
580 {
581 vtr_op = L2_VTR_TRANSLATE_2_2;
582 push_dot1q = 1;
583 }
584 else if (unformat (input, "translate 2-2 dot1ad %d %d", &tag1, &tag2))
585 {
586 vtr_op = L2_VTR_TRANSLATE_2_2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700587
Dave Barach97d8dc22016-08-15 15:31:15 -0400588 }
589 else if (unformat (input, "translate 1-2 dot1q %d %d", &tag1, &tag2))
590 {
591 vtr_op = L2_VTR_TRANSLATE_1_2;
592 push_dot1q = 1;
593 }
594 else if (unformat (input, "translate 1-2 dot1ad %d %d", &tag1, &tag2))
595 {
596 vtr_op = L2_VTR_TRANSLATE_1_2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700597
Dave Barach97d8dc22016-08-15 15:31:15 -0400598 }
599 else
600 {
601 error =
602 clib_error_return (0,
603 "expecting [disable | pop 1 | pop 2 | push {dot1q|dot1ah} <tag> [<tag>]\n"
604 " | translate {1|2}-{1|2} {dot1q|dot1ah} <tag> [<tag>]] but got `%U'",
605 format_unformat_error, input);
606 goto done;
607 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700608
Dave Barach97d8dc22016-08-15 15:31:15 -0400609 if (l2vtr_configure (vm, vnm, sw_if_index, vtr_op, push_dot1q, tag1, tag2))
610 {
611 error =
612 clib_error_return (0,
613 "vlan tag rewrite is not compatible with interface");
614 goto done;
615 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700616
Dave Barach97d8dc22016-08-15 15:31:15 -0400617done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700618 return error;
619}
620
Billy McFall22aa3e92016-09-09 08:46:40 -0400621/*?
622 * VLAN tag rewrite provides the ability to change the VLAN tags on a packet.
623 * Existing tags can be popped, new tags can be pushed, and existing tags can
624 * be swapped with new tags. The rewrite feature is attached to a subinterface
625 * as input and output operations. The input operation is explicitly configured.
626 * The output operation is the symmetric opposite and is automatically derived
627 * from the input operation.
628 *
629 * <b>POP:</b> For pop operations, the subinterface encapsulation (the vlan
630 * tags specified when it was created) must have at least the number of popped
631 * tags. e.g. the \"pop 2\" operation would be rejected on a single-vlan interface.
632 * The output tag-rewrite operation for pops is to push the specified number of
633 * vlan tags onto the packet. The pushed tag values are the ones in the
634 * subinterface encapsulation.
635 *
636 * <b>PUSH:</b> For push operations, the ethertype is also specified. The
637 * output tag-rewrite operation for pushes is to pop the same number of tags
638 * off the packet. If the packet doesn't have enough tags it is dropped.
639 *
640 *
641 * @cliexpar
642 * @parblock
643 * By default a subinterface has no tag-rewrite. To return a subinterface to
644 * this state use:
645 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 disable}
646 *
647 * To pop vlan tags off packets received from a subinterface, use:
648 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 1}
649 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 2}
650 *
651 * To push one or two vlan tags onto packets received from an interface, use:
652 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1q 100}
653 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1ad 100 150}
654 *
655 * Tags can also be translated, which is basically a combination of a pop and push.
656 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-1 dot1ad 100}
657 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-2 dot1ad 100 150}
658 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-2 dot1q 100}
659 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-1 dot1q 100 150}
660 *
661 * To display the VLAN Tag settings, show the associate bridge-domain:
662 * @cliexstart{show bridge-domain 200 detail}
663 * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf
664 * 200 1 on on on on off N/A
665 *
666 * Interface Index SHG BVI VLAN-Tag-Rewrite
667 * GigabitEthernet0/8/0.200 5 0 - trans-1-1 dot1ad 100
668 * GigabitEthernet0/9/0.200 4 0 - none
669 * GigabitEthernet0/a/0.200 6 0 - none
670 * @cliexend
671 * @endparblock
672?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400673/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700674VLIB_CLI_COMMAND (int_l2_vtr_cli, static) = {
675 .path = "set interface l2 tag-rewrite",
676 .short_help = "set interface l2 tag-rewrite <interface> [disable | pop {1|2} | push {dot1q|dot1ad} <tag> <tag>]",
677 .function = int_l2_vtr,
678};
Dave Barach97d8dc22016-08-15 15:31:15 -0400679/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700680
Pavel Kotucek95300d12016-08-26 16:11:36 +0200681/**
Pavel Kotucek65e84572017-01-16 17:01:56 +0100682 * Get pbb tag rewrite on the given interface.
683 * Return 1 if there is an error, 0 if ok
684 */
685u32
686l2pbb_get (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index,
Gabriel Gannef7f2a9f2017-03-06 15:19:40 +0100687 u32 * vtr_op, u16 * outer_tag, ethernet_header_t * eth_hdr,
Pavel Kotucek65e84572017-01-16 17:01:56 +0100688 u16 * b_vlanid, u32 * i_sid)
689{
690 u32 error = 1;
691 ptr_config_t *in_config;
692
693 if (!vtr_op || !outer_tag || !b_vlanid || !i_sid)
694 {
695 clib_warning ("invalid arguments");
696 error = VNET_API_ERROR_INVALID_ARGUMENT;
697 goto done;
698 }
699
700 *vtr_op = L2_VTR_DISABLED;
701 *outer_tag = 0;
Pavel Kotucek65e84572017-01-16 17:01:56 +0100702 *b_vlanid = 0;
703 *i_sid = 0;
704
705 if (sw_if_index >= vec_len (l2output_main.configs))
706 {
707 /* no specific config (return disabled) */
708 goto done;
709 }
710
711 /* Get the config for this interface */
712 in_config =
713 &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_pbb_vtr);
714
715 if (in_config->push_and_pop_bytes == 0)
716 {
717 /* DISABLED */
718 goto done;
719 }
720 else
721 {
722 if (in_config->pop_bytes && in_config->push_bytes)
723 *vtr_op = L2_VTR_TRANSLATE_2_1;
724 else if (in_config->pop_bytes)
725 *vtr_op = L2_VTR_POP_2;
726 else if (in_config->push_bytes)
727 *vtr_op = L2_VTR_PUSH_2;
728
Dave Barach178cf492018-11-13 16:34:13 -0500729 clib_memcpy_fast (&eth_hdr->dst_address,
730 in_config->macs_tags.b_dst_address,
731 sizeof (eth_hdr->dst_address));
732 clib_memcpy_fast (&eth_hdr->src_address,
733 in_config->macs_tags.b_src_address,
734 sizeof (eth_hdr->src_address));
Pavel Kotucek65e84572017-01-16 17:01:56 +0100735
736 *b_vlanid =
737 clib_host_to_net_u16 (in_config->macs_tags.priority_dei_id) & 0xFFF;
738 *i_sid =
Gabriel Gannef7f2a9f2017-03-06 15:19:40 +0100739 clib_host_to_net_u32 (in_config->macs_tags.
740 priority_dei_uca_res_sid) & 0xFFFFF;
Pavel Kotucek65e84572017-01-16 17:01:56 +0100741 error = 0;
742 }
743done:
744 return error;
745}
746
747/**
Pavel Kotucek95300d12016-08-26 16:11:36 +0200748 * Set subinterface pbb vtr enable/disable.
749 * The CLI format is:
750 * set interface l2 pbb-tag-rewrite <interface> [disable | pop | push | translate_pbb_stag <outer_tag> dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]
751 */
752static clib_error_t *
753int_l2_pbb_vtr (vlib_main_t * vm,
754 unformat_input_t * input, vlib_cli_command_t * cmd)
755{
756 vnet_main_t *vnm = vnet_get_main ();
757 clib_error_t *error = 0;
758 u32 sw_if_index, tmp;
759 u32 vtr_op = L2_VTR_DISABLED;
760 u32 outer_tag = 0;
761 u8 dmac[6];
762 u8 smac[6];
763 u8 dmac_set = 0, smac_set = 0;
764 u16 b_vlanid = 0;
765 u32 s_id = ~0;
766
767 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
768 {
769 if (unformat_user
770 (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
771 ;
772 else if (unformat (input, "disable"))
773 vtr_op = L2_VTR_DISABLED;
774 else if (vtr_op == L2_VTR_DISABLED && unformat (input, "pop"))
775 vtr_op = L2_VTR_POP_2;
776 else if (vtr_op == L2_VTR_DISABLED && unformat (input, "push"))
777 vtr_op = L2_VTR_PUSH_2;
778 else if (vtr_op == L2_VTR_DISABLED
779 && unformat (input, "translate_pbb_stag %d", &outer_tag))
780 vtr_op = L2_VTR_TRANSLATE_2_1;
781 else if (unformat (input, "dmac %U", unformat_ethernet_address, dmac))
782 dmac_set = 1;
783 else if (unformat (input, "smac %U", unformat_ethernet_address, smac))
784 smac_set = 1;
785 else if (unformat (input, "b_vlanid %d", &tmp))
786 b_vlanid = tmp;
787 else if (unformat (input, "s_id %d", &s_id))
788 ;
789 else
790 {
791 error = clib_error_return (0,
792 "expecting [disable | pop | push | translate_pbb_stag <outer_tag>\n"
793 "dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]");
794 goto done;
795 }
796 }
797
798 if ((vtr_op == L2_VTR_PUSH_2 || vtr_op == L2_VTR_TRANSLATE_2_1)
799 && (!dmac_set || !smac_set || s_id == ~0))
800 {
801 error = clib_error_return (0,
802 "expecting dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]");
803 goto done;
804 }
805
806 if (l2pbb_configure
807 (vm, vnm, sw_if_index, vtr_op, dmac, smac, b_vlanid, s_id, outer_tag))
808 {
809 error =
810 clib_error_return (0,
811 "pbb tag rewrite is not compatible with interface");
812 goto done;
813 }
814
815done:
816 return error;
817}
818
819/* *INDENT-OFF* */
820VLIB_CLI_COMMAND (int_l2_pbb_vtr_cli, static) = {
821 .path = "set interface l2 pbb-tag-rewrite",
822 .short_help = "set interface l2 pbb-tag-rewrite <interface> [disable | pop | push | translate_pbb_stag <outer_tag> dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]",
823 .function = int_l2_pbb_vtr,
824};
825/* *INDENT-ON* */
Dave Barach97d8dc22016-08-15 15:31:15 -0400826
827/*
828 * fd.io coding-style-patch-verification: ON
829 *
830 * Local Variables:
831 * eval: (c-set-style "gnu")
832 * End:
833 */