#include <vnet/ip/ip6_to_ip4.h>
#include <vnet/feature/feature.h>
#include <vnet/qos/qos_types.h>
+#include <vnet/l2/l2_input.h>
+#include <vnet/l2/feat_bitmap.h>
/**
* Per-interface, per-protocol vector of feature on/off configurations
enable);
break;
case QOS_SOURCE_MPLS:
+ vnet_feature_enable_disable ("mpls-input", "mpls-qos-record",
+ sw_if_index, enable, NULL, 0);
+ break;
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:
- // not implemented yet
+ /* not a valid option for recording */
break;
}
}
int
qos_record_disable (u32 sw_if_index, qos_source_t input_source)
{
- if (vec_len (qos_record_configs[input_source]) < sw_if_index)
+ if (vec_len (qos_record_configs[input_source]) <= sw_if_index)
return VNET_API_ERROR_NO_MATCHING_INTERFACE;
if (0 == qos_record_configs[input_source][sw_if_index])
}
/*
- * Disable recording feautre for all protocols when the interface
+ * Disable recording feature for all protocols when the interface
* is deleted
*/
static clib_error_t *
FOR_EACH_QOS_SOURCE (qs)
{
- qos_record_disable (sw_if_index, qs);
+ while (qos_record_disable (sw_if_index, qs) == 0);
}
}
static inline uword
qos_record_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
- vlib_frame_t * frame, int is_ip6, int is_l2)
+ vlib_frame_t * frame,
+ qos_source_t qos_src, dpo_proto_t dproto, int is_l2)
{
u32 n_left_from, *from, *to_next, next_index;
ip4_header_t *ip4_0;
ip6_header_t *ip6_0;
vlib_buffer_t *b0;
- u32 sw_if_index0, next0, bi0;
+ u32 next0, bi0;
qos_bits_t qos0;
u8 l2_len;
ethertype = clib_net_to_host_u16 (*(u16 *) (l3h - 2));
if (ethertype == ETHERNET_TYPE_IP4)
- is_ip6 = 0;
+ dproto = DPO_PROTO_IP4;
else if (ethertype == ETHERNET_TYPE_IP6)
- is_ip6 = 1;
+ dproto = DPO_PROTO_IP6;
+ else if (ethertype == ETHERNET_TYPE_MPLS)
+ dproto = DPO_PROTO_MPLS;
else
goto non_ip;
}
- if (is_ip6)
+ if (DPO_PROTO_IP6 == dproto)
{
ip6_0 = vlib_buffer_get_current (b0);
qos0 = ip6_traffic_class_network_order (ip6_0);
}
- else
+ else if (DPO_PROTO_IP4 == dproto)
{
ip4_0 = vlib_buffer_get_current (b0);
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.source = QOS_SOURCE_IP;
+ vnet_buffer2 (b0)->qos.source = qos_src;
b0->flags |= VNET_BUFFER_F_QOS_DATA_VALID;
- sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
(b0->flags & VLIB_BUFFER_IS_TRACED)))
{
vlib_buffer_advance (b0, -l2_len);
next0 = vnet_l2_feature_next (b0,
- l2_qos_input_next[QOS_SOURCE_IP],
+ l2_qos_input_next[qos_src],
L2INPUT_FEAT_L2_IP_QOS_RECORD);
}
else
- vnet_feature_next (sw_if_index0, &next0, b0);
+ vnet_feature_next (&next0, b0);
/* verify speculative enqueue, maybe switch current next frame */
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
ip4_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
- return (qos_record_inline (vm, node, frame, 0, 0));
+ return (qos_record_inline (vm, node, frame, QOS_SOURCE_IP,
+ DPO_PROTO_IP4, 0));
}
static inline uword
ip6_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
- return (qos_record_inline (vm, node, frame, 1, 0));
+ return (qos_record_inline (vm, node, frame, QOS_SOURCE_IP,
+ 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, QOS_SOURCE_MPLS,
+ 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, QOS_SOURCE_VLAN,
+ 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, QOS_SOURCE_VLAN,
+ 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, QOS_SOURCE_VLAN,
+ DPO_PROTO_ETHERNET, 0));
}
static inline uword
l2_ip_qos_record (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
- return (qos_record_inline (vm, node, frame, 0, 1));
+ return (qos_record_inline (vm, node, frame, QOS_SOURCE_VLAN, 0, 1));
}
/* *INDENT-OFF* */
.arc_name = "ip4-unicast",
.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) = {
.function = ip6_qos_record,
.arc_name = "ip6-unicast",
.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-record"),
+};
+
+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-record"),
+};
+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-record"),
+};
+
+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-record"),
+};
+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-record"),
+};
VLIB_REGISTER_NODE (l2_ip_qos_record_node, static) = {
.function = l2_ip_qos_record,
};
VLIB_NODE_FUNCTION_MULTIARCH (l2_ip_qos_record_node, l2_ip_qos_record);
+
/* *INDENT-ON* */
clib_error_t *
l2_ip_qos_init (vlib_main_t * vm)
{
+ qos_source_t qs;
+
/* Initialize the feature next-node indexes */
- feat_bitmap_init_next_nodes (vm,
- l2_ip_qos_record_node.index,
- L2INPUT_N_FEAT,
- l2input_get_feat_names (),
- l2_qos_input_next[QOS_SOURCE_IP]);
+ FOR_EACH_QOS_SOURCE (qs)
+ feat_bitmap_init_next_nodes (vm,
+ l2_ip_qos_record_node.index,
+ L2INPUT_N_FEAT,
+ l2input_get_feat_names (),
+ l2_qos_input_next[qs]);
return 0;
}
/*?
* Enable QoS bit recording on an interface using the packet's input DSCP bits
* Which input QoS bits to use are either; IP, MPLS or VLAN. If more than
- * one protocol is chosen (which is foolish) the higer layers override the
+ * one protocol is chosen (which is foolish) the higher layers override the
* lower.
*
* @cliexpar