summaryrefslogtreecommitdiffstats
path: root/src/network/netdev/fou-tunnel.c
blob: 65dad384e2213d13a5ede5df4a99c81b7e84a295 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* SPDX-License-Identifier: LGPL-2.1+ */

#include <arpa/inet.h>
#include <net/if.h>
#include <linux/ip.h>

#include "conf-parser.h"
#include "missing.h"
#include "netdev/fou-tunnel.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "parse-util.h"
#include "sd-netlink.h"
#include "string-table.h"
#include "string-util.h"
#include "util.h"

static const char* const fou_encap_type_table[_NETDEV_FOO_OVER_UDP_ENCAP_MAX] = {
        [NETDEV_FOO_OVER_UDP_ENCAP_DIRECT] = "FooOverUDP",
        [NETDEV_FOO_OVER_UDP_ENCAP_GUE] = "GenericUDPEncapsulation",
};

DEFINE_STRING_TABLE_LOOKUP(fou_encap_type, FooOverUDPEncapType);
DEFINE_CONFIG_PARSE_ENUM(config_parse_fou_encap_type, fou_encap_type, FooOverUDPEncapType,
                         "Failed to parse Encapsulation=");

static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **ret) {
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
        FouTunnel *t;
        int r;

        assert(netdev);

        t = FOU(netdev);

        assert(t);

        r = sd_genl_message_new(netdev->manager->genl, SD_GENL_FOU, FOU_CMD_ADD, &m);
        if (r < 0)
                return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");

        r = sd_netlink_message_append_u16(m, FOU_ATTR_PORT, htobe16(t->port));
        if (r < 0)
                return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_PORT attribute: %m");

        r = sd_netlink_message_append_u8(m, FOU_ATTR_TYPE, FOU_ENCAP_GUE);
        if (r < 0)
                return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_TYPE attribute: %m");

        r = sd_netlink_message_append_u8(m, FOU_ATTR_AF, AF_INET);
        if (r < 0)
                return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_AF attribute: %m");

        r = sd_netlink_message_append_u8(m, FOU_ATTR_IPPROTO, t->fou_protocol);
        if (r < 0)
                return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_IPPROTO attribute: %m");

        *ret = m;
        m = NULL;

        return 0;
}

static int netdev_fou_tunnel_create(NetDev *netdev) {
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
        uint32_t serial;
        FouTunnel *t;
        int r;

        assert(netdev);

        t = FOU(netdev);

        assert(t);

        r = netdev_fill_fou_tunnel_message(netdev, &m);
        if (r < 0)
                return r;

        r = sd_netlink_send(netdev->manager->genl, m, &serial);
        if (r < 0 && r != -EADDRINUSE)
                return log_netdev_error_errno(netdev, r, "Failed to add FooOverUDP tunnel: %m");

        return 0;
}

static int netdev_fou_tunnel_verify(NetDev *netdev, const char *filename) {
        FouTunnel *t;

        assert(netdev);
        assert(filename);

        t = FOU(netdev);

        assert(t);

        if (t->fou_encap_type == NETDEV_FOO_OVER_UDP_ENCAP_DIRECT && t->fou_protocol <= 0) {
                log_netdev_error(netdev, "FooOverUDP protocol not configured in %s. Rejecting configuration.", filename);
                return -EINVAL;
        }

        if (t->fou_encap_type == NETDEV_FOO_OVER_UDP_ENCAP_GUE && t->fou_protocol > 0) {
                log_netdev_error(netdev, "FooOverUDP GUE can't be set with protocol configured in %s. Rejecting configuration.", filename);
                return -EINVAL;
        }

        return 0;
}

static void fou_tunnel_init(NetDev *netdev) {
        FouTunnel *t;

        assert(netdev);

        t = FOU(netdev);

        assert(t);

        t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT;
}

const NetDevVTable foutnl_vtable = {
        .object_size = sizeof(FouTunnel),
        .init = fou_tunnel_init,
        .sections = "Match\0NetDev\0FooOverUDP\0",
        .create = netdev_fou_tunnel_create,
        .create_type = NETDEV_CREATE_INDEPENDENT,
        .config_verify = netdev_fou_tunnel_verify,
};