Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PATCH v10] api: add custom LSO operation for setting flag bits #2117

Merged
merged 4 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example/sysinfo/odp_sysinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ static void print_pktio_capa(appl_args_t *appl_args)
printf(" lso.mod_op.add_payload_len: %u\n", capa->lso.mod_op.add_payload_len);
printf(" lso.mod_op.add_payload_offset: %u\n",
capa->lso.mod_op.add_payload_offset);
printf(" lso.mod_op.write_bits: %u\n", capa->lso.mod_op.write_bits);
printf(" lso.max_num_custom: %u\n", capa->lso.max_num_custom);
printf(" lso.proto.custom: %u\n", capa->lso.proto.custom);
printf(" lso.proto.ipv4: %u\n", capa->lso.proto.ipv4);
Expand Down
50 changes: 45 additions & 5 deletions include/odp/api/spec/packet_io_types.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) 2013-2018 Linaro Limited
* Copyright (c) 2020-2023 Nokia
* Copyright (c) 2020-2024 Nokia
*/

/**
Expand Down Expand Up @@ -777,7 +777,10 @@ typedef enum odp_lso_modify_t {
ODP_LSO_ADD_PAYLOAD_LEN = 0x2,

/** Add number of payload bytes in all previous segments */
ODP_LSO_ADD_PAYLOAD_OFFSET = 0x4
ODP_LSO_ADD_PAYLOAD_OFFSET = 0x4,

/** Write bits in the first, middle and last segment */
ODP_LSO_WRITE_BITS,

} odp_lso_modify_t;

Expand Down Expand Up @@ -857,6 +860,9 @@ typedef struct odp_lso_capability_t {
/** ODP_LSO_ADD_PAYLOAD_OFFSET support */
uint16_t add_payload_offset:1;

/** ODP_LSO_WRITE_BITS support */
uint16_t write_bits:1;

} mod_op;

/** Maximum number of custom fields supported per LSO profile. When zero, custom
Expand Down Expand Up @@ -1080,6 +1086,18 @@ typedef struct odp_pktio_capability_t {

} odp_pktio_capability_t;

/** Parameters for ODP_LSO_WRITE_BITS custom operation */
typedef struct odp_lso_write_bits_t {
/** Bitmask to select which bits to write */
uint8_t mask[1];

/** Value to be written using the mask:
* new_value[n] = (old_value[n] & ~mask[n]) | (value[n] & mask[n])
*/
uint8_t value[1];

} odp_lso_write_bits_t;

