mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-20 07:00:05 +01:00
n-acd: re-import git-subtree for 'src/n-acd'
git subtree pull --prefix src/n-acd git@github.com:nettools/n-acd.git master --squash
This commit is contained in:
commit
3a769bca67
12 changed files with 72 additions and 104 deletions
36
src/n-acd/.github/workflows/ci.yml
vendored
36
src/n-acd/.github/workflows/ci.yml
vendored
|
|
@ -49,42 +49,6 @@ jobs:
|
||||||
"--m32=1" \
|
"--m32=1" \
|
||||||
"--source=/github/workspace"
|
"--source=/github/workspace"
|
||||||
|
|
||||||
ci-no-ebpf:
|
|
||||||
name: CI without eBPF
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# See above in 'ci' job.
|
|
||||||
- name: Fetch CI
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
repository: c-util/automation
|
|
||||||
ref: v1
|
|
||||||
path: automation
|
|
||||||
- name: Build CI
|
|
||||||
working-directory: automation/src/ci-c-util
|
|
||||||
run: docker build --tag ci-c-util:v1 .
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run CI
|
|
||||||
#
|
|
||||||
# This again runs the CI, but this time disables eBPF. We do support the
|
|
||||||
# legacy BPF fallback, so lets make sure we test for it.
|
|
||||||
#
|
|
||||||
- name: Fetch Sources
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
path: source
|
|
||||||
- name: Run through C-Util CI
|
|
||||||
run: |
|
|
||||||
docker run \
|
|
||||||
--privileged \
|
|
||||||
-v "$(pwd)/source:/github/workspace" \
|
|
||||||
"ci-c-util:v1" \
|
|
||||||
"--m32=1" \
|
|
||||||
"--mesonargs=-Debpf=false" \
|
|
||||||
"--source=/github/workspace"
|
|
||||||
|
|
||||||
ci-valgrind:
|
ci-valgrind:
|
||||||
name: CI through Valgrind
|
name: CI through Valgrind
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
||||||
|
|
@ -41,13 +41,6 @@ meson test
|
||||||
ninja install
|
ninja install
|
||||||
```
|
```
|
||||||
|
|
||||||
The following configuration options are available:
|
|
||||||
|
|
||||||
* `ebpf`: This boolean controls whether `ebpf` features are used to improve
|
|
||||||
the package filtering performance. If disabled, classic bpf will be
|
|
||||||
used. This feature requires a rather recent kernel (>=3.19).
|
|
||||||
Default is: true
|
|
||||||
|
|
||||||
### Repository:
|
### Repository:
|
||||||
|
|
||||||
- **web**: <https://github.com/nettools/n-acd>
|
- **web**: <https://github.com/nettools/n-acd>
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,4 @@ dep_crbtree = sub_crbtree.get_variable('libcrbtree_dep')
|
||||||
dep_csiphash = sub_csiphash.get_variable('libcsiphash_dep')
|
dep_csiphash = sub_csiphash.get_variable('libcsiphash_dep')
|
||||||
dep_cstdaux = sub_cstdaux.get_variable('libcstdaux_dep')
|
dep_cstdaux = sub_cstdaux.get_variable('libcstdaux_dep')
|
||||||
|
|
||||||
use_ebpf = get_option('ebpf')
|
|
||||||
|
|
||||||
subdir('src')
|
subdir('src')
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
option('ebpf', type: 'boolean', value: true, description: 'Enable eBPF packet filtering')
|
|
||||||
|
|
@ -15,6 +15,7 @@ global:
|
||||||
n_acd_ref;
|
n_acd_ref;
|
||||||
n_acd_unref;
|
n_acd_unref;
|
||||||
n_acd_get_fd;
|
n_acd_get_fd;
|
||||||
|
n_acd_has_bpf;
|
||||||
n_acd_dispatch;
|
n_acd_dispatch;
|
||||||
n_acd_pop_event;
|
n_acd_pop_event;
|
||||||
n_acd_probe;
|
n_acd_probe;
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,9 @@ libnacd_sources = [
|
||||||
'n-acd.c',
|
'n-acd.c',
|
||||||
'n-acd-probe.c',
|
'n-acd-probe.c',
|
||||||
'util/timer.c',
|
'util/timer.c',
|
||||||
|
'n-acd-bpf.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
if use_ebpf
|
|
||||||
libnacd_sources += [
|
|
||||||
'n-acd-bpf.c',
|
|
||||||
]
|
|
||||||
else
|
|
||||||
libnacd_sources += [
|
|
||||||
'n-acd-bpf-fallback.c',
|
|
||||||
]
|
|
||||||
endif
|
|
||||||
|
|
||||||
libnacd_private = static_library(
|
libnacd_private = static_library(
|
||||||
'nacd-private',
|
'nacd-private',
|
||||||
libnacd_sources,
|
libnacd_sources,
|
||||||
|
|
@ -77,10 +68,8 @@ endif
|
||||||
test_api = executable('test-api', ['test-api.c'], link_with: libnacd_shared)
|
test_api = executable('test-api', ['test-api.c'], link_with: libnacd_shared)
|
||||||
test('API Symbol Visibility', test_api)
|
test('API Symbol Visibility', test_api)
|
||||||
|
|
||||||
if use_ebpf
|
test_bpf = executable('test-bpf', ['test-bpf.c'], dependencies: libnacd_dep)
|
||||||
test_bpf = executable('test-bpf', ['test-bpf.c'], dependencies: libnacd_dep)
|
test('eBPF socket filtering', test_bpf)
|
||||||
test('eBPF socket filtering', test_bpf)
|
|
||||||
endif
|
|
||||||
|
|
||||||
test_loopback = executable('test-loopback', ['test-loopback.c'], dependencies: libnacd_dep)
|
test_loopback = executable('test-loopback', ['test-loopback.c'], dependencies: libnacd_dep)
|
||||||
test('Echo Suppression via Loopback', test_loopback)
|
test('Echo Suppression via Loopback', test_loopback)
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
* A noop implementation of eBPF filter for IPv4 Address Conflict Detection
|
|
||||||
*
|
|
||||||
* These are a collection of dummy functions that have no effect, but allows
|
|
||||||
* n-acd to compile without eBPF support.
|
|
||||||
*
|
|
||||||
* See n-acd-bpf.c for documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <c-stdaux.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "n-acd-private.h"
|
|
||||||
|
|
||||||
int n_acd_bpf_map_create(int *mapfdp, size_t max_entries) {
|
|
||||||
*mapfdp = -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n_acd_bpf_map_add(int mapfd, struct in_addr *addrp) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n_acd_bpf_map_remove(int mapfd, struct in_addr *addrp) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n_acd_bpf_compile(int *progfdp, int mapfd, struct ether_addr *macp) {
|
|
||||||
*progfdp = -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -170,6 +170,10 @@ int n_acd_bpf_map_add(int mapfd, struct in_addr *addrp) {
|
||||||
uint8_t _dummy = 0;
|
uint8_t _dummy = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
/* If we don't have a map to update, there is nothing to do. */
|
||||||
|
if (mapfd == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr = (union bpf_attr){
|
attr = (union bpf_attr){
|
||||||
.map_fd = mapfd,
|
.map_fd = mapfd,
|
||||||
|
|
@ -190,6 +194,10 @@ int n_acd_bpf_map_remove(int mapfd, struct in_addr *addrp) {
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
/* If we don't have a map to update, there is nothing to do. */
|
||||||
|
if (mapfd == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr = (union bpf_attr){
|
attr = (union bpf_attr){
|
||||||
.map_fd = mapfd,
|
.map_fd = mapfd,
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,11 @@ int n_acd_ensure_bpf_map_space(NAcd *acd) {
|
||||||
|
|
||||||
max_map = 2 * acd->max_bpf_map;
|
max_map = 2 * acd->max_bpf_map;
|
||||||
|
|
||||||
|
/* If we didn't succeed in creating a map during n_acd_new(),
|
||||||
|
* let's assume we are unable to create it here, and skip it. */
|
||||||
|
if (!n_acd_has_bpf(acd))
|
||||||
|
goto out;
|
||||||
|
|
||||||
r = n_acd_bpf_map_create(&fd_map, max_map);
|
r = n_acd_bpf_map_create(&fd_map, max_map);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
@ -308,6 +313,8 @@ int n_acd_ensure_bpf_map_space(NAcd *acd) {
|
||||||
close(acd->fd_bpf_map);
|
close(acd->fd_bpf_map);
|
||||||
acd->fd_bpf_map = fd_map;
|
acd->fd_bpf_map = fd_map;
|
||||||
fd_map = -1;
|
fd_map = -1;
|
||||||
|
|
||||||
|
out:
|
||||||
acd->max_bpf_map = max_map;
|
acd->max_bpf_map = max_map;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -359,13 +366,16 @@ _c_public_ int n_acd_new(NAcd **acdp, NAcdConfig *config) {
|
||||||
|
|
||||||
acd->max_bpf_map = 8;
|
acd->max_bpf_map = 8;
|
||||||
|
|
||||||
|
/* Let's try to create a BPF map. If we fail, we want to ignore it
|
||||||
|
* only if we lack permissions to create it, and proceed without eBPF. */
|
||||||
r = n_acd_bpf_map_create(&acd->fd_bpf_map, acd->max_bpf_map);
|
r = n_acd_bpf_map_create(&acd->fd_bpf_map, acd->max_bpf_map);
|
||||||
if (r)
|
if (r == 0) {
|
||||||
return r;
|
r = n_acd_bpf_compile(&fd_bpf_prog, acd->fd_bpf_map, (struct ether_addr*) acd->mac);
|
||||||
|
if (r)
|
||||||
r = n_acd_bpf_compile(&fd_bpf_prog, acd->fd_bpf_map, (struct ether_addr*) acd->mac);
|
return r;
|
||||||
if (r)
|
} else if (r != -EPERM) {
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = n_acd_socket_new(&acd->fd_socket, fd_bpf_prog, config);
|
r = n_acd_socket_new(&acd->fd_socket, fd_bpf_prog, config);
|
||||||
if (r)
|
if (r)
|
||||||
|
|
@ -572,6 +582,20 @@ _c_public_ void n_acd_get_fd(NAcd *acd, int *fdp) {
|
||||||
*fdp = acd->fd_epoll;
|
*fdp = acd->fd_epoll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* n_acd_has_bpf() - query the usage of eBPF
|
||||||
|
* @acd: context object to operate on
|
||||||
|
*
|
||||||
|
* Checks whether the ACD probe is using eBPF or not.
|
||||||
|
*
|
||||||
|
* Return: true if the probe is using eBPF, or
|
||||||
|
* false if the probe failed to configure eBPF
|
||||||
|
* (e.g. due to missing capabilities)
|
||||||
|
*/
|
||||||
|
_c_public_ bool n_acd_has_bpf(NAcd *acd) {
|
||||||
|
return acd->fd_bpf_map != -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int n_acd_handle_timeout(NAcd *acd) {
|
static int n_acd_handle_timeout(NAcd *acd) {
|
||||||
NAcdProbe *probe;
|
NAcdProbe *probe;
|
||||||
uint64_t now;
|
uint64_t now;
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ NAcd *n_acd_ref(NAcd *acd);
|
||||||
NAcd *n_acd_unref(NAcd *acd);
|
NAcd *n_acd_unref(NAcd *acd);
|
||||||
|
|
||||||
void n_acd_get_fd(NAcd *acd, int *fdp);
|
void n_acd_get_fd(NAcd *acd, int *fdp);
|
||||||
|
bool n_acd_has_bpf(NAcd *acd);
|
||||||
int n_acd_dispatch(NAcd *acd);
|
int n_acd_dispatch(NAcd *acd);
|
||||||
int n_acd_pop_event(NAcd *acd, NAcdEvent **eventp);
|
int n_acd_pop_event(NAcd *acd, NAcdEvent **eventp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ static void test_api_functions(void) {
|
||||||
(void *)n_acd_ref,
|
(void *)n_acd_ref,
|
||||||
(void *)n_acd_unref,
|
(void *)n_acd_unref,
|
||||||
(void *)n_acd_get_fd,
|
(void *)n_acd_get_fd,
|
||||||
|
(void *)n_acd_has_bpf,
|
||||||
(void *)n_acd_dispatch,
|
(void *)n_acd_dispatch,
|
||||||
(void *)n_acd_pop_event,
|
(void *)n_acd_pop_event,
|
||||||
(void *)n_acd_probe,
|
(void *)n_acd_probe,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@
|
||||||
#include "n-acd-private.h"
|
#include "n-acd-private.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
|
// https://mesonbuild.com/Unit-tests.html#skipped-tests-and-hard-errors
|
||||||
|
#define RETURN_TEST_SKIPPED 77
|
||||||
|
|
||||||
#define ETHER_ARP_PACKET_INIT(_op, _mac, _sip, _tip) { \
|
#define ETHER_ARP_PACKET_INIT(_op, _mac, _sip, _tip) { \
|
||||||
.ea_hdr = { \
|
.ea_hdr = { \
|
||||||
.ar_hrd = htobe16(ARPHRD_ETHER), \
|
.ar_hrd = htobe16(ARPHRD_ETHER), \
|
||||||
|
|
@ -43,11 +46,15 @@
|
||||||
.arp_tpa[3] = be32toh((_tip)->s_addr) & 0xff, \
|
.arp_tpa[3] = be32toh((_tip)->s_addr) & 0xff, \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_map(void) {
|
static int test_map(void) {
|
||||||
int r, mapfd = -1;
|
int r, mapfd = -1;
|
||||||
struct in_addr addr = { 1 };
|
struct in_addr addr = { 1 };
|
||||||
|
|
||||||
r = n_acd_bpf_map_create(&mapfd, 8);
|
r = n_acd_bpf_map_create(&mapfd, 8);
|
||||||
|
if (r == -EPERM) {
|
||||||
|
return RETURN_TEST_SKIPPED;
|
||||||
|
}
|
||||||
|
|
||||||
c_assert(r >= 0);
|
c_assert(r >= 0);
|
||||||
c_assert(mapfd >= 0);
|
c_assert(mapfd >= 0);
|
||||||
|
|
||||||
|
|
@ -67,6 +74,7 @@ static void test_map(void) {
|
||||||
c_assert(r == -ENOENT);
|
c_assert(r == -ENOENT);
|
||||||
|
|
||||||
close(mapfd);
|
close(mapfd);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verify_success(struct ether_arp *packet, int out_fd, int in_fd) {
|
static void verify_success(struct ether_arp *packet, int out_fd, int in_fd) {
|
||||||
|
|
@ -92,7 +100,7 @@ static void verify_failure(struct ether_arp *packet, int out_fd, int in_fd) {
|
||||||
c_assert(errno == EAGAIN);
|
c_assert(errno == EAGAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_filter(void) {
|
static int test_filter(void) {
|
||||||
uint8_t buf[sizeof(struct ether_arp) + 1] = {};
|
uint8_t buf[sizeof(struct ether_arp) + 1] = {};
|
||||||
struct ether_addr mac1 = { { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } };
|
struct ether_addr mac1 = { { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } };
|
||||||
struct ether_addr mac2 = { { 0x01, 0x02, 0x03, 0x04, 0x05, 0x07 } };
|
struct ether_addr mac2 = { { 0x01, 0x02, 0x03, 0x04, 0x05, 0x07 } };
|
||||||
|
|
@ -103,6 +111,10 @@ static void test_filter(void) {
|
||||||
int r, mapfd = -1, progfd = -1, pair[2];
|
int r, mapfd = -1, progfd = -1, pair[2];
|
||||||
|
|
||||||
r = n_acd_bpf_map_create(&mapfd, 1);
|
r = n_acd_bpf_map_create(&mapfd, 1);
|
||||||
|
if (r == -EPERM) {
|
||||||
|
return RETURN_TEST_SKIPPED;
|
||||||
|
}
|
||||||
|
|
||||||
c_assert(r >= 0);
|
c_assert(r >= 0);
|
||||||
|
|
||||||
r = n_acd_bpf_compile(&progfd, mapfd, &mac1);
|
r = n_acd_bpf_compile(&progfd, mapfd, &mac1);
|
||||||
|
|
@ -214,13 +226,21 @@ static void test_filter(void) {
|
||||||
close(pair[1]);
|
close(pair[1]);
|
||||||
close(progfd);
|
close(progfd);
|
||||||
close(mapfd);
|
close(mapfd);
|
||||||
}
|
|
||||||
|
return 0;
|
||||||
int main(int argc, char **argv) {
|
}
|
||||||
test_setup();
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
test_map();
|
int r;
|
||||||
test_filter();
|
test_setup();
|
||||||
|
|
||||||
|
if ((r = test_map())) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r = test_filter())) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue