about summary refs log tree commit diff
path: root/src/n-acd
diff options
context:
space:
mode:
Diffstat (limited to 'src/n-acd')
-rw-r--r--src/n-acd/.github/workflows/ci.yml36
-rw-r--r--src/n-acd/README.md7
-rw-r--r--src/n-acd/meson.build2
-rw-r--r--src/n-acd/meson_options.txt1
-rw-r--r--src/n-acd/src/libnacd.sym1
-rw-r--r--src/n-acd/src/meson.build17
-rw-r--r--src/n-acd/src/n-acd-bpf-fallback.c30
-rw-r--r--src/n-acd/src/n-acd-bpf.c8
-rw-r--r--src/n-acd/src/n-acd.c34
-rw-r--r--src/n-acd/src/n-acd.h1
-rw-r--r--src/n-acd/src/test-api.c1
-rw-r--r--src/n-acd/src/test-bpf.c28
12 files changed, 67 insertions, 99 deletions
diff --git a/src/n-acd/.github/workflows/ci.yml b/src/n-acd/.github/workflows/ci.yml
index 22fc8141..f6987414 100644
--- a/src/n-acd/.github/workflows/ci.yml
+++ b/src/n-acd/.github/workflows/ci.yml
@@ -49,42 +49,6 @@ jobs:
                 "--m32=1" \
                 "--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:
     name: CI through Valgrind
     runs-on: ubuntu-latest
diff --git a/src/n-acd/README.md b/src/n-acd/README.md
index 08954182..d207e700 100644
--- a/src/n-acd/README.md
+++ b/src/n-acd/README.md
@@ -41,13 +41,6 @@ meson test
 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:
 
  - **web**:   <https://github.com/nettools/n-acd>
diff --git a/src/n-acd/meson.build b/src/n-acd/meson.build
index 6479eb1a..ca72e567 100644
--- a/src/n-acd/meson.build
+++ b/src/n-acd/meson.build
@@ -22,6 +22,4 @@ dep_crbtree = sub_crbtree.get_variable('libcrbtree_dep')
 dep_csiphash = sub_csiphash.get_variable('libcsiphash_dep')
 dep_cstdaux = sub_cstdaux.get_variable('libcstdaux_dep')
 
-use_ebpf = get_option('ebpf')
-
 subdir('src')
diff --git a/src/n-acd/meson_options.txt b/src/n-acd/meson_options.txt
deleted file mode 100644
index b024ee1d..00000000
--- a/src/n-acd/meson_options.txt
+++ /dev/null
@@ -1 +0,0 @@
-option('ebpf', type: 'boolean', value: true, description: 'Enable eBPF packet filtering')
diff --git a/src/n-acd/src/libnacd.sym b/src/n-acd/src/libnacd.sym
index f85e13ac..537eab3e 100644
--- a/src/n-acd/src/libnacd.sym
+++ b/src/n-acd/src/libnacd.sym
@@ -15,6 +15,7 @@ global:
         n_acd_ref;
         n_acd_unref;
         n_acd_get_fd;
+        n_acd_has_bpf;
         n_acd_dispatch;
         n_acd_pop_event;
         n_acd_probe;
diff --git a/src/n-acd/src/meson.build b/src/n-acd/src/meson.build
index 3e92681f..c1582f42 100644
--- a/src/n-acd/src/meson.build
+++ b/src/n-acd/src/meson.build
@@ -15,18 +15,9 @@ libnacd_sources = [
         'n-acd.c',
         'n-acd-probe.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(
         'nacd-private',
         libnacd_sources,
@@ -77,10 +68,8 @@ endif
 test_api = executable('test-api', ['test-api.c'], link_with: libnacd_shared)
 test('API Symbol Visibility', test_api)
 
-if use_ebpf
-        test_bpf = executable('test-bpf', ['test-bpf.c'], dependencies: libnacd_dep)
-        test('eBPF socket filtering', test_bpf)
-endif
+test_bpf = executable('test-bpf', ['test-bpf.c'], dependencies: libnacd_dep)
+test('eBPF socket filtering', test_bpf)
 
 test_loopback = executable('test-loopback', ['test-loopback.c'], dependencies: libnacd_dep)
 test('Echo Suppression via Loopback', test_loopback)
diff --git a/src/n-acd/src/n-acd-bpf-fallback.c b/src/n-acd/src/n-acd-bpf-fallback.c
deleted file mode 100644
index 3cf4eb06..00000000
--- a/src/n-acd/src/n-acd-bpf-fallback.c
+++ /dev/null
@@ -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;
-}
diff --git a/src/n-acd/src/n-acd-bpf.c b/src/n-acd/src/n-acd-bpf.c
index 57b29ddf..55b44ab9 100644
--- a/src/n-acd/src/n-acd-bpf.c
+++ b/src/n-acd/src/n-acd-bpf.c
@@ -170,6 +170,10 @@ int n_acd_bpf_map_add(int mapfd, struct in_addr *addrp) {
         uint8_t _dummy = 0;
         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));
         attr = (union bpf_attr){
                 .map_fd = mapfd,
@@ -190,6 +194,10 @@ int n_acd_bpf_map_remove(int mapfd, struct in_addr *addrp) {
         union bpf_attr attr;
         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));
         attr = (union bpf_attr){
                 .map_fd = mapfd,
diff --git a/src/n-acd/src/n-acd.c b/src/n-acd/src/n-acd.c
index c1d92865..9bc32244 100644
--- a/src/n-acd/src/n-acd.c
+++ b/src/n-acd/src/n-acd.c
@@ -284,6 +284,11 @@ int n_acd_ensure_bpf_map_space(NAcd *acd) {
 
         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);
         if (r)
                 return r;
@@ -308,6 +313,8 @@ int n_acd_ensure_bpf_map_space(NAcd *acd) {
                 close(acd->fd_bpf_map);
         acd->fd_bpf_map = fd_map;
         fd_map = -1;
+
+out:
         acd->max_bpf_map = max_map;
         return 0;
 }
@@ -359,13 +366,16 @@ _c_public_ int n_acd_new(NAcd **acdp, NAcdConfig *config) {
 
         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);
-        if (r)
-                return r;
-
-        r = n_acd_bpf_compile(&fd_bpf_prog, acd->fd_bpf_map, (struct ether_addr*) acd->mac);
-        if (r)
+        if (r == 0) {
+                r = n_acd_bpf_compile(&fd_bpf_prog, acd->fd_bpf_map, (struct ether_addr*) acd->mac);
+                if (r)
+                        return r;
+        } else if (r != -EPERM) {
                 return r;
+        }
 
         r = n_acd_socket_new(&acd->fd_socket, fd_bpf_prog, config);
         if (r)
@@ -572,6 +582,20 @@ _c_public_ void n_acd_get_fd(NAcd *acd, int *fdp) {
         *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) {
         NAcdProbe *probe;
         uint64_t now;
diff --git a/src/n-acd/src/n-acd.h b/src/n-acd/src/n-acd.h
index e2b01270..8e5cf59a 100644
--- a/src/n-acd/src/n-acd.h
+++ b/src/n-acd/src/n-acd.h
@@ -93,6 +93,7 @@ NAcd *n_acd_ref(NAcd *acd);
 NAcd *n_acd_unref(NAcd *acd);
 
 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_pop_event(NAcd *acd, NAcdEvent **eventp);
 
diff --git a/src/n-acd/src/test-api.c b/src/n-acd/src/test-api.c
index 70f75208..009838aa 100644
--- a/src/n-acd/src/test-api.c
+++ b/src/n-acd/src/test-api.c
@@ -56,6 +56,7 @@ static void test_api_functions(void) {
                 (void *)n_acd_ref,
                 (void *)n_acd_unref,
                 (void *)n_acd_get_fd,
+                (void *)n_acd_has_bpf,
                 (void *)n_acd_dispatch,
                 (void *)n_acd_pop_event,
                 (void *)n_acd_probe,
diff --git a/src/n-acd/src/test-bpf.c b/src/n-acd/src/test-bpf.c
index 78f9d0f1..17e89803 100644
--- a/src/n-acd/src/test-bpf.c
+++ b/src/n-acd/src/test-bpf.c
@@ -19,6 +19,9 @@
 #include "n-acd-private.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) {                  \
                 .ea_hdr = {                                             \
                         .ar_hrd = htobe16(ARPHRD_ETHER),                \
@@ -43,11 +46,15 @@
                 .arp_tpa[3] =  be32toh((_tip)->s_addr) & 0xff,          \
         }
 
-static void test_map(void) {
+static int test_map(void) {
         int r, mapfd = -1;
         struct in_addr addr = { 1 };
 
         r = n_acd_bpf_map_create(&mapfd, 8);
+        if (r == -EPERM) {
+                return RETURN_TEST_SKIPPED;
+        }
+
         c_assert(r >= 0);
         c_assert(mapfd >= 0);
 
@@ -67,6 +74,7 @@ static void test_map(void) {
         c_assert(r == -ENOENT);
 
         close(mapfd);
+        return 0;
 }
 
 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);
 }
 
-static void test_filter(void) {
+static int test_filter(void) {
         uint8_t buf[sizeof(struct ether_arp) + 1] = {};
         struct ether_addr mac1 = { { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } };
         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];
 
         r = n_acd_bpf_map_create(&mapfd, 1);
+        if (r == -EPERM) {
+                return RETURN_TEST_SKIPPED;
+        }
+
         c_assert(r >= 0);
 
         r = n_acd_bpf_compile(&progfd, mapfd, &mac1);
@@ -214,13 +226,21 @@ static void test_filter(void) {
         close(pair[1]);
         close(progfd);
         close(mapfd);
+
+        return 0;
 }
 
 int main(int argc, char **argv) {
+        int r;
         test_setup();
 
-        test_map();
-        test_filter();
+        if ((r = test_map())) {
+                return r;
+        }
+
+        if ((r = test_filter())) {
+                return r;
+        }
 
         return 0;
 }