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

New module for setting the DSCP field #20

Merged
merged 10 commits into from
Feb 11, 2025
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
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