Commit 97aeb877 authored by David S. Miller's avatar David S. Miller
Browse files
Tony Nguyen says:

====================
ice: GTP support in switchdev

Marcin Szycik says:

Add support for adding GTP-C and GTP-U filters in switchdev mode.

To create a filter for GTP, create a GTP-type netdev with ip tool, enable
hardware offload, add qdisc and add a filter in tc:

ip link add $GTP0 type gtp role <sgsn/ggsn> hsize <hsize>
ethtool -K $PF0 hw-tc-offload on
tc qdisc add dev $GTP0 ingress
tc filter add dev $GTP0 ingress prio 1 flower enc_key_id 1337 \
action mirred egress redirect dev $VF1_PR

By default, a filter for GTP-U will be added. To add a filter for GTP-C,
specify enc_dst_port = 2123, e.g.:

tc filter add dev $GTP0 ingress prio 1 flower enc_key_id 1337 \
enc_dst_port 2123 action mirred egress redirect dev $VF1_PR

Note: outer IPv6 offload is not supported yet.
Note: GTP-U with no payload offload is not supported yet.

ICE COMMS package is required to create a filter as it contains GTP
profiles.

Changes in iproute2 [1] are required to be able to add GTP netdev and use
GTP-specific options (QFI and PDU type).

[1] https://lore.kernel.org/netdev/20220211182902.11542-1-wojciech.drewek@intel.com/T


---
v2: Add more CC
v3: Fix mail thread, sorry for spam
v4: Add GTP echo response in gtp module
v5: Change patch order
v6: Add GTP echo request in gtp module
v7: Fix kernel-docs in ice
v8: Remove handling of GTP Echo Response
v9: Add sending of multicast message on GTP Echo Response, fix GTP-C dummy
    packet selection
v10: Rebase, fixed most 80 char line limits
v11: Rebase, collect Harald's Reviewed-by on patch 3
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4d17d43d 9a225f81
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@
#include <net/gre.h>
#include <net/udp_tunnel.h>
#include <net/vxlan.h>
#include <net/gtp.h>
#if IS_ENABLED(CONFIG_DCB)
#include <scsi/iscsi_proto.h>
#endif /* CONFIG_DCB */
+38 −15
Original line number Diff line number Diff line
@@ -1804,16 +1804,43 @@ static struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
	return bld;
}

static bool ice_is_gtp_u_profile(u16 prof_idx)
{
	return (prof_idx >= ICE_PROFID_IPV6_GTPU_TEID &&
		prof_idx <= ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER) ||
	       prof_idx == ICE_PROFID_IPV4_GTPU_TEID;
}

static bool ice_is_gtp_c_profile(u16 prof_idx)
{
	switch (prof_idx) {
	case ICE_PROFID_IPV4_GTPC_TEID:
	case ICE_PROFID_IPV4_GTPC_NO_TEID:
	case ICE_PROFID_IPV6_GTPC_TEID:
	case ICE_PROFID_IPV6_GTPC_NO_TEID:
		return true;
	default:
		return false;
	}
}

/**
 * ice_get_sw_prof_type - determine switch profile type
 * @hw: pointer to the HW structure
 * @fv: pointer to the switch field vector
 * @prof_idx: profile index to check
 */
