babeld: add add_filter function
authorNick Hainke <vincent@systemli.org>
Sun, 27 Mar 2022 22:04:19 +0000 (00:04 +0200)
committerNick Hainke <vincent@systemli.org>
Wed, 30 Mar 2022 10:32:55 +0000 (12:32 +0200)
You can define filter functions in babeld by:

   in if eth0 metric 128

This commit adds the ubus equivalent to dynamically add filter on
runtime:

  ubus call babeld add_filter '{"ifname":"eth0", "type":"input",
                                "metric":128}'

Signed-off-by: Nick Hainke <vincent@systemli.org>
babeld/patches/000-export-add-filters-and-simplify-interface.patch [new file with mode: 0644]
babeld/patches/600-add-ubus.patch
babeld/src/ubus.c
babeld/src/ubus.h

diff --git a/babeld/patches/000-export-add-filters-and-simplify-interface.patch b/babeld/patches/000-export-add-filters-and-simplify-interface.patch
new file mode 100644 (file)
index 0000000..90bee74
--- /dev/null
@@ -0,0 +1,116 @@
+From 7c053fe7584b7b4fe4effc09624ae620304d6717 Mon Sep 17 00:00:00 2001
+From: Juliusz Chroboczek <jch@irif.fr>
+Date: Tue, 29 Mar 2022 19:26:50 +0200
+Subject: [PATCH] Export add_filters and simplify interface.
+
+---
+ configuration.c | 32 +++++++++++++++++++++++++-------
+ configuration.h |  6 ++++++
+ 2 files changed, 31 insertions(+), 7 deletions(-)
+
+--- a/configuration.c
++++ b/configuration.c
+@@ -693,9 +693,26 @@ parse_ifconf(int c, gnc_t gnc, void *clo
+     return -2;
+ }
+-static void
+-add_filter(struct filter *filter, struct filter **filters)
++int
++add_filter(struct filter *filter, int type)
+ {
++    struct filter **filters;
++    switch(type) {
++    case FILTER_TYPE_INPUT:
++        filters = &input_filters;
++        break;
++    case FILTER_TYPE_OUTPUT:
++        filters = &output_filters;
++        break;
++    case FILTER_TYPE_REDISTRIBUTE:
++        filters = &redistribute_filters;
++        break;
++    case FILTER_TYPE_INSTALL:
++        filters = &install_filters;
++        break;
++    default:
++        return -1;
++    }
+     if(*filters == NULL) {
+         filter->next = NULL;
+         *filters = filter;
+@@ -707,6 +724,7 @@ add_filter(struct filter *filter, struct
+         filter->next = NULL;
+         f->next = filter;
+     }
++    return 1;
+ }
+ static void
+@@ -1012,7 +1030,7 @@ parse_config_line(int c, gnc_t gnc, void
+         c = parse_filter(c, gnc, closure, &filter);
+         if(c < -1)
+             goto fail;
+-        add_filter(filter, &input_filters);
++        add_filter(filter, FILTER_TYPE_INPUT);
+     } else if(strcmp(token, "out") == 0) {
+         struct filter *filter;
+         if(config_finalised)
+@@ -1020,7 +1038,7 @@ parse_config_line(int c, gnc_t gnc, void
+         c = parse_filter(c, gnc, closure, &filter);
+         if(c < -1)
+             goto fail;
+-        add_filter(filter, &output_filters);
++        add_filter(filter, FILTER_TYPE_OUTPUT);
+     } else if(strcmp(token, "redistribute") == 0) {
+         struct filter *filter;
+         if(config_finalised)
+@@ -1028,7 +1046,7 @@ parse_config_line(int c, gnc_t gnc, void
+         c = parse_filter(c, gnc, closure, &filter);
+         if(c < -1)
+             goto fail;
+-        add_filter(filter, &redistribute_filters);
++        add_filter(filter, FILTER_TYPE_REDISTRIBUTE);
+     } else if(strcmp(token, "install") == 0) {
+         struct filter *filter;
+         if(config_finalised)
+@@ -1036,7 +1054,7 @@ parse_config_line(int c, gnc_t gnc, void
+         c = parse_filter(c, gnc, closure, &filter);
+         if(c < -1)
+             goto fail;
+-        add_filter(filter, &install_filters);
++        add_filter(filter, FILTER_TYPE_INSTALL);
+     } else if(strcmp(token, "interface") == 0) {
+         struct interface_conf *if_conf;
+         c = parse_ifconf(c, gnc, closure, &if_conf);
+@@ -1360,7 +1378,7 @@ finalise_config()
+     filter->proto = RTPROT_BABEL_LOCAL;
+     filter->plen_le = 128;
+     filter->src_plen_le = 128;
+-    add_filter(filter, &redistribute_filters);
++    add_filter(filter, FILTER_TYPE_REDISTRIBUTE);
+     while(interface_confs) {
+         struct interface_conf *if_conf;
+--- a/configuration.h
++++ b/configuration.h
+@@ -29,6 +29,11 @@ THE SOFTWARE.
+ #define CONFIG_ACTION_UNMONITOR 4
+ #define CONFIG_ACTION_NO 5
++#define FILTER_TYPE_INPUT 0
++#define FILTER_TYPE_OUTPUT 1
++#define FILTER_TYPE_REDISTRIBUTE 2
++#define FILTER_TYPE_INSTALL 3
++
+ struct filter_result {
+     unsigned int add_metric; /* allow = 0, deny = INF, metric = <0..INF> */
+     unsigned char *src_prefix;
+@@ -60,6 +65,7 @@ void flush_ifconf(struct interface_conf
+ int parse_config_from_file(const char *filename, int *line_return);
+ int parse_config_from_string(char *string, int n, const char **message_return);
++int add_filter(struct filter *filter, int type);
+ void renumber_filters(void);
+ int input_filter(const unsigned char *id,
index 252a299b129361cf45b909333c084df204fe8505..351d55986ab2636d5653177521d63e3d1e4cd6cb 100644 (file)
@@ -57,7 +57,7 @@
  static struct filter *input_filters = NULL;
  static struct filter *output_filters = NULL;
  static struct filter *redistribute_filters = NULL;
-@@ -849,7 +851,8 @@ parse_option(int c, gnc_t gnc, void *clo
+@@ -867,7 +869,8 @@ parse_option(int c, gnc_t gnc, void *clo
                strcmp(token, "daemonise") == 0 ||
                strcmp(token, "skip-kernel-setup") == 0 ||
                strcmp(token, "ipv6-subtrees") == 0 ||
@@ -67,7 +67,7 @@
          int b;
          c = getbool(c, &b, gnc, closure);
          if(c < -1)
-@@ -867,6 +870,8 @@ parse_option(int c, gnc_t gnc, void *clo
+@@ -885,6 +888,8 @@ parse_option(int c, gnc_t gnc, void *clo
              has_ipv6_subtrees = b;
          else if(strcmp(token, "reflect-kernel-metric") == 0)
              reflect_kernel_metric = b;
index 2066994efc2b512979b045e4f34520963b9af576..dec71a1b7759d21b1a485c3c25b979dda81e4ce7 100644 (file)
@@ -2,10 +2,10 @@
 #include <stdlib.h>
 #include <sys/select.h>
 
-#include <libubus.h>
 #include <libubox/blob.h>
 #include <libubox/blobmsg.h>
 #include <libubox/list.h>
+#include <libubus.h>
 
 #include <arpa/inet.h>
 #include <net/if.h>
@@ -63,6 +63,60 @@ static const struct blobmsg_policy interface_policy[__INTERFACE_MAX] = {
     [INTERFACE_IFNAME] = {"ifname", BLOBMSG_TYPE_STRING},
 };
 
+// Definition of filter function enums (to be used with ubox's blobmsg
+// helpers).
+enum { FILTER_IFNAME, FILTER_TYPE, FILTER_METRIC, __FILTER_MAX };
+
+// Definition of filter parsing (to be used with ubox's blobmsg helpers).
+static const struct blobmsg_policy filter_policy[__FILTER_MAX] = {
+    [FILTER_IFNAME] = {"ifname", BLOBMSG_TYPE_STRING},
+    [FILTER_TYPE] = {"type", BLOBMSG_TYPE_INT32},
+    [FILTER_METRIC] = {"metric", BLOBMSG_TYPE_INT32},
+};
+
+// Adds a filter (ubus equivalent to "filter"-function).
+static int babeld_ubus_add_filter(struct ubus_context *ctx_local,
+                                  struct ubus_object *obj,
+                                  struct ubus_request_data *req,
+                                  const char *method, struct blob_attr *msg) {
+  struct blob_attr *tb[__FILTER_MAX];
+  struct blob_buf b = {0};
+  struct filter *filter = NULL;
+  char *ifname;
+  int metric, type;
+
+  blobmsg_parse(filter_policy, __FILTER_MAX, tb, blob_data(msg), blob_len(msg));
+
+  if (!tb[FILTER_IFNAME])
+    return UBUS_STATUS_INVALID_ARGUMENT;
+
+  if (!tb[FILTER_TYPE])
+    return UBUS_STATUS_INVALID_ARGUMENT;
+
+  type = blobmsg_get_u32(tb[FILTER_TYPE]);
+
+  if (tb[FILTER_METRIC])
+    metric = blobmsg_get_u32(tb[FILTER_METRIC]);
+
+  filter = calloc(1, sizeof(struct filter));
+  if (filter == NULL)
+    return UBUS_STATUS_UNKNOWN_ERROR;
+
+  filter->af = AF_INET6;
+  filter->proto = 0;
+  filter->plen_le = 128;
+  filter->src_plen_le = 128;
+  filter->action.add_metric = metric;
+
+  ifname = blobmsg_get_string(tb[FILTER_IFNAME]);
+  filter->ifname = strdup(ifname);
+  filter->ifindex = if_nametoindex(filter->ifname);
+
+  add_filter(filter, type);
+
+  return UBUS_STATUS_OK;
+}
+
 // Adds an inteface (ubus equivalent to "interface"-function).
 static int babeld_ubus_add_interface(struct ubus_context *ctx_local,
                                      struct ubus_object *obj,
@@ -364,6 +418,7 @@ static int babeld_ubus_get_neighbours(struct ubus_context *ctx_local,
 // List of functions we expose via the ubus bus.
 static const struct ubus_method babeld_methods[] = {
     UBUS_METHOD("add_interface", babeld_ubus_add_interface, interface_policy),
+    UBUS_METHOD("add_filter", babeld_ubus_add_filter, filter_policy),
     UBUS_METHOD_NOARG("get_info", babeld_ubus_babeld_info),
     UBUS_METHOD_NOARG("get_xroutes", babeld_ubus_get_xroutes),
     UBUS_METHOD_NOARG("get_routes", babeld_ubus_get_routes),
index 951fee576d1653cc39173a593920da73fc9f84b4..08aeb52a607b03777b25afec3f008edbd01d10ee 100644 (file)
@@ -2,6 +2,12 @@
     IPC integration of babeld with OpenWrt.
 
     The ubus interface offers following functions:
+    - add_filter '{"ifname":"eth0", "type":0, "metric":5000}'
+        type:
+            0: FILTER_TYPE_INPUT
+            1: FILTER_TYPE_OUTPUT
+            2: FILTER_TYPE_REDISTRIBUTE
+            3: FILTER_TYPE_INSTALL
     - add_interface '{"ifname":"eth0"}'
     - get_info
     - get_neighbours