sr: support define src ipv6 per encap policy
[vpp.git] / src / vnet / srv6 / sr_policy_rewrite.c
index c7ac44b..69a4d5e 100644 (file)
@@ -33,7 +33,7 @@
  * Traffic input usually is IPv6 packets. However it is possible to have
  * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
  *
- * This file provides the appropiates VPP graph nodes to do any of these
+ * This file provides the appropriate VPP graph nodes to do any of these
  * methods.
  *
  */
@@ -47,7 +47,9 @@
 #include <vnet/fib/ip6_fib.h>
 #include <vnet/dpo/dpo.h>
 #include <vnet/dpo/replicate_dpo.h>
+#include <vnet/srv6/sr_pt.h>
 
+#include <vppinfra/byte_order.h>
 #include <vppinfra/error.h>
 #include <vppinfra/elog.h>
 
@@ -191,21 +193,29 @@ VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
  * @brief SR rewrite string computation for IPv6 encapsulation (inline)
  *
  * @param sl is a vector of IPv6 addresses composing the Segment List
+ * @param src_v6addr is a encaps IPv6 source addr
  *
  * @return precomputed rewrite string for encapsulation
  */
 static inline u8 *
-compute_rewrite_encaps (ip6_address_t * sl)
+compute_rewrite_encaps (ip6_address_t *sl, ip6_address_t *src_v6addr, u8 type)
 {
   ip6_header_t *iph;
   ip6_sr_header_t *srh;
+  ip6_sr_pt_tlv_t *srh_pt_tlv;
   ip6_address_t *addrp, *this_address;
   u32 header_length = 0;
   u8 *rs = NULL;
 
   header_length = 0;
   header_length += IPv6_DEFAULT_HEADER_LENGTH;
-  if (vec_len (sl) > 1)
+  if (type == SR_POLICY_TYPE_TEF)
+    {
+      header_length += sizeof (ip6_sr_header_t);
+      header_length += vec_len (sl) * sizeof (ip6_address_t);
+      header_length += sizeof (ip6_sr_pt_tlv_t);
+    }
+  else if (vec_len (sl) > 1)
     {
       header_length += sizeof (ip6_sr_header_t);
       header_length += vec_len (sl) * sizeof (ip6_address_t);
@@ -216,13 +226,39 @@ compute_rewrite_encaps (ip6_address_t * sl)
   iph = (ip6_header_t *) rs;
   iph->ip_version_traffic_class_and_flow_label =
     clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
-  iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
-  iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
+  iph->src_address.as_u64[0] = src_v6addr->as_u64[0];
+  iph->src_address.as_u64[1] = src_v6addr->as_u64[1];
   iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
   iph->protocol = IP_PROTOCOL_IPV6;
   iph->hop_limit = sr_pr_encaps_hop_limit;
 
-  if (vec_len (sl) > 1)
+  if (type == SR_POLICY_TYPE_TEF)
+    {
+      srh = (ip6_sr_header_t *) (iph + 1);
+      iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
+      srh->protocol = IP_PROTOCOL_IPV6;
+      srh->type = ROUTING_HEADER_TYPE_SR;
+      srh->flags = 0x00;
+      srh->tag = 0x0000;
+      srh->segments_left = vec_len (sl) - 1;
+      srh->last_entry = vec_len (sl) - 1;
+      srh->length =
+       ((sizeof (ip6_sr_header_t) + (vec_len (sl) * sizeof (ip6_address_t)) +
+         sizeof (ip6_sr_pt_tlv_t)) /
+        8) -
+       1;
+      addrp = srh->segments + vec_len (sl) - 1;
+      vec_foreach (this_address, sl)
+       {
+         clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
+                           sizeof (ip6_address_t));
+         addrp--;
+       }
+      srh_pt_tlv = (ip6_sr_pt_tlv_t *) (srh->segments + vec_len (sl));
+      srh_pt_tlv->type = IP6_SRH_PT_TLV_TYPE;
+      srh_pt_tlv->length = IP6_SRH_PT_TLV_LEN;
+    }
+  else if (vec_len (sl) > 1)
     {
       srh = (ip6_sr_header_t *) (iph + 1);
       iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
@@ -255,7 +291,7 @@ compute_rewrite_encaps (ip6_address_t * sl)
  * @return precomputed rewrite string for SRH insertion
  */
 static inline u8 *
-compute_rewrite_insert (ip6_address_t * sl)
+compute_rewrite_insert (ip6_address_t *sl, u8 type)
 {
   ip6_sr_header_t *srh;
   ip6_address_t *addrp, *this_address;
@@ -335,18 +371,20 @@ compute_rewrite_bsid (ip6_address_t * sl)
  *
  * @param sr_policy is the SR policy where the SL will be added
  * @param sl is a vector of IPv6 addresses composing the Segment List
+ * @param encap_src is a encaps IPv6 source addr. optional.
  * @param weight is the weight of the SegmentList (for load-balancing purposes)
  * @param is_encap represents the mode (SRH insertion vs Encapsulation)
  *
  * @return pointer to the just created segment list
  */
 static inline ip6_sr_sl_t *
-create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
-          u8 is_encap)
+create_sl (ip6_sr_policy_t *sr_policy, ip6_address_t *sl,
+          ip6_address_t *encap_src, u32 weight, u8 is_encap)
 {
   ip6_sr_main_t *sm = &sr_main;
   ip6_sr_sl_t *segment_list;
   sr_policy_fn_registration_t *plugin = 0;
+  ip6_address_t encap_srcv6 = sr_pr_encaps_src;
 
   pool_get (sm->sid_lists, segment_list);
   clib_memset (segment_list, 0, sizeof (*segment_list));
@@ -358,15 +396,25 @@ create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
     (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
 
   segment_list->segments = vec_dup (sl);
+  segment_list->policy_type = sr_policy->type;
+
+  segment_list->egress_fib_table =
+    ip6_fib_index_from_table_id (sr_policy->fib_table);
 
   if (is_encap)
     {
-      segment_list->rewrite = compute_rewrite_encaps (sl);
+      if (encap_src)
+       {
+         clib_memcpy_fast (&encap_srcv6, encap_src, sizeof (ip6_address_t));
+       }
+      segment_list->rewrite =
+       compute_rewrite_encaps (sl, &encap_srcv6, sr_policy->type);
       segment_list->rewrite_bsid = segment_list->rewrite;
+      sr_policy->encap_src = encap_srcv6;
     }
   else
     {
-      segment_list->rewrite = compute_rewrite_insert (sl);
+      segment_list->rewrite = compute_rewrite_insert (sl, sr_policy->type);
       segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
     }
 
@@ -430,7 +478,7 @@ create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
 }
 
 /**
- * @brief Updates the Load Balancer after an SR Policy change
+ * @brief Updates the Load-Balancer after an SR Policy change
  *
  * @param sr_policy is the modified SR Policy
  */
@@ -621,17 +669,19 @@ update_replicate (ip6_sr_policy_t * sr_policy)
  *
  * @param bsid is the bindingSID of the SR Policy
  * @param segments is a vector of IPv6 address composing the segment list
+ * @param encap_src is a encaps IPv6 source addr. optional.
  * @param weight is the weight of the sid list. optional.
  * @param behavior is the behavior of the SR policy. (default//spray)
  * @param fib_table is the VRF where to install the FIB entry for the BSID
- * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
+ * @param is_encap (bool) whether SR policy should behave as Encap/SRH
+ * Insertion
  *
  * @return 0 if correct, else error
  */
 int
-sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
-              u32 weight, u8 behavior, u32 fib_table, u8 is_encap,
-              u16 plugin, void *ls_plugin_mem)
+sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments,
+              ip6_address_t *encap_src, u32 weight, u8 type, u32 fib_table,
+              u8 is_encap, u16 plugin, void *ls_plugin_mem)
 {
   ip6_sr_main_t *sm = &sr_main;
   ip6_sr_policy_t *sr_policy = 0;
@@ -672,7 +722,7 @@ sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
   pool_get (sm->sr_policies, sr_policy);
   clib_memset (sr_policy, 0, sizeof (*sr_policy));
   clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
-  sr_policy->type = behavior;
+  sr_policy->type = type;
   sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0);     //Is default FIB 0 ?
   sr_policy->is_encap = is_encap;
 
@@ -687,7 +737,7 @@ sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
             NULL);
 
   /* Create a segment list and add the index to the SR policy */
-  create_sl (sr_policy, segments, weight, is_encap);
+  create_sl (sr_policy, segments, encap_src, weight, is_encap);
 
   /* If FIB doesnt exist, create them */
   if (sm->fib_table_ip6 == (u32) ~ 0)
@@ -701,7 +751,8 @@ sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
     }
 
   /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
