Coverage Report

Created: 2025-08-28 06:46

/src/systemd/src/network/netdev/geneve.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3
#include <linux/if_arp.h>
4
5
#include "sd-netlink.h"
6
7
#include "conf-parser.h"
8
#include "geneve.h"
9
#include "parse-util.h"
10
#include "string-table.h"
11
#include "string-util.h"
12
13
430
#define GENEVE_FLOW_LABEL_MAX_MASK 0xFFFFFU
14
333
#define DEFAULT_GENEVE_DESTINATION_PORT 6081
15
16
static const char* const geneve_df_table[_NETDEV_GENEVE_DF_MAX] = {
17
        [NETDEV_GENEVE_DF_NO]      = "no",
18
        [NETDEV_GENEVE_DF_YES]     = "yes",
19
        [NETDEV_GENEVE_DF_INHERIT] = "inherit",
20
};
21
22
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(geneve_df, GeneveDF, NETDEV_GENEVE_DF_YES);
23
DEFINE_CONFIG_PARSE_ENUM(config_parse_geneve_df, geneve_df, GeneveDF);
24
25
0
static int netdev_geneve_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
26
0
        assert(m);
27
28
0
        Geneve *v = GENEVE(netdev);
29
0
        int r;
30
31
0
        if (v->id <= GENEVE_VID_MAX) {
32
0
                r = sd_netlink_message_append_u32(m, IFLA_GENEVE_ID, v->id);
33
0
                if (r < 0)
34
0
                        return r;
35
0
        }
36
37
0
        if (in_addr_is_set(v->remote_family, &v->remote)) {
38
0
                if (v->remote_family == AF_INET)
39
0
                        r = sd_netlink_message_append_in_addr(m, IFLA_GENEVE_REMOTE, &v->remote.in);
40
0
                else
41
0
                        r = sd_netlink_message_append_in6_addr(m, IFLA_GENEVE_REMOTE6, &v->remote.in6);
42
0
                if (r < 0)
43
0
                        return r;
44
0
        }
45
46
0
        if (v->inherit) {
47
0
                r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TTL_INHERIT, 1);
48
0
                if (r < 0)
49
0
                        return r;
50
0
        } else {
51
0
                r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TTL, v->ttl);
52
0
                if (r < 0)
53
0
                        return r;
54
0
        }
55
56
0
        r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TOS, v->tos);
57
0
        if (r < 0)
58
0
                return r;
59
60
0
        r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_CSUM, v->udpcsum);
61
0
        if (r < 0)
62
0
                return r;
63
64
0
        r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx);
65
0
        if (r < 0)
66
0
                return r;
67
68
0
        r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx);
69
0
        if (r < 0)
70
0
                return r;
71
72
0
        if (v->dest_port != DEFAULT_GENEVE_DESTINATION_PORT) {
73
0
                r = sd_netlink_message_append_u16(m, IFLA_GENEVE_PORT, htobe16(v->dest_port));
74
0
                if (r < 0)
75
0
                        return r;
76
0
        }
77
78
0
        if (v->flow_label > 0) {
79
0
                r = sd_netlink_message_append_u32(m, IFLA_GENEVE_LABEL, htobe32(v->flow_label));
80
0
                if (r < 0)
81
0
                        return r;
82
0
        }
83
84
0
        if (v->inherit_inner_protocol) {
85
0
                r = sd_netlink_message_append_flag(m, IFLA_GENEVE_INNER_PROTO_INHERIT);
86
0
                if (r < 0)
87
0
                        return r;
88
0
        }
89
90
0
        if (v->geneve_df != _NETDEV_GENEVE_DF_INVALID) {
91
0
                r = sd_netlink_message_append_u8(m, IFLA_GENEVE_DF, v->geneve_df);
92
0
                if (r < 0)
93
0
                        return r;
94
0
        }
95
96
0
        return 0;
