MPLS Unifom mode
[vpp.git] / src / vnet / dpo / mpls_disposition.c
index 77429de..2956e54 100644 (file)
@@ -42,38 +42,55 @@ mpls_disp_dpo_get_index (mpls_disp_dpo_t *mdd)
     return (mdd - mpls_disp_dpo_pool);
 }
 
-index_t
+void
 mpls_disp_dpo_create (dpo_proto_t payload_proto,
                       fib_rpf_id_t rpf_id,
-                      const dpo_id_t *dpo)
+                      fib_mpls_lsp_mode_t mode,
+                      const dpo_id_t *parent,
+                      dpo_id_t *dpo)
 {
     mpls_disp_dpo_t *mdd;
+    dpo_type_t dtype;
 
     mdd = mpls_disp_dpo_alloc();
 
     mdd->mdd_payload_proto = payload_proto;
     mdd->mdd_rpf_id = rpf_id;
-
-    dpo_stack(DPO_MPLS_DISPOSITION,
+    mdd->mdd_mode = mode;
+    dtype = (FIB_MPLS_LSP_MODE_PIPE == mode ?
+             DPO_MPLS_DISPOSITION_PIPE :
+             DPO_MPLS_DISPOSITION_UNIFORM);
+
+    /*
+     * stack this disposition object on the parent given
+     */
+    dpo_stack(dtype,
               mdd->mdd_payload_proto,
               &mdd->mdd_dpo,
-              dpo);
-
-    return (mpls_disp_dpo_get_index(mdd));
+              parent);
+
+    /*
+     * set up the return DPO to refer to this object
+     */
+    dpo_set(dpo,
+            dtype,
+            payload_proto,
+            mpls_disp_dpo_get_index(mdd));
 }
 
 u8*
 format_mpls_disp_dpo (u8 *s, va_list *args)
 {
-    index_t index = va_arg (*args, index_t);
-    u32 indent = va_arg (*args, u32);
+    index_t index = va_arg(*args, index_t);
+    u32 indent = va_arg(*args, u32);
     mpls_disp_dpo_t *mdd;
 
     mdd = mpls_disp_dpo_get(index);
 
-    s = format(s, "mpls-disposition:[%d]:[%U]",
+    s = format(s, "mpls-disposition:[%d]:[%U, %U]",
                index,
-               format_dpo_proto, mdd->mdd_payload_proto);
+               format_dpo_proto, mdd->mdd_payload_proto,
+               format_fib_mpls_lsp_mode, mdd->mdd_mode);
 
     s = format(s, "\n%U", format_white_space, indent);
     s = format(s, "%U", format_dpo_id, &mdd->mdd_dpo, indent+2);
@@ -116,25 +133,41 @@ typedef struct mpls_label_disposition_trace_t_
     index_t mdd;
 } mpls_label_disposition_trace_t;
 
