Skip to content

Commit

Permalink
p4tc: Add checksum and hash externs
Browse files Browse the repository at this point in the history
Implement checksum and hash extern from the P4 spec.
Specifically:

Hash:

- CRC32
- CRC16
- 16Bit 1's Complement

Checksum:

- CRC32 (Add, Get, and Clear)
- CRC16 (Add, Get, and Clear)
- 16Bit 1's Complement (Add, Sub, Get, Clear)

For the checksum externs CRC16 and CRC32 we only have Add, Get and
Clear. Add will add a new value to checksum and recalculate based on
that. Get will retrieve the checksum value and clear will restart the
checksum calculation.

For 16-bit 1's complement checksum we also have the Sub operation, which
will decrease from the current checksum a specified value and recompute.

Co-developed-by: Victor Nogueira <[email protected]>
Signed-off-by: Victor Nogueira <[email protected]>
Co-developed-by: Pedro Tammela <[email protected]>
Signed-off-by: Pedro Tammela <[email protected]>
Signed-off-by: Jamal Hadi Salim <[email protected]>
  • Loading branch information
jhsmt authored and vbnogueira committed Feb 26, 2024
1 parent 608e9cb commit 33c06bf
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 0 deletions.
32 changes: 32 additions & 0 deletions include/net/p4tc_ext/ext_csum.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __NET_P4TC_EXT_CSUM_H
#define __NET_P4TC_EXT_CSUM_H

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/if_arp.h>
#include <net/netlink.h>
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>
#include <net/tc_wrapper.h>
#include <net/p4tc.h>
#include <net/p4tc_ext_api.h>
#include <net/sock.h>
#include <net/sch_generic.h>
#include <linux/filter.h>
#include <linux/list.h>
#include <linux/idr.h>
#include <linux/crc32.h>
#include <linux/crc16.h>

struct p4tc_ext_csum_params {
__wsum csum;
};

BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_crc16_add);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_crc16_get);
#endif
1 change: 1 addition & 0 deletions net/sched/p4tc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ obj-y := p4tc_types.o p4tc_tmpl_api.o p4tc_pipeline.o \
p4tc_filter.o p4tc_runtime_api.o trace.o p4tc_ext.o \
p4tc_tmpl_ext.o
obj-m += externs/ext_Counter.o
obj-m += externs/ext_csum.o
obj-$(CONFIG_DEBUG_INFO_BTF) += p4tc_bpf.o
252 changes: 252 additions & 0 deletions net/sched/p4tc/externs/ext_csum.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* net/sched/ext_csum.c P4TC Checksum e extern
*
* Copyright (c) 2023-2024, Mojatatu Networks
* Copyright (c) 2023-2024, Intel Corporation.
* Authors: Jamal Hadi Salim <[email protected]>
* Victor Nogueira <[email protected]>
* Pedro Tammela <[email protected]>
*/

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/if_arp.h>
#include <net/netlink.h>
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>
#include <net/tc_wrapper.h>
#include <net/p4tc.h>
#include <net/p4tc_ext_api.h>
#include <net/sock.h>
#include <net/sch_generic.h>
#include <linux/filter.h>
#include <linux/list.h>
#include <linux/idr.h>
#include <linux/crc32.h>
#include <linux/crc16.h>
#include <net/p4tc_ext/ext_csum.h>

static __wsum p4tc_ext_hash_16bit_complement(const void *data, int len, u16 prev)
{
return csum_partial(data, len, prev);
}

static u16 p4tc_ext_hash_16bit_complement_get(u16 prev)
{
return csum_fold(prev);
}

static u16
p4tc_ext_hash_crc16(const void *data, int len, u16 prev)
{
return crc16(prev, data, len);
}

static u32
p4tc_ext_hash_crc32(const void * data, int len, u32 prev)
{
return crc32_be(prev, data, len);
}

static void p4tc_ext_csum_params_clear(struct p4tc_ext_csum_params *params)
{
params->csum = 0;
}

/* Sub will be unoptimised
* Will only be used in specific scenarios
*/
static u16 ones_complement_sum(u16 x, u16 y) {
u32 ret = (u32 )x + (u32 )y;

if ((ret & 0xFFFF0000)) {
ret = ret + 1;
}
return (u16)(ret & 0xFFFF);
}

__diag_push();
__diag_ignore_all("-Wmissing-prototypes",
"Global functions as their definitions will be in vmlinux BTF");

__bpf_kfunc __wsum
bpf_p4tc_ext_csum_16bit_complement_add(struct p4tc_ext_csum_params *params,
const void *data, const u32 data__sz)
{
params->csum = p4tc_ext_hash_16bit_complement(data, data__sz,
params->csum);
return params->csum;
}

