MPLS disposition actions at the tail of unicast LSPs

Change-Id: I8c42e26152f2ed1246f91b789887bfc923418bdf
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vnet/fib/fib_entry_src.c b/src/vnet/fib/fib_entry_src.c
index 667aa48..214dafe 100644
--- a/src/vnet/fib/fib_entry_src.c
+++ b/src/vnet/fib/fib_entry_src.c
@@ -259,6 +259,23 @@
     return (dfct);
 }
 
+static dpo_proto_t
+fib_prefix_get_payload_proto (const fib_prefix_t *pfx)
+{
+    switch (pfx->fp_proto)
+    {
+    case FIB_PROTOCOL_IP4:
+        return (DPO_PROTO_IP4);
+    case FIB_PROTOCOL_IP6:
+        return (DPO_PROTO_IP6);
+    case FIB_PROTOCOL_MPLS:
+        return (pfx->fp_payload_proto);
+    }
+
+    ASSERT(0);
+    return (DPO_PROTO_IP4);
+}
+
 static void
 fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
                                    fib_entry_src_collect_forwarding_ctx_t *ctx)
@@ -313,7 +330,7 @@
                                                                       ctx->fct),
                                            &nh->path_dpo);
             fib_path_stack_mpls_disp(path_index,
-                                     ctx->fib_entry->fe_prefix.fp_payload_proto,
+                                     fib_prefix_get_payload_proto(&ctx->fib_entry->fe_prefix),
                                      &nh->path_dpo);
 
             break;
diff --git a/src/vnet/fib/fib_entry_src_mpls.c b/src/vnet/fib/fib_entry_src_mpls.c
index 6fdd5c0..f80d42a 100644
--- a/src/vnet/fib/fib_entry_src_mpls.c
+++ b/src/vnet/fib/fib_entry_src_mpls.c
@@ -170,7 +170,7 @@
 fib_entry_src_mpls_format (fib_entry_src_t *src,
 			   u8* s)
 {
-    return (format(s, "MPLS local-label:%d", src->mpls.fesm_label));
+    return (format(s, " local-label:%d", src->mpls.fesm_label));
 }
 
 const static fib_entry_src_vft_t mpls_src_vft = {
diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c
index 3e03192..8dabfdf 100644
--- a/src/vnet/fib/fib_path.c
+++ b/src/vnet/fib/fib_path.c
@@ -2259,6 +2259,18 @@
 
     switch (path->fp_type)
     {
+    case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
+    {
+        dpo_id_t tmp = DPO_INVALID;
+
+        dpo_copy(&tmp, dpo);
+        dpo_set(dpo,
+                DPO_MPLS_DISPOSITION,
+                payload_proto,
+                mpls_disp_dpo_create(payload_proto, ~0, &tmp));
+        dpo_reset(&tmp);
+        break;
+    }                
     case FIB_PATH_TYPE_DEAG:
     {
         dpo_id_t tmp = DPO_INVALID;
@@ -2275,7 +2287,6 @@
     }
     case FIB_PATH_TYPE_RECEIVE:
     case FIB_PATH_TYPE_ATTACHED:
-    case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
     case FIB_PATH_TYPE_RECURSIVE:
     case FIB_PATH_TYPE_INTF_RX:
     case FIB_PATH_TYPE_UDP_ENCAP:
diff --git a/src/vnet/fib/fib_path_ext.c b/src/vnet/fib/fib_path_ext.c
index 4438671..a285ba0 100644
--- a/src/vnet/fib/fib_path_ext.c
+++ b/src/vnet/fib/fib_path_ext.c
@@ -255,6 +255,15 @@
                     chain_proto,
                     mldi);
 	}
+        else if (child_fct == FIB_FORW_CHAIN_TYPE_MPLS_EOS)
+        {
+            /*
+             * MPLS EOS packets using an imp-null. Insert the disposition.
+             */
+            fib_path_stack_mpls_disp(nh->path_index,
+                                     fib_forw_chain_type_to_dpo_proto(parent_fct),
+                                     &nh->path_dpo);
+        }
     }
     dpo_reset(&via_dpo);
 
