about summary refs log tree commit diff
path: root/shared/n-acd/src/n-acd-private.h
diff options
context:
space:
mode:
Diffstat (limited to 'shared/n-acd/src/n-acd-private.h')
-rw-r--r--shared/n-acd/src/n-acd-private.h172
1 files changed, 172 insertions, 0 deletions
diff --git a/shared/n-acd/src/n-acd-private.h b/shared/n-acd/src/n-acd-private.h
new file mode 100644
index 00000000..3f207912
--- /dev/null
+++ b/shared/n-acd/src/n-acd-private.h
@@ -0,0 +1,172 @@
+#pragma once
+
+#include <c-list.h>
+#include <c-rbtree.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <netinet/if_ether.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include "util/timer.h"
+#include "n-acd.h"
+
+typedef struct NAcdEventNode NAcdEventNode;
+
+#define _cleanup_(_x) __attribute__((__cleanup__(_x)))
+#define _public_ __attribute__((__visibility__("default")))
+
+/* This augments the error-codes with internal ones that are never exposed. */
+enum {
+        _N_ACD_INTERNAL = _N_ACD_E_N,
+
+        N_ACD_E_DROPPED,
+};
+
+enum {
+        N_ACD_PROBE_STATE_PROBING,
+        N_ACD_PROBE_STATE_CONFIGURING,
+        N_ACD_PROBE_STATE_ANNOUNCING,
+        N_ACD_PROBE_STATE_FAILED,
+};
+
+struct NAcdConfig {
+        int ifindex;
+        unsigned int transport;
+        uint8_t mac[ETH_ALEN];
+        size_t n_mac;
+};
+
+#define N_ACD_CONFIG_NULL(_x) {                                                 \
+                .transport = _N_ACD_TRANSPORT_N,                                \
+        }
+
+struct NAcdProbeConfig {
+        struct in_addr ip;
+        uint64_t timeout_msecs;
+};
+
+#define N_ACD_PROBE_CONFIG_NULL(_x) {                                           \
+                .timeout_msecs = N_ACD_TIMEOUT_RFC5227,                         \
+        }
+
+struct NAcdEventNode {
+        CList acd_link;
+        CList probe_link;
+        NAcdEvent event;
+        uint8_t sender[ETH_ALEN];
+        bool is_public : 1;
+};
+
+#define N_ACD_EVENT_NODE_NULL(_x) {                                             \
+                .acd_link = C_LIST_INIT((_x).acd_link),                         \
+                .probe_link = C_LIST_INIT((_x).probe_link),                     \
+        }
+
+struct NAcd {
+        unsigned long n_refs;
+        unsigned int seed;
+        int fd_epoll;
+        int fd_socket;
+        CRBTree ip_tree;
+        CList event_list;
+        Timer timer;
+
+        /* BPF map */
+        int fd_bpf_map;
+        size_t n_bpf_map;
+        size_t max_bpf_map;
+
+        /* configuration */
+        int ifindex;
+        uint8_t mac[ETH_ALEN];
+
+        /* flags */
+        bool preempted : 1;
+};
+
+#define N_ACD_NULL(_x) {                                                        \
+                .n_refs = 1,                                                    \
+                .fd_epoll = -1,                                                 \
+                .fd_socket = -1,                                                \
+                .ip_tree = C_RBTREE_INIT,                                       \
+                .event_list = C_LIST_INIT((_x).event_list),                     \
+                .timer = TIMER_NULL((_x).timer),                                \
+                .fd_bpf_map = -1,                                               \
+        }
+
+struct NAcdProbe {
+        NAcd *acd;
+        CRBNode ip_node;
+        CList event_list;
+        Timeout timeout;
+
+        /* configuration */
+        struct in_addr ip;
+        uint64_t timeout_multiplier;
+        void *userdata;
+
+        /* state */
+        unsigned int state;
+        unsigned int n_iteration;
+        unsigned int defend;
+        uint64_t last_defend;
+};
+
+#define N_ACD_PROBE_NULL(_x) {                                                  \
+                .ip_node = C_RBNODE_INIT((_x).ip_node),                         \
+                .event_list = C_LIST_INIT((_x).event_list),                     \
+                .timeout = TIMEOUT_INIT((_x).timeout),                          \
+                .state = N_ACD_PROBE_STATE_PROBING,                             \
+                .defend = N_ACD_DEFEND_NEVER,                                   \
+        }
+
+/* events */
+
+int n_acd_event_node_new(NAcdEventNode **nodep);
+NAcdEventNode *n_acd_event_node_free(NAcdEventNode *node);
+
+/* contexts */
+
+void n_acd_remember(NAcd *acd, uint64_t now, bool success);
+int n_acd_raise(NAcd *acd, NAcdEventNode **nodep, unsigned int event);
+int n_acd_send(NAcd *acd, const struct in_addr *tpa, const struct in_addr *spa);
+int n_acd_ensure_bpf_map_space(NAcd *acd);
+
+/* probes */
+
+int n_acd_probe_new(NAcdProbe **probep, NAcd *acd, NAcdProbeConfig *config);
+int n_acd_probe_raise(NAcdProbe *probe, NAcdEventNode **nodep, unsigned int event);
+int n_acd_probe_handle_timeout(NAcdProbe *probe);
+int n_acd_probe_handle_packet(NAcdProbe *probe, struct ether_arp *packet, bool hard_conflict);
+
+/* eBPF */
+
+int n_acd_bpf_map_create(int *mapfdp, size_t max_elements);
+int n_acd_bpf_map_add(int mapfd, struct in_addr *addr);
+int n_acd_bpf_map_remove(int mapfd, struct in_addr *addr);
+
+int n_acd_bpf_compile(int *progfdp, int mapfd, struct ether_addr *mac);
+
+/* inline helpers */
+
+static inline int n_acd_errno(void) {
+        /*
+         * Compilers continuously warn about uninitialized variables since they
+         * cannot deduce that `return -errno;` will always be negative. This
+         * small wrapper makes sure compilers figure that out. Use it as
+         * replacement for `errno` read access. Yes, it generates worse code,
+         * but only marginally and only affects slow-paths.
+         */
+        return abs(errno) ? : EIO;
+}
+
+static inline void n_acd_event_node_freep(NAcdEventNode **node) {
+        if (*node)
+                n_acd_event_node_free(*node);
+}
+
+static inline void n_acd_closep(int *fdp) {
+        if (*fdp >= 0)
+                close(*fdp);
+}