/**
* LSO profile parameters
*/
Expand All @@ -1089,8 +1107,10 @@ typedef struct odp_lso_profile_param_t {
*
* Selects on which protocol LSO operation performs segmentation (e.g. IP fragmentation vs.
* TCP segmentation). When ODP_LSO_PROTO_CUSTOM is selected, only custom field
* modifications are performed. The default value is ODP_LSO_PROTO_NONE. Check LSO
* capability for supported protocols.
* modifications are performed. Packet content is not modified when a packet is not
* segmented.
*
* The default value is ODP_LSO_PROTO_NONE. Check LSO capability for supported protocols.
*/
odp_lso_protocol_t lso_proto;

Expand All @@ -1099,6 +1119,12 @@ typedef struct odp_lso_profile_param_t {
*
* Set lso_proto to ODP_LSO_PROTO_CUSTOM when using custom fields. Fields are defined
* in the same order they appear in the packet.
*
* Fields may not modify overlapping packet bytes except as follows:
* - An ODP_LSO_WRITE_BITS operation may modify the same byte as an ODP_LSO_ADD_* operation.
* In that case the write-bits operation is done after the add operation, overwriting
* some of the bits written by the add operation. Such write-bits field must appear
* after the overlapping add field.
*/
struct {
/** Custom field to be modified by LSO */
Expand All @@ -1111,9 +1137,23 @@ typedef struct odp_lso_profile_param_t {
/** Field offset in bytes from packet start */
uint32_t offset;

/** Field size in bytes. Valid values are 1, 2, 4, and 8 bytes. */
/** Field size in bytes. Valid values are 1, 2, 4, and 8 bytes.
* Must be set to 1 in ODP_LSO_WRITE_BITS operation.
*/
uint8_t size;

/** Operation specific parameters */
union {
/** Parameters for ODP_LSO_WRITE_BITS operation */
struct {
/** bits to write in the first segment */
odp_lso_write_bits_t first_seg;
/** bits to write in middle segments */
odp_lso_write_bits_t middle_seg;
/** bits to write in the last segment */
odp_lso_write_bits_t last_seg;
} write_bits;
};
} field[ODP_LSO_MAX_CUSTOM];

/** Number of custom fields specified. The default value is 0. */
Expand Down
28 changes: 24 additions & 4 deletions platform/linux-generic/odp_packet_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -1593,6 +1593,7 @@ int odp_pktio_capability(odp_pktio_t pktio, odp_pktio_capability_t *capa)
capa->lso.proto.ipv4 = 1;
capa->lso.proto.custom = 1;
capa->lso.mod_op.add_segment_num = 1;
capa->lso.mod_op.write_bits = 1;

capa->tx_compl.queue_type_sched = 1;
capa->tx_compl.queue_type_plain = 1;
Expand Down Expand Up @@ -2861,8 +2862,16 @@ odp_lso_profile_t odp_lso_profile_create(odp_pktio_t pktio, const odp_lso_profil
return ODP_LSO_PROFILE_INVALID;
}

/* Currently only segment number supported */
if (mod_op != ODP_LSO_ADD_SEGMENT_NUM) {
switch (mod_op) {
case ODP_LSO_ADD_SEGMENT_NUM:
break;
case ODP_LSO_WRITE_BITS:
if (size != 1) {
_ODP_ERR("Bad custom field size %u\n", size);
return ODP_LSO_PROFILE_INVALID;
}
break;
default:
_ODP_ERR("Custom modify operation %u not supported\n", mod_op);
return ODP_LSO_PROFILE_INVALID;
}
Expand Down Expand Up @@ -2999,7 +3008,7 @@ static int lso_update_ipv4(odp_packet_t pkt, int index, int num_pkt,
return ret;
}

static int lso_update_custom(lso_profile_t *lso_prof, odp_packet_t pkt, int segnum)
static int lso_update_custom(lso_profile_t *lso_prof, odp_packet_t pkt, int segnum, int num_segs)
{
void *ptr;
int i, mod_op;
Expand Down Expand Up @@ -3046,6 +3055,17 @@ static int lso_update_custom(lso_profile_t *lso_prof, odp_packet_t pkt, int segn
u16 = odp_cpu_to_be_16(segnum + odp_be_to_cpu_16(u16));
else
u8 += segnum;
} else if (mod_op == ODP_LSO_WRITE_BITS) {
odp_lso_write_bits_t bits;

if (segnum == 0)
bits = lso_prof->param.custom.field[i].write_bits.first_seg;
else if (segnum == num_segs - 1)
bits = lso_prof->param.custom.field[i].write_bits.last_seg;
else
bits = lso_prof->param.custom.field[i].write_bits.middle_seg;

u8 = (u8 & ~bits.mask[0]) | (bits.value[0] & bits.mask[0]);
}

if (odp_packet_copy_from_mem(pkt, offset, size, ptr)) {
Expand Down Expand Up @@ -3207,7 +3227,7 @@ int _odp_lso_create_packets(odp_packet_t packet, const odp_packet_lso_opt_t *lso
int num_custom = lso_prof->param.custom.num_custom;

for (i = 0; num_custom && i < num_pkt; i++) {
if (lso_update_custom(lso_prof, pkt_out[i], i)) {
if (lso_update_custom(lso_prof, pkt_out[i], i, num_pkt)) {
_ODP_ERR("Custom field update failed. Segment %i\n", i);
goto error;
}
Expand Down
130 changes: 114 additions & 16 deletions test/validation/api/pktio/lso.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,23 @@
#define LSO_TEST_MARKER_ETHERTYPE 0x88B6 /* Local experimental Ethertype */
#define LSO_TEST_CUSTOM_ETHERTYPE 0x88B5 /* Must match test packets. */
#define LSO_TEST_CUSTOM_ETH_SEGNUM_OFFSET 16
#define LSO_TEST_CUSTOM_ETH_BITS_OFFSET LSO_TEST_CUSTOM_ETH_SEGNUM_OFFSET /* Intentional overlap */
#define LSO_TEST_MIN_ETH_PKT_LEN 60 /* CRC not included in ODP packets */
#define LSO_TEST_IPV4_FLAG_MF 0x2000 /* More fragments flag within the frag_offset field */
#define LSO_TEST_IPV4_FLAG_DF 0x4000 /* Don't fragment flag within the frag_offset field */
#define LSO_TEST_IPV4_FRAG_OFFS_MASK 0x1fff /* Fragment offset bits in the frag_offset field */
/* Segment number field value in the original packet. Nonzero to verify that the LSO operation
* adds to the value instead of simply overwriting it. */
#define LSO_TEST_CUSTOM_ETH_SEGNUM 0x00fe
* adds to the value instead of simply overwriting it. We use binary 10101010 bit pattern in the
* most significant byte for testing overlapping write bits operations */
#define LSO_TEST_CUSTOM_ETH_SEGNUM 0xaafe
/* Parameters for write bits custom operation. These should flip the corresponding bit pairs
* of the original packet (in the most significant byte of the segment number field */
#define LSO_TEST_FIRST_SEG_MASK (3 << 2)
#define LSO_TEST_FIRST_SEG_VALUE ((1 << 2) | 1) /* set an extra bit that must be ignored */
#define LSO_TEST_MIDDLE_SEG_MASK (3 << 4)
#define LSO_TEST_MIDDLE_SEG_VALUE (1 << 4)
#define LSO_TEST_LAST_SEG_MASK (3 << 6)
#define LSO_TEST_LAST_SEG_VALUE (1 << 6)

/* Pktio interface info
*/
Expand Down Expand Up @@ -496,7 +506,22 @@ static int check_lso_custom(void)
if (pktio_a->capa.lso.max_profiles == 0 || pktio_a->capa.lso.max_profiles_per_pktio == 0)
return ODP_TEST_INACTIVE;

if (pktio_a->capa.lso.proto.custom == 0 || pktio_a->capa.lso.mod_op.add_segment_num == 0)
if (pktio_a->capa.lso.proto.custom == 0)
return ODP_TEST_INACTIVE;

if (pktio_a->capa.lso.mod_op.add_segment_num == 0 &&
pktio_a->capa.lso.mod_op.write_bits == 0)
return ODP_TEST_INACTIVE;

return ODP_TEST_ACTIVE;
}

static int check_lso_custom_segnum(void)
{
if (check_lso_custom() == ODP_TEST_INACTIVE)
return ODP_TEST_INACTIVE;

if (pktio_a->capa.lso.mod_op.add_segment_num == 0)
return ODP_TEST_INACTIVE;

return ODP_TEST_ACTIVE;
Expand Down Expand Up @@ -596,7 +621,8 @@ static void lso_capability(void)

CU_ASSERT(pktio_a->capa.lso.mod_op.add_segment_num ||
pktio_a->capa.lso.mod_op.add_payload_len ||
pktio_a->capa.lso.mod_op.add_payload_offset)
pktio_a->capa.lso.mod_op.add_payload_offset ||
pktio_a->capa.lso.mod_op.write_bits)
}
}

Expand Down Expand Up @@ -822,8 +848,8 @@ static int is_custom_eth_test_pkt(odp_packet_t pkt)
return ethertype(pkt) == LSO_TEST_CUSTOM_ETHERTYPE;
}

static void update_custom_eth_hdr(uint8_t *hdr, uint32_t hdr_len, odp_packet_t pkt,
uint16_t seg_num, uint16_t seg_offset, uint16_t num_segs)
static void update_custom_hdr_segnum(uint8_t *hdr, uint32_t hdr_len, odp_packet_t pkt,
uint16_t seg_num, uint16_t seg_offset, uint16_t num_segs)
{
(void)pkt;
(void)seg_offset;
Expand All @@ -834,23 +860,95 @@ static void update_custom_eth_hdr(uint8_t *hdr, uint32_t hdr_len, odp_packet_t p
memcpy(hdr + LSO_TEST_CUSTOM_ETH_SEGNUM_OFFSET, &segnum_be, sizeof(segnum_be));
}

static void update_custom_hdr_bits(uint8_t *hdr, uint32_t hdr_len, odp_packet_t pkt,
uint16_t seg_num, uint16_t seg_offset, uint16_t num_segs)
{
(void)hdr_len;
(void)pkt;
(void)seg_offset;
uint8_t value;

if (seg_num == 0) {
value = LSO_TEST_FIRST_SEG_VALUE & LSO_TEST_FIRST_SEG_MASK;
hdr[LSO_TEST_CUSTOM_ETH_BITS_OFFSET] &= ~LSO_TEST_FIRST_SEG_MASK;
hdr[LSO_TEST_CUSTOM_ETH_BITS_OFFSET] |= value;
} else if (seg_num < num_segs - 1) {
value = LSO_TEST_MIDDLE_SEG_VALUE & LSO_TEST_MIDDLE_SEG_MASK;
hdr[LSO_TEST_CUSTOM_ETH_BITS_OFFSET] &= ~LSO_TEST_MIDDLE_SEG_MASK;
hdr[LSO_TEST_CUSTOM_ETH_BITS_OFFSET] |= value;
} else {
value = LSO_TEST_LAST_SEG_VALUE & LSO_TEST_LAST_SEG_MASK;
hdr[LSO_TEST_CUSTOM_ETH_BITS_OFFSET] &= ~LSO_TEST_LAST_SEG_MASK;
hdr[LSO_TEST_CUSTOM_ETH_BITS_OFFSET] |= value;
}
}

static void update_custom_hdr_segnum_bits(uint8_t *hdr, uint32_t hdr_len, odp_packet_t pkt,
uint16_t seg_num, uint16_t seg_offset, uint16_t num_segs)
{
update_custom_hdr_segnum(hdr, hdr_len, pkt, seg_num, seg_offset, num_segs);
update_custom_hdr_bits(hdr, hdr_len, pkt, seg_num, seg_offset, num_segs);
}

static void add_profile_param_custom_segnum(odp_lso_profile_param_t *param)
{
uint8_t idx = param->custom.num_custom++;

param->custom.field[idx].mod_op = ODP_LSO_ADD_SEGMENT_NUM;
param->custom.field[idx].offset = LSO_TEST_CUSTOM_ETH_SEGNUM_OFFSET;
param->custom.field[idx].size = 2;
}

static void add_profile_param_custom_write_bits(odp_lso_profile_param_t *param)
{
uint8_t idx = param->custom.num_custom++;

param->custom.field[idx].mod_op = ODP_LSO_WRITE_BITS;
param->custom.field[idx].offset = LSO_TEST_CUSTOM_ETH_BITS_OFFSET;
param->custom.field[idx].size = 1;
param->custom.field[idx].write_bits.first_seg.mask[0] = LSO_TEST_FIRST_SEG_MASK;
param->custom.field[idx].write_bits.first_seg.value[0] = LSO_TEST_FIRST_SEG_VALUE;
param->custom.field[idx].write_bits.middle_seg.mask[0] = LSO_TEST_MIDDLE_SEG_MASK;
param->custom.field[idx].write_bits.middle_seg.value[0] = LSO_TEST_MIDDLE_SEG_VALUE;
param->custom.field[idx].write_bits.last_seg.mask[0] = LSO_TEST_LAST_SEG_MASK;
param->custom.field[idx].write_bits.last_seg.value[0] = LSO_TEST_LAST_SEG_VALUE;
}

static void lso_send_custom_eth(const uint8_t *test_packet, uint32_t pkt_len, uint32_t max_payload,
int use_opt)
{
odp_lso_profile_param_t param;
const uint32_t hdr_len = ODPH_ETHHDR_LEN + 8; /* Ethernet header + custom header 8B */
uint32_t l3_offset = 0;

odp_lso_profile_param_init(&param);
param.lso_proto = ODP_LSO_PROTO_CUSTOM;
param.custom.num_custom = 1;
param.custom.field[0].mod_op = ODP_LSO_ADD_SEGMENT_NUM;
param.custom.field[0].offset = LSO_TEST_CUSTOM_ETH_SEGNUM_OFFSET;
param.custom.field[0].size = 2;
if (pktio_a->capa.lso.mod_op.add_segment_num) {
odp_lso_profile_param_init(&param);
param.lso_proto = ODP_LSO_PROTO_CUSTOM;
add_profile_param_custom_segnum(&param);
lso_test(param, max_payload, test_packet, pkt_len, hdr_len, l3_offset, use_opt,
is_custom_eth_test_pkt,
update_custom_hdr_segnum);
}
if (pktio_a->capa.lso.mod_op.write_bits) {
odp_lso_profile_param_init(&param);
param.lso_proto = ODP_LSO_PROTO_CUSTOM;
add_profile_param_custom_write_bits(&param);
lso_test(param, max_payload, test_packet, pkt_len, hdr_len, l3_offset, use_opt,
is_custom_eth_test_pkt,
update_custom_hdr_bits);
}

lso_test(param, max_payload, test_packet, pkt_len, hdr_len, l3_offset, use_opt,
is_custom_eth_test_pkt,
update_custom_eth_hdr);
if (pktio_a->capa.lso.max_num_custom >= 2 &&
pktio_a->capa.lso.mod_op.add_segment_num &&
pktio_a->capa.lso.mod_op.write_bits) {
odp_lso_profile_param_init(&param);
param.lso_proto = ODP_LSO_PROTO_CUSTOM;
add_profile_param_custom_segnum(&param);
add_profile_param_custom_write_bits(&param);
lso_test(param, max_payload, test_packet, pkt_len, hdr_len, l3_offset, use_opt,
is_custom_eth_test_pkt,
update_custom_hdr_segnum_bits);
}
}

static void lso_send_custom_eth_723(uint32_t max_payload, int use_opt)
Expand Down Expand Up @@ -1058,7 +1156,7 @@ static void lso_send_ipv4_1500_700_opt(void)
odp_testinfo_t lso_suite[] = {
ODP_TEST_INFO(lso_capability),
ODP_TEST_INFO_CONDITIONAL(lso_create_ipv4_profile, check_lso_ipv4),
ODP_TEST_INFO_CONDITIONAL(lso_create_custom_profile, check_lso_custom),
ODP_TEST_INFO_CONDITIONAL(lso_create_custom_profile, check_lso_custom_segnum),
ODP_TEST_INFO_CONDITIONAL(lso_send_ipv4_325_700_pkt_meta, check_lso_ipv4_segs_1),
ODP_TEST_INFO_CONDITIONAL(lso_send_ipv4_325_700_opt, check_lso_ipv4_segs_1),
ODP_TEST_INFO_CONDITIONAL(lso_send_ipv4_1500_1000_pkt_meta, check_lso_ipv4_segs_2),
Expand Down