linux/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Test that the flow_dissector program can be updated with a single
   4 * syscall by attaching a new program that replaces the existing one.
   5 *
   6 * Corner case - the same program cannot be attached twice.
   7 */
   8
   9#define _GNU_SOURCE
  10#include <errno.h>
  11#include <fcntl.h>
  12#include <sched.h>
  13#include <stdbool.h>
  14#include <unistd.h>
  15
  16#include <linux/bpf.h>
  17#include <bpf/bpf.h>
  18
  19#include "test_progs.h"
  20
  21static bool is_attached(int netns)
  22{
  23        __u32 cnt;
  24        int err;
  25
  26        err = bpf_prog_query(netns, BPF_FLOW_DISSECTOR, 0, NULL, NULL, &cnt);
  27        if (CHECK_FAIL(err)) {
  28                perror("bpf_prog_query");
  29                return true; /* fail-safe */
  30        }
  31
  32        return cnt > 0;
  33}
  34
  35static int load_prog(void)
  36{
  37        struct bpf_insn prog[] = {
  38                BPF_MOV64_IMM(BPF_REG_0, BPF_OK),
  39                BPF_EXIT_INSN(),
  40        };
  41        int fd;
  42
  43        fd = bpf_load_program(BPF_PROG_TYPE_FLOW_DISSECTOR, prog,
  44                              ARRAY_SIZE(prog), "GPL", 0, NULL, 0);
  45        if (CHECK_FAIL(fd < 0))
  46                perror("bpf_load_program");
  47
  48        return fd;
  49}
  50
  51static void do_flow_dissector_reattach(void)
  52{
  53        int prog_fd[2] = { -1, -1 };
  54        int err;
  55
  56        prog_fd[0] = load_prog();
  57        if (prog_fd[0] < 0)
  58                return;
  59
  60        prog_fd[1] = load_prog();
  61        if (prog_fd[1] < 0)
  62                goto out_close;
  63
  64        err = bpf_prog_attach(prog_fd[0], 0, BPF_FLOW_DISSECTOR, 0);
  65        if (CHECK_FAIL(err)) {
  66                perror("bpf_prog_attach-0");
  67                goto out_close;
  68        }
  69
  70        /* Expect success when attaching a different program */
  71        err = bpf_prog_attach(prog_fd[1], 0, BPF_FLOW_DISSECTOR, 0);
  72        if (CHECK_FAIL(err)) {
  73                perror("bpf_prog_attach-1");
  74                goto out_detach;
  75        }
  76
  77        /* Expect failure when attaching the same program twice */
  78        err = bpf_prog_attach(prog_fd[1], 0, BPF_FLOW_DISSECTOR, 0);
  79        if (CHECK_FAIL(!err || errno != EINVAL))
  80                perror("bpf_prog_attach-2");
  81
  82out_detach:
  83        err = bpf_prog_detach(0, BPF_FLOW_DISSECTOR);
  84        if (CHECK_FAIL(err))
  85                perror("bpf_prog_detach");
  86
  87out_close:
  88        close(prog_fd[1]);
  89        close(prog_fd[0]);
  90}
  91
  92void test_flow_dissector_reattach(void)
  93{
  94        int init_net, self_net, err;
  95
  96        self_net = open("/proc/self/ns/net", O_RDONLY);
  97        if (CHECK_FAIL(self_net < 0)) {
  98                perror("open(/proc/self/ns/net");
  99                return;
 100        }
 101
 102        init_net = open("/proc/1/ns/net", O_RDONLY);
 103        if (CHECK_FAIL(init_net < 0)) {
 104                perror("open(/proc/1/ns/net)");
 105                goto out_close;
 106        }
 107
 108        err = setns(init_net, CLONE_NEWNET);
 109        if (CHECK_FAIL(err)) {
 110                perror("setns(/proc/1/ns/net)");
 111                goto out_close;
 112        }
 113
 114        if (is_attached(init_net)) {
 115                test__skip();
 116                printf("Can't test with flow dissector attached to init_net\n");
 117                goto out_setns;
 118        }
 119
 120        /* First run tests in root network namespace */
 121        do_flow_dissector_reattach();
 122
 123        /* Then repeat tests in a non-root namespace */
 124        err = unshare(CLONE_NEWNET);
 125        if (CHECK_FAIL(err)) {
 126                perror("unshare(CLONE_NEWNET)");
 127                goto out_setns;
 128        }
 129        do_flow_dissector_reattach();
 130
 131out_setns:
 132        /* Move back to netns we started in. */
 133        err = setns(self_net, CLONE_NEWNET);
 134        if (CHECK_FAIL(err))
 135                perror("setns(/proc/self/ns/net)");
 136
 137out_close:
 138        close(init_net);
 139        close(self_net);
 140}
 141