97
0
}
98
99
int config_parse_geneve_vni(
100
                const char *unit,
101
                const char *filename,
102
                unsigned line,
103
                const char *section,
104
                unsigned section_line,
105
                const char *lvalue,
106
                int ltype,
107
                const char *rvalue,
108
                void *data,
109
623
                void *userdata) {
110
111
623
        assert(filename);
112
623
        assert(lvalue);
113
623
        assert(rvalue);
114
623
        assert(data);
115
116
623
        Geneve *v = ASSERT_PTR(userdata);
117
118
623
        return config_parse_uint32_bounded(
119
623
                        unit, filename, line, section, section_line, lvalue, rvalue,
120
623
                        0, GENEVE_VID_MAX, true,
121
623
                        &v->id);
122
623
}
123
124
int config_parse_geneve_address(
125
                const char *unit,
126
                const char *filename,
127
                unsigned line,
128
                const char *section,
129
                unsigned section_line,
130
                const char *lvalue,
131
                int ltype,
132
                const char *rvalue,
133
                void *data,
134
608
                void *userdata) {
135
136
608
        assert(filename);
137
608
        assert(lvalue);
138
608
        assert(rvalue);
139
608
        assert(data);
140
141
608
        Geneve *v = ASSERT_PTR(userdata);
142
608
        union in_addr_union *addr = data, buffer;
143
608
        int r, f;
144
145
608
        r = in_addr_from_string_auto(rvalue, &f, &buffer);
146
608
        if (r < 0) {
147
215
                log_syntax(unit, LOG_WARNING, filename, line, r,
148
215
                           "geneve '%s' address is invalid, ignoring assignment: %s", lvalue, rvalue);
149
215
                return 0;
150
215
        }
151
152
393
        r = in_addr_is_multicast(f, &buffer);
153
393
        if (r > 0) {
154
195
                log_syntax(unit, LOG_WARNING, filename, line, 0,
155
195
                           "geneve invalid multicast '%s' address, ignoring assignment: %s", lvalue, rvalue);
156
195
                return 0;
157
195
        }
158
159
198
        v->remote_family = f;
160
198
        *addr = buffer;
161
162
198
        return 0;
163
393
}
164
165
int config_parse_geneve_flow_label(
166
                const char *unit,
167
                const char *filename,
168
                unsigned line,
169
                const char *section,
170
                unsigned section_line,
171
                const char *lvalue,
172
                int ltype,
173
                const char *rvalue,
174
                void *data,
175
647
                void *userdata) {
176
177
647
        assert(filename);
178
647
        assert(lvalue);
179
647
        assert(rvalue);
180
647
        assert(data);
181
182
647
        Geneve *v = ASSERT_PTR(userdata);
183
647
        uint32_t f;
184
647
        int r;
185
186
647
        r = safe_atou32(rvalue, &f);
187
647
        if (r < 0) {
188
217
                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse Geneve flow label '%s'.", rvalue);
189
217
                return 0;
190
217
        }
191
192
430
        if (f & ~GENEVE_FLOW_LABEL_MAX_MASK) {
193
216
                log_syntax(unit, LOG_WARNING, filename, line, 0,
194
216
                           "Geneve flow label '%s' not valid. Flow label range should be [0-1048575].", rvalue);
195
216
                return 0;
196
216
        }
197
198
214
        v->flow_label = f;
199
200
214
        return 0;
201
430
}
202
203
int config_parse_geneve_ttl(
204
                const char *unit,
205
                const char *filename,
206
                unsigned line,
207
                const char *section,
208
                unsigned section_line,
209
                const char *lvalue,
210
                int ltype,
211
                const char *rvalue,
212
                void *data,
213
649
                void *userdata) {
214
215
649
        assert(filename);
216
649
        assert(lvalue);
217
649
        assert(rvalue);
218
649
        assert(data);
219
220
649
        Geneve *v = ASSERT_PTR(userdata);
221
649
        int r;
222
223
649
        if (streq(rvalue, "inherit")) {
224
194
                v->inherit = true;
225
194
                v->ttl = 0;  /* unset the unused ttl field for clarity */
226
194
                return 0;
227
194
        }
228
229
455
        r = config_parse_uint8_bounded(
230
455
                        unit, filename, line, section, section_line, lvalue, rvalue,
231
455
                        0, UINT8_MAX, true,
232
455
                        &v->ttl);
233
455
        if (r <= 0)
234
255
                return r;
235
200
        v->inherit = false;
236
200
        return 0;
237
455
}
238
239
333
static int netdev_geneve_verify(NetDev *netdev, const char *filename) {
240
333
        assert(filename);
241
242
333
        Geneve *v = GENEVE(netdev);
243
244
333
        if (v->id > GENEVE_VID_MAX)
245
294
                return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
246
39
                                                "%s: Geneve without valid VNI (or Virtual Network Identifier) configured. Ignoring.",
247
39
                                                filename);
248
39
        return 0;
249
333
}
250
251
0
static bool geneve_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
252
0
        return true;
253
0
}
254
255
333
static void geneve_init(NetDev *netdev) {
256
333
        Geneve *v = GENEVE(netdev);
257
258
333
        v->id = GENEVE_VID_MAX + 1;
259
333
        v->geneve_df = _NETDEV_GENEVE_DF_INVALID;
260
333
        v->dest_port = DEFAULT_GENEVE_DESTINATION_PORT;
261
333
        v->udpcsum = false;
262
333
        v->udp6zerocsumtx = false;
263
333
        v->udp6zerocsumrx = false;
264
333
}
265
266
const NetDevVTable geneve_vtable = {
267
        .object_size = sizeof(Geneve),
268
        .init = geneve_init,
269
        .sections = NETDEV_COMMON_SECTIONS "GENEVE\0",
270
        .fill_message_create = netdev_geneve_fill_message_create,
271
        .create_type = NETDEV_CREATE_INDEPENDENT,
272
        .config_verify = netdev_geneve_verify,
273
        .can_set_mac = geneve_can_set_mac,
274
        .iftype = ARPHRD_ETHER,
275
        .generate_mac = true,
276
};