diff --git a/src/vnet/fib/fib_test.c b/src/vnet/fib/fib_test.c
index 2658eb2..b74ec33 100644
--- a/src/vnet/fib/fib_test.c
+++ b/src/vnet/fib/fib_test.c
@@ -29,6 +29,7 @@
 #include <vnet/dpo/interface_rx_dpo.h>
 #include <vnet/dpo/replicate_dpo.h>
 #include <vnet/dpo/l2_bridge_dpo.h>
+#include <vnet/dpo/mpls_disposition.h>
 
 #include <vnet/mpls/mpls.h>
 
@@ -514,6 +515,30 @@
 			bucket,
 			exp->adj.adj);
 	    break;
+	case FT_LB_MPLS_DISP_O_ADJ:
+        {
+            const mpls_disp_dpo_t *mdd;
+
+            FIB_TEST_I((DPO_MPLS_DISPOSITION == dpo->dpoi_type),
+		       "bucket %d stacks on %U",
+		       bucket,
+		       format_dpo_type, dpo->dpoi_type);
+	    
+            mdd = mpls_disp_dpo_get(dpo->dpoi_index);
+
+            dpo = &mdd->mdd_dpo;
+
+	    FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
+			(DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
+		       "bucket %d stacks on %U",
+		       bucket,
+		       format_dpo_type, dpo->dpoi_type);
+	    FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
+			"bucket %d stacks on adj %d",
+			bucket,
+			exp->adj.adj);
+	    break;
+        }
 	case FT_LB_INTF:
 	    FIB_TEST_I((DPO_INTERFACE_RX == dpo->dpoi_type),
 		       "bucket %d stacks on %U",
@@ -6380,6 +6405,12 @@
 	.fp_label = 24001,
 	.fp_eos = MPLS_NON_EOS,
     };