__bpf_kfunc int
bpf_p4tc_ext_csum_16bit_complement_sub(struct p4tc_ext_csum_params *params,
const void *data, const u32 data__sz)
{
const u16 *data_u16 = data;
int i;

if (data__sz < sizeof(u16) || (data__sz % sizeof(u16)))
return -EINVAL;

for (i = 0; i < data__sz / sizeof(u16); i++) {
u16 diff = ~data_u16[i];

params->csum = ones_complement_sum(params->csum, diff);
}

return params->csum;
}

__bpf_kfunc u16
bpf_p4tc_ext_csum_16bit_complement_get(struct p4tc_ext_csum_params *params)
{
return p4tc_ext_hash_16bit_complement_get(params->csum);
}

__bpf_kfunc void
bpf_p4tc_ext_csum_16bit_complement_clear(struct p4tc_ext_csum_params *params)
{
p4tc_ext_csum_params_clear(params);
}

__bpf_kfunc void
bpf_p4tc_ext_csum_16bit_complement_set_state(struct p4tc_ext_csum_params *params,
u16 csum)
{
params->csum = csum;
}

__bpf_kfunc u16
bpf_p4tc_ext_csum_crc16_add(struct p4tc_ext_csum_params *params,
const void *data, const u32 data__sz)
{
u16 csum;

csum = p4tc_ext_hash_crc16(data, data__sz, params->csum);

params->csum = csum;

return csum;
}

__bpf_kfunc u16
bpf_p4tc_ext_csum_crc16_get(struct p4tc_ext_csum_params *params)
{
return (u16) params->csum;
}

__bpf_kfunc void
bpf_p4tc_ext_csum_crc16_clear(struct p4tc_ext_csum_params *params)
{
p4tc_ext_csum_params_clear(params);
}

__bpf_kfunc u32
bpf_p4tc_ext_csum_crc32_add(struct p4tc_ext_csum_params *params,
const void *data, const u32 data__sz)
{
params->csum = p4tc_ext_hash_crc32(data, data__sz, params->csum);

return params->csum;
}

__bpf_kfunc u32
bpf_p4tc_ext_csum_crc32_get(struct p4tc_ext_csum_params *params)
{
return params->csum;
}

__bpf_kfunc void
bpf_p4tc_ext_csum_crc32_clear(struct p4tc_ext_csum_params *params)
{
p4tc_ext_csum_params_clear(params);
}

__bpf_kfunc u16
bpf_p4tc_ext_hash_16bit_complement(const void *data, const u32 data__sz,
u16 seed)
{
u16 hash = p4tc_ext_hash_16bit_complement(data, data__sz, seed);

return p4tc_ext_hash_16bit_complement_get(hash);
}

__bpf_kfunc u16
bpf_p4tc_ext_hash_crc16(const void * data, int len, u16 seed)
{
return p4tc_ext_hash_crc16(data, len, seed);
}

__bpf_kfunc u32
bpf_p4tc_ext_hash_crc32(const void * data, const u32 data__sz, u32 seed)
{
return p4tc_ext_hash_crc32(data, data__sz, seed);
}

__diag_pop();

#define EXTERN_HASH 1240

BTF_SET8_START(p4tc_kfunc_ext_csum_set)
BTF_ID_FLAGS(func, bpf_p4tc_ext_hash_16bit_complement);
BTF_ID_FLAGS(func, bpf_p4tc_ext_hash_crc16);
BTF_ID_FLAGS(func, bpf_p4tc_ext_hash_crc32);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_16bit_complement_add);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_16bit_complement_sub);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_16bit_complement_get);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_16bit_complement_clear);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_16bit_complement_set_state);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_crc16_add);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_crc16_get);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_crc16_clear);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_crc32_add);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_crc32_get);
BTF_ID_FLAGS(func, bpf_p4tc_ext_csum_crc32_clear);
BTF_SET8_END(p4tc_kfunc_ext_csum_set)

static const struct btf_kfunc_id_set p4tc_kfunc_ext_set_skb = {
.owner = THIS_MODULE,
.set = &p4tc_kfunc_ext_csum_set,
};

static struct p4tc_extern_ops ext_csum_ops = {
.kind = "ext_csum",
.id = EXTERN_HASH,
.owner = THIS_MODULE,
};

MODULE_AUTHOR("Mojatatu Networks, Inc");
MODULE_DESCRIPTION("P4TC Checksum extern");
MODULE_LICENSE("GPL");

static int __init csum_init_module(void)
{
int ret = p4tc_register_extern(&ext_csum_ops);
if (!ret)
pr_info("Checksum TC extern Loaded\n");

ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_ACT,
&p4tc_kfunc_ext_set_skb);
if (ret < 0)
p4tc_unregister_extern(&ext_csum_ops);

ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP,
&p4tc_kfunc_ext_set_skb);
if (ret < 0)
p4tc_unregister_extern(&ext_csum_ops);

return ret;
}

static void __exit hash_cleanup_module(void)
{
p4tc_unregister_extern(&ext_csum_ops);
}

module_init(csum_init_module);
module_exit(hash_cleanup_module);

0 comments on commit 33c06bf

Please sign in to comment.