sr: SRv6 TEF behavior support
Adding support for the SRv6 TEF (Timestamp, Encapsulation and Forward) behavior defined in
draft-filsfils-spring-path-tracing (https://datatracker.ietf.org/doc/draft-filsfils-spring-path-tracing/).
Type: feature
Change-Id: I7f38b593147daf8d27af9c983448cf82947e5bed
Signed-off-by: Ahmed Abdelsalam <ahabdels@cisco.com>
diff --git a/src/vnet/srv6/sr.h b/src/vnet/srv6/sr.h
index 507f8df..02ccead 100644
--- a/src/vnet/srv6/sr.h
+++ b/src/vnet/srv6/sr.h
@@ -90,6 +90,7 @@
/* SR policy types */
#define SR_POLICY_TYPE_DEFAULT 0
#define SR_POLICY_TYPE_SPRAY 1
+#define SR_POLICY_TYPE_TEF 2
/**
* @brief SR Policy
*/
diff --git a/src/vnet/srv6/sr_packet.h b/src/vnet/srv6/sr_packet.h
index dda776b..cf9fcb7 100644
--- a/src/vnet/srv6/sr_packet.h
+++ b/src/vnet/srv6/sr_packet.h
@@ -116,6 +116,9 @@
#define ROUTING_HEADER_TYPE_SR 4
+#define IP6_SRH_PT_TLV_TYPE 128
+#define IP6_SRH_PT_TLV_LEN 14
+
typedef struct
{
/* Protocol for next header. */
@@ -156,6 +159,21 @@
u8 value[0];
} __attribute__ ((packed)) ip6_sr_tlv_t;
+typedef struct
+{
+ u32 sec;
+ u32 nsec;
+} __attribute__ ((packed)) timestamp_64_t;
+
+typedef struct
+{
+ u8 type;
+ u8 length;
+ u16 id_ld;
+ timestamp_64_t t64;
+ u16 session_id;
+ u16 seq_num;
+} __attribute__ ((packed)) ip6_sr_pt_tlv_t;
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/srv6/sr_policy_rewrite.c b/src/vnet/srv6/sr_policy_rewrite.c
index fdbf0dd..0134f3c 100644
--- a/src/vnet/srv6/sr_policy_rewrite.c
+++ b/src/vnet/srv6/sr_policy_rewrite.c
@@ -199,13 +199,20 @@
{
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);
@@ -222,7 +229,33 @@
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;
@@ -705,7 +738,8 @@
}
/* 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);
@@ -973,6 +1007,8 @@
is_encap = 0;
else if (unformat (input, "spray"))
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;
@@ -1137,6 +1173,10 @@
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;
@@ -1232,6 +1272,27 @@
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;
+ 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 = htobe32 (ts.sec);
+ srh_pt_tlv->t64.nsec = htobe32 (ts.nsec);
+}
/**
* @brief IPv6 encapsulation processing as per RFC2473
@@ -1257,6 +1318,8 @@
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);
}
/**
@@ -3108,6 +3171,8 @@
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: