The SmartNIC can fully offload GTPv1-U encapsulation and decapsulation for UPF frame processing in the 5G core network architecture. Use this DPDK API example to configure the SmartNIC for GTPv1-U encapsulation and decapsulation.
GTPv1-U encapsulation on downlink
For GTP-U encapsulation, the MAC headers must be decapsulated using RTE_FLOW_ACTION_TYPE_RAW_DECAP first. After the MAC header is decapsulated, the GTP-U header can be encapsulated using RTE_FLOW_ACTION_TYPE_RAW_ENCAP. This example shows how to configure the SmartNIC to decapsulate the MAC header using the rte_flow_action_raw_decap structure and encapsulate the MAC/IP/UDP/GTPv1-U headers using the rte_flow_action_raw_encap structure.
/* Create group 1 exact match 5-tuple to retransmit offloaded IPv4 UDP packets. */ struct rte_flow_attr attr = { .group = 1, .ingress = 1 }; struct rte_flow_item_ipv4 ipv4 = { .hdr = { .src_addr = RTE_BE32(RTE_IPV4(192, 168, 0, 2)), .dst_addr = RTE_BE32(RTE_IPV4(192, 168, 1, 1)) }}; struct rte_flow_item_udp udp = { .hdr = { .src_port = RTE_BE16(0x1000), .dst_port = RTE_BE16(0x1001) }}; struct rte_flow_item pattern[] = { [0] = { .type = RTE_FLOW_ITEM_TYPE_IPV4, .spec = &ipv4, .mask = &rte_flow_item_ipv4_mask }, [1] = { .type = RTE_FLOW_ITEM_TYPE_UDP, .spec = &udp, .mask = &rte_flow_item_udp_mask }}; /* Decap data */ struct rte_ether_hdr d_eth = { .ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4) }; uint8_t decap_data[sizeof(d_eth)]; memcpy(decap_data, &d_eth, sizeof(d_eth)); /* Encap data */ struct rte_ether_hdr e_eth = { .dst_addr.addr_bytes = "\xAA\xBB\xCC\xDD\xEE\xFF", .src_addr.addr_bytes = "\x11\xEE\xDD\xCC\xBB\xAA", .ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4) }; struct rte_ipv4_hdr e_ipv4 = { .version_ihl = 0x45, .src_addr = RTE_BE32(RTE_IPV4(10, 10, 0, 0)), .dst_addr = RTE_BE32(RTE_IPV4(10, 10, 0, 0)), .type_of_service = 10, .time_to_live = 0x40, .next_proto_id = IPPROTO_UDP }; struct rte_udp_hdr e_udp = { .dst_port = RTE_BE16(RTE_GTPU_UDP_PORT) }; struct rte_gtp_hdr e_gtp = { .ver = 1, .pt = 1, .e = 1, .msg_type = 255, .teid = RTE_BE32(0x00000000) }; struct rte_gtp_hdr_ext_word e_gtp_ext = { .next_ext = 0x85 }; struct gtp_pdu_session_container { uint8_t ext_hdr_len; uint8_t type_spare; uint8_t ppp_rqi_qfi; uint8_t next_ext; } e_gtp_psc = { .ext_hdr_len = 1, .type_spare = 0x10, .ppp_rqi_qfi = 6, .next_ext = 0 }; uint64_t encap_it = 0; uint8_t encap_data[sizeof(e_eth) + sizeof(e_ipv4) + sizeof(e_udp) + sizeof(e_gtp) + sizeof(e_gtp_ext) + sizeof(e_gtp_psc)]; memcpy(encap_data + encap_it, &e_eth, sizeof(e_eth)); encap_it += sizeof(e_eth); memcpy(encap_data + encap_it, &e_ipv4, sizeof(e_ipv4)); encap_it += sizeof(e_ipv4); memcpy(encap_data + encap_it, &e_udp, sizeof(e_udp)); encap_it += sizeof(e_udp); memcpy(encap_data + encap_it, &e_gtp, sizeof(e_gtp)); encap_it += sizeof(e_gtp); memcpy(encap_data + encap_it, &e_gtp_ext, sizeof(e_gtp_ext)); encap_it += sizeof(e_gtp_ext); memcpy(encap_data + encap_it, &e_gtp_psc, sizeof(e_gtp_psc)); /* Actions */ struct rte_flow_action_raw_decap raw_decap = { .data = decap_data, .size = sizeof(decap_data) }; struct rte_flow_action_raw_encap raw_encap = { .data = encap_data, .size = sizeof(encap_data) }; struct rte_flow_action_modify_field modify_field = { .operation = RTE_FLOW_MODIFY_SET, .dst = { .field = RTE_FLOW_FIELD_GTP_TEID }, .src = { .field = RTE_FLOW_FIELD_VALUE, .value = "\x40\x41\x42\x43" }, .width = 4}; struct rte_flow_action_port_id port_id = { .id = 1 }; struct rte_flow_action action[] = { [0] = { .type = RTE_FLOW_ACTION_TYPE_RAW_DECAP, .conf = &raw_decap }, [1] = { .type = RTE_FLOW_ACTION_TYPE_RAW_ENCAP, .conf = &raw_encap }, [2] = { .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, .conf = &modify_field }, [3] = { .type = RTE_FLOW_ACTION_TYPE_PORT_ID, .conf = &port_id }, [4] = { .type = RTE_FLOW_ACTION_TYPE_END }}; struct rte_flow_error error; struct rte_flow *flow = rte_flow_create(PORT_ID, &attr, pattern, action, &error); if (!flow) { /* Error handling */ }
GTPv1-U decapsulation on uplink
For GTPv1-U decapsulation, the MAC/IP/UDP/GTPv-U headers must be decapsulated using RTE_FLOW_ACTION_TYPE_RAW_DECAP first. After the GTPv1-U header is decapsulated, the MAC header can be encapsulated using RTE_FLOW_ACTION_TYPE_RAW_ENCAP. This example shows how to decapsulate the MAC/IP/UDP/GTPv1-U headers using the rte_flow_action_raw_decap structure and encapsulate the MAC header using the rte_flow_action_raw_encap structure.
/* Create group 1 exact match 5-tuple to retransmit offloaded IPv4 UDP packets. */ struct rte_flow_attr attr = { .group = 1, .ingress = 1 }; struct rte_flow_item_ipv4 ipv4 = { .hdr = { .src_addr = RTE_BE32(RTE_IPV4(192, 168, 0, 2)), .dst_addr = RTE_BE32(RTE_IPV4(192, 168, 1, 1)) }}; struct rte_flow_item_udp udp = { .hdr = { .src_port = RTE_BE16(0x1000), .dst_port = RTE_BE16(0x1001) }}; struct rte_flow_item pattern[] = { [0] = { .type = RTE_FLOW_ITEM_TYPE_IPV4, .spec = &ipv4, .mask = &rte_flow_item_ipv4_mask }, [1] = { .type = RTE_FLOW_ITEM_TYPE_UDP, .spec = &udp, .mask = &rte_flow_item_udp_mask }}; /* Decap data */ struct rte_ether_hdr d_eth = { .ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4) }; struct rte_ipv4_hdr d_ipv4 = { .version_ihl = 0x45, .next_proto_id = IPPROTO_UDP }; struct rte_udp_hdr d_udp = { .dst_port = RTE_BE16(RTE_GTPU_UDP_PORT) }; struct rte_gtp_hdr d_gtp = { .ver = 1, .pt = 1, .e = 1, .msg_type = 255}; struct rte_gtp_hdr_ext_word d_gtp_ext = { .next_ext = 0x85 }; struct gtp_pdu_session_container { uint8_t ext_hdr_len; uint8_t type_spare; uint8_t ppp_rqi_qfi; uint8_t next_ext; } d_gtp_psc = { .ext_hdr_len = 1, .type_spare = 0x10}; uint64_t decap_it = 0; uint8_t decap_data[sizeof(d_eth) + sizeof(d_ipv4) + sizeof(d_udp) + sizeof(d_gtp) + sizeof(d_gtp_ext) + sizeof(d_gtp_psc)]; memcpy(decap_data + decap_it, &d_eth, sizeof(d_eth)); decap_it += sizeof(d_eth); memcpy(decap_data + decap_it, &d_ipv4, sizeof(d_ipv4)); decap_it += sizeof(d_ipv4); memcpy(decap_data + decap_it, &d_udp, sizeof(d_udp)); decap_it += sizeof(d_udp); memcpy(decap_data + decap_it, &d_gtp, sizeof(d_gtp)); decap_it += sizeof(d_gtp); memcpy(decap_data + decap_it, &d_gtp_ext, sizeof(d_gtp_ext)); decap_it += sizeof(d_gtp_ext); memcpy(decap_data + decap_it, &d_gtp_psc, sizeof(d_gtp_psc)); /* Encap data */ struct rte_ether_hdr e_eth = { .dst_addr.addr_bytes = "\xAA\xBB\xCC\xDD\xEE\xFF", .src_addr.addr_bytes = "\x11\xEE\xDD\xCC\xBB\xAA", .ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4) }; uint8_t encap_data[sizeof(e_eth)]; memcpy(encap_data, &e_eth, sizeof(e_eth)); /* Actions */ struct rte_flow_action_raw_decap raw_decap = { .data = decap_data, .size = sizeof(decap_data) }; struct rte_flow_action_raw_encap raw_encap = { .data = encap_data, .size = sizeof(encap_data) }; struct rte_flow_action_port_id port_id = { .id = 1 }; struct rte_flow_action action[] = { [0] = { .type = RTE_FLOW_ACTION_TYPE_RAW_DECAP, .conf = &raw_decap }, [1] = { .type = RTE_FLOW_ACTION_TYPE_RAW_ENCAP, .conf = &raw_encap }, [2] = { .type = RTE_FLOW_ACTION_TYPE_PORT_ID, .conf = &port_id }, [3] = { .type = RTE_FLOW_ACTION_TYPE_END }}; struct rte_flow_error error; struct rte_flow *flow = rte_flow_create(PORT_ID, &attr, pattern, action, &error); if (!flow) { /* Error handling */ }