]> git.proxmox.com Git - ovs.git/blame - lib/dpif-netlink-rtnl.c
compat: Add ipv6 GRE and IPV6 Tunneling
[ovs.git] / lib / dpif-netlink-rtnl.c
CommitLineData
c4e08753
EG
1/*
2 * Copyright (c) 2017 Red Hat, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
18
19#include "dpif-netlink-rtnl.h"
20
21#include <net/if.h>
22#include <linux/ip.h>
23#include <linux/rtnetlink.h>
24
25#include "dpif-netlink.h"
26#include "netdev-vport.h"
27#include "netlink-socket.h"
28#include "openvswitch/vlog.h"
29
30VLOG_DEFINE_THIS_MODULE(dpif_netlink_rtnl);
31
825e45e0
EG
32/* On some older systems, these enums are not defined. */
33#ifndef IFLA_VXLAN_MAX
34#define IFLA_VXLAN_MAX 0
35#endif
c33c412f 36#if IFLA_VXLAN_MAX < 27
825e45e0
EG
37#define IFLA_VXLAN_LEARNING 7
38#define IFLA_VXLAN_PORT 15
39#define IFLA_VXLAN_UDP_ZERO_CSUM6_RX 20
40#define IFLA_VXLAN_GBP 23
41#define IFLA_VXLAN_COLLECT_METADATA 25
c33c412f 42#define IFLA_VXLAN_GPE 27
825e45e0
EG
43#endif
44
f658f95e
EG
45#ifndef IFLA_GRE_MAX
46#define IFLA_GRE_MAX 0
47#endif
48#if IFLA_GRE_MAX < 18
49#define IFLA_GRE_COLLECT_METADATA 18
50#endif
51
b6d6830d
EG
52#ifndef IFLA_GENEVE_MAX
53#define IFLA_GENEVE_MAX 0
54#endif
55#if IFLA_GENEVE_MAX < 10
56#define IFLA_GENEVE_PORT 5
57#define IFLA_GENEVE_COLLECT_METADATA 6
58#define IFLA_GENEVE_UDP_ZERO_CSUM6_RX 10
59#endif
60
c4e08753
EG
61static const struct nl_policy rtlink_policy[] = {
62 [IFLA_LINKINFO] = { .type = NL_A_NESTED },
63};
64static const struct nl_policy linkinfo_policy[] = {
65 [IFLA_INFO_KIND] = { .type = NL_A_STRING },
66 [IFLA_INFO_DATA] = { .type = NL_A_NESTED },
67};
825e45e0
EG
68static const struct nl_policy vxlan_policy[] = {
69 [IFLA_VXLAN_COLLECT_METADATA] = { .type = NL_A_U8 },
70 [IFLA_VXLAN_LEARNING] = { .type = NL_A_U8 },
71 [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NL_A_U8 },
72 [IFLA_VXLAN_PORT] = { .type = NL_A_U16 },
76e2d4e7
EG
73 [IFLA_VXLAN_GBP] = { .type = NL_A_FLAG, .optional = true },
74 [IFLA_VXLAN_GPE] = { .type = NL_A_FLAG, .optional = true },
825e45e0 75};
f658f95e
EG
76static const struct nl_policy gre_policy[] = {
77 [IFLA_GRE_COLLECT_METADATA] = { .type = NL_A_FLAG },
78};
b6d6830d
EG
79static const struct nl_policy geneve_policy[] = {
80 [IFLA_GENEVE_COLLECT_METADATA] = { .type = NL_A_FLAG },
81 [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NL_A_U8 },
82 [IFLA_GENEVE_PORT] = { .type = NL_A_U16 },
83};
c4e08753
EG
84
85static const char *
2fd3d5ed
EG
86vport_type_to_kind(enum ovs_vport_type type,
87 const struct netdev_tunnel_config *tnl_cfg)
c4e08753
EG
88{
89 switch (type) {
90 case OVS_VPORT_TYPE_VXLAN:
91 return "vxlan";
92 case OVS_VPORT_TYPE_GRE:
c387d817
GR
93 case OVS_VPORT_TYPE_ERSPAN:
94 case OVS_VPORT_TYPE_IP6ERSPAN:
95 case OVS_VPORT_TYPE_IP6GRE:
2fd3d5ed
EG
96 if (tnl_cfg->pt_mode == NETDEV_PT_LEGACY_L3) {
97 return "gre";
98 } else if (tnl_cfg->pt_mode == NETDEV_PT_LEGACY_L2) {
99 return "gretap";
100 } else {
101 return NULL;
102 }
c4e08753
EG
103 case OVS_VPORT_TYPE_GENEVE:
104 return "geneve";
105 case OVS_VPORT_TYPE_NETDEV:
106 case OVS_VPORT_TYPE_INTERNAL:
107 case OVS_VPORT_TYPE_LISP:
108 case OVS_VPORT_TYPE_STT:
109 case OVS_VPORT_TYPE_UNSPEC:
110 case __OVS_VPORT_TYPE_MAX:
111 default:
112 break;
113 }
114
115 return NULL;
116}
117
118static int
119rtnl_transact(uint32_t type, uint32_t flags, const char *name,
120 struct ofpbuf **reply)
121{
122 struct ofpbuf request;
123 int err;
124
125 ofpbuf_init(&request, 0);
126 nl_msg_put_nlmsghdr(&request, 0, type, flags);
127 ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg));
128 nl_msg_put_string(&request, IFLA_IFNAME, name);
129
130 err = nl_transact(NETLINK_ROUTE, &request, reply);
131 ofpbuf_uninit(&request);
132
133 return err;
134}
135
136static int
137dpif_netlink_rtnl_destroy(const char *name)
138{
139 return rtnl_transact(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK, name, NULL);
140}
141
825e45e0 142static int
c4e08753
EG
143dpif_netlink_rtnl_getlink(const char *name, struct ofpbuf **reply)
144{
145 return rtnl_transact(RTM_GETLINK, NLM_F_REQUEST, name, reply);
146}
147
825e45e0 148static int
c4e08753
EG
149rtnl_policy_parse(const char *kind, struct ofpbuf *reply,
150 const struct nl_policy *policy,
151 struct nlattr *tnl_info[],
152 size_t policy_size)
153{
154 struct nlattr *linkinfo[ARRAY_SIZE(linkinfo_policy)];
155 struct nlattr *rtlink[ARRAY_SIZE(rtlink_policy)];
c4e08753
EG
156 int error = 0;
157
fae145ca 158 if (!nl_policy_parse(reply, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
c4e08753
EG
159 rtlink_policy, rtlink, ARRAY_SIZE(rtlink_policy))
160 || !nl_parse_nested(rtlink[IFLA_LINKINFO], linkinfo_policy,
161 linkinfo, ARRAY_SIZE(linkinfo_policy))
162 || strcmp(nl_attr_get_string(linkinfo[IFLA_INFO_KIND]), kind)
163 || !nl_parse_nested(linkinfo[IFLA_INFO_DATA], policy,
164 tnl_info, policy_size)) {
165 error = EINVAL;
166 }
167
168 return error;
169}
170
171static int
825e45e0 172dpif_netlink_rtnl_vxlan_verify(const struct netdev_tunnel_config *tnl_cfg,
caeda348 173 const char *kind, struct ofpbuf *reply)
825e45e0 174{
caeda348 175 struct nlattr *vxlan[ARRAY_SIZE(vxlan_policy)];
825e45e0
EG
176 int err;
177
caeda348
JS
178 err = rtnl_policy_parse(kind, reply, vxlan_policy, vxlan,
179 ARRAY_SIZE(vxlan_policy));
825e45e0 180 if (!err) {
caeda348
JS
181 if (0 != nl_attr_get_u8(vxlan[IFLA_VXLAN_LEARNING])
182 || 1 != nl_attr_get_u8(vxlan[IFLA_VXLAN_COLLECT_METADATA])
183 || 1 != nl_attr_get_u8(vxlan[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])
184 || (tnl_cfg->dst_port
185 != nl_attr_get_be16(vxlan[IFLA_VXLAN_PORT]))
186 || (tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GBP)
c33c412f
EG
187 && !nl_attr_get_flag(vxlan[IFLA_VXLAN_GBP]))
188 || (tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GPE)
189 && !nl_attr_get_flag(vxlan[IFLA_VXLAN_GPE]))) {
caeda348 190 err = EINVAL;
825e45e0 191 }
825e45e0
EG
192 }
193
194 return err;
195}
196
f658f95e
EG
197static int
198dpif_netlink_rtnl_gre_verify(const struct netdev_tunnel_config OVS_UNUSED *tnl,
caeda348 199 const char *kind, struct ofpbuf *reply)
f658f95e 200{
caeda348 201 struct nlattr *gre[ARRAY_SIZE(gre_policy)];
f658f95e
EG
202 int err;
203
caeda348
JS
204 err = rtnl_policy_parse(kind, reply, gre_policy, gre,
205 ARRAY_SIZE(gre_policy));
f658f95e 206 if (!err) {
caeda348
JS
207 if (!nl_attr_get_flag(gre[IFLA_GRE_COLLECT_METADATA])) {
208 err = EINVAL;
f658f95e 209 }
f658f95e
EG
210 }
211
212 return err;
213}
825e45e0 214
b6d6830d
EG
215static int
216dpif_netlink_rtnl_geneve_verify(const struct netdev_tunnel_config *tnl_cfg,
caeda348 217 const char *kind, struct ofpbuf *reply)
b6d6830d 218{
caeda348 219 struct nlattr *geneve[ARRAY_SIZE(geneve_policy)];
b6d6830d
EG
220 int err;
221
caeda348
JS
222 err = rtnl_policy_parse(kind, reply, geneve_policy, geneve,
223 ARRAY_SIZE(geneve_policy));
b6d6830d 224 if (!err) {
caeda348
JS
225 if (!nl_attr_get_flag(geneve[IFLA_GENEVE_COLLECT_METADATA])
226 || 1 != nl_attr_get_u8(geneve[IFLA_GENEVE_UDP_ZERO_CSUM6_RX])
227 || (tnl_cfg->dst_port
228 != nl_attr_get_be16(geneve[IFLA_GENEVE_PORT]))) {
229 err = EINVAL;
b6d6830d 230 }
b6d6830d
EG
231 }
232
233 return err;
234}
235
825e45e0
EG
236static int
237dpif_netlink_rtnl_verify(const struct netdev_tunnel_config *tnl_cfg,
238 enum ovs_vport_type type, const char *name)
c4e08753 239{
caeda348 240 struct ofpbuf *reply;
c4e08753 241 const char *kind;
caeda348 242 int err;
c4e08753 243
2fd3d5ed 244 kind = vport_type_to_kind(type, tnl_cfg);
c4e08753
EG
245 if (!kind) {
246 return EOPNOTSUPP;
247 }
248
caeda348
JS
249 err = dpif_netlink_rtnl_getlink(name, &reply);
250 if (err) {
251 return err;
252 }
253
c4e08753
EG
254 switch (type) {
255 case OVS_VPORT_TYPE_VXLAN:
caeda348
JS
256 err = dpif_netlink_rtnl_vxlan_verify(tnl_cfg, kind, reply);
257 break;
c4e08753 258 case OVS_VPORT_TYPE_GRE:
caeda348
JS
259 err = dpif_netlink_rtnl_gre_verify(tnl_cfg, kind, reply);
260 break;
c4e08753 261 case OVS_VPORT_TYPE_GENEVE:
caeda348
JS
262 err = dpif_netlink_rtnl_geneve_verify(tnl_cfg, kind, reply);
263 break;
c4e08753
EG
264 case OVS_VPORT_TYPE_NETDEV:
265 case OVS_VPORT_TYPE_INTERNAL:
266 case OVS_VPORT_TYPE_LISP:
267 case OVS_VPORT_TYPE_STT:
c387d817
GR
268 case OVS_VPORT_TYPE_ERSPAN:
269 case OVS_VPORT_TYPE_IP6ERSPAN:
270 case OVS_VPORT_TYPE_IP6GRE:
c4e08753
EG
271 case OVS_VPORT_TYPE_UNSPEC:
272 case __OVS_VPORT_TYPE_MAX:
273 default:
b50fcaa0 274 OVS_NOT_REACHED();
c4e08753
EG
275 }
276
caeda348
JS
277 ofpbuf_delete(reply);
278 return err;
c4e08753
EG
279}
280
825e45e0
EG
281static int
282dpif_netlink_rtnl_create(const struct netdev_tunnel_config *tnl_cfg,
c4e08753
EG
283 const char *name, enum ovs_vport_type type,
284 const char *kind, uint32_t flags)
285{
0ca24ab2
BP
286 enum {
287 /* For performance, we want to use the largest MTU that the system
288 * supports. Most existing tunnels will accept UINT16_MAX, treating it
289 * as the actual max MTU, but some do not. Thus, we use a slightly
290 * smaller value, that should always be safe yet does not noticeably
291 * reduce performance. */
292 MAX_MTU = 65000
293 };
294
c4e08753
EG
295 size_t linkinfo_off, infodata_off;
296 struct ifinfomsg *ifinfo;
297 struct ofpbuf request;
298 int err;
299
300 ofpbuf_init(&request, 0);
301 nl_msg_put_nlmsghdr(&request, 0, RTM_NEWLINK, flags);
302 ifinfo = ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg));
303 ifinfo->ifi_change = ifinfo->ifi_flags = IFF_UP;
304 nl_msg_put_string(&request, IFLA_IFNAME, name);
0ca24ab2 305 nl_msg_put_u32(&request, IFLA_MTU, MAX_MTU);
c4e08753
EG
306 linkinfo_off = nl_msg_start_nested(&request, IFLA_LINKINFO);
307 nl_msg_put_string(&request, IFLA_INFO_KIND, kind);
308 infodata_off = nl_msg_start_nested(&request, IFLA_INFO_DATA);
309
310 /* tunnel unique info */
311 switch (type) {
312 case OVS_VPORT_TYPE_VXLAN:
825e45e0
EG
313 nl_msg_put_u8(&request, IFLA_VXLAN_LEARNING, 0);
314 nl_msg_put_u8(&request, IFLA_VXLAN_COLLECT_METADATA, 1);
315 nl_msg_put_u8(&request, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, 1);
316 if (tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GBP)) {
317 nl_msg_put_flag(&request, IFLA_VXLAN_GBP);
318 }
c33c412f
EG
319 if (tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GPE)) {
320 nl_msg_put_flag(&request, IFLA_VXLAN_GPE);
321 }
825e45e0
EG
322 nl_msg_put_be16(&request, IFLA_VXLAN_PORT, tnl_cfg->dst_port);
323 break;
c4e08753 324 case OVS_VPORT_TYPE_GRE:
c387d817
GR
325 case OVS_VPORT_TYPE_ERSPAN:
326 case OVS_VPORT_TYPE_IP6ERSPAN:
327 case OVS_VPORT_TYPE_IP6GRE:
f658f95e
EG
328 nl_msg_put_flag(&request, IFLA_GRE_COLLECT_METADATA);
329 break;
c4e08753 330 case OVS_VPORT_TYPE_GENEVE:
b6d6830d
EG
331 nl_msg_put_flag(&request, IFLA_GENEVE_COLLECT_METADATA);
332 nl_msg_put_u8(&request, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, 1);
333 nl_msg_put_be16(&request, IFLA_GENEVE_PORT, tnl_cfg->dst_port);
334 break;
c4e08753
EG
335 case OVS_VPORT_TYPE_NETDEV:
336 case OVS_VPORT_TYPE_INTERNAL:
337 case OVS_VPORT_TYPE_LISP:
338 case OVS_VPORT_TYPE_STT:
339 case OVS_VPORT_TYPE_UNSPEC:
340 case __OVS_VPORT_TYPE_MAX:
341 default:
342 err = EOPNOTSUPP;
343 goto exit;
344 }
345
346 nl_msg_end_nested(&request, infodata_off);
347 nl_msg_end_nested(&request, linkinfo_off);
348
349 err = nl_transact(NETLINK_ROUTE, &request, NULL);
2927a473
BP
350 if (!err && type == OVS_VPORT_TYPE_GRE) {
351 /* Work around a bug in kernel GRE driver, which ignores IFLA_MTU in
352 * RTM_NEWLINK, by setting the MTU again. See
353 * https://bugzilla.redhat.com/show_bug.cgi?id=1488484. */
354 ofpbuf_clear(&request);
355 nl_msg_put_nlmsghdr(&request, 0, RTM_SETLINK,
356 NLM_F_REQUEST | NLM_F_ACK);
357 ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg));
358 nl_msg_put_string(&request, IFLA_IFNAME, name);
359 nl_msg_put_u32(&request, IFLA_MTU, MAX_MTU);
360
361 int err2 = nl_transact(NETLINK_ROUTE, &request, NULL);
362 if (err2) {
363 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
364
365 VLOG_WARN_RL(&rl, "setting MTU of tunnel %s failed (%s)",
366 name, ovs_strerror(err2));
367 }
368 }
c4e08753
EG
369
370exit:
371 ofpbuf_uninit(&request);
372
373 return err;
374}
375
376int
377dpif_netlink_rtnl_port_create(struct netdev *netdev)
378{
379 const struct netdev_tunnel_config *tnl_cfg;
380 char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
381 enum ovs_vport_type type;
382 const char *name;
383 const char *kind;
384 uint32_t flags;
385 int err;
386
387 type = netdev_to_ovs_vport_type(netdev_get_type(netdev));
c4e08753
EG
388 tnl_cfg = netdev_get_tunnel_config(netdev);
389 if (!tnl_cfg) {
acf2e6c0 390 return EOPNOTSUPP;
c4e08753
EG
391 }
392
2fd3d5ed
EG
393 kind = vport_type_to_kind(type, tnl_cfg);
394 if (!kind) {
395 return EOPNOTSUPP;
396 }
397
c4e08753
EG
398 name = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
399 flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
400
401 err = dpif_netlink_rtnl_create(tnl_cfg, name, type, kind, flags);
402
403 /* If the device exists, validate and/or attempt to recreate it. */
404 if (err == EEXIST) {
405 err = dpif_netlink_rtnl_verify(tnl_cfg, type, name);
406 if (!err) {
407 return 0;
c4e08753 408 }
9db6b04e
JS
409 err = dpif_netlink_rtnl_destroy(name);
410 if (err) {
411 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
412
413 VLOG_WARN_RL(&rl, "RTNL device %s exists and cannot be "
414 "deleted: %s", name, ovs_strerror(err));
415 return err;
416 }
417 err = dpif_netlink_rtnl_create(tnl_cfg, name, type, kind, flags);
c4e08753
EG
418 }
419 if (err) {
420 return err;
421 }
422
423 err = dpif_netlink_rtnl_verify(tnl_cfg, type, name);
424 if (err) {
425 int err2 = dpif_netlink_rtnl_destroy(name);
426
427 if (err2) {
428 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
429
430 VLOG_WARN_RL(&rl, "Failed to delete device %s during rtnl port "
431 "creation: %s", name, ovs_strerror(err2));
432 }
433 }
434
435 return err;
436}
437
438int
825e45e0 439dpif_netlink_rtnl_port_destroy(const char *name, const char *type)
c4e08753
EG
440{
441 switch (netdev_to_ovs_vport_type(type)) {
442 case OVS_VPORT_TYPE_VXLAN:
443 case OVS_VPORT_TYPE_GRE:
444 case OVS_VPORT_TYPE_GENEVE:
b6d6830d 445 return dpif_netlink_rtnl_destroy(name);
c4e08753
EG
446 case OVS_VPORT_TYPE_NETDEV:
447 case OVS_VPORT_TYPE_INTERNAL:
448 case OVS_VPORT_TYPE_LISP:
449 case OVS_VPORT_TYPE_STT:
c387d817
GR
450 case OVS_VPORT_TYPE_ERSPAN:
451 case OVS_VPORT_TYPE_IP6ERSPAN:
452 case OVS_VPORT_TYPE_IP6GRE:
c4e08753
EG
453 case OVS_VPORT_TYPE_UNSPEC:
454 case __OVS_VPORT_TYPE_MAX:
455 default:
456 return EOPNOTSUPP;
457 }
458 return 0;
459}
921c370a
EG
460
461/**
462 * Probe for whether the modules are out-of-tree (openvswitch) or in-tree
463 * (upstream kernel).
464 *
465 * We probe for "ovs_geneve" via rtnetlink. As long as this returns something
466 * other than EOPNOTSUPP we know that the module in use is the out-of-tree one.
467 * This will be used to determine which netlink interface to use when creating
468 * ports; rtnetlink or compat/genetlink.
469 *
470 * See ovs_tunnels_out_of_tree
471 */
472bool
473dpif_netlink_rtnl_probe_oot_tunnels(void)
474{
475 char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
476 struct netdev *netdev = NULL;
477 bool out_of_tree = false;
478 const char *name;
479 int error;
480
481 error = netdev_open("ovs-system-probe", "geneve", &netdev);
482 if (!error) {
c848e1cd 483 struct ofpbuf *reply;
921c370a
EG
484 const struct netdev_tunnel_config *tnl_cfg;
485
486 tnl_cfg = netdev_get_tunnel_config(netdev);
487 if (!tnl_cfg) {
488 return true;
489 }
490
491 name = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
c848e1cd
WT
492
493 /* The geneve module exists when ovs-vswitchd crashes
494 * and restarts, handle the case here.
495 */
496 error = dpif_netlink_rtnl_getlink(name, &reply);
497 if (!error) {
498
499 struct nlattr *linkinfo[ARRAY_SIZE(linkinfo_policy)];
500 struct nlattr *rtlink[ARRAY_SIZE(rtlink_policy)];
501 const char *kind;
502
503 if (!nl_policy_parse(reply,
504 NLMSG_HDRLEN + sizeof(struct ifinfomsg),
505 rtlink_policy, rtlink,
506 ARRAY_SIZE(rtlink_policy))
507 || !nl_parse_nested(rtlink[IFLA_LINKINFO], linkinfo_policy,
508 linkinfo, ARRAY_SIZE(linkinfo_policy))) {
509 VLOG_ABORT("Error fetching Geneve tunnel device %s "
510 "linkinfo", name);
511 }
512
513 kind = nl_attr_get_string(linkinfo[IFLA_INFO_KIND]);
514
515 if (!strcmp(kind, "ovs_geneve")) {
516 out_of_tree = true;
517 } else if (!strcmp(kind, "geneve")) {
518 out_of_tree = false;
519 } else {
520 VLOG_ABORT("Geneve tunnel device %s with kind %s"
521 " not supported", name, kind);
522 }
523
524 ofpbuf_delete(reply);
525 netdev_close(netdev);
526
527 return out_of_tree;
528 }
529
921c370a
EG
530 error = dpif_netlink_rtnl_create(tnl_cfg, name, OVS_VPORT_TYPE_GENEVE,
531 "ovs_geneve",
532 (NLM_F_REQUEST | NLM_F_ACK
533 | NLM_F_CREATE));
534 if (error != EOPNOTSUPP) {
535 if (!error) {
536 dpif_netlink_rtnl_destroy(name);
537 }
538 out_of_tree = true;
539 }
540 netdev_close(netdev);
541 }
542
543 return out_of_tree;
544}