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