-  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
+  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT ||
+      sr_policy->type == SR_POLICY_TYPE_TEF)
     update_lb (sr_policy);
   else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
     update_replicate (sr_policy);
@@ -736,8 +787,6 @@ sr_policy_del (ip6_address_t * bsid, u32 index)
   else
     {
       sr_policy = pool_elt_at_index (sm->sr_policies, index);
-      if (!sr_policy)
-       return -1;
     }
 
   /* Remove BindingSID FIB entry */
@@ -818,6 +867,7 @@ sr_policy_del (ip6_address_t * bsid, u32 index)
  * @param fib_table is the VRF where to install the FIB entry for the BSID
  * @param operation is the operation to perform (among the top ones)
  * @param segments is a vector of IPv6 address composing the segment list
+ * @param encap_src is a encaps IPv6 source addr. optional.
  * @param sl_index is the index of the Segment List to modify/delete
  * @param weight is the weight of the sid list. optional.
  * @param is_encap Mode. Encapsulation or SRH insertion.
@@ -825,8 +875,8 @@ sr_policy_del (ip6_address_t * bsid, u32 index)
  * @return 0 if correct, else error
  */
 int
-sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
-              u8 operation, ip6_address_t * segments, u32 sl_index,
+sr_policy_mod (ip6_address_t *bsid, u32 index, u32 fib_table, u8 operation,
+              ip6_address_t *segments, ip6_address_t *encap_src, u32 sl_index,
               u32 weight)
 {
   ip6_sr_main_t *sm = &sr_main;
@@ -846,15 +896,13 @@ sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
   else
     {
       sr_policy = pool_elt_at_index (sm->sr_policies, index);
-      if (!sr_policy)
-       return -1;
     }
 
   if (operation == 1)          /* Add SR List to an existing SR policy */
     {
       /* Create the new SL */
-      segment_list =
-       create_sl (sr_policy, segments, weight, sr_policy->is_encap);
+      segment_list = create_sl (sr_policy, segments, encap_src, weight,
+                               sr_policy->is_encap);
 
       /* Create a new LB DPO */
       if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
@@ -927,15 +975,16 @@ sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
   int rv = -1;
   char is_del = 0, is_add = 0, is_mod = 0;
   char policy_set = 0;
-  ip6_address_t bsid, next_address;
+  ip6_address_t bsid, next_address, src_v6addr;
   u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
   u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
   ip6_address_t *segments = 0, *this_seg;
   u8 operation = 0;
   char is_encap = 1;
-  char is_spray = 0;
+  u8 type = SR_POLICY_TYPE_DEFAULT;
   u16 behavior = 0;
   void *ls_plugin_mem = 0;
+  ip6_address_t *encap_src = 0;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
@@ -959,6 +1008,10 @@ sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
          clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
                            sizeof (*this_seg));
        }
