+// Function for SRv6 GTP6.DT function
+VLIB_NODE_FN (srv6_end_m_gtp6_dt) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ srv6_end_main_v6_dt_t *sm = &srv6_end_main_v6_dt;
+ ip6_sr_main_t *sm2 = &sr_main;
+ u32 n_left_from, next_index, *from, *to_next;
+ u32 thread_index = vm->thread_index;
+
+ u32 good_n = 0, bad_n = 0;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0;
+ vlib_buffer_t *b0;
+ srv6_end_gtp6_dt_param_t *ls_param;
+ ip6_sr_localsid_t *ls0;
+
+ ip6_gtpu_header_t *hdr0 = NULL;
+ ip4_header_t *ip4 = NULL;
+ ip6_header_t *ip6 = NULL;
+ ip6_address_t src, dst;
+ u32 teid;
+ u32 hdrlen;
+ u32 len0;
+
+ u32 next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
+
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ ls0 =
+ pool_elt_at_index (sm2->localsids,
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
+
+ ls_param = (srv6_end_gtp6_dt_param_t *) ls0->plugin_mem;
+
+ hdr0 = vlib_buffer_get_current (b0);
+
+ hdrlen = sizeof (ip6_gtpu_header_t);
+
+ len0 = vlib_buffer_length_in_chain (vm, b0);
+
+ if ((hdr0->ip6.protocol != IP_PROTOCOL_UDP)
+ || (hdr0->udp.dst_port !=
+ clib_host_to_net_u16 (SRV6_GTP_UDP_DST_PORT))
+ || (len0 < sizeof (ip6_gtpu_header_t)))
+ {
+ next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
+
+ bad_n++;
+ }
+ else
+ {
+ clib_memcpy_fast (src.as_u8, hdr0->ip6.src_address.as_u8,
+ sizeof (ip6_address_t));
+ clib_memcpy_fast (dst.as_u8, hdr0->ip6.dst_address.as_u8,
+ sizeof (ip6_address_t));
+
+ teid = hdr0->gtpu.teid;
+
+ if (hdr0->gtpu.ver_flags & GTPU_EXTHDR_FLAG)
+ {
+ hdrlen += sizeof (gtpu_exthdr_t);
+ if (hdr0->gtpu.ext->nextexthdr == GTPU_EXTHDR_PDU_SESSION)
+ {
+ gtpu_pdu_session_t *sess;
+
+ sess =
+ (gtpu_pdu_session_t *) (((char *) hdr0) +
+ sizeof (ip6_gtpu_header_t) +
+ sizeof (gtpu_exthdr_t));
+
+ hdrlen += sizeof (gtpu_pdu_session_t);
+ if (sess->u.val & GTPU_PDU_SESSION_P_BIT_MASK)
+ {
+ hdrlen += sizeof (gtpu_paging_policy_t);
+ }
+ }
+ }
+
+ if (ls_param->type == SRV6_GTP6_DT4)
+ {
+ vlib_buffer_advance (b0, (word) hdrlen);
+ ip4 = vlib_buffer_get_current (b0);
+ if ((ip4->ip_version_and_header_length & 0xf0) != 0x40)
+ {
+ next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
+ bad_n++;
+ goto DONE;
+ }
+
+ next0 = SRV6_END_M_GTP6_DT_NEXT_LOOKUP4;
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->fib4_index;
+ }
+ else if (ls_param->type == SRV6_GTP6_DT6)
+ {
+ ip6 = (ip6_header_t *) ((u8 *) hdr0 + hdrlen);
+ if ((clib_net_to_host_u32
+ (ip6->ip_version_traffic_class_and_flow_label) >> 28)
+ != 6)
+ {
+ next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
+ bad_n++;
+ goto DONE;
+ }
+
+ next0 = SRV6_END_M_GTP6_DT_NEXT_LOOKUP6;
+ if ((ip6->dst_address.as_u8[0] == 0xff)
+ && ((ip6->dst_address.as_u8[1] & 0xc0) == 0x80))
+ {
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->local_fib_index;
+ }
+ else
+ {
+ vlib_buffer_advance (b0, (word) hdrlen);
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->fib6_index;
+ }
+ }
+ else if (ls_param->type == SRV6_GTP6_DT46)
+ {
+ ip6 = (ip6_header_t *) ((u8 *) hdr0 + hdrlen);
+ if ((clib_net_to_host_u32
+ (ip6->ip_version_traffic_class_and_flow_label) >> 28)
+ == 6)
+ {
+ next0 = SRV6_END_M_GTP6_DT_NEXT_LOOKUP6;
+ if ((ip6->dst_address.as_u8[0] == 0xff)
+ && ((ip6->dst_address.as_u8[1] & 0xc0) == 0x80))
+ {
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->local_fib_index;
+ }
+ else
+ {
+ vlib_buffer_advance (b0, (word) hdrlen);
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->fib6_index;
+ }
+ }
+ else
+ if ((clib_net_to_host_u32
+ (ip6->ip_version_traffic_class_and_flow_label) >> 28)
+ == 4)
+ {
+ vlib_buffer_advance (b0, (word) hdrlen);
+ next0 = SRV6_END_M_GTP6_DT_NEXT_LOOKUP4;
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->fib4_index;
+ }
+ else
+ {
+ next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
+ bad_n++;
+ goto DONE;
+ }
+ }
+ else
+ {
+ next0 = SRV6_END_M_GTP6_DT_NEXT_DROP;
+ bad_n++;
+ goto DONE;
+ }
+
+ good_n++;
+
+ if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
+ PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ srv6_end_rewrite_trace_t *tr =
+ vlib_add_trace (vm, node, b0, sizeof (*tr));
+ clib_memcpy (tr->src.as_u8, src.as_u8,
+ sizeof (ip6_address_t));
+ clib_memcpy (tr->dst.as_u8, dst.as_u8,
+ sizeof (ip6_address_t));
+ tr->teid = teid;
+ }
+ }
+
+ DONE:
+ vlib_increment_combined_counter
+ (((next0 ==
+ SRV6_END_M_GTP6_DT_NEXT_DROP) ? &(sm2->sr_ls_invalid_counters)
+ : &(sm2->sr_ls_valid_counters)), thread_index,
+ ls0 - sm2->localsids, 1, vlib_buffer_length_in_chain (vm, b0));
+
+ 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_node_increment_counter (vm, sm->end_m_gtp6_dt_node_index,
+ SRV6_END_ERROR_M_GTP6_DT_BAD_PACKETS, bad_n);
+
+ vlib_node_increment_counter (vm, sm->end_m_gtp6_dt_node_index,
+ SRV6_END_ERROR_M_GTP6_DT_PACKETS, good_n);
+
+ return frame->n_vectors;
+}
+
+// Function for SRv6 GTP4.DT function
+VLIB_NODE_FN (srv6_t_m_gtp4_dt) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ srv6_t_main_v4_dt_t *sm = &srv6_t_main_v4_dt;
+ ip6_sr_main_t *sm2 = &sr_main;
+ u32 n_left_from, next_index, *from, *to_next;
+
+ u32 good_n = 0, bad_n = 0;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0;
+ vlib_buffer_t *b0;
+ srv6_t_gtp4_dt_param_t *ls_param;
+ ip6_sr_sl_t *ls0;
+
+ ip4_gtpu_header_t *hdr0 = NULL;
+ ip4_header_t *ip4 = NULL;
+ ip6_header_t *ip6 = NULL;
+ ip6_address_t src, dst;
+ u32 teid;
+ u32 hdrlen;
+ u32 len0;
+
+ u32 next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
+
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ ls0 =
+ pool_elt_at_index (sm2->sid_lists,
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
+
+ ls_param = (srv6_t_gtp4_dt_param_t *) ls0->plugin_mem;
+
+ hdr0 = vlib_buffer_get_current (b0);
+
+ hdrlen = sizeof (ip4_gtpu_header_t);
+
+ len0 = vlib_buffer_length_in_chain (vm, b0);
+
+ if ((hdr0->ip4.protocol != IP_PROTOCOL_UDP)
+ || (hdr0->udp.dst_port !=
+ clib_host_to_net_u16 (SRV6_GTP_UDP_DST_PORT))
+ || (len0 < sizeof (ip4_gtpu_header_t)))
+ {
+ next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
+
+ bad_n++;
+ }
+ else
+ {
+ clib_memcpy_fast (src.as_u8, hdr0->ip4.src_address.as_u8,
+ sizeof (ip4_address_t));
+ clib_memcpy_fast (dst.as_u8, hdr0->ip4.dst_address.as_u8,
+ sizeof (ip4_address_t));
+
+ teid = hdr0->gtpu.teid;
+
+ if (hdr0->gtpu.ver_flags & GTPU_EXTHDR_FLAG)
+ {
+ hdrlen += sizeof (gtpu_exthdr_t);
+ if (hdr0->gtpu.ext->nextexthdr == GTPU_EXTHDR_PDU_SESSION)
+ {
+ gtpu_pdu_session_t *sess;
+
+ sess =
+ (gtpu_pdu_session_t *) (((char *) hdr0) +
+ sizeof (ip6_gtpu_header_t) +
+ sizeof (gtpu_exthdr_t));
+
+ hdrlen += sizeof (gtpu_pdu_session_t);
+ if (sess->u.val & GTPU_PDU_SESSION_P_BIT_MASK)
+ {
+ hdrlen += sizeof (gtpu_paging_policy_t);
+ }
+ }
+ }
+
+ if (ls_param->type == SRV6_GTP4_DT4)
+ {
+ vlib_buffer_advance (b0, (word) hdrlen);
+ ip4 = vlib_buffer_get_current (b0);
+ if ((ip4->ip_version_and_header_length & 0xf0) != 0x40)
+ {
+ next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
+ bad_n++;
+ goto DONE;
+ }
+
+ next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP4;
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->fib4_index;
+ }
+ else if (ls_param->type == SRV6_GTP4_DT6)
+ {
+ ip6 = (ip6_header_t *) ((u8 *) hdr0 + hdrlen);
+ if ((clib_net_to_host_u32
+ (ip6->ip_version_traffic_class_and_flow_label) >> 28)
+ != 6)
+ {
+ next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
+ bad_n++;
+ goto DONE;
+ }
+
+ next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP6;
+ if ((ip6->dst_address.as_u8[0] == 0xff)
+ && ((ip6->dst_address.as_u8[1] & 0xc0) == 0x80))
+ {
+ next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP4;
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->local_fib_index;
+ }
+ else
+ {
+ vlib_buffer_advance (b0, (word) hdrlen);
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->fib6_index;
+ }
+ }
+ else if (ls_param->type == SRV6_GTP4_DT46)
+ {
+ ip6 = (ip6_header_t *) ((u8 *) hdr0 + hdrlen);
+ if ((clib_net_to_host_u32
+ (ip6->ip_version_traffic_class_and_flow_label) >> 28)
+ == 6)
+ {
+ next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP6;
+ if ((ip6->dst_address.as_u8[0] == 0xff)
+ && ((ip6->dst_address.as_u8[1] & 0xc0) == 0x80))
+ {
+ next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP4;
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->local_fib_index;
+ }
+ else
+ {
+ vlib_buffer_advance (b0, (word) hdrlen);
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->fib6_index;
+ }
+ }
+ else
+ if ((clib_net_to_host_u32
+ (ip6->ip_version_traffic_class_and_flow_label) >> 28)
+ == 4)
+ {
+ vlib_buffer_advance (b0, (word) hdrlen);
+ next0 = SRV6_T_M_GTP4_DT_NEXT_LOOKUP4;
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ ls_param->fib4_index;
+ }
+ else
+ {
+ next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
+ bad_n++;
+ goto DONE;
+ }
+ }
+ else
+ {
+ next0 = SRV6_T_M_GTP4_DT_NEXT_DROP;
+ bad_n++;
+ goto DONE;
+ }
+
+ good_n++;
+
+ if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
+ PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ srv6_end_rewrite_trace_t *tr =
+ vlib_add_trace (vm, node, b0, sizeof (*tr));
+ clib_memcpy (tr->src.as_u8, src.as_u8,
+ sizeof (ip6_address_t));
+ clib_memcpy (tr->dst.as_u8, dst.as_u8,
+ sizeof (ip6_address_t));
+ tr->teid = teid;
+ }
+ }
+
+ DONE:
+ 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_node_increment_counter (vm, sm->t_m_gtp4_dt_node_index,
+ SRV6_T_ERROR_M_GTP4_DT_BAD_PACKETS, bad_n);
+
+ vlib_node_increment_counter (vm, sm->t_m_gtp4_dt_node_index,
+ SRV6_T_ERROR_M_GTP4_DT_PACKETS, good_n);
+
+ return frame->n_vectors;
+}
+