-extern vlib_node_registration_t ip4_mpls_label_disposition_node;
-extern vlib_node_registration_t ip6_mpls_label_disposition_node;
+extern vlib_node_registration_t ip4_mpls_label_disposition_pipe_node;
+extern vlib_node_registration_t ip6_mpls_label_disposition_pipe_node;
+extern vlib_node_registration_t ip4_mpls_label_disposition_uniform_node;
+extern vlib_node_registration_t ip6_mpls_label_disposition_uniform_node;
 
 always_inline uword
 mpls_label_disposition_inline (vlib_main_t * vm,
-                              vlib_node_runtime_t * node,
-                              vlib_frame_t * from_frame,
-                              u8 payload_is_ip4,
-                              u8 payload_is_ip6)
+                               vlib_node_runtime_t * node,
+                               vlib_frame_t * from_frame,
+                               u8 payload_is_ip4,
+                               u8 payload_is_ip6,
+                               fib_mpls_lsp_mode_t mode)
 {
     u32 n_left_from, next_index, * from, * to_next;
     vlib_node_runtime_t *error_node;
 
     if (payload_is_ip4)
-        error_node = vlib_node_get_runtime (vm, ip4_mpls_label_disposition_node.index);
+    {
+        if (FIB_MPLS_LSP_MODE_PIPE == mode)
+            error_node =
+                vlib_node_get_runtime(vm, ip4_mpls_label_disposition_pipe_node.index);
+        else
+            error_node =
+                vlib_node_get_runtime(vm, ip4_mpls_label_disposition_uniform_node.index);
+    }
     else
-        error_node = vlib_node_get_runtime (vm, ip6_mpls_label_disposition_node.index);
-
-    from = vlib_frame_vector_args (from_frame);
+    {
+        if (FIB_MPLS_LSP_MODE_PIPE == mode)
+            error_node =
+                vlib_node_get_runtime(vm, ip6_mpls_label_disposition_uniform_node.index);
+        else
+            error_node =
+                vlib_node_get_runtime(vm, ip6_mpls_label_disposition_uniform_node.index);
+    }
+    from = vlib_frame_vector_args(from_frame);
     n_left_from = from_frame->n_vectors;
 
     next_index = node->cached_next_index;
@@ -159,14 +192,14 @@ mpls_label_disposition_inline (vlib_main_t * vm,
             {
                 vlib_buffer_t * p2, * p3;
 
-                p2 = vlib_get_buffer (vm, from[2]);
-                p3 = vlib_get_buffer (vm, from[3]);
+                p2 = vlib_get_buffer(vm, from[2]);
+                p3 = vlib_get_buffer(vm, from[3]);
 
-                vlib_prefetch_buffer_header (p2, STORE);
-                vlib_prefetch_buffer_header (p3, STORE);
+                vlib_prefetch_buffer_header(p2, STORE);
+                vlib_prefetch_buffer_header(p3, STORE);
 
-                CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), STORE);
-                CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), STORE);
+                CLIB_PREFETCH(p2->data, sizeof(ip6_header_t), STORE);
+                CLIB_PREFETCH(p3->data, sizeof(ip6_header_t), STORE);
             }
 
             from += 2;
@@ -174,8 +207,8 @@ mpls_label_disposition_inline (vlib_main_t * vm,
             n_left_from -= 2;
             n_left_to_next -= 2;
 
-            b0 = vlib_get_buffer (vm, bi0);
-            b1 = vlib_get_buffer (vm, bi1);
+            b0 = vlib_get_buffer(vm, bi0);
+            b1 = vlib_get_buffer(vm, bi1);
 
             /* dst lookup was done by ip4 lookup */
             mddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
@@ -190,30 +223,62 @@ mpls_label_disposition_inline (vlib_main_t * vm,
             {
                 ip4_header_t *ip0, *ip1;
 
-                ip0 = vlib_buffer_get_current (b0);
-                ip1 = vlib_buffer_get_current (b1);
+                ip0 = vlib_buffer_get_current(b0);
+                ip1 = vlib_buffer_get_current(b1);
 
                 /*
                  * IPv4 input checks on the exposed IP header
                  * including checksum
                  */
-                ip4_input_check_x2 (vm, error_node,
-                                    b0, b1, ip0, ip1,
-                                    &next0, &next1, 1);
+                ip4_input_check_x2(vm, error_node,
+                                   b0, b1, ip0, ip1,
+                                   &next0, &next1, 1);
+
+                if (FIB_MPLS_LSP_MODE_UNIFORM == mode)
+                {
+                    /*
+                     * Copy the TTL from the MPLS packet into the
+                     * exposed IP. recalc the chksum
+                     */
+                    ip0->ttl = vnet_buffer(b0)->mpls.ttl;
+                    ip1->ttl = vnet_buffer(b1)->mpls.ttl;
+                    ip0->tos = mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp);
+                    ip1->tos = mpls_exp_to_ip_dscp(vnet_buffer(b1)->mpls.exp);
+
+                    ip0->checksum = ip4_header_checksum(ip0);
+                    ip1->checksum = ip4_header_checksum(ip1);
+                }
             }
             else if (payload_is_ip6)
             {
                 ip6_header_t *ip0, *ip1;
 
-                ip0 = vlib_buffer_get_current (b0);
-                ip1 = vlib_buffer_get_current (b1);
+                ip0 = vlib_buffer_get_current(b0);
+                ip1 = vlib_buffer_get_current(b1);
 
                 /*
                  * IPv6 input checks on the exposed IP header
                  */
-                ip6_input_check_x2 (vm, error_node,
-                                    b0, b1, ip0, ip1,
-                                    &next0, &next1);
+                ip6_input_check_x2(vm, error_node,
+                                   b0, b1, ip0, ip1,
+                                   &next0, &next1);
+
+                if (FIB_MPLS_LSP_MODE_UNIFORM == mode)
+                {
+                    /*
+                     * Copy the TTL from the MPLS packet into the
+                     * exposed IP
+                     */
+                    ip0->hop_limit = vnet_buffer(b0)->mpls.ttl;
+                    ip1->hop_limit = vnet_buffer(b1)->mpls.ttl;
+
+                    ip6_set_traffic_class_network_order(
+                        ip0,
+                        mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp));
+                    ip6_set_traffic_class_network_order(
+                        ip1,
+                        mpls_exp_to_ip_dscp(vnet_buffer(b1)->mpls.exp));
+                }
             }
 
             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mdd0->mdd_dpo.dpoi_index;
@@ -224,14 +289,14 @@ mpls_label_disposition_inline (vlib_main_t * vm,
             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
             {
                 mpls_label_disposition_trace_t *tr =
-                    vlib_add_trace (vm, node, b0, sizeof (*tr));
+                    vlib_add_trace(vm, node, b0, sizeof(*tr));
 
                 tr->mdd = mddi0;
             }
             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
             {
                 mpls_label_disposition_trace_t *tr =
-                    vlib_add_trace (vm, node, b1, sizeof (*tr));
+                    vlib_add_trace(vm, node, b1, sizeof(*tr));
                 tr->mdd = mddi1;
             }
 
@@ -254,7 +319,7 @@ mpls_label_disposition_inline (vlib_main_t * vm,
             n_left_from -= 1;
             n_left_to_next -= 1;
 
-            b0 = vlib_get_buffer (vm, bi0);
+            b0 = vlib_get_buffer(vm, bi0);
 
             /* dst lookup was done by ip4 lookup */
             mddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
@@ -265,24 +330,48 @@ mpls_label_disposition_inline (vlib_main_t * vm,
             {
                 ip4_header_t *ip0;
 
-                ip0 = vlib_buffer_get_current (b0);
+                ip0 = vlib_buffer_get_current(b0);
 
                 /*
                  * IPv4 input checks on the exposed IP header
                  * including checksum
                  */
-                ip4_input_check_x1 (vm, error_node, b0, ip0, &next0, 1);
+                ip4_input_check_x1(vm, error_node, b0, ip0, &next0, 1);
+
+                if (FIB_MPLS_LSP_MODE_UNIFORM == mode)
+                {
+                    /*
+                     * Copy the TTL from the MPLS packet into the
+                     * exposed IP. recalc the chksum
+                     */
+                    ip0->ttl = vnet_buffer(b0)->mpls.ttl;
+                    ip0->tos = mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp);
+                    ip0->checksum = ip4_header_checksum(ip0);
+                }
             }
             else if (payload_is_ip6)
             {
                 ip6_header_t *ip0;
 
-                ip0 = vlib_buffer_get_current (b0);
+                ip0 = vlib_buffer_get_current(b0);
 
                 /*
                  * IPv6 input checks on the exposed IP header
                  */
-                ip6_input_check_x1 (vm, error_node, b0, ip0, &next0);
+                ip6_input_check_x1(vm, error_node, b0, ip0, &next0);
+
+                if (FIB_MPLS_LSP_MODE_UNIFORM == mode)
+                {
+                    /*
+                     * Copy the TTL from the MPLS packet into the
+                     * exposed IP
+                     */
+                    ip0->hop_limit = vnet_buffer(b0)->mpls.ttl;
+
+                    ip6_set_traffic_class_network_order(
+                        ip0,
+                        mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp));
+                }
             }
 
             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mdd0->mdd_dpo.dpoi_index;
@@ -291,14 +380,14 @@ mpls_label_disposition_inline (vlib_main_t * vm,
             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
             {
                 mpls_label_disposition_trace_t *tr =
-                    vlib_add_trace (vm, node, b0, sizeof (*tr));
+                    vlib_add_trace(vm, node, b0, sizeof(*tr));
                 tr->mdd = mddi0;
             }
 
             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
                                             n_left_to_next, bi0, next0);
         }
-        vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+        vlib_put_next_frame(vm, node, next_index, n_left_to_next);
     }
     return from_frame->n_vectors;
 }