+      else if (unformat (input, "v6src %U", unformat_ip6_address, &src_v6addr))
+       {
+         encap_src = &src_v6addr;
+       }
       else if (unformat (input, "add sl"))
        operation = 1;
       else if (unformat (input, "del sl index %d", &sl_index))
@@ -972,7 +1025,9 @@ sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
       else if (unformat (input, "insert"))
        is_encap = 0;
       else if (unformat (input, "spray"))
-       is_spray = 1;
+       type = SR_POLICY_TYPE_SPRAY;
+      else if (unformat (input, "tef"))
+       type = SR_POLICY_TYPE_TEF;
       else if (!behavior && unformat (input, "behavior"))
        {
          sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
@@ -1021,10 +1076,8 @@ sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
       if (vec_len (segments) == 0)
        return clib_error_return (0, "No Segment List specified");
 
-      rv = sr_policy_add (&bsid, segments, weight,
-                         (is_spray ? SR_POLICY_TYPE_SPRAY :
-                          SR_POLICY_TYPE_DEFAULT), fib_table, is_encap,
-                         behavior, ls_plugin_mem);
+      rv = sr_policy_add (&bsid, segments, encap_src, weight, type, fib_table,
+                         is_encap, behavior, ls_plugin_mem);
 
       vec_free (segments);
     }