static enum ice_prof_type
ice_get_sw_prof_type(struct ice_hw *hw, struct ice_fv *fv)
ice_get_sw_prof_type(struct ice_hw *hw, struct ice_fv *fv, u32 prof_idx)
{
	u16 i;

	if (ice_is_gtp_c_profile(prof_idx))
		return ICE_PROF_TUN_GTPC;

	if (ice_is_gtp_u_profile(prof_idx))
		return ICE_PROF_TUN_GTPU;

	for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) {
		/* UDP tunnel will have UDP_OF protocol ID and VNI offset */
		if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF &&
@@ -1860,7 +1887,7 @@ ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,

		if (fv) {
			/* Determine field vector type */
			prof_type = ice_get_sw_prof_type(hw, fv);
			prof_type = ice_get_sw_prof_type(hw, fv, offset);

			if (req_profs & prof_type)
				set_bit((u16)offset, bm);
@@ -1871,20 +1898,19 @@ ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
/**
 * ice_get_sw_fv_list
 * @hw: pointer to the HW structure
 * @prot_ids: field vector to search for with a given protocol ID
 * @ids_cnt: lookup/protocol count
 * @lkups: list of protocol types
 * @bm: bitmap of field vectors to consider
 * @fv_list: Head of a list
 *
 * Finds all the field vector entries from switch block that contain
 * a given protocol ID and returns a list of structures of type
 * a given protocol ID and offset and returns a list of structures of type
 * "ice_sw_fv_list_entry". Every structure in the list has a field vector
 * definition and profile ID information
 * NOTE: The caller of the function is responsible for freeing the memory
 * allocated for every list entry.
 */
int
ice_get_sw_fv_list(struct ice_hw *hw, u8 *prot_ids, u16 ids_cnt,
ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups,
		   unsigned long *bm, struct list_head *fv_list)
{
	struct ice_sw_fv_list_entry *fvl;
@@ -1896,7 +1922,7 @@ ice_get_sw_fv_list(struct ice_hw *hw, u8 *prot_ids, u16 ids_cnt,

	memset(&state, 0, sizeof(state));

	if (!ids_cnt || !hw->seg)
	if (!lkups->n_val_words || !hw->seg)
		return -EINVAL;

	ice_seg = hw->seg;
@@ -1915,20 +1941,17 @@ ice_get_sw_fv_list(struct ice_hw *hw, u8 *prot_ids, u16 ids_cnt,
		if (!test_bit((u16)offset, bm))
			continue;

		for (i = 0; i < ids_cnt; i++) {
		for (i = 0; i < lkups->n_val_words; i++) {
			int j;

			/* This code assumes that if a switch field vector line
			 * has a matching protocol, then this line will contain
			 * the entries necessary to represent every field in
			 * that protocol header.
			 */
			for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
				if (fv->ew[j].prot_id == prot_ids[i])
				if (fv->ew[j].prot_id ==
				    lkups->fv_words[i].prot_id &&
				    fv->ew[j].off == lkups->fv_words[i].off)
					break;
			if (j >= hw->blk[ICE_BLK_SW].es.fvw)
				break;
			if (i + 1 == ids_cnt) {
			if (i + 1 == lkups->n_val_words) {
				fvl = devm_kzalloc(ice_hw_to_dev(hw),
						   sizeof(*fvl), GFP_KERNEL);
				if (!fvl)
+1 −1
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type type,
void
ice_init_prof_result_bm(struct ice_hw *hw);
int
ice_get_sw_fv_list(struct ice_hw *hw, u8 *prot_ids, u16 ids_cnt,
ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups,
		   unsigned long *bm, struct list_head *fv_list);
int
ice_pkg_buf_unreserve_section(struct ice_buf_build *bld, u16 count);
+5 −1
Original line number Diff line number Diff line
@@ -417,6 +417,8 @@ enum ice_tunnel_type {
	TNL_VXLAN = 0,
	TNL_GENEVE,
	TNL_GRETAP,
	TNL_GTPC,
	TNL_GTPU,
	__TNL_TYPE_CNT,
	TNL_LAST = 0xFF,
	TNL_ALL = 0xFF,
@@ -673,7 +675,9 @@ enum ice_prof_type {
	ICE_PROF_NON_TUN = 0x1,
	ICE_PROF_TUN_UDP = 0x2,
	ICE_PROF_TUN_GRE = 0x4,
	ICE_PROF_TUN_ALL = 0x6,
	ICE_PROF_TUN_GTPU = 0x8,
	ICE_PROF_TUN_GTPC = 0x10,
	ICE_PROF_TUN_ALL = 0x1E,
	ICE_PROF_ALL = 0xFF,
};

+19 −0
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@ enum ice_protocol_type {
	ICE_VXLAN,
	ICE_GENEVE,
	ICE_NVGRE,
	ICE_GTP,
	ICE_GTP_NO_PAY,
	ICE_VXLAN_GPE,
	ICE_SCTP_IL,
	ICE_PROTOCOL_LAST
@@ -52,6 +54,8 @@ enum ice_sw_tunnel_type {
	ICE_SW_TUN_VXLAN,
	ICE_SW_TUN_GENEVE,
	ICE_SW_TUN_NVGRE,
	ICE_SW_TUN_GTPU,
	ICE_SW_TUN_GTPC,
	ICE_ALL_TUNNELS /* All tunnel types including NVGRE */
};

@@ -182,6 +186,20 @@ struct ice_udp_tnl_hdr {
	__be32 vni;     /* only use lower 24-bits */
};

struct ice_udp_gtp_hdr {
	u8 flags;
	u8 msg_type;
	__be16 rsrvd_len;
	__be32 teid;
	__be16 rsrvd_seq_nbr;
	u8 rsrvd_n_pdu_nbr;
	u8 rsrvd_next_ext;
	u8 rsvrd_ext_len;
	u8 pdu_type;
	u8 qfi;
	u8 rsvrd;
};

struct ice_nvgre_hdr {
	__be16 flags;
	__be16 protocol;
@@ -198,6 +216,7 @@ union ice_prot_hdr {
	struct ice_sctp_hdr sctp_hdr;
	struct ice_udp_tnl_hdr tnl_hdr;
	struct ice_nvgre_hdr nvgre_hdr;
	struct ice_udp_gtp_hdr gtp_hdr;
};

/* This is mapping table entry that maps every word within a given protocol
Loading