blob: 3c5365f9b51faeafa279800c0c45fba1a099a0b2 [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;
64 hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
65
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 {
94 clib_memcpy (in_config->macs_tags.b_dst_address, b_dmac,
95 sizeof (in_config->macs_tags.b_dst_address));
96 clib_memcpy (in_config->macs_tags.b_src_address, b_smac,
97 sizeof (in_config->macs_tags.b_src_address));
98 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
152 hi = vnet_get_sup_hw_interface (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
Dave Barach97d8dc22016-08-15 15:31:15 -0400180 /* Determine number of vlan tags with explictly 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;
232
233 out_config->push_bytes = in_config->pop_bytes;
234 out_config->pop_bytes = in_config->push_bytes;
235 break;
236
237 case L2_VTR_PUSH_1:
238 in_config->pop_bytes = 0;
239 in_config->push_bytes = 4;
240 in_config->tags[1].priority_cfi_and_id = vtr_tag1;
241 in_config->tags[1].type = push_outer_et;
242 break;
243
244 case L2_VTR_PUSH_2:
245 in_config->pop_bytes = 0;
246 in_config->push_bytes = 8;
247 in_config->tags[0].priority_cfi_and_id = vtr_tag1;
248 in_config->tags[0].type = push_outer_et;
249 in_config->tags[1].priority_cfi_and_id = vtr_tag2;
250 in_config->tags[1].type = push_inner_et;
251 break;
252
253 case L2_VTR_TRANSLATE_1_1:
254 if (cfg_tags < 1)
255 {
256 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */
257 goto done;
258 }
259 in_config->pop_bytes = 4;
260 in_config->push_bytes = 4;
261 in_config->tags[1].priority_cfi_and_id = vtr_tag1;
262 in_config->tags[1].type = push_outer_et;
263 break;
264
265 case L2_VTR_TRANSLATE_1_2:
266 if (cfg_tags < 1)
267 {
268 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */
269 goto done;
270 }
271 in_config->pop_bytes = 4;
272 in_config->push_bytes = 8;
273 in_config->tags[0].priority_cfi_and_id = vtr_tag1;
274 in_config->tags[0].type = push_outer_et;
275 in_config->tags[1].priority_cfi_and_id = vtr_tag2;
276 in_config->tags[1].type = push_inner_et;
277 break;
278
279 case L2_VTR_TRANSLATE_2_1:
280 if (cfg_tags < 2)
281 {
282 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
283 goto done;
284 }
285 in_config->pop_bytes = 8;
286 in_config->push_bytes = 4;
287 in_config->tags[1].priority_cfi_and_id = vtr_tag1;
288 in_config->tags[1].type = push_outer_et;
289 break;
290
291 case L2_VTR_TRANSLATE_2_2:
292 if (cfg_tags < 2)
293 {
294 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
295 goto done;
296 }
297 in_config->pop_bytes = 8;
298 in_config->push_bytes = 8;
299 in_config->tags[0].priority_cfi_and_id = vtr_tag1;
300 in_config->tags[0].type = push_outer_et;
301 in_config->tags[1].priority_cfi_and_id = vtr_tag2;
302 in_config->tags[1].type = push_inner_et;
303 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700304 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305
Dave Barach97d8dc22016-08-15 15:31:15 -0400306 /*
307 * Construct the output tag-rewrite config
308 *
309 * The push/pop values are always reversed
310 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700311 out_config->push_bytes = in_config->pop_bytes;
312 out_config->pop_bytes = in_config->push_bytes;
313
Dave Barach97d8dc22016-08-15 15:31:15 -0400314 /* Any pushed tags are derived from the subinterface config */
315 push_outer_et =
316 clib_net_to_host_u16 (si->sub.eth.flags.dot1ad ? ETHERNET_TYPE_DOT1AD :
317 ETHERNET_TYPE_VLAN);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318 push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN);
319 vtr_tag1 = clib_net_to_host_u16 (si->sub.eth.outer_vlan_id);
320 vtr_tag2 = clib_net_to_host_u16 (si->sub.eth.inner_vlan_id);
321
Dave Barach97d8dc22016-08-15 15:31:15 -0400322 if (out_config->push_bytes == 4)
323 {
324 out_config->tags[1].priority_cfi_and_id = vtr_tag1;
325 out_config->tags[1].type = push_outer_et;
326 }
327 else if (out_config->push_bytes == 8)
328 {
329 out_config->tags[0].priority_cfi_and_id = vtr_tag1;
330 out_config->tags[0].type = push_outer_et;
331 out_config->tags[1].priority_cfi_and_id = vtr_tag2;
332 out_config->tags[1].type = push_inner_et;
333 }
334
335 /* set the interface enable flags */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700336 enable = (vtr_op != L2_VTR_DISABLED);
Pavel Kotucek95300d12016-08-26 16:11:36 +0200337 config->out_vtr_flag = (u8) enable;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338 l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
Dave Barach97d8dc22016-08-15 15:31:15 -0400339 /* output vtr enable is checked explicitly in l2_output */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340
Dave Barach97d8dc22016-08-15 15:31:15 -0400341done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342 return error;
343}
344
Dave Barach97d8dc22016-08-15 15:31:15 -0400345/**
Chris Luke16bcf7d2016-09-01 14:31:46 -0400346 * Get vtag tag rewrite on the given interface.
Dave Barach97d8dc22016-08-15 15:31:15 -0400347 * Return 1 if there is an error, 0 if ok
348 */
349u32
350l2vtr_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 */
351 u32 * vtr_tag1, /* first pushed tag */
352 u32 * vtr_tag2) /* second pushed tag */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700353{
Dave Barach97d8dc22016-08-15 15:31:15 -0400354 vnet_hw_interface_t *hi;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700355 u32 error = 0;
Dave Barach97d8dc22016-08-15 15:31:15 -0400356 vtr_config_t *in_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357
Dave Barach97d8dc22016-08-15 15:31:15 -0400358 if (!vtr_op || !push_dot1q || !vtr_tag1 || !vtr_tag2)
359 {
360 clib_warning ("invalid arguments");
361 error = VNET_API_ERROR_INVALID_ARGUMENT;
362 goto done;
363 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364
365 *vtr_op = L2_VTR_DISABLED;
366 *vtr_tag1 = 0;
367 *vtr_tag2 = 0;
368 *push_dot1q = 0;
369
370 hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
Dave Barach97d8dc22016-08-15 15:31:15 -0400371 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
372 {
373 /* non-ethernet interface */
374 goto done;
375 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376
Dave Barach97d8dc22016-08-15 15:31:15 -0400377 if (sw_if_index >= vec_len (l2output_main.configs))
378 {
379 /* no specific config (return disabled) */
380 goto done;
381 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382
Dave Barach97d8dc22016-08-15 15:31:15 -0400383 /* Get the config for this interface */
384 in_config =
385 &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_vtr);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386
Dave Barach97d8dc22016-08-15 15:31:15 -0400387 /* DISABLED */
388 if (in_config->push_and_pop_bytes == 0)
389 {
390 goto done;
391 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392
Dave Barach97d8dc22016-08-15 15:31:15 -0400393 /* find out vtr_op */
394 switch (in_config->pop_bytes)
395 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396 case 0:
Dave Barach97d8dc22016-08-15 15:31:15 -0400397 switch (in_config->push_bytes)
398 {
399 case 0:
400 /* DISABLED */
401 goto done;
402 case 4:
403 *vtr_op = L2_VTR_PUSH_1;
404 *vtr_tag1 =
405 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
406 *push_dot1q =
407 (ETHERNET_TYPE_VLAN ==
408 clib_host_to_net_u16 (in_config->tags[1].type));
409 break;
410 case 8:
411 *vtr_op = L2_VTR_PUSH_2;
412 *vtr_tag1 =
413 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
414 *vtr_tag2 =
415 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
416 *push_dot1q =
417 (ETHERNET_TYPE_VLAN ==
418 clib_host_to_net_u16 (in_config->tags[0].type));
419 break;
420 default:
421 clib_warning ("invalid push_bytes count: %d",
422 in_config->push_bytes);
423 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
424 goto done;
425 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426 break;
427
428 case 4:
Dave Barach97d8dc22016-08-15 15:31:15 -0400429 switch (in_config->push_bytes)
430 {
431 case 0:
432 *vtr_op = L2_VTR_POP_1;
433 break;
434 case 4:
435 *vtr_op = L2_VTR_TRANSLATE_1_1;
436 *vtr_tag1 =
437 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
438 *push_dot1q =
439 (ETHERNET_TYPE_VLAN ==
440 clib_host_to_net_u16 (in_config->tags[1].type));
441 break;
442 case 8:
443 *vtr_op = L2_VTR_TRANSLATE_1_2;
444 *vtr_tag1 =
445 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
446 *vtr_tag2 =
447 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
448 *push_dot1q =
449 (ETHERNET_TYPE_VLAN ==
450 clib_host_to_net_u16 (in_config->tags[0].type));
451 break;
452 default:
453 clib_warning ("invalid push_bytes count: %d",
454 in_config->push_bytes);
455 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
456 goto done;
457 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700458 break;
459
460 case 8:
Dave Barach97d8dc22016-08-15 15:31:15 -0400461 switch (in_config->push_bytes)
462 {
463 case 0:
464 *vtr_op = L2_VTR_POP_2;
465 break;
466 case 4:
467 *vtr_op = L2_VTR_TRANSLATE_2_1;
468 *vtr_tag1 =
469 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
470 *push_dot1q =
471 (ETHERNET_TYPE_VLAN ==
472 clib_host_to_net_u16 (in_config->tags[1].type));
473 break;
474 case 8:
475 *vtr_op = L2_VTR_TRANSLATE_2_2;
476 *vtr_tag1 =
477 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
478 *vtr_tag2 =
479 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
480 *push_dot1q =
481 (ETHERNET_TYPE_VLAN ==
482 clib_host_to_net_u16 (in_config->tags[0].type));
483 break;
484 default:
485 clib_warning ("invalid push_bytes count: %d",
486 in_config->push_bytes);
487 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
488 goto done;
489 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490 break;
491
492 default:
493 clib_warning ("invalid pop_bytes count: %d", in_config->pop_bytes);
494 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
495 goto done;
Dave Barach97d8dc22016-08-15 15:31:15 -0400496 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497
Dave Barach97d8dc22016-08-15 15:31:15 -0400498done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499 return error;
500}
501
Dave Barach97d8dc22016-08-15 15:31:15 -0400502/**
Chris Luke16bcf7d2016-09-01 14:31:46 -0400503 * Set subinterface vtr enable/disable.
Dave Barach97d8dc22016-08-15 15:31:15 -0400504 * The CLI format is:
505 * set interface l2 tag-rewrite <interface> [disable | pop 1 | pop 2 | push {dot1q|dot1ad} <tag> [<tag>]]
506 *
507 * "push" can also be replaced by "translate-{1|2}-{1|2}"
508 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700509static clib_error_t *
510int_l2_vtr (vlib_main_t * vm,
Dave Barach97d8dc22016-08-15 15:31:15 -0400511 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700512{
Dave Barach97d8dc22016-08-15 15:31:15 -0400513 vnet_main_t *vnm = vnet_get_main ();
514 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515 u32 sw_if_index;
516 u32 vtr_op;
517 u32 push_dot1q = 0;
518 u32 tag1 = 0, tag2 = 0;
519
Dave Barach97d8dc22016-08-15 15:31:15 -0400520 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521 {
522 error = clib_error_return (0, "unknown interface `%U'",
Dave Barach97d8dc22016-08-15 15:31:15 -0400523 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700524 goto done;
525 }
526
527 vtr_op = L2_VTR_DISABLED;
528
Dave Barach97d8dc22016-08-15 15:31:15 -0400529 if (unformat (input, "disable"))
530 {
531 vtr_op = L2_VTR_DISABLED;
532 }
533 else if (unformat (input, "pop 1"))
534 {
535 vtr_op = L2_VTR_POP_1;
536 }
537 else if (unformat (input, "pop 2"))
538 {
539 vtr_op = L2_VTR_POP_2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540
Dave Barach97d8dc22016-08-15 15:31:15 -0400541 }
542 else if (unformat (input, "push dot1q %d %d", &tag1, &tag2))
543 {
544 vtr_op = L2_VTR_PUSH_2;
545 push_dot1q = 1;
546 }
547 else if (unformat (input, "push dot1ad %d %d", &tag1, &tag2))
548 {
549 vtr_op = L2_VTR_PUSH_2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550
Dave Barach97d8dc22016-08-15 15:31:15 -0400551 }
552 else if (unformat (input, "push dot1q %d", &tag1))
553 {
554 vtr_op = L2_VTR_PUSH_1;
555 push_dot1q = 1;
556 }
557 else if (unformat (input, "push dot1ad %d", &tag1))
558 {
559 vtr_op = L2_VTR_PUSH_1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700560
Dave Barach97d8dc22016-08-15 15:31:15 -0400561 }
562 else if (unformat (input, "translate 1-1 dot1q %d", &tag1))
563 {
564 vtr_op = L2_VTR_TRANSLATE_1_1;
565 push_dot1q = 1;
566 }
567 else if (unformat (input, "translate 1-1 dot1ad %d", &tag1))
568 {
569 vtr_op = L2_VTR_TRANSLATE_1_1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700570
Dave Barach97d8dc22016-08-15 15:31:15 -0400571 }
572 else if (unformat (input, "translate 2-1 dot1q %d", &tag1))
573 {
574 vtr_op = L2_VTR_TRANSLATE_2_1;
575 push_dot1q = 1;
576 }
577 else if (unformat (input, "translate 2-1 dot1ad %d", &tag1))
578 {
579 vtr_op = L2_VTR_TRANSLATE_2_1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700580
Dave Barach97d8dc22016-08-15 15:31:15 -0400581 }
582 else if (unformat (input, "translate 2-2 dot1q %d %d", &tag1, &tag2))
583 {
584 vtr_op = L2_VTR_TRANSLATE_2_2;
585 push_dot1q = 1;
586 }
587 else if (unformat (input, "translate 2-2 dot1ad %d %d", &tag1, &tag2))
588 {
589 vtr_op = L2_VTR_TRANSLATE_2_2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700590
Dave Barach97d8dc22016-08-15 15:31:15 -0400591 }
592 else if (unformat (input, "translate 1-2 dot1q %d %d", &tag1, &tag2))
593 {
594 vtr_op = L2_VTR_TRANSLATE_1_2;
595 push_dot1q = 1;
596 }
597 else if (unformat (input, "translate 1-2 dot1ad %d %d", &tag1, &tag2))
598 {
599 vtr_op = L2_VTR_TRANSLATE_1_2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700600
Dave Barach97d8dc22016-08-15 15:31:15 -0400601 }
602 else
603 {
604 error =
605 clib_error_return (0,
606 "expecting [disable | pop 1 | pop 2 | push {dot1q|dot1ah} <tag> [<tag>]\n"
607 " | translate {1|2}-{1|2} {dot1q|dot1ah} <tag> [<tag>]] but got `%U'",
608 format_unformat_error, input);
609 goto done;
610 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700611
Dave Barach97d8dc22016-08-15 15:31:15 -0400612 if (l2vtr_configure (vm, vnm, sw_if_index, vtr_op, push_dot1q, tag1, tag2))
613 {
614 error =
615 clib_error_return (0,
616 "vlan tag rewrite is not compatible with interface");
617 goto done;
618 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700619
Dave Barach97d8dc22016-08-15 15:31:15 -0400620done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700621 return error;
622}
623
Billy McFall22aa3e92016-09-09 08:46:40 -0400624/*?
625 * VLAN tag rewrite provides the ability to change the VLAN tags on a packet.
626 * Existing tags can be popped, new tags can be pushed, and existing tags can
627 * be swapped with new tags. The rewrite feature is attached to a subinterface
628 * as input and output operations. The input operation is explicitly configured.
629 * The output operation is the symmetric opposite and is automatically derived
630 * from the input operation.
631 *
632 * <b>POP:</b> For pop operations, the subinterface encapsulation (the vlan
633 * tags specified when it was created) must have at least the number of popped
634 * tags. e.g. the \"pop 2\" operation would be rejected on a single-vlan interface.
635 * The output tag-rewrite operation for pops is to push the specified number of
636 * vlan tags onto the packet. The pushed tag values are the ones in the
637 * subinterface encapsulation.
638 *
639 * <b>PUSH:</b> For push operations, the ethertype is also specified. The
640 * output tag-rewrite operation for pushes is to pop the same number of tags
641 * off the packet. If the packet doesn't have enough tags it is dropped.
642 *
643 *
644 * @cliexpar
645 * @parblock
646 * By default a subinterface has no tag-rewrite. To return a subinterface to
647 * this state use:
648 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 disable}
649 *
650 * To pop vlan tags off packets received from a subinterface, use:
651 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 1}
652 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 2}
653 *
654 * To push one or two vlan tags onto packets received from an interface, use:
655 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1q 100}
656 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1ad 100 150}
657 *
658 * Tags can also be translated, which is basically a combination of a pop and push.
659 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-1 dot1ad 100}
660 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-2 dot1ad 100 150}
661 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-2 dot1q 100}
662 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-1 dot1q 100 150}
663 *
664 * To display the VLAN Tag settings, show the associate bridge-domain:
665 * @cliexstart{show bridge-domain 200 detail}
666 * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf
667 * 200 1 on on on on off N/A
668 *
669 * Interface Index SHG BVI VLAN-Tag-Rewrite
670 * GigabitEthernet0/8/0.200 5 0 - trans-1-1 dot1ad 100
671 * GigabitEthernet0/9/0.200 4 0 - none
672 * GigabitEthernet0/a/0.200 6 0 - none
673 * @cliexend
674 * @endparblock
675?*/
Dave Barach97d8dc22016-08-15 15:31:15 -0400676/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677VLIB_CLI_COMMAND (int_l2_vtr_cli, static) = {
678 .path = "set interface l2 tag-rewrite",
679 .short_help = "set interface l2 tag-rewrite <interface> [disable | pop {1|2} | push {dot1q|dot1ad} <tag> <tag>]",
680 .function = int_l2_vtr,
681};
Dave Barach97d8dc22016-08-15 15:31:15 -0400682/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683
Pavel Kotucek95300d12016-08-26 16:11:36 +0200684/**
Pavel Kotucek65e84572017-01-16 17:01:56 +0100685 * Get pbb tag rewrite on the given interface.
686 * Return 1 if there is an error, 0 if ok
687 */
688u32
689l2pbb_get (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index,
Gabriel Gannef7f2a9f2017-03-06 15:19:40 +0100690 u32 * vtr_op, u16 * outer_tag, ethernet_header_t * eth_hdr,
Pavel Kotucek65e84572017-01-16 17:01:56 +0100691 u16 * b_vlanid, u32 * i_sid)
692{
693 u32 error = 1;
694 ptr_config_t *in_config;
695
696 if (!vtr_op || !outer_tag || !b_vlanid || !i_sid)
697 {
698 clib_warning ("invalid arguments");
699 error = VNET_API_ERROR_INVALID_ARGUMENT;
700 goto done;
701 }
702
703 *vtr_op = L2_VTR_DISABLED;
704 *outer_tag = 0;
Pavel Kotucek65e84572017-01-16 17:01:56 +0100705 *b_vlanid = 0;
706 *i_sid = 0;
707
708 if (sw_if_index >= vec_len (l2output_main.configs))
709 {
710 /* no specific config (return disabled) */
711 goto done;
712 }
713
714 /* Get the config for this interface */
715 in_config =
716 &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_pbb_vtr);
717
718 if (in_config->push_and_pop_bytes == 0)
719 {
720 /* DISABLED */
721 goto done;
722 }
723 else
724 {
725 if (in_config->pop_bytes && in_config->push_bytes)
726 *vtr_op = L2_VTR_TRANSLATE_2_1;
727 else if (in_config->pop_bytes)
728 *vtr_op = L2_VTR_POP_2;
729 else if (in_config->push_bytes)
730 *vtr_op = L2_VTR_PUSH_2;
731
Gabriel Gannef7f2a9f2017-03-06 15:19:40 +0100732 clib_memcpy (&eth_hdr->dst_address, in_config->macs_tags.b_dst_address,
733 sizeof (eth_hdr->dst_address));
734 clib_memcpy (&eth_hdr->src_address, in_config->macs_tags.b_src_address,
735 sizeof (eth_hdr->src_address));
Pavel Kotucek65e84572017-01-16 17:01:56 +0100736
737 *b_vlanid =
738 clib_host_to_net_u16 (in_config->macs_tags.priority_dei_id) & 0xFFF;
739 *i_sid =
Gabriel Gannef7f2a9f2017-03-06 15:19:40 +0100740 clib_host_to_net_u32 (in_config->macs_tags.
741 priority_dei_uca_res_sid) & 0xFFFFF;
Pavel Kotucek65e84572017-01-16 17:01:56 +0100742 error = 0;
743 }
744done:
745 return error;
746}
747
748/**
Pavel Kotucek95300d12016-08-26 16:11:36 +0200749 * Set subinterface pbb vtr enable/disable.
750 * The CLI format is:
751 * 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>]]
752 */
753static clib_error_t *
754int_l2_pbb_vtr (vlib_main_t * vm,
755 unformat_input_t * input, vlib_cli_command_t * cmd)
756{
757 vnet_main_t *vnm = vnet_get_main ();
758 clib_error_t *error = 0;
759 u32 sw_if_index, tmp;
760 u32 vtr_op = L2_VTR_DISABLED;
761 u32 outer_tag = 0;
762 u8 dmac[6];
763 u8 smac[6];
764 u8 dmac_set = 0, smac_set = 0;
765 u16 b_vlanid = 0;
766 u32 s_id = ~0;
767
768 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
769 {
770 if (unformat_user
771 (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
772 ;
773 else if (unformat (input, "disable"))
774 vtr_op = L2_VTR_DISABLED;
775 else if (vtr_op == L2_VTR_DISABLED && unformat (input, "pop"))
776 vtr_op = L2_VTR_POP_2;
777 else if (vtr_op == L2_VTR_DISABLED && unformat (input, "push"))
778 vtr_op = L2_VTR_PUSH_2;
779 else if (vtr_op == L2_VTR_DISABLED
780 && unformat (input, "translate_pbb_stag %d", &outer_tag))
781 vtr_op = L2_VTR_TRANSLATE_2_1;
782 else if (unformat (input, "dmac %U", unformat_ethernet_address, dmac))
783 dmac_set = 1;
784 else if (unformat (input, "smac %U", unformat_ethernet_address, smac))
785 smac_set = 1;
786 else if (unformat (input, "b_vlanid %d", &tmp))
787 b_vlanid = tmp;
788 else if (unformat (input, "s_id %d", &s_id))
789 ;
790 else
791 {
792 error = clib_error_return (0,
793 "expecting [disable | pop | push | translate_pbb_stag <outer_tag>\n"
794 "dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]");
795 goto done;
796 }
797 }
798
799 if ((vtr_op == L2_VTR_PUSH_2 || vtr_op == L2_VTR_TRANSLATE_2_1)
800 && (!dmac_set || !smac_set || s_id == ~0))
801 {
802 error = clib_error_return (0,
803 "expecting dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]");
804 goto done;
805 }
806
807 if (l2pbb_configure
808 (vm, vnm, sw_if_index, vtr_op, dmac, smac, b_vlanid, s_id, outer_tag))
809 {
810 error =
811 clib_error_return (0,
812 "pbb tag rewrite is not compatible with interface");
813 goto done;
814 }
815
816done:
817 return error;
818}
819
820/* *INDENT-OFF* */
821VLIB_CLI_COMMAND (int_l2_pbb_vtr_cli, static) = {
822 .path = "set interface l2 pbb-tag-rewrite",
823 .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>]]",
824 .function = int_l2_pbb_vtr,
825};
826/* *INDENT-ON* */
Dave Barach97d8dc22016-08-15 15:31:15 -0400827
828/*
829 * fd.io coding-style-patch-verification: ON
830 *
831 * Local Variables:
832 * eval: (c-set-style "gnu")
833 * End:
834 */