Systemd/src/libsystemd/sd-netlink/generic-netlink.c
Susant Sahani 53cb501a13 networkd and sd-netlink: add support for Generic netlink And FooOverUDP to IPIP tunnel
This work add support to generic netlink to sd-netlink.
See https://lwn.net/Articles/208755/

networkd: add support FooOverUDP support to IPIP tunnel netdev
https://lwn.net/Articles/614348/

Example conf:

/lib/systemd/network/1-fou-tunnel.netdev
```
[NetDev]
Name=fou-tun
Kind=fou

[FooOverUDP]
Port=5555
Protocol=4

```

/lib/systemd/network/ipip-tunnel.netdev
```
[NetDev]
Name=ipip-tun
Kind=ipip

[Tunnel]
Independent=true
Local=10.65.208.212
Remote=10.65.208.211
FooOverUDP=true
FOUDestinationPort=5555
```

$ ip -d link show ipip-tun
```
5: ipip-tun@NONE: <POINTOPOINT,NOARP> mtu 1472 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ipip 10.65.208.212 peer 10.65.208.211 promiscuity 0
    ipip remote 10.65.208.211 local 10.65.208.212 ttl inherit pmtudisc encap fou encap-sport auto encap-dport 5555 noencap-csum noencap-csum6 noencap-remcsum numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
```
2018-08-23 11:30:37 +02:00

98 lines
2.9 KiB
C

#include <linux/genetlink.h>
#include "sd-netlink.h"
#include "netlink-internal.h"
#include "alloc-util.h"
typedef struct {
const char* name;
uint8_t version;
} genl_family;
static const genl_family genl_families[] = {
[SD_GENL_ID_CTRL] = { .name = "", .version = 1 },
[SD_GENL_WIREGUARD] = { .name = "wireguard", .version = 1 },
[SD_GENL_FOU] = { .name = "fou", .version = 1 },
};
int sd_genl_socket_open(sd_netlink **ret) {
return netlink_open_family(ret, NETLINK_GENERIC);
}
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id);
static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
int r;
struct genlmsghdr *genl;
const NLType *genl_cmd_type, *nl_type;
const NLTypeSystem *type_system;
size_t size;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
r = type_system_get_type(&genl_family_type_system_root, &genl_cmd_type, family);
if (r < 0)
return r;
r = message_new_empty(nl, &m);
if (r < 0)
return r;
size = NLMSG_SPACE(sizeof(struct genlmsghdr));
m->hdr = malloc0(size);
if (!m->hdr)
return -ENOMEM;
m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
type_get_type_system(genl_cmd_type, &type_system);
r = type_system_get_type(type_system, &nl_type, cmd);
if (r < 0)
return r;
m->hdr->nlmsg_len = size;
m->hdr->nlmsg_type = nlmsg_type;
type_get_type_system(nl_type, &m->containers[0].type_system);
genl = NLMSG_DATA(m->hdr);
genl->cmd = cmd;
genl->version = genl_families[family].version;
*ret = TAKE_PTR(m);
return 0;
}
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) {
int r;
uint16_t id = GENL_ID_CTRL;
if (family != SD_GENL_ID_CTRL) {
r = lookup_id(nl, family, &id);
if (r < 0)
return r;
}
return genl_message_new(nl, family, id, cmd, ret);
}
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) {
int r;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
r = sd_genl_message_new(nl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req);
if (r < 0)
return r;
r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, genl_families[family].name);
if (r < 0)
return r;
r = sd_netlink_call(nl, req, 0, &reply);
if (r < 0)
return r;
return sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, id);
}