Skip to content

Commit

Permalink
New module for setting the DSCP field (#20)
Browse files Browse the repository at this point in the history
* feat: add dscp module
* chore: add tests for the dscp module
* feat: add test runs into the build workflow
* fix: add go build cache
  • Loading branch information
sakateka authored Feb 11, 2025
1 parent 4251dec commit 9844420
Show file tree
Hide file tree
Showing 14 changed files with 536 additions and 1 deletion.
34 changes: 33 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,53 @@ on:
jobs:
build:
runs-on: ubuntu-24.04
env:
cache_name: build-and-test

steps:
- uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: meson clang python3-pyelftools libnuma-dev libpcap-dev git
version: 1.0
version: 1.1

- uses: actions/checkout@v4
with:
submodules: true

- uses: hendrikmuhs/[email protected]
name: ccache
with:
key: ${{ runner.os }}-build-cache
- run: |
meson setup build -Dbuildtype=debug
meson compile -C build
- uses: actions/setup-go@v5
with:
go-version: '1.23.x'
cache: false
check-latest: true
# https://github.com/actions/setup-go/issues/358
- name: Get Go environment
run: |
echo "cache=$(go env GOCACHE)" >> $GITHUB_ENV
echo "modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV
- name: Set up go cache
uses: actions/cache@v3
with:
path: |
${{ env.cache }}
${{ env.modcache }}
key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }}
restore-keys: |
${{ env.cache_name }}-${{ runner.os }}-go-
- run:
meson test -C build
- name: Show meson test log
run:
grep -v 'Inherited environment' build/meson-logs/testlog.txt

- uses: cpp-linter/cpp-linter-action@main
id: linter
continue-on-error: true
Expand Down
24 changes: 24 additions & 0 deletions common/checksum.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

#include <stdint.h>

static inline uint16_t
csum_plus(uint16_t val0, uint16_t val1) {
uint16_t sum = val0 + val1;

if (sum < val0) {
++sum;
}

return sum;
}

static inline uint16_t
csum_minus(uint16_t val0, uint16_t val1) {
uint16_t sum = val0 - val1;

if (sum > val0) {
--sum;
}

return sum;
}
6 changes: 6 additions & 0 deletions lib/dataplane/module/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ packet_front_switch(struct packet_front *packet_front) {
packet_list_init(&packet_front->output);
}

static inline void
packet_front_pass(struct packet_front *packet_front) {
packet_front->output = packet_front->input;
packet_list_init(&packet_front->input);
}

struct module;
struct module_config;

Expand Down
50 changes: 50 additions & 0 deletions lib/dataplane/packet/dscp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <rte_ip.h>

#include "checksum.h"
#include "dscp.h"

int
dscp_mark_v4(struct rte_ipv4_hdr *ip4_hdr, struct dscp_config config) {
uint8_t mark = ip4_hdr->type_of_service & DSCP_MARK_MASK;
if (config.flag & DSCP_MARK_DEFAULT && mark != 0) {
// do not remark
return -1;
}

uint16_t checksum = ~rte_be_to_cpu_16(ip4_hdr->hdr_checksum);
checksum = csum_minus(checksum, mark);
uint8_t new_mark = config.mark << DSCP_MARK_SHIFT;
checksum = csum_plus(checksum, new_mark);
ip4_hdr->hdr_checksum = ~rte_cpu_to_be_16(checksum);

uint8_t ecn = ip4_hdr->type_of_service & DSCP_ECN_MASK;
ip4_hdr->type_of_service = new_mark | ecn;
return 0;
}

static inline uint8_t
get_ipv6_tc(rte_be32_t vtc_flow) {
uint32_t v = rte_be_to_cpu_32(vtc_flow);
return v >> RTE_IPV6_HDR_TC_SHIFT;
}

static inline rte_be32_t
set_ipv6_tc(rte_be32_t vtc_flow, uint32_t tc) {
// Shift by the length of the Flow Label - 20-bit.
uint32_t v = rte_cpu_to_be_32(tc << RTE_IPV6_HDR_TC_SHIFT);
vtc_flow &= ~rte_cpu_to_be_32(RTE_IPV6_HDR_TC_MASK);
return (v | vtc_flow);
}

int
dscp_mark_v6(struct rte_ipv6_hdr *ip6_hdr, struct dscp_config config) {
uint8_t tc = get_ipv6_tc(ip6_hdr->vtc_flow);
uint8_t mark = tc & DSCP_MARK_MASK;
if (config.flag & DSCP_MARK_DEFAULT && mark != 0) {
// do not remark
return -1;
}
uint8_t new_mark = config.mark << DSCP_MARK_SHIFT;
ip6_hdr->vtc_flow = set_ipv6_tc(ip6_hdr->vtc_flow, new_mark);
return 0;
}
26 changes: 26 additions & 0 deletions lib/dataplane/packet/dscp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <stdint.h>

#define DSCP_MARK_NEVER 0
#define DSCP_MARK_DEFAULT 1
#define DSCP_MARK_ALWAYS 2

#define DSCP_MARK_MASK 0xFC
#define DSCP_MARK_SHIFT 2
#define DSCP_ECN_MASK 0x03

// #include <rte_ip.h>
struct rte_ipv4_hdr;
struct rte_ipv6_hdr;

