sr: support define src ipv6 per encap policy
[vpp.git] / src / vnet / srv6 / sr_policy_rewrite.c
index 77e1485..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,17 +1025,19 @@ 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;
          sr_policy_fn_registration_t **plugin_it = 0;
 
          /* *INDENT-OFF* */
-         pool_foreach (plugin, sm->policy_plugin_functions,
+         pool_foreach (plugin, sm->policy_plugin_functions)
            {
              vec_add1 (vec_plugins, plugin);
-           });
+           }
          /* *INDENT-ON* */
 
          vec_foreach (plugin_it, vec_plugins)
@@ -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);
@@ -1121,8 +1174,8 @@ show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
   vlib_cli_output (vm, "SR policies:");
 
   /* *INDENT-OFF* */
-  pool_foreach  (sr_policy, sm->sr_policies,
-                {vec_add1 (vec_policies, sr_policy); } );
+  pool_foreach (sr_policy, sm->sr_policies)
+                {vec_add1 (vec_policies, sr_policy); }
   /* *INDENT-ON* */
 
   vec_foreach_index (i, vec_policies)
@@ -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));
@@ -1189,6 +1257,27 @@ VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
 };
 /* *INDENT-ON* */
 
+/**
+ * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
+ */
+static clib_error_t *
+show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
+                                    unformat_input_t * input,
+                                    vlib_cli_command_t * cmd)
+{
+  vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
+
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
+  .path = "show sr encaps hop-limit",
+  .short_help = "show sr encaps hop-limit",
+  .function = show_sr_encaps_hop_limit_command_fn,
+};
+/* *INDENT-ON* */
+
 /*************************** SR rewrite graph node ****************************/
 /**
  * @brief Trace for the SR Policy Rewrite graph node
@@ -1207,24 +1296,63 @@ 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;
 
   ip0_encap->hop_limit -= 1;
   new_l0 =
     ip0->payload_length + sizeof (ip6_header_t) +
     clib_net_to_host_u16 (ip0_encap->payload_length);
   ip0->payload_length = clib_host_to_net_u16 (new_l0);
-  ip0->ip_version_traffic_class_and_flow_label =
-    ip0_encap->ip_version_traffic_class_and_flow_label;
+
+  flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
+  ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
+    0 |
+    (clib_net_to_host_u32 (
+       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);
 }
 
 /**
@@ -1276,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];
@@ -1342,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)))
            {
@@ -1427,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))
@@ -1489,6 +1624,7 @@ encaps_processing_v4 (vlib_node_runtime_t * node,
   ip6_sr_header_t *sr0;
 
   u32 checksum0;
+  u32 flow_label;
 
   /* Inner IPv4: Decrement TTL & update checksum */
   ip0_encap->ttl -= 1;
@@ -1499,9 +1635,10 @@ encaps_processing_v4 (vlib_node_runtime_t * node,
   /* Outer IPv6: Update length, FL, proto */
   new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
   ip0->payload_length = clib_host_to_net_u16 (new_l0);
-  ip0->ip_version_traffic_class_and_flow_label =
-    clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
-                         ((ip0_encap->tos & 0xFF) << 20));
+  flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
+  ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
+    0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
+    (flow_label & 0x0000ffff));
   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
     {
       sr0 = (void *) (ip0 + 1);
@@ -1560,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];
@@ -1630,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))
@@ -1713,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))
            {
@@ -1840,6 +1984,7 @@ sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
          ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
          ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
          ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
+         u32 flow_label0, flow_label1, flow_label2, flow_label3;
 
          /* Prefetch next iteration. */
          {
@@ -1856,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];
@@ -1895,12 +2040,16 @@ sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
                                   sm->sw_iface_sr_policies[vnet_buffer
                                                            (b3)->sw_if_index
                                                            [VLIB_RX]]);
+         flow_label0 = l2_flow_hash (b0);
+         flow_label1 = l2_flow_hash (b1);
+         flow_label2 = l2_flow_hash (b2);
+         flow_label3 = l2_flow_hash (b3);
 
          if (vec_len (sp0->segments_lists) == 1)
            vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
          else
            {
-             vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
+             vnet_buffer (b0)->ip.flow_hash = flow_label0;
              vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
                sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
                                     (vec_len (sp0->segments_lists) - 1))];
@@ -1910,7 +2059,7 @@ sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
            vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
          else
            {
-             vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
+             vnet_buffer (b1)->ip.flow_hash = flow_label1;
              vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
                sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
                                     (vec_len (sp1->segments_lists) - 1))];
@@ -1920,7 +2069,7 @@ sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
            vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
          else
            {
-             vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
+             vnet_buffer (b2)->ip.flow_hash = flow_label2;
              vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
                sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
                                     (vec_len (sp2->segments_lists) - 1))];
@@ -1930,7 +2079,7 @@ sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
            vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
          else
            {
-             vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
+             vnet_buffer (b3)->ip.flow_hash = flow_label3;
              vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
                sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
                                     (vec_len (sp3->segments_lists) - 1))];
@@ -2023,8 +2172,16 @@ sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
          else
            ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
 
-         /* Which Traffic class and flow label do I set ? */
-         //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
+         /* TC is set to 0 for all ethernet frames, should be taken from COS
+          * od DSCP of encapsulated packet in the future */
+         ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
+           0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
+         ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
+           0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
+         ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
+           0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
+         ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
+           0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
 
          if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
            {
@@ -2086,6 +2243,7 @@ sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
          ip6_sr_policy_t *sp0;
          ip6_sr_sl_t *sl0;
          u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
+         u32 flow_label0;
 
          bi0 = from[0];
          to_next[0] = bi0;
@@ -2100,13 +2258,14 @@ sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
                                   sm->sw_iface_sr_policies[vnet_buffer
                                                            (b0)->sw_if_index
                                                            [VLIB_RX]]);
+         flow_label0 = l2_flow_hash (b0);
 
          /* In case there is more than one SL, LB among them */
          if (vec_len (sp0->segments_lists) == 1)
            vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
          else
            {
-             vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
+             vnet_buffer (b0)->ip.flow_hash = flow_label0;
              vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
                sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
                                     (vec_len (sp0->segments_lists) - 1))];
@@ -2137,6 +2296,9 @@ sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
          else
            ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
 
+         ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
+           0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
+
          if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
              PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
            {
@@ -2235,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];
@@ -2657,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];
@@ -3022,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;
 
@@ -3043,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:
@@ -3100,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];
@@ -3159,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));
@@ -3183,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)))
            {
@@ -3265,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));
@@ -3273,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))
@@ -3390,8 +3558,8 @@ show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
   vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
 
   /* *INDENT-OFF* */
-  pool_foreach (plugin, sm->policy_plugin_functions,
-    ({ vec_add1 (plugins_vec, plugin); }));
+  pool_foreach (plugin, sm->policy_plugin_functions)
+     { vec_add1 (plugins_vec, plugin); }
   /* *INDENT-ON* */
 
   vlib_cli_output (vm, "Plugin behaviors:\n");