@@ -306,57 +395,103 @@ mpls_label_disposition_inline (vlib_main_t * vm,
 static u8 *
 format_mpls_label_disposition_trace (u8 * s, va_list * args)
 {
-    CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
-    CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-    CLIB_UNUSED (mpls_label_disposition_trace_t * t);
+    CLIB_UNUSED(vlib_main_t * vm) = va_arg(*args, vlib_main_t *);
+    CLIB_UNUSED(vlib_node_t * node) = va_arg(*args, vlib_node_t *);
+    CLIB_UNUSED(mpls_label_disposition_trace_t * t);
 
-    t = va_arg (*args, mpls_label_disposition_trace_t *);
+    t = va_arg(*args, mpls_label_disposition_trace_t *);
 
     s = format(s, "disp:%d", t->mdd);
     return (s);
 }
 
 static uword
-ip4_mpls_label_disposition (vlib_main_t * vm,
-                           vlib_node_runtime_t * node,
-                           vlib_frame_t * frame)
+ip4_mpls_label_disposition_pipe (vlib_main_t * vm,
+                                 vlib_node_runtime_t * node,
+                                 vlib_frame_t * frame)
 {
-    return (mpls_label_disposition_inline(vm, node, frame, 1, 0));
+    return (mpls_label_disposition_inline(vm, node, frame, 1, 0,
+                                          FIB_MPLS_LSP_MODE_PIPE));
 }
 
-VLIB_REGISTER_NODE (ip4_mpls_label_disposition_node) = {
-    .function = ip4_mpls_label_disposition,
-    .name = "ip4-mpls-label-disposition",
-    .vector_size = sizeof (u32),
+VLIB_REGISTER_NODE(ip4_mpls_label_disposition_pipe_node) = {
+    .function = ip4_mpls_label_disposition_pipe,
+    .name = "ip4-mpls-label-disposition-pipe",
+    .vector_size = sizeof(u32),
 
     .format_trace = format_mpls_label_disposition_trace,
     .sibling_of = "ip4-input",
     .n_errors = IP4_N_ERROR,
     .error_strings = ip4_error_strings,
 };
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_disposition_node,
-                              ip4_mpls_label_disposition)
+VLIB_NODE_FUNCTION_MULTIARCH(ip4_mpls_label_disposition_pipe_node,
+                              ip4_mpls_label_disposition_pipe)
 
 static uword
-ip6_mpls_label_disposition (vlib_main_t * vm,
-                           vlib_node_runtime_t * node,
-                           vlib_frame_t * frame)
+ip6_mpls_label_disposition_pipe (vlib_main_t * vm,
+                                 vlib_node_runtime_t * node,
+                                 vlib_frame_t * frame)
 {
-    return (mpls_label_disposition_inline(vm, node, frame, 0, 1));
+    return (mpls_label_disposition_inline(vm, node, frame, 0, 1,
+                                          FIB_MPLS_LSP_MODE_PIPE));
 }
 
-VLIB_REGISTER_NODE (ip6_mpls_label_disposition_node) = {
-    .function = ip6_mpls_label_disposition,
-    .name = "ip6-mpls-label-disposition",
-    .vector_size = sizeof (u32),
+VLIB_REGISTER_NODE(ip6_mpls_label_disposition_pipe_node) = {
+    .function = ip6_mpls_label_disposition_pipe,
+    .name = "ip6-mpls-label-disposition-pipe",
+    .vector_size = sizeof(u32),
 
     .format_trace = format_mpls_label_disposition_trace,
     .sibling_of = "ip6-input",
     .n_errors = IP6_N_ERROR,
     .error_strings = ip6_error_strings,
 };
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_disposition_node,
-                              ip6_mpls_label_disposition)
+VLIB_NODE_FUNCTION_MULTIARCH(ip6_mpls_label_disposition_pipe_node,
+                             ip6_mpls_label_disposition_pipe)
+
+static uword
+ip4_mpls_label_disposition_uniform (vlib_main_t * vm,
+                                 vlib_node_runtime_t * node,
+                                 vlib_frame_t * frame)
+{
+    return (mpls_label_disposition_inline(vm, node, frame, 1, 0,
+                                          FIB_MPLS_LSP_MODE_UNIFORM));
+}
+
+VLIB_REGISTER_NODE(ip4_mpls_label_disposition_uniform_node) = {
+    .function = ip4_mpls_label_disposition_uniform,
+    .name = "ip4-mpls-label-disposition-uniform",
+    .vector_size = sizeof(u32),
+
+    .format_trace = format_mpls_label_disposition_trace,
+    .sibling_of = "ip4-input",
+    .n_errors = IP4_N_ERROR,
+    .error_strings = ip4_error_strings,
+};
+VLIB_NODE_FUNCTION_MULTIARCH(ip4_mpls_label_disposition_uniform_node,
+                             ip4_mpls_label_disposition_uniform)
+
+static uword
+ip6_mpls_label_disposition_uniform (vlib_main_t * vm,
+                                    vlib_node_runtime_t * node,
+                                    vlib_frame_t * frame)
+{
+    return (mpls_label_disposition_inline(vm, node, frame, 0, 1,
+                                          FIB_MPLS_LSP_MODE_UNIFORM));
+}
+
+VLIB_REGISTER_NODE(ip6_mpls_label_disposition_uniform_node) = {
+    .function = ip6_mpls_label_disposition_uniform,
+    .name = "ip6-mpls-label-disposition-uniform",
+    .vector_size = sizeof(u32),
+
+    .format_trace = format_mpls_label_disposition_trace,
+    .sibling_of = "ip6-input",
+    .n_errors = IP6_N_ERROR,
+    .error_strings = ip6_error_strings,
+};
+VLIB_NODE_FUNCTION_MULTIARCH(ip6_mpls_label_disposition_uniform_node,
+                             ip6_mpls_label_disposition_uniform)
 
 static void
 mpls_disp_dpo_mem_show (void)
@@ -374,25 +509,44 @@ const static dpo_vft_t mdd_vft = {
     .dv_mem_show = mpls_disp_dpo_mem_show,
 };
 
-const static char* const mpls_label_disp_ip4_nodes[] =
+const static char* const mpls_label_disp_pipe_ip4_nodes[] =
+{
+    "ip4-mpls-label-disposition-pipe",
+    NULL,
+};
+const static char* const mpls_label_disp_pipe_ip6_nodes[] =
+{
+    "ip6-mpls-label-disposition-pipe",
+    NULL,
+};
+const static char* const * const mpls_label_disp_pipe_nodes[DPO_PROTO_NUM] =
+{
+    [DPO_PROTO_IP4]  = mpls_label_disp_pipe_ip4_nodes,
+    [DPO_PROTO_IP6]  = mpls_label_disp_pipe_ip6_nodes,
+};
+
+const static char* const mpls_label_disp_uniform_ip4_nodes[] =
 {
-    "ip4-mpls-label-disposition",
+    "ip4-mpls-label-disposition-uniform",
     NULL,
 };
-const static char* const mpls_label_disp_ip6_nodes[] =
+const static char* const mpls_label_disp_uniform_ip6_nodes[] =
 {
-    "ip6-mpls-label-disposition",
+    "ip6-mpls-label-disposition-uniform",
     NULL,
 };
-const static char* const * const mpls_label_disp_nodes[DPO_PROTO_NUM] =
+const static char* const * const mpls_label_disp_uniform_nodes[DPO_PROTO_NUM] =
 {
-    [DPO_PROTO_IP4]  = mpls_label_disp_ip4_nodes,
-    [DPO_PROTO_IP6]  = mpls_label_disp_ip6_nodes,
+    [DPO_PROTO_IP4]  = mpls_label_disp_uniform_ip4_nodes,
+    [DPO_PROTO_IP6]  = mpls_label_disp_uniform_ip6_nodes,
 };
 
 
 void
-mpls_disp_dpo_module_init (void)
+mpls_disp_dpo_module_init(void)
 {
-    dpo_register(DPO_MPLS_DISPOSITION, &mdd_vft, mpls_label_disp_nodes);
+    dpo_register(DPO_MPLS_DISPOSITION_PIPE, &mdd_vft,
+                 mpls_label_disp_pipe_nodes);
+    dpo_register(DPO_MPLS_DISPOSITION_UNIFORM, &mdd_vft,
+                 mpls_label_disp_uniform_nodes);
 }