struct dscp_config {
uint8_t flag;
uint8_t mark;
};

int
dscp_mark_v4(struct rte_ipv4_hdr *ip4_hdr, struct dscp_config config);

int
dscp_mark_v6(struct rte_ipv6_hdr *ip6_hdr, struct dscp_config config);
1 change: 1 addition & 0 deletions lib/dataplane/packet/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ sources = files(
'packet.c',
'encap.c',
'decap.c',
'dscp.c',
)

lib_packet_dp = static_library(
Expand Down
130 changes: 130 additions & 0 deletions modules/dscp/dataplane.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include "dataplane.h"

#include <rte_ether.h>
#include <rte_ip.h>

#include "dataplane/module/module.h"
#include "dataplane/packet/dscp.h"
#include "dataplane/packet/packet.h"

static int
dscp_handle_v4(struct dscp_module_config *config, struct packet *packet) {
struct rte_mbuf *mbuf = packet_to_mbuf(packet);

struct rte_ipv4_hdr *header = rte_pktmbuf_mtod_offset(
mbuf, struct rte_ipv4_hdr *, packet->network_header.offset
);

if (lpm_lookup(&config->lpm_v4, 4, (uint8_t *)&header->dst_addr) !=
LPM_VALUE_INVALID) {
return dscp_mark_v4(header, config->dscp);
}

return -1;
}

static int
dscp_handle_v6(struct dscp_module_config *config, struct packet *packet) {
struct rte_mbuf *mbuf = packet_to_mbuf(packet);

struct rte_ipv6_hdr *header = rte_pktmbuf_mtod_offset(
mbuf, struct rte_ipv6_hdr *, packet->network_header.offset
);

if (lpm_lookup(&config->lpm_v6, 16, (uint8_t *)&header->dst_addr) !=
LPM_VALUE_INVALID) {
return dscp_mark_v6(header, config->dscp);
}

return -1;
}

static inline int
dscp_handle(struct dscp_module_config *config, struct packet *packet) {
uint16_t type = packet->network_header.type;
int result = -1;
if (type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
result = dscp_handle_v4(config, packet);
} else if (type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
result = dscp_handle_v6(config, packet);
}
return result;
}

void
dscp_handle_packets(
struct module *module,
struct module_config *config,
struct packet_front *packet_front
) {
(void)module;
struct dscp_module_config *dscp_config =
container_of(config, struct dscp_module_config, config);

if (dscp_config->dscp.flag != DSCP_MARK_NEVER) {
struct packet *packet;
while ((packet = packet_list_pop(&packet_front->input)) != NULL
) {
dscp_handle(dscp_config, packet);
packet_list_add(&packet_front->output, packet);
}
} else {
packet_front_pass(packet_front);
}

return;
}

static int
dscp_handle_configure(
struct module *module,
const void *config_data,
size_t config_data_size,
struct module_config **new_config
) {

(void)module;

struct dscp_module_config *config = (struct dscp_module_config *)malloc(
sizeof(struct dscp_module_config)
);

uint8_t ip6min[16] = {0};
uint8_t ip6max[16] = {0};
memset(ip6max, 0xff, 16);
lpm_init(&config->lpm_v4);
lpm_init(&config->lpm_v6);
lpm_insert(&config->lpm_v4, 4, ip6min, ip6max, 1);
lpm_insert(&config->lpm_v6, 16, ip6min, ip6max, 1);

if (config_data_size != sizeof(struct dscp_config)) {
return -1;
}
config->dscp = *(struct dscp_config *)config_data;

*new_config = &config->config;

return 0;
};

struct dscp_module {
struct module module;
};

struct module *
new_module_dscp() {
struct dscp_module *module =
(struct dscp_module *)malloc(sizeof(struct dscp_module));

if (module == NULL) {
return NULL;
}

snprintf(
module->module.name, sizeof(module->module.name), "%s", "dscp"
);
module->module.handler = dscp_handle_packets;
module->module.config_handler = dscp_handle_configure;

return &module->module;
}
16 changes: 16 additions & 0 deletions modules/dscp/dataplane.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include "dataplane/module/module.h"
#include "dataplane/packet/dscp.h"
#include "lpm.h"

struct dscp_module_config {
struct module_config config;

struct lpm lpm_v4;
struct lpm lpm_v6;
struct dscp_config dscp;
};

struct module *
new_module_kernel();
29 changes: 29 additions & 0 deletions modules/dscp/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# common dependecies
dependencies += lib_common_dep
dependencies += lib_filter_dep

# dataplane dependecies
dp_dependencies = dependencies
dp_dependencies += lib_packet_dp_dep

dp_dependencies += lib_module_dp_dep

dp_sources = files(
'dataplane.c',
)

lib_dscp_dp = static_library(
'dscp_dp',
dp_sources,
dependencies: dp_dependencies,
install: false,
)

lib_dscp_dp_dep = declare_dependency(
link_with: lib_dscp_dp,
link_args: [
'-Wl,--defsym', '-Wl,new_module_dscp=new_module_dscp',
'-Wl,--export-dynamic-symbol=new_module_dscp',
],
)

1 change: 1 addition & 0 deletions modules/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ subdir('balancer')
subdir('acl')
subdir('route')
subdir('forward')
subdir('dscp')
Loading

0 comments on commit 9844420

Please sign in to comment.