summaryrefslogtreecommitdiffstats
path: root/vnet
diff options
context:
space:
mode:
authorPavel Kotucek <pkotucek@cisco.com>2016-08-26 16:11:36 +0200
committerJohn Lo <loj@cisco.com>2016-10-04 17:15:16 +0000
commit95300d19152877dca8dfbd574dc6da50620125e8 (patch)
treee645d4dd4a83c37f7b407042132ebf4fbaf0582c /vnet
parentac09280947dcf035f51cb394b88de3c7b66a6320 (diff)
VPP-355: add PBB (802.1ah) tag rewrite
- new API/CLI to define pbb tag rewrite on interface - encapsulation/decapsulation of PBB tags - tracing of PBB header - PBB tag rewrite operations Change-Id: I538b3025a8b2e41cdeed9f10fea94bbcd28b5f5f Signed-off-by: Pavel Kotucek <pkotucek@cisco.com>
Diffstat (limited to 'vnet')
-rw-r--r--vnet/vnet/ethernet/format.c87
-rw-r--r--vnet/vnet/ethernet/packet.h39
-rw-r--r--vnet/vnet/ethernet/types.def1
-rw-r--r--vnet/vnet/l2/l2_input_vtr.c99
-rw-r--r--vnet/vnet/l2/l2_output.c143
-rw-r--r--vnet/vnet/l2/l2_output.h5
-rw-r--r--vnet/vnet/l2/l2_vtr.c165
-rw-r--r--vnet/vnet/l2/l2_vtr.h67
8 files changed, 503 insertions, 103 deletions
diff --git a/vnet/vnet/ethernet/format.c b/vnet/vnet/ethernet/format.c
index 1b6712773e9..4edef5adbeb 100644
--- a/vnet/vnet/ethernet/format.c
+++ b/vnet/vnet/ethernet/format.c
@@ -88,9 +88,35 @@ format_ethernet_vlan_tci (u8 * s, va_list * va)
}
u8 *
+format_ethernet_pbb (u8 * s, va_list * va)
+{
+ u32 b_tag = va_arg (*va, u32);
+ u32 i_tag = va_arg (*va, u32);
+ u32 vid = (b_tag & 0xfff);
+ u32 bdei = (b_tag >> 12) & 1;
+ u32 bpcp = (b_tag >> 13);
+ u32 sid = (i_tag & 0xffffff);
+ u8 ires = (i_tag >> 24) & 3;
+ u8 iuca = (i_tag >> 27) & 1;
+ u8 idei = (i_tag >> 28) & 1;
+ u8 ipcp = (i_tag >> 29);
+
+ s =
+ format (s, "B_tag %04X (vid %d, dei %d, pcp %d), ", b_tag, vid, bdei,
+ bpcp);
+ s =
+ format (s, "I_tag %08X (sid %d, res %d, dei %d, pcp %d)", i_tag, sid,
+ ires, iuca, idei, ipcp);
+
+ return s;
+}
+
+u8 *
format_ethernet_header_with_length (u8 * s, va_list * args)
{
- ethernet_max_header_t *m = va_arg (*args, ethernet_max_header_t *);
+ ethernet_pbb_header_packed_t *ph =
+ va_arg (*args, ethernet_pbb_header_packed_t *);
+ ethernet_max_header_t *m = (ethernet_max_header_t *) ph;
u32 max_header_bytes = va_arg (*args, u32);
ethernet_main_t *em = &ethernet_main;
ethernet_header_t *e = &m->ethernet;
@@ -100,12 +126,15 @@ format_ethernet_header_with_length (u8 * s, va_list * args)
u32 n_vlan = 0, i, header_bytes;
uword indent;
- while ((type == ETHERNET_TYPE_VLAN || type == ETHERNET_TYPE_DOT1AD)
- && n_vlan < ARRAY_LEN (m->vlan))
+ while ((type == ETHERNET_TYPE_VLAN || type == ETHERNET_TYPE_DOT1AD
+ || type == ETHERNET_TYPE_DOT1AH) && n_vlan < ARRAY_LEN (m->vlan))
{
vlan_type[n_vlan] = type;
- v = m->vlan + n_vlan;
- type = clib_net_to_host_u16 (v->type);
+ if (type != ETHERNET_TYPE_DOT1AH)
+ {
+ v = m->vlan + n_vlan;
+ type = clib_net_to_host_u16 (v->type);
+ }
n_vlan++;
}
@@ -120,28 +149,38 @@ format_ethernet_header_with_length (u8 * s, va_list * args)
format_ethernet_address, e->src_address,
format_ethernet_address, e->dst_address);
- for (i = 0; i < n_vlan; i++)
+ if (type != ETHERNET_TYPE_DOT1AH)
{
- u32 v = clib_net_to_host_u16 (m->vlan[i].priority_cfi_and_id);
- if (*vlan_type == ETHERNET_TYPE_VLAN)
- s = format (s, " 802.1q vlan %U", format_ethernet_vlan_tci, v);
- else
- s = format (s, " 802.1ad vlan %U", format_ethernet_vlan_tci, v);
- }
+ for (i = 0; i < n_vlan; i++)
+ {
+ u32 v = clib_net_to_host_u16 (m->vlan[i].priority_cfi_and_id);
+ if (*vlan_type == ETHERNET_TYPE_VLAN)
+ s = format (s, " 802.1q vlan %U", format_ethernet_vlan_tci, v);
+ else
+ s = format (s, " 802.1ad vlan %U", format_ethernet_vlan_tci, v);
+ }
- if (max_header_bytes != 0 && header_bytes < max_header_bytes)
+ if (max_header_bytes != 0 && header_bytes < max_header_bytes)
+ {
+ ethernet_type_info_t *ti;
+ vlib_node_t *node = 0;
+
+ ti = ethernet_get_type_info (em, type);
+ if (ti && ti->node_index != ~0)
+ node = vlib_get_node (em->vlib_main, ti->node_index);
+ if (node && node->format_buffer)
+ s = format (s, "\n%U%U",
+ format_white_space, indent,
+ node->format_buffer, (void *) m + header_bytes,
+ max_header_bytes - header_bytes);
+ }
+ }
+ else
{
- ethernet_type_info_t *ti;
- vlib_node_t *node = 0;
-
- ti = ethernet_get_type_info (em, type);
- if (ti && ti->node_index != ~0)
- node = vlib_get_node (em->vlib_main, ti->node_index);
- if (node && node->format_buffer)
- s = format (s, "\n%U%U",
- format_white_space, indent,
- node->format_buffer, (void *) m + header_bytes,
- max_header_bytes - header_bytes);
+ s = format (s, "\n%UPBB header : %U", format_white_space, indent,
+ format_ethernet_pbb,
+ clib_net_to_host_u16 (ph->priority_dei_id),
+ clib_net_to_host_u32 (ph->priority_dei_uca_res_sid));
}
return s;
diff --git a/vnet/vnet/ethernet/packet.h b/vnet/vnet/ethernet/packet.h
index b50f9303f23..964cf638101 100644
--- a/vnet/vnet/ethernet/packet.h
+++ b/vnet/vnet/ethernet/packet.h
@@ -102,6 +102,45 @@ typedef struct
u16 priority_cfi_and_id;
} ethernet_vlan_header_tv_t;
+/* PBB header with B-TAG - backbone VLAN indicator and I-TAG - service encapsulation */
+typedef struct
+{
+ /* Backbone source/destination address. */
+ u8 b_dst_address[6];
+ u8 b_src_address[6];
+
+ /* B-tag */
+ u16 b_type;
+ /* 3 bit priority, 1 bit DEI and 12 bit vlan id */
+ u16 priority_dei_id;
+
+ /* I-tag */
+ u16 i_type;
+ /* 3 bit priority, 1 bit DEI, 1 bit UCA, 3 bit RES and 24 bit I_SID (service identifier) */
+ u32 priority_dei_uca_res_sid;
+
+#define ETHERNET_N_PBB (1 << 24)
+} ethernet_pbb_header_t;
+
+/* *INDENT-OFF* */
+typedef CLIB_PACKED (struct
+{
+ /* Backbone source/destination address. */
+ u8 b_dst_address[6];
+ u8 b_src_address[6];
+
+ /* B-tag */
+ u16 b_type;
+ /* 3 bit priority, 1 bit DEI and 12 bit vlan id */
+ u16 priority_dei_id;
+
+ /* I-tag */
+ u16 i_type;
+ /* 3 bit priority, 1 bit DEI, 1 bit UCA, 3 bit RES and 24 bit I_SID (service identifier) */
+ u32 priority_dei_uca_res_sid;
+}) ethernet_pbb_header_packed_t;
+/* *INDENT-ON* */
+
#endif /* included_ethernet_packet_h */
/*
diff --git a/vnet/vnet/ethernet/types.def b/vnet/vnet/ethernet/types.def
index 37c97f62cdb..643f3152a85 100644
--- a/vnet/vnet/ethernet/types.def
+++ b/vnet/vnet/ethernet/types.def
@@ -101,6 +101,7 @@ ethernet_type (0x88AE, BRDWALK)
ethernet_type (0x88B7, 802_OUI_EXTENDED)
ethernet_type (0x88c7, 802_11I_PRE_AUTHENTICATION)
ethernet_type (0x88cc, 802_1_LLDP)
+ethernet_type (0x88e7, DOT1AH)
ethernet_type (0x894f, VPATH_3)
ethernet_type (0x9000, LOOPBACK)
ethernet_type (0x9021, RTNET_MAC)
diff --git a/vnet/vnet/l2/l2_input_vtr.c b/vnet/vnet/l2/l2_input_vtr.c
index 47b12115071..60a39631e87 100644
--- a/vnet/vnet/l2/l2_input_vtr.c
+++ b/vnet/vnet/l2/l2_input_vtr.c
@@ -178,24 +178,59 @@ l2_invtr_node_fn (vlib_main_t * vm,
next1 = feat_bitmap_get_next_node_index (msm->feat_next_node_index,
feature_bitmap1);
- /* perform the tag rewrite on two packets */
- if (l2_vtr_process
- (b0,
- &(vec_elt_at_index
- (l2output_main.configs, sw_if_index0)->input_vtr)))
+ l2_output_config_t *config0;
+ l2_output_config_t *config1;
+ config0 = vec_elt_at_index (l2output_main.configs, sw_if_index0);
+ config1 = vec_elt_at_index (l2output_main.configs, sw_if_index1);
+
+ if (PREDICT_FALSE (config0->out_vtr_flag))
{
- /* Drop packet */
- next0 = L2_INVTR_NEXT_DROP;
- b0->error = node->errors[L2_INVTR_ERROR_DROP];
+ if (config0->output_vtr.push_and_pop_bytes)
+ {
+ /* perform the tag rewrite on two packets */
+ if (l2_vtr_process
+ (b0,
+ &(vec_elt_at_index
+ (l2output_main.configs, sw_if_index0)->input_vtr)))
+ {
+ /* Drop packet */
+ next0 = L2_INVTR_NEXT_DROP;
+ b0->error = node->errors[L2_INVTR_ERROR_DROP];
+ }
+ }
+ else if (config0->output_pbb_vtr.push_and_pop_bytes)
+ {
+ if (l2_pbb_process (b0, &(config0->input_pbb_vtr)))
+ {
+ /* Drop packet */
+ next0 = L2_INVTR_NEXT_DROP;
+ b0->error = node->errors[L2_INVTR_ERROR_DROP];
+ }
+ }
}
- if (l2_vtr_process
- (b1,
- &(vec_elt_at_index
- (l2output_main.configs, sw_if_index1)->input_vtr)))
+ if (PREDICT_FALSE (config1->out_vtr_flag))
{
- /* Drop packet */
- next1 = L2_INVTR_NEXT_DROP;
- b1->error = node->errors[L2_INVTR_ERROR_DROP];
+ if (config1->output_vtr.push_and_pop_bytes)
+ {
+ if (l2_vtr_process
+ (b1,
+ &(vec_elt_at_index
+ (l2output_main.configs, sw_if_index1)->input_vtr)))
+ {
+ /* Drop packet */
+ next1 = L2_INVTR_NEXT_DROP;
+ b1->error = node->errors[L2_INVTR_ERROR_DROP];
+ }
+ }
+ else if (config1->output_pbb_vtr.push_and_pop_bytes)
+ {
+ if (l2_pbb_process (b1, &(config1->input_pbb_vtr)))
+ {
+ /* Drop packet */
+ next1 = L2_INVTR_NEXT_DROP;
+ b1->error = node->errors[L2_INVTR_ERROR_DROP];
+ }
+ }
}
if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
@@ -262,15 +297,33 @@ l2_invtr_node_fn (vlib_main_t * vm,
next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index,
feature_bitmap0);
- /* perform the tag rewrite on one packet */
- if (l2_vtr_process
- (b0,
- &(vec_elt_at_index
- (l2output_main.configs, sw_if_index0)->input_vtr)))
+ l2_output_config_t *config0;
+ config0 = vec_elt_at_index (l2output_main.configs, sw_if_index0);
+
+ if (PREDICT_FALSE (config0->out_vtr_flag))
{
- /* Drop packet */
- next0 = L2_INVTR_NEXT_DROP;
- b0->error = node->errors[L2_INVTR_ERROR_DROP];
+ if (config0->output_vtr.push_and_pop_bytes)
+ {
+ /* perform the tag rewrite on one packet */
+ if (l2_vtr_process
+ (b0,
+ &(vec_elt_at_index
+ (l2output_main.configs, sw_if_index0)->input_vtr)))
+ {
+ /* Drop packet */
+ next0 = L2_INVTR_NEXT_DROP;
+ b0->error = node->errors[L2_INVTR_ERROR_DROP];
+ }
+ }
+ else if (config0->output_pbb_vtr.push_and_pop_bytes)
+ {
+ if (l2_pbb_process (b0, &(config0->input_pbb_vtr)))
+ {
+ /* Drop packet */
+ next0 = L2_INVTR_NEXT_DROP;
+ b0->error = node->errors[L2_INVTR_ERROR_DROP];
+ }
+ }
}
if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
diff --git a/vnet/vnet/l2/l2_output.c b/vnet/vnet/l2/l2_output.c
index f03796ebf76..b84501aa691 100644
--- a/vnet/vnet/l2/l2_output.c
+++ b/vnet/vnet/l2/l2_output.c
@@ -232,51 +232,77 @@ l2output_node_fn (vlib_main_t * vm,
&msm->next_nodes,
b1, sw_if_index1, feature_bitmap1, &next1);
- /*
- * Perform output vlan tag rewrite and the pre-vtr EFP filter check.
- * The EFP Filter only needs to be run if there is an output VTR
- * configured. The flag for the post-vtr EFP Filter node is used
- * to trigger the pre-vtr check as well.
- */
-
- if (PREDICT_FALSE (config0->output_vtr.push_and_pop_bytes))
+ if (PREDICT_FALSE (config0->out_vtr_flag))
{
/* Perform pre-vtr EFP filter check if configured */
- u32 failed1 = (feature_bitmap0 & L2OUTPUT_FEAT_EFP_FILTER) &&
- (l2_efp_filter_process (b0, &(config0->input_vtr)));
- u32 failed2 = l2_vtr_process (b0, &(config0->output_vtr));
-
- if (PREDICT_FALSE (failed1 | failed2))
+ if (config0->output_vtr.push_and_pop_bytes)
{
- next0 = L2OUTPUT_NEXT_DROP;
- if (failed2)
+ /*
+ * Perform output vlan tag rewrite and the pre-vtr EFP filter check.
+ * The EFP Filter only needs to be run if there is an output VTR
+ * configured. The flag for the post-vtr EFP Filter node is used
+ * to trigger the pre-vtr check as well.
+ */
+ u32 failed1 = (feature_bitmap0 & L2OUTPUT_FEAT_EFP_FILTER)
+ && (l2_efp_filter_process (b0, &(config0->input_vtr)));
+ u32 failed2 = l2_vtr_process (b0, &(config0->output_vtr));
+
+ if (PREDICT_FALSE (failed1 | failed2))
{
- b0->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
+ next0 = L2OUTPUT_NEXT_DROP;
+ if (failed2)
+ {
+ b0->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
+ }
+ if (failed1)
+ {
+ b0->error = node->errors[L2OUTPUT_ERROR_EFP_DROP];
+ }
}
- if (failed1)
+ }
+ // perform the PBB rewrite
+ else if (config0->output_pbb_vtr.push_and_pop_bytes)
+ {
+ u32 failed =
+ l2_pbb_process (b0, &(config0->output_pbb_vtr));
+ if (PREDICT_FALSE (failed))
{
- b0->error = node->errors[L2OUTPUT_ERROR_EFP_DROP];
+ next0 = L2OUTPUT_NEXT_DROP;
+ b0->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
}
}
}
-
- if (PREDICT_FALSE (config1->output_vtr.push_and_pop_bytes))
+ if (PREDICT_FALSE (config1->out_vtr_flag))
{
/* Perform pre-vtr EFP filter check if configured */
- u32 failed1 = (feature_bitmap1 & L2OUTPUT_FEAT_EFP_FILTER) &&
- (l2_efp_filter_process (b1, &(config1->input_vtr)));
- u32 failed2 = l2_vtr_process (b1, &(config1->output_vtr));
-
- if (PREDICT_FALSE (failed1 | failed2))
+ if (config1->output_vtr.push_and_pop_bytes)
{
- next1 = L2OUTPUT_NEXT_DROP;
- if (failed2)
+ u32 failed1 = (feature_bitmap1 & L2OUTPUT_FEAT_EFP_FILTER)
+ && (l2_efp_filter_process (b1, &(config1->input_vtr)));
+ u32 failed2 = l2_vtr_process (b1, &(config1->output_vtr));
+
+ if (PREDICT_FALSE (failed1 | failed2))
{
- b1->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
+ next1 = L2OUTPUT_NEXT_DROP;
+ if (failed2)
+ {
+ b1->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
+ }
+ if (failed1)
+ {
+ b1->error = node->errors[L2OUTPUT_ERROR_EFP_DROP];
+ }
}
- if (failed1)
+ }
+ // perform the PBB rewrite
+ else if (config1->output_pbb_vtr.push_and_pop_bytes)
+ {
+ u32 failed =
+ l2_pbb_process (b0, &(config1->output_pbb_vtr));
+ if (PREDICT_FALSE (failed))
{
- b1->error = node->errors[L2OUTPUT_ERROR_EFP_DROP];
+ next1 = L2OUTPUT_NEXT_DROP;
+ b1->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
}
}
}
@@ -342,8 +368,8 @@ l2output_node_fn (vlib_main_t * vm,
clib_memcpy (t->dst, h0->dst_address, 6);
}
- em->counters[node_counter_base_index + L2OUTPUT_ERROR_L2OUTPUT] +=
- 1;
+ em->counters[node_counter_base_index +
+ L2OUTPUT_ERROR_L2OUTPUT] += 1;
/* Get config for the output interface */
config0 = vec_elt_at_index (msm->configs, sw_if_index0);
@@ -364,34 +390,47 @@ l2output_node_fn (vlib_main_t * vm,
&msm->next_nodes,
b0, sw_if_index0, feature_bitmap0, &next0);
- /*
- * Perform output vlan tag rewrite and the pre-vtr EFP filter check.
- * The EFP Filter only needs to be run if there is an output VTR
- * configured. The flag for the post-vtr EFP Filter node is used
- * to trigger the pre-vtr check as well.
- */
-
- if (config0->output_vtr.push_and_pop_bytes)
+ if (PREDICT_FALSE (config0->out_vtr_flag))
{
- /* Perform pre-vtr EFP filter check if configured */
- u32 failed1 = (feature_bitmap0 & L2OUTPUT_FEAT_EFP_FILTER) &&
- (l2_efp_filter_process (b0, &(config0->input_vtr)));
- u32 failed2 = l2_vtr_process (b0, &(config0->output_vtr));
-
- if (PREDICT_FALSE (failed1 | failed2))
+ /*
+ * Perform output vlan tag rewrite and the pre-vtr EFP filter check.
+ * The EFP Filter only needs to be run if there is an output VTR
+ * configured. The flag for the post-vtr EFP Filter node is used
+ * to trigger the pre-vtr check as well.
+ */
+
+ if (config0->output_vtr.push_and_pop_bytes)
{
- next0 = L2OUTPUT_NEXT_DROP;
- if (failed2)
+ /* Perform pre-vtr EFP filter check if configured */
+ u32 failed1 = (feature_bitmap0 & L2OUTPUT_FEAT_EFP_FILTER)
+ && (l2_efp_filter_process (b0, &(config0->input_vtr)));
+ u32 failed2 = l2_vtr_process (b0, &(config0->output_vtr));
+
+ if (PREDICT_FALSE (failed1 | failed2))
{
- b0->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
+ next0 = L2OUTPUT_NEXT_DROP;
+ if (failed2)
+ {
+ b0->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
+ }
+ if (failed1)
+ {
+ b0->error = node->errors[L2OUTPUT_ERROR_EFP_DROP];
+ }
}
- if (failed1)
+ }
+ // perform the PBB rewrite
+ else if (config0->output_pbb_vtr.push_and_pop_bytes)
+ {
+ u32 failed =
+ l2_pbb_process (b0, &(config0->output_pbb_vtr));
+ if (PREDICT_FALSE (failed))
{
- b0->error = node->errors[L2OUTPUT_ERROR_EFP_DROP];
+ next0 = L2OUTPUT_NEXT_DROP;
+ b0->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
}
}
}
-
/* Perform the split horizon check */
if (PREDICT_FALSE
(split_horizon_violation
diff --git a/vnet/vnet/l2/l2_output.h b/vnet/vnet/l2/l2_output.h
index 6a846f377ba..2e049148951 100644
--- a/vnet/vnet/l2/l2_output.h
+++ b/vnet/vnet/l2/l2_output.h
@@ -37,6 +37,8 @@ typedef struct
*/
vtr_config_t input_vtr;
vtr_config_t output_vtr;
+ ptr_config_t input_pbb_vtr;
+ ptr_config_t output_pbb_vtr;
/* some of these flags may get integrated into the feature bitmap */
u8 fwd_enable;
@@ -45,6 +47,9 @@ typedef struct
/* split horizon group */
u8 shg;
+ /* flag for output vtr operation */
+ u8 out_vtr_flag;
+
} l2_output_config_t;
diff --git a/vnet/vnet/l2/l2_vtr.c b/vnet/vnet/l2/l2_vtr.c
index 9cb0a7e9da3..95a4f15700a 100644
--- a/vnet/vnet/l2/l2_vtr.c
+++ b/vnet/vnet/l2/l2_vtr.c
@@ -50,6 +50,83 @@ l2_vtr_init (vlib_main_t * vm)
VLIB_INIT_FUNCTION (l2_vtr_init);
+u32
+l2pbb_configure (vlib_main_t * vlib_main,
+ vnet_main_t * vnet_main, u32 sw_if_index, u32 vtr_op,
+ u8 * b_dmac, u8 * b_smac,
+ u16 b_vlanid, u32 i_sid, u16 vlan_outer_tag)
+{
+ u32 error = 0;
+ u32 enable = 0;
+
+ l2_output_config_t *config = 0;
+ vnet_hw_interface_t *hi;
+ hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
+
+ if (!hi)
+ {
+ error = VNET_API_ERROR_INVALID_INTERFACE;
+ goto done;
+ }
+
+ // Config for this interface should be already initialized
+ ptr_config_t *in_config;
+ ptr_config_t *out_config;
+ config = vec_elt_at_index (l2output_main.configs, sw_if_index);
+ in_config = &(config->input_pbb_vtr);
+ out_config = &(config->output_pbb_vtr);
+
+ in_config->pop_bytes = 0;
+ in_config->push_bytes = 0;
+ out_config->pop_bytes = 0;
+ out_config->push_bytes = 0;
+ enable = (vtr_op != L2_VTR_DISABLED);
+
+ if (!enable)
+ goto done;
+
+ if (vtr_op == L2_VTR_POP_2)
+ {
+ in_config->pop_bytes = sizeof (ethernet_pbb_header_packed_t);
+ }
+ else if (vtr_op == L2_VTR_PUSH_2)
+ {
+ clib_memcpy (in_config->macs_tags.b_dst_address, b_dmac,
+ sizeof (in_config->macs_tags.b_dst_address));
+ clib_memcpy (in_config->macs_tags.b_src_address, b_smac,
+ sizeof (in_config->macs_tags.b_src_address));
+ in_config->macs_tags.b_type =
+ clib_net_to_host_u16 (ETHERNET_TYPE_DOT1AD);
+ in_config->macs_tags.priority_dei_id =
+ clib_net_to_host_u16 (b_vlanid & 0xFFF);
+ in_config->macs_tags.i_type =
+ clib_net_to_host_u16 (ETHERNET_TYPE_DOT1AH);
+ in_config->macs_tags.priority_dei_uca_res_sid =
+ clib_net_to_host_u32 (i_sid & 0xFFFFF);
+ in_config->push_bytes = sizeof (ethernet_pbb_header_packed_t);
+ }
+ else if (vtr_op == L2_VTR_TRANSLATE_2_2)
+ {
+ /* TODO after PoC */
+ }
+
+ /*
+ * Construct the output tag-rewrite config
+ *
+ * The push/pop values are always reversed
+ */
+ out_config->raw_data = in_config->raw_data;
+ out_config->pop_bytes = in_config->push_bytes;
+ out_config->push_bytes = in_config->pop_bytes;
+
+done:
+ l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
+ if (config)
+ config->out_vtr_flag = (u8) enable;
+
+ /* output vtr enable is checked explicitly in l2_output */
+ return error;
+}
/**
* Configure vtag tag rewrite on the given interface.
@@ -64,6 +141,7 @@ l2vtr_configure (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_ind
vnet_sw_interface_t *si;
u32 hw_no_tags;
u32 error = 0;
+ l2_output_config_t *config;
vtr_config_t *in_config;
vtr_config_t *out_config;
u32 enable;
@@ -80,10 +158,9 @@ l2vtr_configure (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_ind
/* Init the config for this interface */
vec_validate (l2output_main.configs, sw_if_index);
- in_config =
- &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_vtr);
- out_config =
- &(vec_elt_at_index (l2output_main.configs, sw_if_index)->output_vtr);
+ config = vec_elt_at_index (l2output_main.configs, sw_if_index);
+ in_config = &(config->input_vtr);
+ out_config = &(config->output_vtr);
in_config->raw_tags = 0;
out_config->raw_tags = 0;
@@ -257,6 +334,7 @@ l2vtr_configure (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_ind
/* set the interface enable flags */
enable = (vtr_op != L2_VTR_DISABLED);
+ config->out_vtr_flag = (u8) enable;
l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
/* output vtr enable is checked explicitly in l2_output */
@@ -603,6 +681,85 @@ VLIB_CLI_COMMAND (int_l2_vtr_cli, static) = {
};
/* *INDENT-ON* */
+/**
+ * Set subinterface pbb vtr enable/disable.
+ * The CLI format is:
+ * 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>]]
+ */
+static clib_error_t *
+int_l2_pbb_vtr (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ clib_error_t *error = 0;
+ u32 sw_if_index, tmp;
+ u32 vtr_op = L2_VTR_DISABLED;
+ u32 outer_tag = 0;
+ u8 dmac[6];
+ u8 smac[6];
+ u8 dmac_set = 0, smac_set = 0;
+ u16 b_vlanid = 0;
+ u32 s_id = ~0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat_user
+ (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
+ ;
+ else if (unformat (input, "disable"))
+ vtr_op = L2_VTR_DISABLED;
+ else if (vtr_op == L2_VTR_DISABLED && unformat (input, "pop"))
+ vtr_op = L2_VTR_POP_2;
+ else if (vtr_op == L2_VTR_DISABLED && unformat (input, "push"))
+ vtr_op = L2_VTR_PUSH_2;
+ else if (vtr_op == L2_VTR_DISABLED
+ && unformat (input, "translate_pbb_stag %d", &outer_tag))
+ vtr_op = L2_VTR_TRANSLATE_2_1;
+ else if (unformat (input, "dmac %U", unformat_ethernet_address, dmac))
+ dmac_set = 1;
+ else if (unformat (input, "smac %U", unformat_ethernet_address, smac))
+ smac_set = 1;
+ else if (unformat (input, "b_vlanid %d", &tmp))
+ b_vlanid = tmp;
+ else if (unformat (input, "s_id %d", &s_id))
+ ;
+ else
+ {
+ error = clib_error_return (0,
+ "expecting [disable | pop | push | translate_pbb_stag <outer_tag>\n"
+ "dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]");
+ goto done;
+ }
+ }
+
+ if ((vtr_op == L2_VTR_PUSH_2 || vtr_op == L2_VTR_TRANSLATE_2_1)
+ && (!dmac_set || !smac_set || s_id == ~0))
+ {
+ error = clib_error_return (0,
+ "expecting dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]");
+ goto done;
+ }
+
+ if (l2pbb_configure
+ (vm, vnm, sw_if_index, vtr_op, dmac, smac, b_vlanid, s_id, outer_tag))
+ {
+ error =
+ clib_error_return (0,
+ "pbb tag rewrite is not compatible with interface");
+ goto done;
+ }
+
+done:
+ return error;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (int_l2_pbb_vtr_cli, static) = {
+ .path = "set interface l2 pbb-tag-rewrite",
+ .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>]]",
+ .function = int_l2_pbb_vtr,
+};
+/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
diff --git a/vnet/vnet/l2/l2_vtr.h b/vnet/vnet/l2/l2_vtr.h
index 5e41c6d91ad..893b2272b04 100644
--- a/vnet/vnet/l2/l2_vtr.h
+++ b/vnet/vnet/l2/l2_vtr.h
@@ -171,6 +171,73 @@ l2_efp_filter_process (vlib_buffer_t * b0, vtr_config_t * in_config)
return (packet_tags & tag_mask) != in_config->raw_tags;
}
+typedef struct
+{
+ union
+ {
+ ethernet_pbb_header_t macs_tags;
+ struct
+ {
+ u64 data1;
+ u64 data2;
+ u16 data3;
+ u32 data4;
+ } raw_data;
+ };
+ union
+ {
+ struct
+ {
+ u8 push_bytes; /* number of bytes to push pbb tags */
+ u8 pop_bytes; /* number of bytes to pop pbb tags */
+ };
+ u16 push_and_pop_bytes; /* if 0 then the feature is disabled */
+ };
+} ptr_config_t;
+
+always_inline u32
+l2_pbb_process (vlib_buffer_t * b0, ptr_config_t * config)
+{
+ u8 *eth = vlib_buffer_get_current (b0);
+
+ if (config->pop_bytes > 0)
+ {
+ ethernet_pbb_header_packed_t *ph = (ethernet_pbb_header_packed_t *) eth;
+
+ // drop packet without PBB header or with wrong I-tag or B-tag
+ if (clib_net_to_host_u16 (ph->priority_dei_id) !=
+ clib_net_to_host_u16 (config->macs_tags.priority_dei_id)
+ || clib_net_to_host_u32 (ph->priority_dei_uca_res_sid) !=
+ clib_net_to_host_u32 (config->macs_tags.priority_dei_uca_res_sid))
+ return 1;
+
+ eth += config->pop_bytes;
+ }
+
+ if (config->push_bytes > 0)
+ {
+ eth -= config->push_bytes;
+ // copy the B-DA (6B), B-SA (6B), B-TAG (4B), I-TAG (6B)
+ *((u64 *) eth) = config->raw_data.data1;
+ *((u64 *) (eth + 8)) = config->raw_data.data2;
+ *((u16 *) (eth + 16)) = config->raw_data.data3;
+ *((u32 *) (eth + 18)) = config->raw_data.data4;
+ }
+
+ /* Update l2_len */
+ vnet_buffer (b0)->l2.l2_len +=
+ (word) config->push_bytes - (word) config->pop_bytes;
+ /* Update packet len */
+ vlib_buffer_advance (b0,
+ (word) config->pop_bytes - (word) config->push_bytes);
+
+ return 0;
+}
+
+u32 l2pbb_configure (vlib_main_t * vlib_main,
+ vnet_main_t * vnet_main, u32 sw_if_index, u32 vtr_op,
+ u8 * b_dmac, u8 * b_smac,
+ u16 b_vlanid, u32 i_sid, u16 vlan_outer_tag);
/**
* Configure vtag tag rewrite on the given interface.