@@ -1042,9 +1095,9 @@ sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
       if (operation == 3 && weight == (u32) ~ 0)
        return clib_error_return (0, "No new weight for the SL specified");
 
-      rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
+      rv = sr_policy_mod ((sr_policy_index != (u32) ~0 ? NULL : &bsid),
                          sr_policy_index, fib_table, operation, segments,
-                         sl_index, weight);
+                         encap_src, sl_index, weight);
 
       if (segments)
        vec_free (segments);
@@ -1134,9 +1187,24 @@ show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
     vlib_cli_output (vm, "\tBehavior: %s",
                     (sr_policy->is_encap ? "Encapsulation" :
                      "SRH insertion"));
-    vlib_cli_output (vm, "\tType: %s",
-                    (sr_policy->type ==
-                     SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
+    if (sr_policy->is_encap)
+      {
+       vlib_cli_output (vm, "\tEncapSrcIP: %U", format_ip6_address,
+                        &sr_policy->encap_src);
+      }
+    switch (sr_policy->type)
+      {
+      case SR_POLICY_TYPE_SPRAY:
+       vlib_cli_output (vm, "\tType: %s", "Spray");
+       break;
+      case SR_POLICY_TYPE_TEF:
+       vlib_cli_output (vm, "\tType: %s",
+                        "TEF (Timestamp, Encapsulate, and Forward)");
+       break;
+      default:
+       vlib_cli_output (vm, "\tType: %s", "Default");
+       break;
+      }
     vlib_cli_output (vm, "\tFIB table: %u",
                     (sr_policy->fib_table !=
                      (u32) ~ 0 ? sr_policy->fib_table : 0));
@@ -1228,14 +1296,44 @@ format_sr_policy_rewrite_trace (u8 * s, va_list * args)
 
   return s;
 }
+/**
+ * @brief SRv6 TEF (Timestamp, Encapsulate, and Forward) behavior
+ */
+static_always_inline void
+srv6_tef_behavior (vlib_node_runtime_t *node, vlib_buffer_t *b0,
+                  ip6_header_t *ip0)
+{
+  ip6_sr_header_t *srh;
+  ip6_sr_pt_tlv_t *srh_pt_tlv;
+  timestamp_64_t ts;
+  sr_pt_iface_t *ls = 0;
+  u16 id_ld = 0;
+  srh = (ip6_sr_header_t *) (ip0 + 1);
+
+  srh_pt_tlv =
+    (ip6_sr_pt_tlv_t *) ((u8 *) ip0 + sizeof (ip6_header_t) +
+                        sizeof (ip6_sr_header_t) +
+                        sizeof (ip6_address_t) * (srh->last_entry + 1));
+
+  unix_time_now_nsec_fraction (&ts.sec, &ts.nsec);
+  srh_pt_tlv->t64.sec = clib_host_to_net_u32 (ts.sec);
+  srh_pt_tlv->t64.nsec = clib_host_to_net_u32 (ts.nsec);
+  ls = sr_pt_find_iface (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
+  if (ls)
+    {
+      id_ld = ls->id << 4;
+      id_ld |= ls->ingress_load;
+      srh_pt_tlv->id_ld = clib_host_to_net_u16 (id_ld);
+    }
+}
 
 /**
  * @brief IPv6 encapsulation processing as per RFC2473
  */
 static_always_inline void
-encaps_processing_v6 (vlib_node_runtime_t * node,
-                     vlib_buffer_t * b0,
-                     ip6_header_t * ip0, ip6_header_t * ip0_encap)
+encaps_processing_v6 (vlib_node_runtime_t *node, vlib_buffer_t *b0,
+                     ip6_header_t *ip0, ip6_header_t *ip0_encap,
+                     u8 policy_type)
 {
   u32 new_l0;
   u32 flow_label;
@@ -1253,6 +1351,8 @@ encaps_processing_v6 (vlib_node_runtime_t * node,
        ip0_encap->ip_version_traffic_class_and_flow_label) &
      0xfff00000) |
     (flow_label & 0x0000ffff));
+  if (policy_type == SR_POLICY_TYPE_TEF)
+    srv6_tef_behavior (node, b0, ip0);
 }
 
 /**
@@ -1304,10 +1404,10 @@ sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
            vlib_prefetch_buffer_header (p6, LOAD);
            vlib_prefetch_buffer_header (p7, LOAD);
 
-           CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
+           clib_prefetch_store (p4->data);
+           clib_prefetch_store (p5->data);
+           clib_prefetch_store (p6->data);
+           clib_prefetch_store (p7->data);
          }
 
          to_next[0] = bi0 = from[0];
@@ -1370,10 +1470,15 @@ sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
          ip2 = vlib_buffer_get_current (b2);
          ip3 = vlib_buffer_get_current (b3);
 
-         encaps_processing_v6 (node, b0, ip0, ip0_encap);
-         encaps_processing_v6 (node, b1, ip1, ip1_encap);
-         encaps_processing_v6 (node, b2, ip2, ip2_encap);
-         encaps_processing_v6 (node, b3, ip3, ip3_encap);
+         encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
+         encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
+         encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
+         encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
+
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
+         vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
+         vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
+         vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
 
          if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
            {
@@ -1455,7 +1560,9 @@ sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
 
          ip0 = vlib_buffer_get_current (b0);
 
-         encaps_processing_v6 (node, b0, ip0, ip0_encap);
+         encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
+
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
 
          if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
              PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
@@ -1590,10 +1697,10 @@ sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
            vlib_prefetch_buffer_header (p6, LOAD);
            vlib_prefetch_buffer_header (p7, LOAD);
 
-           CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
+           clib_prefetch_store (p4->data);
+           clib_prefetch_store (p5->data);
+           clib_prefetch_store (p6->data);
+           clib_prefetch_store (p7->data);
          }
 
          to_next[0] = bi0 = from[0];
@@ -1660,6 +1767,11 @@ sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
          encaps_processing_v4 (node, b2, ip2, ip2_encap);
          encaps_processing_v4 (node, b3, ip3, ip3_encap);
 
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
+         vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
+         vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
+         vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
+
          if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
            {
              if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
@@ -1743,6 +1855,8 @@ sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
 
          encaps_processing_v4 (node, b0, ip0, ip0_encap);
 
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
+
          if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
              PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
            {
@@ -1887,10 +2001,10 @@ sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
            vlib_prefetch_buffer_header (p6, LOAD);
            vlib_prefetch_buffer_header (p7, LOAD);
 
-           CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
+           clib_prefetch_store (p4->data);
+           clib_prefetch_store (p5->data);
+           clib_prefetch_store (p6->data);
+           clib_prefetch_store (p7->data);
          }
 
          to_next[0] = bi0 = from[0];
@@ -2283,10 +2397,10 @@ sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
            vlib_prefetch_buffer_header (p6, LOAD);
            vlib_prefetch_buffer_header (p7, LOAD);
 
-           CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
+           clib_prefetch_store (p4->data);
+           clib_prefetch_store (p5->data);
+           clib_prefetch_store (p6->data);
+           clib_prefetch_store (p7->data);
          }
 
          to_next[0] = bi0 = from[0];
@@ -2705,10 +2819,10 @@ sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
            vlib_prefetch_buffer_header (p6, LOAD);
            vlib_prefetch_buffer_header (p7, LOAD);
 
-           CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
+           clib_prefetch_store (p4->data);
+           clib_prefetch_store (p5->data);
+           clib_prefetch_store (p6->data);
+           clib_prefetch_store (p7->data);
          }
 
          to_next[0] = bi0 = from[0];
@@ -3070,10 +3184,9 @@ VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
  * @brief Function BSID encapsulation
  */
 static_always_inline void
