diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2019-06-01 14:28:03 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2019-06-01 14:28:03 +0200 |
commit | 8d15854eb57c8a16523a986aa72e3a2c993a8c50 (patch) | |
tree | 4e2eb93d61d3a96b2b37fb4b7b31f277144a8164 /src | |
parent | 8b5af11ebe1211861b422cc6737219c28594eecd (diff) | |
download | neco-8d15854eb57c8a16523a986aa72e3a2c993a8c50.tar neco-8d15854eb57c8a16523a986aa72e3a2c993a8c50.zip |
device: bridge: implement initial bridge setup
Diffstat (limited to 'src')
-rw-r--r-- | src/device-bridge.c | 122 |
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)) |