summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2019-06-01 14:28:03 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2019-06-01 14:28:03 +0200
commit8d15854eb57c8a16523a986aa72e3a2c993a8c50 (patch)
tree4e2eb93d61d3a96b2b37fb4b7b31f277144a8164 /src
parent8b5af11ebe1211861b422cc6737219c28594eecd (diff)
downloadneco-8d15854eb57c8a16523a986aa72e3a2c993a8c50.tar
neco-8d15854eb57c8a16523a986aa72e3a2c993a8c50.zip
device: bridge: implement initial bridge setup
Diffstat (limited to 'src')
-rw-r--r--src/device-bridge.c122
1 files changed, 118 insertions, 4 deletions
diff --git a/src/device-bridge.c b/src/device-bridge.c
index 4a8d24c..11b24b0 100644
--- a/src/device-bridge.c
+++ b/src/device-bridge.c
@@ -1,14 +1,128 @@
-#include "device.h"
+#include "device-common.h"
+#include "netlink.h"
+#include "util.h"
-#include <stdio.h>
+#include <string.h>
+
+#include <net/if.h>
+
+#include <linux/if.h>
+#include <linux/if_link.h>
+#include <linux/rtnetlink.h>
+
+static device_type_t device_type_bridge;
+
+typedef struct _device_bridge {
+ device_t device;
+ device_common_t common;
+} device_bridge_t;
+
+static void bridge_free(device_t *dev) {
+ device_bridge_t *iface = container_of(dev, device_bridge_t, device);
+
+ VECTOR_FREE(iface->common.addrs);
+ free(NODE_NAME(dev));
+ free(iface);
+}
static device_t * bridge_process_config(const char *name, struct json_object *config) {
- printf("Bridge: %s\n", name);
+ device_bridge_t *iface = calloc(1, sizeof(*iface));
+ if (!iface)
+ return NULL;
+
+ device_t *dev = &iface->device;
+ dev->type = &device_type_bridge;
+
+ NODE_NAME(dev) = strdup(name);
+ if (!NODE_NAME(dev)) {
+ free(iface);
+ return NULL;
+ }
+
+ if (!device_common_process_config(&iface->common, config))
+ goto err;
+
+ return dev;
+
+err:
+ bridge_free(dev);
return NULL;
}
-device_type_t device_type_bridge = {
+static bool bridge_nl_create(device_bridge_t *bridge) {
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+
+ struct mnl_socket *nl = nl_socket();
+
+ struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = RTM_NEWLINK;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE;
+ int seq = nlh->nlmsg_seq = nl_seq();
+
+ struct ifinfomsg *ifi = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifi));
+ ifi->ifi_family = AF_UNSPEC;
+
+ mnl_attr_put_str(nlh, IFLA_IFNAME, NODE_NAME(&bridge->device));
+
+ struct nlattr *linkinfo = mnl_attr_nest_start(nlh, IFLA_LINKINFO);
+ mnl_attr_put_str(nlh, IFLA_INFO_KIND, "bridge");
+ mnl_attr_nest_end(nlh, linkinfo);
+
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+ perror("mnl_socket_sendto");
+ return false;
+ }
+
+ int ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ if (ret == -1) {
+ perror("mnl_socket_recvfrom");
+ return false;
+ }
+
+ ret = mnl_cb_run(buf, ret, seq, mnl_socket_get_portid(nl), NULL, NULL);
+ if (ret == -1) {
+ perror("mnl_cb_run");
+ return false;
+ }
+
+ return true;
+}
+
+static void bridge_init(device_t *dev) {
+ device_bridge_t *bridge = container_of(dev, device_bridge_t, device);
+
+ if (!bridge_nl_create(bridge))
+ return;
+
+ unsigned ifindex = if_nametoindex(NODE_NAME(dev));
+ if (!ifindex)
+ return;
+
+ device_common_init(&bridge->common, ifindex);
+}
+
+static void bridge_update(device_t *dev) {
+}
+
+static void bridge_release(device_t *dev) {
+ /*
+ device_bridge_t *bridge = container_of(dev, device_bridge_t, device);
+
+ unsigned ifindex = if_nametoindex(NODE_NAME(dev));
+ if (!ifindex)
+ return;
+
+ device_common_release(&bridge->common, ifindex);
+ */
+}
+
+static device_type_t device_type_bridge = {
.process_config = bridge_process_config,
+ .free = bridge_free,
+
+ .init = bridge_init,
+ .update = bridge_update,
+ .release = bridge_release,
};
__attribute__((constructor))