QoS: marking and recording for MPLS and VLAN
Change-Id: Icec79aa9039d5d7835d311fde0b7c1a0c76c9eb1 Signed-off-by: Neale Ranns <nranns@cisco.com>
This commit is contained in:

committed by
Damjan Marion

parent
c34b2e0f7c
commit
0809f6c030
@ -146,6 +146,14 @@ ethernet_vlan_header_set_priority_net_order (ethernet_vlan_header_t * h,
|
|||||||
bytes[0] |= (prio & 0x7) << 5;
|
bytes[0] |= (prio & 0x7) << 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
always_inline u8
|
||||||
|
ethernet_vlan_header_get_priority_net_order (ethernet_vlan_header_t * h)
|
||||||
|
{
|
||||||
|
u8 *bytes = (u8 *) (&h->priority_cfi_and_id);
|
||||||
|
|
||||||
|
return (bytes[0] >> 5);
|
||||||
|
}
|
||||||
|
|
||||||
/* VLAN with ethertype first and vlan id second */
|
/* VLAN with ethertype first and vlan id second */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,15 @@ qos_mark_ip_enable_disable (u32 sw_if_index, u8 enable)
|
|||||||
void
|
void
|
||||||
qos_mark_vlan_enable_disable (u32 sw_if_index, u8 enable)
|
qos_mark_vlan_enable_disable (u32 sw_if_index, u8 enable)
|
||||||
{
|
{
|
||||||
vnet_feature_enable_disable ("interface-output", "vlan-qos-mark",
|
/*
|
||||||
|
* one cannot run a feature on a sub-interface, so we need
|
||||||
|
* to enable a feature on all the L3 output paths
|
||||||
|
*/
|
||||||
|
vnet_feature_enable_disable ("ip6-output", "vlan-ip6-qos-mark",
|
||||||
|
sw_if_index, enable, NULL, 0);
|
||||||
|
vnet_feature_enable_disable ("ip4-output", "vlan-ip4-qos-mark",
|
||||||
|
sw_if_index, enable, NULL, 0);
|
||||||
|
vnet_feature_enable_disable ("mpls-output", "vlan-mpls-qos-mark",
|
||||||
sw_if_index, enable, NULL, 0);
|
sw_if_index, enable, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,8 +247,22 @@ mpls_qos_mark (vlib_main_t * vm, vlib_node_runtime_t * node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline uword
|
static inline uword
|
||||||
vlan_qos_mark (vlib_main_t * vm, vlib_node_runtime_t * node,
|
vlan_mpls_qos_mark (vlib_main_t * vm, vlib_node_runtime_t * node,
|
||||||
vlib_frame_t * frame)
|
vlib_frame_t * frame)
|
||||||
|
{
|
||||||
|
return (qos_mark_inline (vm, node, frame, QOS_SOURCE_VLAN, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uword
|
||||||
|
vlan_ip4_qos_mark (vlib_main_t * vm, vlib_node_runtime_t * node,
|
||||||
|
vlib_frame_t * frame)
|
||||||
|
{
|
||||||
|
return (qos_mark_inline (vm, node, frame, QOS_SOURCE_VLAN, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uword
|
||||||
|
vlan_ip6_qos_mark (vlib_main_t * vm, vlib_node_runtime_t * node,
|
||||||
|
vlib_frame_t * frame)
|
||||||
{
|
{
|
||||||
return (qos_mark_inline (vm, node, frame, QOS_SOURCE_VLAN, 0));
|
return (qos_mark_inline (vm, node, frame, QOS_SOURCE_VLAN, 0));
|
||||||
}
|
}
|
||||||
@ -311,9 +333,10 @@ VNET_FEATURE_INIT (mpls_qos_mark_node, static) = {
|
|||||||
.arc_name = "mpls-output",
|
.arc_name = "mpls-output",
|
||||||
.node_name = "mpls-qos-mark",
|
.node_name = "mpls-qos-mark",
|
||||||
};
|
};
|
||||||
VLIB_REGISTER_NODE (vlan_qos_mark_node) = {
|
|
||||||
.function = vlan_qos_mark,
|
VLIB_REGISTER_NODE (vlan_ip4_qos_mark_node) = {
|
||||||
.name = "vlan-qos-mark",
|
.function = vlan_ip4_qos_mark,
|
||||||
|
.name = "vlan-ip4-qos-mark",
|
||||||
.vector_size = sizeof (u32),
|
.vector_size = sizeof (u32),
|
||||||
.format_trace = format_qos_mark_trace,
|
.format_trace = format_qos_mark_trace,
|
||||||
.type = VLIB_NODE_TYPE_INTERNAL,
|
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||||
@ -326,11 +349,58 @@ VLIB_REGISTER_NODE (vlan_qos_mark_node) = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
VLIB_NODE_FUNCTION_MULTIARCH (vlan_qos_mark_node, vlan_qos_mark);
|
VLIB_NODE_FUNCTION_MULTIARCH (vlan_ip4_qos_mark_node, vlan_ip4_qos_mark);
|
||||||
|
|
||||||
VNET_FEATURE_INIT (vlan_qos_mark_node, static) = {
|
VNET_FEATURE_INIT (vlan_ip4_qos_mark_node, static) = {
|
||||||
.arc_name = "interface-output",
|
.arc_name = "ip4-output",
|
||||||
.node_name = "vlan-qos-mark",
|
.node_name = "vlan-ip4-qos-mark",
|
||||||
|
.runs_after = VNET_FEATURES ("ip4-qos-mark"),
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_REGISTER_NODE (vlan_ip6_qos_mark_node) = {
|
||||||
|
.function = vlan_ip6_qos_mark,
|
||||||
|
.name = "vlan-ip6-qos-mark",
|
||||||
|
.vector_size = sizeof (u32),
|
||||||
|
.format_trace = format_qos_mark_trace,
|
||||||
|
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||||
|
|
||||||
|
.n_errors = 0,
|
||||||
|
.n_next_nodes = 1,
|
||||||
|
|
||||||
|
.next_nodes = {
|
||||||
|
[0] = "error-drop",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_NODE_FUNCTION_MULTIARCH (vlan_ip6_qos_mark_node, vlan_ip6_qos_mark);
|
||||||
|
|
||||||
|
VNET_FEATURE_INIT (vlan_ip6_qos_mark_node, static) = {
|
||||||
|
.arc_name = "ip6-output",
|
||||||
|
.node_name = "vlan-ip6-qos-mark",
|
||||||
|
.runs_after = VNET_FEATURES ("ip6-qos-mark"),
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_REGISTER_NODE (vlan_mpls_qos_mark_node) = {
|
||||||
|
.function = vlan_mpls_qos_mark,
|
||||||
|
.name = "vlan-mpls-qos-mark",
|
||||||
|
.vector_size = sizeof (u32),
|
||||||
|
.format_trace = format_qos_mark_trace,
|
||||||
|
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||||
|
|
||||||
|
.n_errors = 0,
|
||||||
|
.n_next_nodes = 1,
|
||||||
|
|
||||||
|
.next_nodes = {
|
||||||
|
[0] = "error-drop",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_NODE_FUNCTION_MULTIARCH (vlan_mpls_qos_mark_node, vlan_mpls_qos_mark);
|
||||||
|
|
||||||
|
VNET_FEATURE_INIT (vlan_mpls_qos_mark_node, static) = {
|
||||||
|
.arc_name = "mpls-output",
|
||||||
|
.node_name = "vlan-mpls-qos-mark",
|
||||||
|
.runs_after = VNET_FEATURES ("mpls-qos-mark"),
|
||||||
};
|
};
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
@ -44,9 +44,23 @@ qos_record_feature_config (u32 sw_if_index,
|
|||||||
enable);
|
enable);
|
||||||
break;
|
break;
|
||||||
case QOS_SOURCE_MPLS:
|
case QOS_SOURCE_MPLS:
|
||||||
|
vnet_feature_enable_disable ("mpls-input", "mpls-qos-record",
|
||||||
|
sw_if_index, enable, NULL, 0);
|
||||||
|
break;
|
||||||
case QOS_SOURCE_VLAN:
|
case QOS_SOURCE_VLAN:
|
||||||
|
vnet_feature_enable_disable ("ip6-unicast", "vlan-ip6-qos-record",
|
||||||
|
sw_if_index, enable, NULL, 0);
|
||||||
|
vnet_feature_enable_disable ("ip6-multicast", "vlan-ip6-qos-record",
|
||||||
|
sw_if_index, enable, NULL, 0);
|
||||||
|
vnet_feature_enable_disable ("ip4-unicast", "vlan-ip4-qos-record",
|
||||||
|
sw_if_index, enable, NULL, 0);
|
||||||
|
vnet_feature_enable_disable ("ip4-multicast", "vlan-ip4-qos-record",
|
||||||
|
sw_if_index, enable, NULL, 0);
|
||||||
|
vnet_feature_enable_disable ("mpls-input", "vlan-mpls-qos-record",
|
||||||
|
sw_if_index, enable, NULL, 0);
|
||||||
|
break;
|
||||||
case QOS_SOURCE_EXT:
|
case QOS_SOURCE_EXT:
|
||||||
// not implemented yet
|
/* not a valid option for recording */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +133,7 @@ typedef struct qos_record_trace_t_
|
|||||||
static inline uword
|
static inline uword
|
||||||
qos_record_inline (vlib_main_t * vm,
|
qos_record_inline (vlib_main_t * vm,
|
||||||
vlib_node_runtime_t * node,
|
vlib_node_runtime_t * node,
|
||||||
vlib_frame_t * frame, int is_ip6, int is_l2)
|
vlib_frame_t * frame, dpo_proto_t dproto, int is_l2)
|
||||||
{
|
{
|
||||||
u32 n_left_from, *from, *to_next, next_index;
|
u32 n_left_from, *from, *to_next, next_index;
|
||||||
|
|
||||||
@ -164,23 +178,42 @@ qos_record_inline (vlib_main_t * vm,
|
|||||||
ethertype = clib_net_to_host_u16 (*(u16 *) (l3h - 2));
|
ethertype = clib_net_to_host_u16 (*(u16 *) (l3h - 2));
|
||||||
|
|
||||||
if (ethertype == ETHERNET_TYPE_IP4)
|
if (ethertype == ETHERNET_TYPE_IP4)
|
||||||
is_ip6 = 0;
|
dproto = DPO_PROTO_IP4;
|
||||||
else if (ethertype == ETHERNET_TYPE_IP6)
|
else if (ethertype == ETHERNET_TYPE_IP6)
|
||||||
is_ip6 = 1;
|
dproto = DPO_PROTO_IP6;
|
||||||
|
else if (ethertype == ETHERNET_TYPE_MPLS)
|
||||||
|
dproto = DPO_PROTO_MPLS;
|
||||||
else
|
else
|
||||||
goto non_ip;
|
goto non_ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_ip6)
|
if (DPO_PROTO_IP6 == dproto)
|
||||||
{
|
{
|
||||||
ip6_0 = vlib_buffer_get_current (b0);
|
ip6_0 = vlib_buffer_get_current (b0);
|
||||||
qos0 = ip6_traffic_class_network_order (ip6_0);
|
qos0 = ip6_traffic_class_network_order (ip6_0);
|
||||||
}
|
}
|
||||||
else
|
else if (DPO_PROTO_IP4 == dproto)
|
||||||
{
|
{
|
||||||
ip4_0 = vlib_buffer_get_current (b0);
|
ip4_0 = vlib_buffer_get_current (b0);
|
||||||
qos0 = ip4_0->tos;
|
qos0 = ip4_0->tos;
|
||||||
}
|
}
|
||||||
|
else if (DPO_PROTO_ETHERNET == dproto)
|
||||||
|
{
|
||||||
|
ethernet_vlan_header_t *vlan0;
|
||||||
|
|
||||||
|
vlan0 = (vlib_buffer_get_current (b0) -
|
||||||
|
sizeof (ethernet_vlan_header_t));
|
||||||
|
|
||||||
|
qos0 = ethernet_vlan_header_get_priority_net_order (vlan0);
|
||||||
|
}
|
||||||
|
else if (DPO_PROTO_MPLS)
|
||||||
|
{
|
||||||
|
mpls_unicast_header_t *mh;
|
||||||
|
|
||||||
|
mh = vlib_buffer_get_current (b0);
|
||||||
|
qos0 = vnet_mpls_uc_get_exp (mh->label_exp_s_ttl);
|
||||||
|
}
|
||||||
|
|
||||||
vnet_buffer2 (b0)->qos.bits = qos0;
|
vnet_buffer2 (b0)->qos.bits = qos0;
|
||||||
vnet_buffer2 (b0)->qos.source = QOS_SOURCE_IP;
|
vnet_buffer2 (b0)->qos.source = QOS_SOURCE_IP;
|
||||||
b0->flags |= VNET_BUFFER_F_QOS_DATA_VALID;
|
b0->flags |= VNET_BUFFER_F_QOS_DATA_VALID;
|
||||||
@ -233,14 +266,42 @@ static inline uword
|
|||||||
ip4_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
|
ip4_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
|
||||||
vlib_frame_t * frame)
|
vlib_frame_t * frame)
|
||||||
{
|
{
|
||||||
return (qos_record_inline (vm, node, frame, 0, 0));
|
return (qos_record_inline (vm, node, frame, DPO_PROTO_IP4, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uword
|
static inline uword
|
||||||
ip6_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
|
ip6_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
|
||||||
vlib_frame_t * frame)
|
vlib_frame_t * frame)
|
||||||
{
|
{
|
||||||
return (qos_record_inline (vm, node, frame, 1, 0));
|
return (qos_record_inline (vm, node, frame, DPO_PROTO_IP6, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uword
|
||||||
|
mpls_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
|
||||||
|
vlib_frame_t * frame)
|
||||||
|
{
|
||||||
|
return (qos_record_inline (vm, node, frame, DPO_PROTO_MPLS, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uword
|
||||||
|
vlan_ip4_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
|
||||||
|
vlib_frame_t * frame)
|
||||||
|
{
|
||||||
|
return (qos_record_inline (vm, node, frame, DPO_PROTO_ETHERNET, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uword
|
||||||
|
vlan_ip6_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
|
||||||
|
vlib_frame_t * frame)
|
||||||
|
{
|
||||||
|
return (qos_record_inline (vm, node, frame, DPO_PROTO_ETHERNET, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uword
|
||||||
|
vlan_mpls_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
|
||||||
|
vlib_frame_t * frame)
|
||||||
|
{
|
||||||
|
return (qos_record_inline (vm, node, frame, DPO_PROTO_ETHERNET, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uword
|
static inline uword
|
||||||
@ -272,6 +333,10 @@ VNET_FEATURE_INIT (ip4_qos_record_node, static) = {
|
|||||||
.arc_name = "ip4-unicast",
|
.arc_name = "ip4-unicast",
|
||||||
.node_name = "ip4-qos-record",
|
.node_name = "ip4-qos-record",
|
||||||
};
|
};
|
||||||
|
VNET_FEATURE_INIT (ip4m_qos_record_node, static) = {
|
||||||
|
.arc_name = "ip4-multicast",
|
||||||
|
.node_name = "ip4-qos-record",
|
||||||
|
};
|
||||||
|
|
||||||
VLIB_REGISTER_NODE (ip6_qos_record_node) = {
|
VLIB_REGISTER_NODE (ip6_qos_record_node) = {
|
||||||
.function = ip6_qos_record,
|
.function = ip6_qos_record,
|
||||||
@ -294,6 +359,111 @@ VNET_FEATURE_INIT (ip6_qos_record_node, static) = {
|
|||||||
.arc_name = "ip6-unicast",
|
.arc_name = "ip6-unicast",
|
||||||
.node_name = "ip6-qos-record",
|
.node_name = "ip6-qos-record",
|
||||||
};
|
};
|
||||||
|
VNET_FEATURE_INIT (ip6m_qos_record_node, static) = {
|
||||||
|
.arc_name = "ip6-multicast",
|
||||||
|
.node_name = "ip6-qos-record",
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_REGISTER_NODE (mpls_qos_record_node) = {
|
||||||
|
.function = mpls_qos_record,
|
||||||
|
.name = "mpls-qos-record",
|
||||||
|
.vector_size = sizeof (u32),
|
||||||
|
.format_trace = format_qos_record_trace,
|
||||||
|
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||||
|
|
||||||
|
.n_errors = 0,
|
||||||
|
.n_next_nodes = 1,
|
||||||
|
|
||||||
|
.next_nodes = {
|
||||||
|
[0] = "mpls-drop",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_NODE_FUNCTION_MULTIARCH (mpls_qos_record_node, mpls_qos_record);
|
||||||
|
|
||||||
|
VNET_FEATURE_INIT (mpls_qos_record_node, static) = {
|
||||||
|
.arc_name = "mpls-input",
|
||||||
|
.node_name = "mpls-qos-record",
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_REGISTER_NODE (vlan_mpls_qos_record_node) = {
|
||||||
|
.function = vlan_mpls_qos_record,
|
||||||
|
.name = "vlan-mpls-qos-record",
|
||||||
|
.vector_size = sizeof (u32),
|
||||||
|
.format_trace = format_qos_record_trace,
|
||||||
|
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||||
|
|
||||||
|
.n_errors = 0,
|
||||||
|
.n_next_nodes = 1,
|
||||||
|
|
||||||
|
.next_nodes = {
|
||||||
|
[0] = "mpls-drop",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_NODE_FUNCTION_MULTIARCH (vlan_mpls_qos_record_node, vlan_mpls_qos_record);
|
||||||
|
|
||||||
|
VNET_FEATURE_INIT (vlan_mpls_qos_record_node, static) = {
|
||||||
|
.arc_name = "mpls-input",
|
||||||
|
.node_name = "vlan-mpls-qos-record",
|
||||||
|
.runs_before = VNET_FEATURES ("mpls-qos-mark"),
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_REGISTER_NODE (vlan_ip4_qos_record_node) = {
|
||||||
|
.function = vlan_ip4_qos_record,
|
||||||
|
.name = "vlan-ip4-qos-record",
|
||||||
|
.vector_size = sizeof (u32),
|
||||||
|
.format_trace = format_qos_record_trace,
|
||||||
|
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||||
|
|
||||||
|
.n_errors = 0,
|
||||||
|
.n_next_nodes = 1,
|
||||||
|
|
||||||
|
.next_nodes = {
|
||||||
|
[0] = "ip4-drop",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_NODE_FUNCTION_MULTIARCH (vlan_ip4_qos_record_node, vlan_ip4_qos_record);
|
||||||
|
|
||||||
|
VNET_FEATURE_INIT (vlan_ip4_qos_record_node, static) = {
|
||||||
|
.arc_name = "ip4-unicast",
|
||||||
|
.node_name = "vlan-ip4-qos-record",
|
||||||
|
.runs_before = VNET_FEATURES ("ip4-qos-mark"),
|
||||||
|
};
|
||||||
|
VNET_FEATURE_INIT (vlan_ip4m_qos_record_node, static) = {
|
||||||
|
.arc_name = "ip4-multicast",
|
||||||
|
.node_name = "vlan-ip4-qos-record",
|
||||||
|
.runs_before = VNET_FEATURES ("ip4-qos-mark"),
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_REGISTER_NODE (vlan_ip6_qos_record_node) = {
|
||||||
|
.function = vlan_ip6_qos_record,
|
||||||
|
.name = "vlan-ip6-qos-record",
|
||||||
|
.vector_size = sizeof (u32),
|
||||||
|
.format_trace = format_qos_record_trace,
|
||||||
|
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||||
|
|
||||||
|
.n_errors = 0,
|
||||||
|
.n_next_nodes = 1,
|
||||||
|
|
||||||
|
.next_nodes = {
|
||||||
|
[0] = "ip6-drop",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
VLIB_NODE_FUNCTION_MULTIARCH (vlan_ip6_qos_record_node, vlan_ip6_qos_record);
|
||||||
|
|
||||||
|
VNET_FEATURE_INIT (vlan_ip6_qos_record_node, static) = {
|
||||||
|
.arc_name = "ip6-unicast",
|
||||||
|
.node_name = "vlan-ip6-qos-record",
|
||||||
|
.runs_before = VNET_FEATURES ("ip6-qos-mark"),
|
||||||
|
};
|
||||||
|
VNET_FEATURE_INIT (vlan_ip6m_qos_record_node, static) = {
|
||||||
|
.arc_name = "ip6-multicast",
|
||||||
|
.node_name = "vlan-ip6-qos-record",
|
||||||
|
.runs_before = VNET_FEATURES ("ip6-qos-mark"),
|
||||||
|
};
|
||||||
|
|
||||||
VLIB_REGISTER_NODE (l2_ip_qos_record_node, static) = {
|
VLIB_REGISTER_NODE (l2_ip_qos_record_node, static) = {
|
||||||
.function = l2_ip_qos_record,
|
.function = l2_ip_qos_record,
|
||||||
@ -312,6 +482,7 @@ VLIB_REGISTER_NODE (l2_ip_qos_record_node, static) = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
VLIB_NODE_FUNCTION_MULTIARCH (l2_ip_qos_record_node, l2_ip_qos_record);
|
VLIB_NODE_FUNCTION_MULTIARCH (l2_ip_qos_record_node, l2_ip_qos_record);
|
||||||
|
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
clib_error_t *
|
clib_error_t *
|
||||||
|
214
test/test_qos.py
214
test/test_qos.py
@ -4,10 +4,12 @@ import unittest
|
|||||||
|
|
||||||
from framework import VppTestCase, VppTestRunner
|
from framework import VppTestCase, VppTestRunner
|
||||||
from vpp_papi_provider import QOS_SOURCE
|
from vpp_papi_provider import QOS_SOURCE
|
||||||
from vpp_ip_route import VppIpRoute, VppRoutePath
|
from vpp_sub_interface import VppDot1QSubint
|
||||||
|
from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
|
||||||
|
VppMplsLabel, VppMplsTable, DpoProto
|
||||||
|
|
||||||
from scapy.packet import Raw
|
from scapy.packet import Raw
|
||||||
from scapy.layers.l2 import Ether
|
from scapy.layers.l2 import Ether, Dot1Q
|
||||||
from scapy.layers.inet import IP, UDP
|
from scapy.layers.inet import IP, UDP
|
||||||
from scapy.layers.inet6 import IPv6
|
from scapy.layers.inet6 import IPv6
|
||||||
from scapy.contrib.mpls import MPLS
|
from scapy.contrib.mpls import MPLS
|
||||||
@ -21,22 +23,27 @@ class TestQOS(VppTestCase):
|
|||||||
|
|
||||||
self.create_pg_interfaces(range(5))
|
self.create_pg_interfaces(range(5))
|
||||||
|
|
||||||
|
tbl = VppMplsTable(self, 0)
|
||||||
|
tbl.add_vpp_config()
|
||||||
|
|
||||||
for i in self.pg_interfaces:
|
for i in self.pg_interfaces:
|
||||||
i.admin_up()
|
i.admin_up()
|
||||||
i.config_ip4()
|
i.config_ip4()
|
||||||
i.resolve_arp()
|
i.resolve_arp()
|
||||||
i.config_ip6()
|
i.config_ip6()
|
||||||
i.resolve_ndp()
|
i.resolve_ndp()
|
||||||
|
i.enable_mpls()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
for i in self.pg_interfaces:
|
for i in self.pg_interfaces:
|
||||||
i.unconfig_ip4()
|
i.unconfig_ip4()
|
||||||
i.unconfig_ip6()
|
i.unconfig_ip6()
|
||||||
|
i.disable_mpls()
|
||||||
|
|
||||||
super(TestQOS, self).tearDown()
|
super(TestQOS, self).tearDown()
|
||||||
|
|
||||||
def test_qos_ip(self):
|
def test_qos_ip(self):
|
||||||
""" QoS Mark IP """
|
""" QoS Mark/Record IP """
|
||||||
|
|
||||||
#
|
#
|
||||||
# for table 1 map the n=0xff possible values of input QoS mark,
|
# for table 1 map the n=0xff possible values of input QoS mark,
|
||||||
@ -265,7 +272,7 @@ class TestQOS(VppTestCase):
|
|||||||
self.vapi.qos_egress_map_delete(7)
|
self.vapi.qos_egress_map_delete(7)
|
||||||
|
|
||||||
def test_qos_mpls(self):
|
def test_qos_mpls(self):
|
||||||
""" QoS Mark MPLS """
|
""" QoS Mark/Record MPLS """
|
||||||
|
|
||||||
#
|
#
|
||||||
# 255 QoS for all input values
|
# 255 QoS for all input values
|
||||||
@ -345,6 +352,64 @@ class TestQOS(VppTestCase):
|
|||||||
self.assertEqual(h[MPLS].label, 34)
|
self.assertEqual(h[MPLS].label, 34)
|
||||||
self.assertEqual(h[MPLS].s, 1)
|
self.assertEqual(h[MPLS].s, 1)
|
||||||
|
|
||||||
|
#
|
||||||
|
# enable MPLS QoS recording on the input Pg0 and IP egress marking
|
||||||
|
# on Pg1
|
||||||
|
#
|
||||||
|
self.vapi.qos_record_enable_disable(self.pg0.sw_if_index,
|
||||||
|
QOS_SOURCE.MPLS,
|
||||||
|
1)
|
||||||
|
self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
|
||||||
|
QOS_SOURCE.IP,
|
||||||
|
1,
|
||||||
|
1)
|
||||||
|
|
||||||
|
#
|
||||||
|
# MPLS x-connect - COS is preserved
|
||||||
|
#
|
||||||
|
route_32_eos = VppMplsRoute(self, 32, 1,
|
||||||
|
[VppRoutePath(self.pg1.remote_ip4,
|
||||||
|
self.pg1.sw_if_index,
|
||||||
|
labels=[VppMplsLabel(33)])])
|
||||||
|
route_32_eos.add_vpp_config()
|
||||||
|
|
||||||
|
p_m1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
|
||||||
|
MPLS(label=32, cos=3, ttl=2) /
|
||||||
|
IP(src=self.pg0.remote_ip4, dst="10.0.0.1", tos=1) /
|
||||||
|
UDP(sport=1234, dport=1234) /
|
||||||
|
Raw(chr(100) * 65))
|
||||||
|
|
||||||
|
rx = self.send_and_expect(self.pg0, p_m1 * 65, self.pg1)
|
||||||
|
for p in rx:
|
||||||
|
self.assertEqual(p[MPLS].cos, 7)
|
||||||
|
self.assertEqual(p[MPLS].label, 33)
|
||||||
|
self.assertEqual(p[MPLS].s, 1)
|
||||||
|
|
||||||
|
#
|
||||||
|
# MPLS deag - COS is copied from MPLS to IP
|
||||||
|
#
|
||||||
|
route_33_eos = VppMplsRoute(self, 33, 1,
|
||||||
|
[VppRoutePath("0.0.0.0",
|
||||||
|
0xffffffff,
|
||||||
|
nh_table_id=0)])
|
||||||
|
route_33_eos.add_vpp_config()
|
||||||
|
|
||||||
|
route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
|
||||||
|
[VppRoutePath(self.pg1.remote_ip4,
|
||||||
|
self.pg1.sw_if_index)])
|
||||||
|
route_10_0_0_4.add_vpp_config()
|
||||||
|
|
||||||
|
p_m2 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
|
||||||
|
MPLS(label=33, ttl=2, cos=3) /
|
||||||
|
IP(src=self.pg0.remote_ip4, dst="10.0.0.4", tos=1) /
|
||||||
|
UDP(sport=1234, dport=1234) /
|
||||||
|
Raw(chr(100) * 65))
|
||||||
|
|
||||||
|
rx = self.send_and_expect(self.pg0, p_m2 * 65, self.pg1)
|
||||||
|
|
||||||
|
for p in rx:
|
||||||
|
self.assertEqual(p[IP].tos, 255)
|
||||||
|
|
||||||
#
|
#
|
||||||
# cleanup
|
# cleanup
|
||||||
#
|
#
|
||||||
@ -355,8 +420,149 @@ class TestQOS(VppTestCase):
|
|||||||
QOS_SOURCE.MPLS,
|
QOS_SOURCE.MPLS,
|
||||||
1,
|
1,
|
||||||
0)
|
0)
|
||||||
|
self.vapi.qos_record_enable_disable(self.pg0.sw_if_index,
|
||||||
|
QOS_SOURCE.MPLS,
|
||||||
|
0)
|
||||||
|
self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
|
||||||
|
QOS_SOURCE.IP,
|
||||||
|
1,
|
||||||
|
0)
|
||||||
self.vapi.qos_egress_map_delete(1)
|
self.vapi.qos_egress_map_delete(1)
|
||||||
|
|
||||||
|
def test_qos_vlan(self):
|
||||||
|
"""QoS mark/record VLAN """
|
||||||
|
|
||||||
|
#
|
||||||
|
# QoS for all input values
|
||||||
|
#
|
||||||
|
output = [chr(0)] * 256
|
||||||
|
for i in range(0, 255):
|
||||||
|
output[i] = chr(255 - i)
|
||||||
|
os = ''.join(output)
|
||||||
|
rows = [{'outputs': os},
|
||||||
|
{'outputs': os},
|
||||||
|
{'outputs': os},
|
||||||
|
{'outputs': os}]
|
||||||
|
|
||||||
|
self.vapi.qos_egress_map_update(1, rows)
|
||||||
|
|
||||||
|
sub_if = VppDot1QSubint(self, self.pg0, 11)
|
||||||
|
|
||||||
|
sub_if.admin_up()
|
||||||
|
sub_if.config_ip4()
|
||||||
|
sub_if.resolve_arp()
|
||||||
|
sub_if.config_ip6()
|
||||||
|
sub_if.resolve_ndp()
|
||||||
|
|
||||||
|
#
|
||||||
|
# enable VLAN QoS recording/marking on the input Pg0 subinterface and
|
||||||
|
#
|
||||||
|
self.vapi.qos_record_enable_disable(sub_if.sw_if_index,
|
||||||
|
QOS_SOURCE.VLAN,
|
||||||
|
1)
|
||||||
|
self.vapi.qos_mark_enable_disable(sub_if.sw_if_index,
|
||||||
|
QOS_SOURCE.VLAN,
|
||||||
|
1,
|
||||||
|
1)
|
||||||
|
|
||||||
|
#
|
||||||
|
# IP marking/recording on pg1
|
||||||
|
#
|
||||||
|
self.vapi.qos_record_enable_disable(self.pg1.sw_if_index,
|
||||||
|
QOS_SOURCE.IP,
|
||||||
|
1)
|
||||||
|
self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
|
||||||
|
QOS_SOURCE.IP,
|
||||||
|
1,
|
||||||
|
1)
|
||||||
|
|
||||||
|
#
|
||||||
|
# a routes to/from sub-interface
|
||||||
|
#
|
||||||
|
route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
|
||||||
|
[VppRoutePath(sub_if.remote_ip4,
|
||||||
|
sub_if.sw_if_index)])
|
||||||
|
route_10_0_0_1.add_vpp_config()
|
||||||
|
route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
|
||||||
|
[VppRoutePath(self.pg1.remote_ip4,
|
||||||
|
self.pg1.sw_if_index)])
|
||||||
|
route_10_0_0_2.add_vpp_config()
|
||||||
|
route_2001_1 = VppIpRoute(self, "2001::1", 128,
|
||||||
|
[VppRoutePath(sub_if.remote_ip6,
|
||||||
|
sub_if.sw_if_index,
|
||||||
|
proto=DpoProto.DPO_PROTO_IP6)],
|
||||||
|
is_ip6=1)
|
||||||
|
route_2001_1.add_vpp_config()
|
||||||
|
route_2001_2 = VppIpRoute(self, "2001::2", 128,
|
||||||
|
[VppRoutePath(self.pg1.remote_ip6,
|
||||||
|
self.pg1.sw_if_index,
|
||||||
|
proto=DpoProto.DPO_PROTO_IP6)],
|
||||||
|
is_ip6=1)
|
||||||
|
route_2001_2.add_vpp_config()
|
||||||
|
|
||||||
|
p_v1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
|
||||||
|
Dot1Q(vlan=11, prio=1) /
|
||||||
|
IP(src="1.1.1.1", dst="10.0.0.2", tos=1) /
|
||||||
|
UDP(sport=1234, dport=1234) /
|
||||||
|
Raw(chr(100) * 65))
|
||||||
|
|
||||||
|
p_v2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
|
||||||
|
IP(src="1.1.1.1", dst="10.0.0.1", tos=1) /
|
||||||
|
UDP(sport=1234, dport=1234) /
|
||||||
|
Raw(chr(100) * 65))
|
||||||
|
|
||||||
|
rx = self.send_and_expect(self.pg1, p_v2 * 65, self.pg0)
|
||||||
|
|
||||||
|
for p in rx:
|
||||||
|
self.assertEqual(p[Dot1Q].prio, 6)
|
||||||
|
|
||||||
|
rx = self.send_and_expect(self.pg0, p_v1 * 65, self.pg1)
|
||||||
|
|
||||||
|
for p in rx:
|
||||||
|
self.assertEqual(p[IP].tos, 254)
|
||||||
|
|
||||||
|
p_v1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
|
||||||
|
Dot1Q(vlan=11, prio=2) /
|
||||||
|
IPv6(src="2001::1", dst="2001::2", tc=1) /
|
||||||
|
UDP(sport=1234, dport=1234) /
|
||||||
|
Raw(chr(100) * 65))
|
||||||
|
|
||||||
|
p_v2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
|
||||||
|
IPv6(src="3001::1", dst="2001::1", tc=1) /
|
||||||
|
UDP(sport=1234, dport=1234) /
|
||||||
|
Raw(chr(100) * 65))
|
||||||
|
|
||||||
|
rx = self.send_and_expect(self.pg1, p_v2 * 65, self.pg0)
|
||||||
|
|
||||||
|
for p in rx:
|
||||||
|
self.assertEqual(p[Dot1Q].prio, 6)
|
||||||
|
|
||||||
|
rx = self.send_and_expect(self.pg0, p_v1 * 65, self.pg1)
|
||||||
|
|
||||||
|
for p in rx:
|
||||||
|
self.assertEqual(p[IPv6].tc, 253)
|
||||||
|
|
||||||
|
#
|
||||||
|
# cleanup
|
||||||
|
#
|
||||||
|
sub_if.unconfig_ip4()
|
||||||
|
sub_if.unconfig_ip6()
|
||||||
|
|
||||||
|
self.vapi.qos_record_enable_disable(sub_if.sw_if_index,
|
||||||
|
QOS_SOURCE.VLAN,
|
||||||
|
0)
|
||||||
|
self.vapi.qos_mark_enable_disable(sub_if.sw_if_index,
|
||||||
|
QOS_SOURCE.VLAN,
|
||||||
|
1,
|
||||||
|
0)
|
||||||
|
self.vapi.qos_record_enable_disable(self.pg1.sw_if_index,
|
||||||
|
QOS_SOURCE.IP,
|
||||||
|
0)
|
||||||
|
self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index,
|
||||||
|
QOS_SOURCE.IP,
|
||||||
|
1,
|
||||||
|
0)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main(testRunner=VppTestRunner)
|
unittest.main(testRunner=VppTestRunner)
|
||||||
|
Reference in New Issue
Block a user