+    fib_test_lb_bucket_t disp_o_10_10_11_1 = {
+	.type = FT_LB_MPLS_DISP_O_ADJ,
+	.adj = {
+	    .adj = ai_v4_10_10_11_1,
+	},
+    };
 
     /*
      * The EOS entry should link to both the paths,
@@ -6393,10 +6424,10 @@
 				     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
 				     2,
 				     &l99_eos_o_10_10_10_1,
-				     &a_o_10_10_11_1),
+				     &disp_o_10_10_11_1),
 	     "24001/eos LB 2 buckets via: "
 	     "label 99 over 10.10.10.1, "
-	     "adj over 10.10.11.1");
+	     "mpls disp adj over 10.10.11.1");
 
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
@@ -6419,6 +6450,13 @@
 	    .adj = ai_v4_10_10_11_2,
 	},
     };
+    fib_test_lb_bucket_t disp_o_10_10_11_2 = {
+	.type = FT_LB_MPLS_DISP_O_ADJ,
+	.adj = {
+	    .adj = ai_v4_10_10_11_2,
+	},
+    };
+
 
     fei = fib_table_entry_path_add(fib_index,
 				   &pfx_1_1_1_1_s_32,
@@ -6567,11 +6605,11 @@
     FIB_TEST(fib_test_validate_entry(fei, 
 				     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
 				     2,
-				     &a_o_10_10_11_1,
-				     &adj_o_10_10_11_2),
+				     &disp_o_10_10_11_1,
+				     &disp_o_10_10_11_2),
 	     "24001/eos LB 2 buckets via: "
-	     "adj over 10.10.11.1, ",
-	     "adj-v4 over 10.10.11.2");
+	     "mpls-disp adj over 10.10.11.1, ",
+	     "mpls-disp adj-v4 over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
 			   &pfx_24001_neos);
@@ -6644,20 +6682,20 @@
 				     &l99_eos_o_10_10_10_1,
 				     &l99_eos_o_10_10_10_1,
 				     &l99_eos_o_10_10_10_1,
-				     &a_o_10_10_11_1,
-				     &a_o_10_10_11_1,
-				     &a_o_10_10_11_1,
-				     &a_o_10_10_11_1,
-				     &a_o_10_10_11_1,
-				     &adj_o_10_10_11_2,
-				     &adj_o_10_10_11_2,
-				     &adj_o_10_10_11_2,
-				     &adj_o_10_10_11_2,
-				     &adj_o_10_10_11_2),
+				     &disp_o_10_10_11_1,
+				     &disp_o_10_10_11_1,
+				     &disp_o_10_10_11_1,
+				     &disp_o_10_10_11_1,
+				     &disp_o_10_10_11_1,
+				     &disp_o_10_10_11_2,
+				     &disp_o_10_10_11_2,
+				     &disp_o_10_10_11_2,
+				     &disp_o_10_10_11_2,
+				     &disp_o_10_10_11_2),
 	     "24001/eos LB 16 buckets via: "
 	     "label 99 over 10.10.10.1, "
-	     "adj over 10.10.11.1",
-	     "adj-v4 over 10.10.11.2");
+	     "MPLS disp adj over 10.10.11.1",
+	     "MPLS disp adj-v4 over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
 			   &pfx_24001_neos);
@@ -6698,11 +6736,11 @@
     FIB_TEST(fib_test_validate_entry(fei, 
 				     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
 				     2,
-				     &a_o_10_10_11_1,
-				     &adj_o_10_10_11_2),
+				     &disp_o_10_10_11_1,
+				     &disp_o_10_10_11_2),
 	     "24001/eos LB 2 buckets via: "
-	     "adj over 10.10.11.1, "
-	     "adj-v4 over 10.10.11.2");
+	     "MPLS disp adj over 10.10.11.1, "
+	     "MPLS disp adj-v4 over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
 			   &pfx_24001_neos);
@@ -6750,9 +6788,9 @@
     FIB_TEST(fib_test_validate_entry(fei, 
 				     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
 				     1,
-				     &adj_o_10_10_11_2),
+				     &disp_o_10_10_11_2),
 	     "24001/eos LB 1 buckets via: "
-	     "adj over 10.10.11.2");
+	     "MPLS disp adj over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
 			   &pfx_24001_neos);
@@ -6796,10 +6834,10 @@
 				     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
 				     2,
 				     &l99_eos_o_10_10_10_1,
-				     &adj_o_10_10_11_2),
+				     &disp_o_10_10_11_2),
 	     "24001/eos LB 2 buckets via: "
 	     "label 99 over 10.10.10.1, "
-	     "adj over 10.10.11.2");
+	     "MPLS disp adj over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
 			   &pfx_24001_neos);
@@ -6841,10 +6879,10 @@
 				     FIB_FORW_CHAIN_TYPE_MPLS_EOS,
 				     2,
 				     &l99_eos_o_10_10_10_1,
-				     &adj_o_10_10_11_2),
+				     &disp_o_10_10_11_2),
 	     "25005/eos LB 2 buckets via: "
 	     "label 99 over 10.10.10.1, "
-	     "adj over 10.10.11.2");
+	     "MPLS disp adj over 10.10.11.2");
 
     fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
 			   &pfx_25005_neos);
diff --git a/src/vnet/fib/fib_test.h b/src/vnet/fib/fib_test.h
index f3d8346..53697cb 100644
--- a/src/vnet/fib/fib_test.h
+++ b/src/vnet/fib/fib_test.h
@@ -29,6 +29,7 @@
     FT_LB_LABEL_STACK_O_ADJ,
     FT_LB_LABEL_O_LB,
     FT_LB_O_LB,
+    FT_LB_MPLS_DISP_O_ADJ,
     FT_LB_INTF,
     FT_LB_L2,
     FT_LB_BIER_TABLE,