-end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
-                               vlib_buffer_t * b0,
-                               ip6_header_t * ip0,
-                               ip6_sr_header_t * sr0, u32 * next0)
+end_bsid_encaps_srh_processing (vlib_node_runtime_t *node, vlib_buffer_t *b0,
+                               ip6_header_t *ip0, ip6_sr_header_t *sr0,
+                               u32 *next0, u8 policy_type)
 {
   ip6_address_t *new_dst0;
 
@@ -3091,6 +3204,8 @@ end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
          ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
          return;
        }
+      else if (sr0->segments_left == 0 && policy_type == SR_POLICY_TYPE_TEF)
+       return;
     }
 
 error_bsid_encaps:
@@ -3148,10 +3263,10 @@ sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
            vlib_prefetch_buffer_header (p6, LOAD);
            vlib_prefetch_buffer_header (p7, LOAD);
 
-           CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
+           clib_prefetch_store (p4->data);
+           clib_prefetch_store (p5->data);
+           clib_prefetch_store (p6->data);
+           clib_prefetch_store (p7->data);
          }
 
          to_next[0] = bi0 = from[0];
@@ -3207,10 +3322,14 @@ sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
            ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
                                 NULL);
 
-         end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
-         end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
-         end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
-         end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
+         end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
+                                         sl0->policy_type);
+         end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1,
+                                         sl1->policy_type);
+         end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2,
+                                         sl2->policy_type);
+         end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3,
+                                         sl3->policy_type);
 
          clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
                            sl0->rewrite, vec_len (sl0->rewrite));
@@ -3231,10 +3350,10 @@ sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
          ip2 = vlib_buffer_get_current (b2);
          ip3 = vlib_buffer_get_current (b3);
 
-         encaps_processing_v6 (node, b0, ip0, ip0_encap);
-         encaps_processing_v6 (node, b1, ip1, ip1_encap);
-         encaps_processing_v6 (node, b2, ip2, ip2_encap);
-         encaps_processing_v6 (node, b3, ip3, ip3_encap);
+         encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
+         encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
+         encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
+         encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
 
          if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
            {
@@ -3313,7 +3432,8 @@ sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
          sr0 =
            ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
                                 NULL);
-         end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
+         end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
+                                         sl0->policy_type);
 
          clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
                            sl0->rewrite, vec_len (sl0->rewrite));
@@ -3321,7 +3441,7 @@ sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
 
          ip0 = vlib_buffer_get_current (b0);
 
-         encaps_processing_v6 (node, b0, ip0, ip0_encap);
+         encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
 
          if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
              PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))