]> git.proxmox.com Git - mirror_ovs.git/blame - lib/netdev-vport.c
ovn-performance.at: Fix syntax error in ACL.
[mirror_ovs.git] / lib / netdev-vport.c
CommitLineData
777ece09 1/*
f9ac0f03 2 * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2017 Nicira, Inc.
68da36fe 3 * Copyright (c) 2016 Red Hat, Inc.
777ece09
JG
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
6fcfff1b 11 * Unless required by applicable law or agreed to in writing, software
777ece09
JG
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <config.h>
2b9d6589
BP
19
20#include "netdev-vport.h"
21
777ece09
JG
22#include <errno.h>
23#include <fcntl.h>
ea83a2fc 24#include <sys/socket.h>
2b9d6589 25#include <net/if.h>
b2befd5b 26#include <sys/types.h>
2456f331 27#include <netinet/in.h>
370e373b 28#include <netinet/ip6.h>
777ece09
JG
29#include <sys/ioctl.h>
30
b9298d3f 31#include "byte-order.h"
5059eff3
JP
32#include "daemon.h"
33#include "dirs.h"
0a740f48 34#include "dpif.h"
aca40d4f
TLSC
35#include "netdev.h"
36#include "netdev-native-tnl.h"
2b9d6589 37#include "netdev-provider.h"
6b241d64 38#include "netdev-vport-private.h"
9fff138e 39#include "openvswitch/dynamic-string.h"
d9b4ebc5 40#include "ovs-router.h"
2b9d6589 41#include "packets.h"
fd016ae3 42#include "openvswitch/poll-loop.h"
a132aa96 43#include "route-table.h"
189de33f 44#include "simap.h"
aca40d4f 45#include "smap.h"
777ece09 46#include "socket-util.h"
a36de779
PS
47#include "unaligned.h"
48#include "unixctl.h"
aca40d4f 49#include "openvswitch/vlog.h"
01b25786
PB
50#ifdef __linux__
51#include "netdev-linux.h"
52#endif
777ece09 53
d98e6007 54VLOG_DEFINE_THIS_MODULE(netdev_vport);
5136ce49 55
c1fc1411 56#define GENEVE_DST_PORT 6081
4f2abb7b 57#define VXLAN_DST_PORT 4789
a6ae068b 58#define LISP_DST_PORT 4341
4237026e 59#define STT_DST_PORT 7471
a6ae068b 60
f431bf7d
EJ
61#define DEFAULT_TTL 64
62
41ca1e0a
AW
63/* Last read of the route-table's change number. */
64static uint64_t rt_change_seqno;
65
86383816 66static int get_patch_config(const struct netdev *netdev, struct smap *args);
b5d57fc8 67static int get_tunnel_config(const struct netdev *, struct smap *args);
41ca1e0a 68static bool tunnel_check_status_change__(struct netdev_vport *);
189de33f
EC
69static void update_vxlan_global_cfg(struct netdev *,
70 struct netdev_tunnel_config *,
71 struct netdev_tunnel_config *);
2b9d6589 72
6b241d64
PS
73struct vport_class {
74 const char *dpif_port;
75 struct netdev_class netdev_class;
189de33f 76 struct simap global_cfg_tracker;
6b241d64 77};
777ece09 78
41ca1e0a
AW
79bool
80netdev_vport_is_vport_class(const struct netdev_class *class)
81{
82 return is_vport_class(class);
83}
84
189de33f 85static struct vport_class *
2b9d6589
BP
86vport_class_cast(const struct netdev_class *class)
87{
cb22974d 88 ovs_assert(is_vport_class(class));
2b9d6589
BP
89 return CONTAINER_OF(class, struct vport_class, netdev_class);
90}
91
f431bf7d 92static const struct netdev_tunnel_config *
b5d57fc8 93get_netdev_tunnel_config(const struct netdev *netdev)
f431bf7d 94{
b5d57fc8 95 return &netdev_vport_cast(netdev)->tnl_cfg;
f431bf7d
EJ
96}
97
0a740f48
EJ
98bool
99netdev_vport_is_patch(const struct netdev *netdev)
100{
b5d57fc8 101 const struct netdev_class *class = netdev_get_class(netdev);
f18a39b7 102
c060c4cf 103 return class->get_config == get_patch_config;
0a740f48
EJ
104}
105
56b11f0b 106static bool
b5d57fc8 107netdev_vport_needs_dst_port(const struct netdev *dev)
56b11f0b 108{
b5d57fc8
BP
109 const struct netdev_class *class = netdev_get_class(dev);
110 const char *type = netdev_get_type(dev);
56b11f0b 111
a6ae068b 112 return (class->get_config == get_tunnel_config &&
c1fc1411 113 (!strcmp("geneve", type) || !strcmp("vxlan", type) ||
4237026e 114 !strcmp("lisp", type) || !strcmp("stt", type)) );
56b11f0b
KM
115}
116
94a53842
AW
117const char *
118netdev_vport_class_get_dpif_port(const struct netdev_class *class)
119{
120 return is_vport_class(class) ? vport_class_cast(class)->dpif_port : NULL;
121}
122
de281153 123const char *
3aa30359
BP
124netdev_vport_get_dpif_port(const struct netdev *netdev,
125 char namebuf[], size_t bufsize)
de281153 126{
a5d4fadd
JG
127 const struct netdev_class *class = netdev_get_class(netdev);
128 const char *dpif_port = netdev_vport_class_get_dpif_port(class);
129
130 if (!dpif_port) {
131 return netdev_get_name(netdev);
132 }
133
b5d57fc8
BP
134 if (netdev_vport_needs_dst_port(netdev)) {
135 const struct netdev_vport *vport = netdev_vport_cast(netdev);
56b11f0b
KM
136
137 /*
a5d4fadd
JG
138 * Note: IFNAMSIZ is 16 bytes long. Implementations should choose
139 * a dpif port name that is short enough to fit including any
140 * port numbers but assert just in case.
56b11f0b 141 */
3aa30359 142 BUILD_ASSERT(NETDEV_VPORT_NAME_BUFSIZE >= IFNAMSIZ);
a5d4fadd
JG
143 ovs_assert(strlen(dpif_port) + 6 < IFNAMSIZ);
144 snprintf(namebuf, bufsize, "%s_%d", dpif_port,
56b11f0b 145 ntohs(vport->tnl_cfg.dst_port));
3aa30359 146 return namebuf;
56b11f0b 147 } else {
a5d4fadd 148 return dpif_port;
56b11f0b 149 }
2b9d6589 150}
777ece09 151
41ca1e0a
AW
152/* Whenever the route-table change number is incremented,
153 * netdev_vport_route_changed() should be called to update
154 * the corresponding tunnel interface status. */
155static void
156netdev_vport_route_changed(void)
157{
158 struct netdev **vports;
159 size_t i, n_vports;
160
161 vports = netdev_get_vports(&n_vports);
162 for (i = 0; i < n_vports; i++) {
163 struct netdev *netdev_ = vports[i];
164 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
165
166 ovs_mutex_lock(&netdev->mutex);
167 /* Finds all tunnel vports. */
3ae91c01 168 if (ipv6_addr_is_set(&netdev->tnl_cfg.ipv6_dst)) {
41ca1e0a
AW
169 if (tunnel_check_status_change__(netdev)) {
170 netdev_change_seq_changed(netdev_);
171 }
172 }
41ca1e0a 173 ovs_mutex_unlock(&netdev->mutex);
b2f771ef
BP
174
175 netdev_close(netdev_);
41ca1e0a
AW
176 }
177
178 free(vports);
179}
180
9dc63482
BP
181static struct netdev *
182netdev_vport_alloc(void)
183{
184 struct netdev_vport *netdev = xzalloc(sizeof *netdev);
185 return &netdev->up;
186}
187
6b241d64 188int
9dc63482 189netdev_vport_construct(struct netdev *netdev_)
2b9d6589 190{
69987881
CM
191 const struct netdev_class *class = netdev_get_class(netdev_);
192 const char *dpif_port = netdev_vport_class_get_dpif_port(class);
a36de779 193 struct netdev_vport *dev = netdev_vport_cast(netdev_);
69987881 194 const char *p, *name = netdev_get_name(netdev_);
a36de779 195 const char *type = netdev_get_type(netdev_);
69987881 196 uint16_t port = 0;
6d9e6eb4 197
a36de779 198 ovs_mutex_init(&dev->mutex);
74ff3298 199 eth_addr_random(&dev->etheraddr);
a36de779 200
69987881
CM
201 if (name && dpif_port && (strlen(name) > strlen(dpif_port) + 1) &&
202 (!strncmp(name, dpif_port, strlen(dpif_port)))) {
203 p = name + strlen(dpif_port) + 1;
204 port = atoi(p);
205 }
206
207 /* If a destination port for tunnel ports is specified in the netdev
208 * name, use it instead of the default one. Otherwise, use the default
209 * destination port */
a36de779 210 if (!strcmp(type, "geneve")) {
69987881 211 dev->tnl_cfg.dst_port = port ? htons(port) : htons(GENEVE_DST_PORT);
a36de779 212 } else if (!strcmp(type, "vxlan")) {
69987881 213 dev->tnl_cfg.dst_port = port ? htons(port) : htons(VXLAN_DST_PORT);
189de33f 214 update_vxlan_global_cfg(netdev_, NULL, &dev->tnl_cfg);
a36de779 215 } else if (!strcmp(type, "lisp")) {
69987881 216 dev->tnl_cfg.dst_port = port ? htons(port) : htons(LISP_DST_PORT);
4237026e 217 } else if (!strcmp(type, "stt")) {
69987881 218 dev->tnl_cfg.dst_port = port ? htons(port) : htons(STT_DST_PORT);
a36de779 219 }
6d9e6eb4 220
0890056e
PS
221 dev->tnl_cfg.dont_fragment = true;
222 dev->tnl_cfg.ttl = DEFAULT_TTL;
de5cdb90 223 return 0;
777ece09
JG
224}
225
2b9d6589 226static void
9dc63482 227netdev_vport_destruct(struct netdev *netdev_)
2b9d6589 228{
b5d57fc8 229 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
189de33f
EC
230 const char *type = netdev_get_type(netdev_);
231
232 if (!strcmp(type, "vxlan")) {
233 update_vxlan_global_cfg(netdev_, &netdev->tnl_cfg, NULL);
234 }
2b9d6589 235
b5d57fc8 236 free(netdev->peer);
86383816 237 ovs_mutex_destroy(&netdev->mutex);
9dc63482
BP
238}
239
240static void
241netdev_vport_dealloc(struct netdev *netdev_)
242{
243 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
2b9d6589
BP
244 free(netdev);
245}
246
2b9d6589 247static int
74ff3298 248netdev_vport_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac)
777ece09 249{
b5d57fc8 250 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
86383816
BP
251
252 ovs_mutex_lock(&netdev->mutex);
74ff3298 253 netdev->etheraddr = mac;
86383816 254 ovs_mutex_unlock(&netdev->mutex);
3e912ffc 255 netdev_change_seq_changed(netdev_);
86383816 256
35b769cb 257 return 0;
777ece09
JG
258}
259
2b9d6589 260static int
74ff3298 261netdev_vport_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac)
777ece09 262{
86383816
BP
263 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
264
265 ovs_mutex_lock(&netdev->mutex);
74ff3298 266 *mac = netdev->etheraddr;
86383816
BP
267 ovs_mutex_unlock(&netdev->mutex);
268
35b769cb 269 return 0;
777ece09
JG
270}
271
41ca1e0a
AW
272/* Checks if the tunnel status has changed and returns a boolean.
273 * Updates the tunnel status if it has changed. */
274static bool
275tunnel_check_status_change__(struct netdev_vport *netdev)
276 OVS_REQUIRES(netdev->mutex)
ea763e0e 277{
3dea0874 278 char iface[IFNAMSIZ];
41ca1e0a 279 bool status = false;
3ae91c01
JB
280 struct in6_addr *route;
281 struct in6_addr gw;
ed52ca57 282 uint32_t mark;
ea763e0e 283
41ca1e0a 284 iface[0] = '\0';
3ae91c01 285 route = &netdev->tnl_cfg.ipv6_dst;
ed52ca57
PS
286 mark = netdev->tnl_cfg.egress_pkt_mark;
287 if (ovs_router_lookup(mark, route, iface, NULL, &gw)) {
a404826e
AE
288 struct netdev *egress_netdev;
289
6c607a64 290 if (!netdev_open(iface, NULL, &egress_netdev)) {
41ca1e0a 291 status = netdev_get_carrier(egress_netdev);
a404826e
AE
292 netdev_close(egress_netdev);
293 }
ea763e0e
EJ
294 }
295
41ca1e0a
AW
296 if (strcmp(netdev->egress_iface, iface)
297 || netdev->carrier_status != status) {
f9ac0f03 298 ovs_strlcpy_arrays(netdev->egress_iface, iface);
41ca1e0a
AW
299 netdev->carrier_status = status;
300
301 return true;
302 }
303
304 return false;
305}
306
307static int
308tunnel_get_status(const struct netdev *netdev_, struct smap *smap)
309{
310 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
311
312 if (netdev->egress_iface[0]) {
313 smap_add(smap, "tunnel_egress_iface", netdev->egress_iface);
314
315 smap_add(smap, "tunnel_egress_iface_carrier",
316 netdev->carrier_status ? "up" : "down");
317 }
318
ea763e0e
EJ
319 return 0;
320}
321
2b9d6589 322static int
b5d57fc8
BP
323netdev_vport_update_flags(struct netdev *netdev OVS_UNUSED,
324 enum netdev_flags off,
325 enum netdev_flags on OVS_UNUSED,
326 enum netdev_flags *old_flagsp)
777ece09
JG
327{
328 if (off & (NETDEV_UP | NETDEV_PROMISC)) {
329 return EOPNOTSUPP;
330 }
331
332 *old_flagsp = NETDEV_UP | NETDEV_PROMISC;
333 return 0;
334}
335
ea83a2fc 336static void
1c33f0c3 337netdev_vport_run(const struct netdev_class *netdev_class OVS_UNUSED)
ea83a2fc 338{
41ca1e0a
AW
339 uint64_t seq;
340
a132aa96 341 route_table_run();
41ca1e0a
AW
342 seq = route_table_get_change_seq();
343 if (rt_change_seqno != seq) {
344 rt_change_seqno = seq;
345 netdev_vport_route_changed();
346 }
ea83a2fc
EJ
347}
348
349static void
1c33f0c3 350netdev_vport_wait(const struct netdev_class *netdev_class OVS_UNUSED)
ea83a2fc 351{
41ca1e0a
AW
352 uint64_t seq;
353
a132aa96 354 route_table_wait();
41ca1e0a
AW
355 seq = route_table_get_change_seq();
356 if (rt_change_seqno != seq) {
357 poll_immediate_wake();
358 }
ea83a2fc
EJ
359}
360\f
0a740f48 361/* Code specific to tunnel types. */
2b9d6589 362
f431bf7d
EJ
363static ovs_be64
364parse_key(const struct smap *args, const char *name,
365 bool *present, bool *flow)
c19e6535
BP
366{
367 const char *s;
368
f431bf7d
EJ
369 *present = false;
370 *flow = false;
371
79f1cbe9 372 s = smap_get(args, name);
c19e6535 373 if (!s) {
79f1cbe9 374 s = smap_get(args, "key");
c19e6535 375 if (!s) {
f431bf7d 376 return 0;
c19e6535
BP
377 }
378 }
379
f431bf7d
EJ
380 *present = true;
381
c19e6535 382 if (!strcmp(s, "flow")) {
f431bf7d
EJ
383 *flow = true;
384 return 0;
c19e6535 385 } else {
f431bf7d 386 return htonll(strtoull(s, NULL, 0));
c19e6535
BP
387 }
388}
389
3ae91c01
JB
390static int
391parse_tunnel_ip(const char *value, bool accept_mcast, bool *flow,
392 struct in6_addr *ipv6, uint16_t *protocol)
393{
394 if (!strcmp(value, "flow")) {
395 *flow = true;
396 *protocol = 0;
397 return 0;
398 }
399 if (addr_is_ipv6(value)) {
400 if (lookup_ipv6(value, ipv6)) {
401 return ENOENT;
402 }
403 if (!accept_mcast && ipv6_addr_is_multicast(ipv6)) {
404 return EINVAL;
405 }
406 *protocol = ETH_TYPE_IPV6;
407 } else {
408 struct in_addr ip;
409 if (lookup_ip(value, &ip)) {
410 return ENOENT;
411 }
412 if (!accept_mcast && ip_is_multicast(ip.s_addr)) {
413 return EINVAL;
414 }
415 in6_addr_set_mapped_ipv4(ipv6, ip.s_addr);
416 *protocol = ETH_TYPE_IP;
417 }
418 return 0;
419}
420
875ab130
BP
421enum tunnel_layers {
422 TNL_L2 = 1 << 0, /* 1 if a tunnel type can carry Ethernet traffic. */
423 TNL_L3 = 1 << 1 /* 1 if a tunnel type can carry L3 traffic. */
424};
425static enum tunnel_layers
426tunnel_supported_layers(const char *type,
427 const struct netdev_tunnel_config *tnl_cfg)
428{
429 if (!strcmp(type, "lisp")) {
430 return TNL_L3;
431 } else if (!strcmp(type, "gre")) {
432 return TNL_L2 | TNL_L3;
ea4cb65c
EG
433 } else if (!strcmp(type, "vxlan")
434 && tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GPE)) {
875ab130
BP
435 return TNL_L2 | TNL_L3;
436 } else {
437 return TNL_L2;
438 }
439}
440static enum netdev_pt_mode
441default_pt_mode(enum tunnel_layers layers)
442{
443 return layers == TNL_L3 ? NETDEV_PT_LEGACY_L3 : NETDEV_PT_LEGACY_L2;
444}
445
189de33f
EC
446static char *
447vxlan_get_port_ext_gbp_str(uint16_t port, bool gbp,
448 char namebuf[], size_t bufsize)
449{
450 snprintf(namebuf, bufsize, "dst_port_%d%s",
451 port, gbp ? "_gbp" : "");
452
453 return namebuf;
454}
455
456static void
457update_vxlan_global_cfg(struct netdev *netdev,
458 struct netdev_tunnel_config *old_cfg,
459 struct netdev_tunnel_config *new_cfg)
460{
461 unsigned int count;
462 char namebuf[20];
463 const char *type = netdev_get_type(netdev);
464 struct vport_class *vclass = vport_class_cast(netdev_get_class(netdev));
465
466 if (strcmp(type, "vxlan") ||
467 (old_cfg != NULL && new_cfg != NULL &&
468 old_cfg->dst_port == new_cfg->dst_port &&
469 old_cfg->exts == new_cfg->exts)) {
470 return;
471 }
472
473 if (old_cfg != NULL) {
474 vxlan_get_port_ext_gbp_str(ntohs(old_cfg->dst_port),
475 old_cfg->exts &
476 (1 << OVS_VXLAN_EXT_GBP),
477 namebuf, sizeof(namebuf));
478
479 count = simap_get(&vclass->global_cfg_tracker, namebuf);
480 if (count != 0) {
481 if (--count) {
482 simap_put(&vclass->global_cfg_tracker, namebuf, count);
483 } else {
484 simap_find_and_delete(&vclass->global_cfg_tracker, namebuf);
485 }
486 }
487 }
488
489 if (new_cfg != NULL) {
490 vxlan_get_port_ext_gbp_str(ntohs(new_cfg->dst_port),
491 new_cfg->exts &
492 (1 << OVS_VXLAN_EXT_GBP),
493 namebuf, sizeof(namebuf));
494
495 simap_increase(&vclass->global_cfg_tracker, namebuf, 1);
496 }
497}
498
499static bool
500is_concomitant_vxlan_tunnel_present(struct netdev_vport *dev,
501 const struct netdev_tunnel_config *tnl_cfg)
502{
503 char namebuf[20];
504 const char *type = netdev_get_type(&dev->up);
505 struct vport_class *vclass = vport_class_cast(netdev_get_class(&dev->up));
506
507 if (strcmp(type, "vxlan")) {
508 return false;
509 }
510
511 if (dev->tnl_cfg.dst_port == tnl_cfg->dst_port &&
512 (dev->tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GBP)) ==
513 (tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GBP))) {
514
515 if (ntohs(dev->tnl_cfg.dst_port) == VXLAN_DST_PORT) {
516 /* Special case where we kept the default port/gbp, only ok if
517 the opposite of the default does not exits */
518 vxlan_get_port_ext_gbp_str(ntohs(tnl_cfg->dst_port),
519 !(tnl_cfg->exts &
520 (1 << OVS_VXLAN_EXT_GBP)),
521 namebuf, sizeof(namebuf));
522
523 if (simap_get(&vclass->global_cfg_tracker, namebuf) > 0) {
524 return true;
525 }
526 }
527 return false;
528 }
529
530 /* Same port: ok if no one is left with the previous configuration */
531 if (dev->tnl_cfg.dst_port == tnl_cfg->dst_port) {
532 vxlan_get_port_ext_gbp_str(ntohs(dev->tnl_cfg.dst_port),
533 dev->tnl_cfg.exts &
534 (1 << OVS_VXLAN_EXT_GBP),
535 namebuf, sizeof(namebuf));
536
537 if (simap_get(&vclass->global_cfg_tracker, namebuf) > 1) {
538 return true;
539 }
540
541 return false;
542 }
543
544 /* Different port: ok if the opposite gbp option does not yet exists */
545 vxlan_get_port_ext_gbp_str(ntohs(tnl_cfg->dst_port),
546 !(tnl_cfg->exts &
547 (1 << OVS_VXLAN_EXT_GBP)),
548 namebuf, sizeof(namebuf));
549
550 if (simap_get(&vclass->global_cfg_tracker, namebuf) > 0) {
551 return true;
552 }
553
554 return false;
555}
556
2b9d6589 557static int
9fff138e 558set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp)
2b9d6589 559{
b5d57fc8
BP
560 struct netdev_vport *dev = netdev_vport_cast(dev_);
561 const char *name = netdev_get_name(dev_);
562 const char *type = netdev_get_type(dev_);
9fff138e 563 struct ds errors = DS_EMPTY_INITIALIZER;
0ffff497 564 bool needs_dst_port, has_csum, has_seq;
3ae91c01 565 uint16_t dst_proto = 0, src_proto = 0;
f431bf7d 566 struct netdev_tunnel_config tnl_cfg;
79f1cbe9 567 struct smap_node *node;
9fff138e 568 int err;
f431bf7d 569
4752cc0c 570 has_csum = strstr(type, "gre") || strstr(type, "geneve") ||
4237026e 571 strstr(type, "stt") || strstr(type, "vxlan");
0ffff497 572 has_seq = strstr(type, "gre");
f431bf7d 573 memset(&tnl_cfg, 0, sizeof tnl_cfg);
2b9d6589 574
a36de779
PS
575 /* Add a default destination port for tunnel ports if none specified. */
576 if (!strcmp(type, "geneve")) {
577 tnl_cfg.dst_port = htons(GENEVE_DST_PORT);
578 }
579
580 if (!strcmp(type, "vxlan")) {
581 tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
582 }
583
584 if (!strcmp(type, "lisp")) {
585 tnl_cfg.dst_port = htons(LISP_DST_PORT);
586 }
587
4237026e
PS
588 if (!strcmp(type, "stt")) {
589 tnl_cfg.dst_port = htons(STT_DST_PORT);
590 }
591
a6ae068b 592 needs_dst_port = netdev_vport_needs_dst_port(dev_);
f431bf7d 593 tnl_cfg.dont_fragment = true;
e16a28b5 594
79f1cbe9
EJ
595 SMAP_FOR_EACH (node, args) {
596 if (!strcmp(node->key, "remote_ip")) {
3ae91c01
JB
597 err = parse_tunnel_ip(node->value, false, &tnl_cfg.ip_dst_flow,
598 &tnl_cfg.ipv6_dst, &dst_proto);
599 switch (err) {
600 case ENOENT:
9fff138e 601 ds_put_format(&errors, "%s: bad %s 'remote_ip'\n", name, type);
3ae91c01
JB
602 break;
603 case EINVAL:
9fff138e
DDP
604 ds_put_format(&errors,
605 "%s: multicast remote_ip=%s not allowed\n",
606 name, node->value);
607 goto out;
2b9d6589 608 }
79f1cbe9 609 } else if (!strcmp(node->key, "local_ip")) {
3ae91c01
JB
610 err = parse_tunnel_ip(node->value, true, &tnl_cfg.ip_src_flow,
611 &tnl_cfg.ipv6_src, &src_proto);
612 switch (err) {
613 case ENOENT:
9fff138e 614 ds_put_format(&errors, "%s: bad %s 'local_ip'\n", name, type);
3ae91c01 615 break;
2b9d6589 616 }
79f1cbe9
EJ
617 } else if (!strcmp(node->key, "tos")) {
618 if (!strcmp(node->value, "inherit")) {
f431bf7d 619 tnl_cfg.tos_inherit = true;
2b9d6589 620 } else {
3fca7064
PS
621 char *endptr;
622 int tos;
79f1cbe9 623 tos = strtol(node->value, &endptr, 0);
91aff446 624 if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
f431bf7d 625 tnl_cfg.tos = tos;
91aff446 626 } else {
9fff138e
DDP
627 ds_put_format(&errors, "%s: invalid TOS %s\n", name,
628 node->value);
3fca7064 629 }
2b9d6589 630 }
79f1cbe9
EJ
631 } else if (!strcmp(node->key, "ttl")) {
632 if (!strcmp(node->value, "inherit")) {
f431bf7d 633 tnl_cfg.ttl_inherit = true;
2b9d6589 634 } else {
f431bf7d 635 tnl_cfg.ttl = atoi(node->value);
2b9d6589 636 }
79f827fa 637 } else if (!strcmp(node->key, "dst_port") && needs_dst_port) {
f431bf7d 638 tnl_cfg.dst_port = htons(atoi(node->value));
f431bf7d 639 } else if (!strcmp(node->key, "csum") && has_csum) {
79f1cbe9 640 if (!strcmp(node->value, "true")) {
f431bf7d 641 tnl_cfg.csum = true;
2b9d6589 642 }
0ffff497
WT
643 } else if (!strcmp(node->key, "seq") && has_seq) {
644 if (!strcmp(node->value, "true")) {
645 tnl_cfg.set_seq = true;
646 }
79f1cbe9
EJ
647 } else if (!strcmp(node->key, "df_default")) {
648 if (!strcmp(node->value, "false")) {
f431bf7d 649 tnl_cfg.dont_fragment = false;
66409d1b 650 }
79f1cbe9
EJ
651 } else if (!strcmp(node->key, "key") ||
652 !strcmp(node->key, "in_key") ||
875ab130
BP
653 !strcmp(node->key, "out_key") ||
654 !strcmp(node->key, "packet_type")) {
c19e6535 655 /* Handled separately below. */
875ab130 656 } else if (!strcmp(node->key, "exts") && !strcmp(type, "vxlan")) {
526df7d8
TG
657 char *str = xstrdup(node->value);
658 char *ext, *save_ptr = NULL;
659
660 tnl_cfg.exts = 0;
661
662 ext = strtok_r(str, ",", &save_ptr);
663 while (ext) {
664 if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
665 tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
439f39cb
GS
666 } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) {
667 tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
526df7d8 668 } else {
9fff138e
DDP
669 ds_put_format(&errors, "%s: unknown extension '%s'\n",
670 name, ext);
526df7d8
TG
671 }
672
673 ext = strtok_r(NULL, ",", &save_ptr);
674 }
675
676 free(str);
bf4bbd0d
PS
677 } else if (!strcmp(node->key, "egress_pkt_mark")) {
678 tnl_cfg.egress_pkt_mark = strtoul(node->value, NULL, 10);
679 tnl_cfg.set_egress_pkt_mark = true;
7dc18ae9 680 } else if (!strcmp(node->key, "erspan_idx")) {
068794b4
GR
681 if (!strcmp(node->value, "flow")) {
682 tnl_cfg.erspan_idx_flow = true;
683 } else {
684 tnl_cfg.erspan_idx_flow = false;
685 tnl_cfg.erspan_idx = strtol(node->value, NULL, 16);
686
687 if (tnl_cfg.erspan_idx & ~ERSPAN_IDX_MASK) {
688 ds_put_format(&errors, "%s: invalid erspan index: %s\n",
689 name, node->value);
690 err = EINVAL;
691 goto out;
692 }
7dc18ae9
WT
693 }
694 } else if (!strcmp(node->key, "erspan_ver")) {
068794b4
GR
695 if (!strcmp(node->value, "flow")) {
696 tnl_cfg.erspan_ver_flow = true;
697 tnl_cfg.erspan_idx_flow = true;
698 tnl_cfg.erspan_dir_flow = true;
699 tnl_cfg.erspan_hwid_flow = true;
700 } else {
701 tnl_cfg.erspan_ver_flow = false;
702 tnl_cfg.erspan_ver = atoi(node->value);
703
704 if (tnl_cfg.erspan_ver != 1 && tnl_cfg.erspan_ver != 2) {
705 ds_put_format(&errors, "%s: invalid erspan version: %s\n",
706 name, node->value);
707 err = EINVAL;
708 goto out;
709 }
7dc18ae9
WT
710 }
711 } else if (!strcmp(node->key, "erspan_dir")) {
068794b4
GR
712 if (!strcmp(node->value, "flow")) {
713 tnl_cfg.erspan_dir_flow = true;
714 } else {
715 tnl_cfg.erspan_dir_flow = false;
716 tnl_cfg.erspan_dir = atoi(node->value);
717
718 if (tnl_cfg.erspan_dir != 0 && tnl_cfg.erspan_dir != 1) {
719 ds_put_format(&errors, "%s: invalid erspan direction: %s\n",
720 name, node->value);
721 err = EINVAL;
722 goto out;
723 }
7dc18ae9
WT
724 }
725 } else if (!strcmp(node->key, "erspan_hwid")) {
068794b4
GR
726 if (!strcmp(node->value, "flow")) {
727 tnl_cfg.erspan_hwid_flow = true;
728 } else {
729 tnl_cfg.erspan_hwid_flow = false;
730 tnl_cfg.erspan_hwid = strtol(node->value, NULL, 16);
731
732 if (tnl_cfg.erspan_hwid & ~(ERSPAN_HWID_MASK >> 4)) {
733 ds_put_format(&errors, "%s: invalid erspan hardware ID: %s\n",
734 name, node->value);
735 err = EINVAL;
736 goto out;
737 }
7dc18ae9 738 }
2b9d6589 739 } else {
439f39cb
GS
740 ds_put_format(&errors, "%s: unknown %s argument '%s'\n", name,
741 type, node->key);
2b9d6589
BP
742 }
743 }
744
875ab130
BP
745 enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg);
746 const char *full_type = (strcmp(type, "vxlan") ? type
ea4cb65c
EG
747 : (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GPE)
748 ? "VXLAN-GPE" : "VXLAN (without GPE"));
875ab130
BP
749 const char *packet_type = smap_get(args, "packet_type");
750 if (!packet_type) {
751 tnl_cfg.pt_mode = default_pt_mode(layers);
752 } else if (!strcmp(packet_type, "legacy_l2")) {
753 tnl_cfg.pt_mode = NETDEV_PT_LEGACY_L2;
754 if (!(layers & TNL_L2)) {
755 ds_put_format(&errors, "%s: legacy_l2 configured on %s tunnel "
756 "that cannot carry L2 traffic\n",
757 name, full_type);
758 err = EINVAL;
759 goto out;
760 }
761 } else if (!strcmp(packet_type, "legacy_l3")) {
762 tnl_cfg.pt_mode = NETDEV_PT_LEGACY_L3;
763 if (!(layers & TNL_L3)) {
764 ds_put_format(&errors, "%s: legacy_l3 configured on %s tunnel "
765 "that cannot carry L3 traffic\n",
766 name, full_type);
767 err = EINVAL;
768 goto out;
769 }
770 } else if (!strcmp(packet_type, "ptap")) {
771 tnl_cfg.pt_mode = NETDEV_PT_AWARE;
772 } else {
773 ds_put_format(&errors, "%s: unknown packet_type '%s'\n",
774 name, packet_type);
775 err = EINVAL;
776 goto out;
439f39cb
GS
777 }
778
3ae91c01 779 if (!ipv6_addr_is_set(&tnl_cfg.ipv6_dst) && !tnl_cfg.ip_dst_flow) {
9fff138e
DDP
780 ds_put_format(&errors,
781 "%s: %s type requires valid 'remote_ip' argument\n",
782 name, type);
783 err = EINVAL;
784 goto out;
2b9d6589 785 }
0ad90c84 786 if (tnl_cfg.ip_src_flow && !tnl_cfg.ip_dst_flow) {
9fff138e
DDP
787 ds_put_format(&errors,
788 "%s: %s type requires 'remote_ip=flow' "
789 "with 'local_ip=flow'\n",
790 name, type);
791 err = EINVAL;
792 goto out;
0ad90c84 793 }
3ae91c01 794 if (src_proto && dst_proto && src_proto != dst_proto) {
9fff138e
DDP
795 ds_put_format(&errors,
796 "%s: 'remote_ip' and 'local_ip' "
797 "has to be of the same address family\n",
798 name);
799 err = EINVAL;
800 goto out;
3ae91c01 801 }
f431bf7d
EJ
802 if (!tnl_cfg.ttl) {
803 tnl_cfg.ttl = DEFAULT_TTL;
804 }
805
806 tnl_cfg.in_key = parse_key(args, "in_key",
807 &tnl_cfg.in_key_present,
808 &tnl_cfg.in_key_flow);
f431bf7d
EJ
809
810 tnl_cfg.out_key = parse_key(args, "out_key",
811 &tnl_cfg.out_key_present,
812 &tnl_cfg.out_key_flow);
2b9d6589 813
189de33f
EC
814 if (is_concomitant_vxlan_tunnel_present(dev, &tnl_cfg)) {
815 ds_put_format(&errors, "%s: VXLAN-GBP, and non-VXLAN-GBP "
816 "tunnels can't be configured on the same "
817 "dst_port\n",
818 name);
819 err = EEXIST;
820 goto out;
821 }
822 update_vxlan_global_cfg(dev_, &dev->tnl_cfg, &tnl_cfg);
823
86383816 824 ovs_mutex_lock(&dev->mutex);
a1908399
AW
825 if (memcmp(&dev->tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) {
826 dev->tnl_cfg = tnl_cfg;
827 tunnel_check_status_change__(dev);
828 netdev_change_seq_changed(dev_);
829 }
86383816 830 ovs_mutex_unlock(&dev->mutex);
f431bf7d 831
9fff138e
DDP
832 err = 0;
833
834out:
c296d3f8
DDP
835 if (errors.length) {
836 ds_chomp(&errors, '\n');
837 VLOG_WARN("%s", ds_cstr(&errors));
838 if (err) {
839 *errp = ds_steal_cstr(&errors);
840 }
9fff138e
DDP
841 }
842
843 ds_destroy(&errors);
844
845 return err;
c19e6535
BP
846}
847
2b9d6589 848static int
b5d57fc8 849get_tunnel_config(const struct netdev *dev, struct smap *args)
6d9e6eb4 850{
86383816 851 struct netdev_vport *netdev = netdev_vport_cast(dev);
63171f04 852 const char *type = netdev_get_type(dev);
86383816
BP
853 struct netdev_tunnel_config tnl_cfg;
854
855 ovs_mutex_lock(&netdev->mutex);
856 tnl_cfg = netdev->tnl_cfg;
857 ovs_mutex_unlock(&netdev->mutex);
6d9e6eb4 858
3ae91c01
JB
859 if (ipv6_addr_is_set(&tnl_cfg.ipv6_dst)) {
860 smap_add_ipv6(args, "remote_ip", &tnl_cfg.ipv6_dst);
86383816 861 } else if (tnl_cfg.ip_dst_flow) {
0ad90c84 862 smap_add(args, "remote_ip", "flow");
0a740f48
EJ
863 }
864
3ae91c01
JB
865 if (ipv6_addr_is_set(&tnl_cfg.ipv6_src)) {
866 smap_add_ipv6(args, "local_ip", &tnl_cfg.ipv6_src);
86383816 867 } else if (tnl_cfg.ip_src_flow) {
0ad90c84 868 smap_add(args, "local_ip", "flow");
7f804ea5 869 }
c19e6535 870
86383816 871 if (tnl_cfg.in_key_flow && tnl_cfg.out_key_flow) {
6d9e6eb4 872 smap_add(args, "key", "flow");
86383816
BP
873 } else if (tnl_cfg.in_key_present && tnl_cfg.out_key_present
874 && tnl_cfg.in_key == tnl_cfg.out_key) {
875 smap_add_format(args, "key", "%"PRIu64, ntohll(tnl_cfg.in_key));
6d9e6eb4 876 } else {
86383816 877 if (tnl_cfg.in_key_flow) {
b9ad7294 878 smap_add(args, "in_key", "flow");
86383816 879 } else if (tnl_cfg.in_key_present) {
b9ad7294 880 smap_add_format(args, "in_key", "%"PRIu64,
86383816 881 ntohll(tnl_cfg.in_key));
b9ad7294 882 }
6d9e6eb4 883
86383816 884 if (tnl_cfg.out_key_flow) {
b9ad7294 885 smap_add(args, "out_key", "flow");
86383816 886 } else if (tnl_cfg.out_key_present) {
b9ad7294 887 smap_add_format(args, "out_key", "%"PRIu64,
86383816 888 ntohll(tnl_cfg.out_key));
6d9e6eb4
BP
889 }
890 }
891
86383816 892 if (tnl_cfg.ttl_inherit) {
62827e6a 893 smap_add(args, "ttl", "inherit");
86383816
BP
894 } else if (tnl_cfg.ttl != DEFAULT_TTL) {
895 smap_add_format(args, "ttl", "%"PRIu8, tnl_cfg.ttl);
c19e6535
BP
896 }
897
86383816 898 if (tnl_cfg.tos_inherit) {
6d9e6eb4 899 smap_add(args, "tos", "inherit");
86383816
BP
900 } else if (tnl_cfg.tos) {
901 smap_add_format(args, "tos", "0x%x", tnl_cfg.tos);
6d9e6eb4
BP
902 }
903
86383816
BP
904 if (tnl_cfg.dst_port) {
905 uint16_t dst_port = ntohs(tnl_cfg.dst_port);
9eeb949b 906
c1fc1411
JG
907 if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) ||
908 (!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
4237026e
PS
909 (!strcmp("lisp", type) && dst_port != LISP_DST_PORT) ||
910 (!strcmp("stt", type) && dst_port != STT_DST_PORT)) {
79f827fa
KM
911 smap_add_format(args, "dst_port", "%d", dst_port);
912 }
913 }
914
86383816 915 if (tnl_cfg.csum) {
6d9e6eb4
BP
916 smap_add(args, "csum", "true");
917 }
8a9ff93a 918
0ffff497
WT
919 if (tnl_cfg.set_seq) {
920 smap_add(args, "seq", "true");
921 }
922
875ab130
BP
923 enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg);
924 if (tnl_cfg.pt_mode != default_pt_mode(layers)) {
925 smap_add(args, "packet_type",
926 tnl_cfg.pt_mode == NETDEV_PT_LEGACY_L2 ? "legacy_l2"
927 : tnl_cfg.pt_mode == NETDEV_PT_LEGACY_L3 ? "legacy_l3"
928 : "ptap");
63171f04
JS
929 }
930
86383816 931 if (!tnl_cfg.dont_fragment) {
66409d1b
AE
932 smap_add(args, "df_default", "false");
933 }
6d9e6eb4 934
bf4bbd0d
PS
935 if (tnl_cfg.set_egress_pkt_mark) {
936 smap_add_format(args, "egress_pkt_mark",
937 "%"PRIu32, tnl_cfg.egress_pkt_mark);
938 }
7dc18ae9 939
068794b4
GR
940 if (!strcmp("erspan", type) || !strcmp("ip6erspan", type)) {
941 if (tnl_cfg.erspan_ver_flow) {
942 /* since version number is not determined,
943 * assume print all other as flow
944 */
945 smap_add(args, "erspan_ver", "flow");
946 smap_add(args, "erspan_idx", "flow");
947 smap_add(args, "erspan_dir", "flow");
948 smap_add(args, "erspan_hwid", "flow");
949 } else {
950 smap_add_format(args, "erspan_ver", "%d", tnl_cfg.erspan_ver);
951
952 if (tnl_cfg.erspan_ver == 1) {
953 if (tnl_cfg.erspan_idx_flow) {
954 smap_add(args, "erspan_idx", "flow");
955 } else {
956 smap_add_format(args, "erspan_idx", "0x%x",
957 tnl_cfg.erspan_idx);
958 }
959 } else if (tnl_cfg.erspan_ver == 2) {
960 if (tnl_cfg.erspan_dir_flow) {
961 smap_add(args, "erspan_dir", "flow");
962 } else {
963 smap_add_format(args, "erspan_dir", "%d",
964 tnl_cfg.erspan_dir);
965 }
966 if (tnl_cfg.erspan_hwid_flow) {
967 smap_add(args, "erspan_hwid", "flow");
968 } else {
969 smap_add_format(args, "erspan_hwid", "0x%x",
970 tnl_cfg.erspan_hwid);
971 }
972 }
973 }
7dc18ae9
WT
974 }
975
6d9e6eb4
BP
976 return 0;
977}
0a740f48
EJ
978\f
979/* Code specific to patch ports. */
980
161b6042
BP
981/* If 'netdev' is a patch port, returns the name of its peer as a malloc()'d
982 * string that the caller must free.
983 *
984 * If 'netdev' is not a patch port, returns NULL. */
985char *
986netdev_vport_patch_peer(const struct netdev *netdev_)
0a740f48 987{
161b6042
BP
988 char *peer = NULL;
989
990 if (netdev_vport_is_patch(netdev_)) {
991 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
86383816
BP
992
993 ovs_mutex_lock(&netdev->mutex);
161b6042
BP
994 if (netdev->peer) {
995 peer = xstrdup(netdev->peer);
996 }
86383816 997 ovs_mutex_unlock(&netdev->mutex);
161b6042
BP
998 }
999
1000 return peer;
0a740f48
EJ
1001}
1002
1003void
b9ad7294 1004netdev_vport_inc_rx(const struct netdev *netdev,
9e04d6f6 1005 const struct dpif_flow_stats *stats)
0a740f48 1006{
b5d57fc8
BP
1007 if (is_vport_class(netdev_get_class(netdev))) {
1008 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
1009
1010 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
1011 dev->stats.rx_packets += stats->n_packets;
1012 dev->stats.rx_bytes += stats->n_bytes;
86383816 1013 ovs_mutex_unlock(&dev->mutex);
0a740f48
EJ
1014 }
1015}
1016
1017void
b9ad7294
EJ
1018netdev_vport_inc_tx(const struct netdev *netdev,
1019 const struct dpif_flow_stats *stats)
0a740f48 1020{
b5d57fc8
BP
1021 if (is_vport_class(netdev_get_class(netdev))) {
1022 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
1023
1024 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
1025 dev->stats.tx_packets += stats->n_packets;
1026 dev->stats.tx_bytes += stats->n_bytes;
86383816 1027 ovs_mutex_unlock(&dev->mutex);
0a740f48
EJ
1028 }
1029}
1030
1031static int
b5d57fc8 1032get_patch_config(const struct netdev *dev_, struct smap *args)
0a740f48 1033{
b5d57fc8 1034 struct netdev_vport *dev = netdev_vport_cast(dev_);
0a740f48 1035
86383816 1036 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
1037 if (dev->peer) {
1038 smap_add(args, "peer", dev->peer);
1039 }
86383816
BP
1040 ovs_mutex_unlock(&dev->mutex);
1041
0a740f48
EJ
1042 return 0;
1043}
6d9e6eb4
BP
1044
1045static int
9fff138e 1046set_patch_config(struct netdev *dev_, const struct smap *args, char **errp)
2b9d6589 1047{
b5d57fc8
BP
1048 struct netdev_vport *dev = netdev_vport_cast(dev_);
1049 const char *name = netdev_get_name(dev_);
2b9d6589
BP
1050 const char *peer;
1051
79f1cbe9 1052 peer = smap_get(args, "peer");
2b9d6589 1053 if (!peer) {
9fff138e
DDP
1054 VLOG_ERR_BUF(errp, "%s: patch type requires valid 'peer' argument",
1055 name);
2b9d6589
BP
1056 return EINVAL;
1057 }
1058
79f1cbe9 1059 if (smap_count(args) > 1) {
9fff138e
DDP
1060 VLOG_ERR_BUF(errp, "%s: patch type takes only a 'peer' argument",
1061 name);
2b9d6589
BP
1062 return EINVAL;
1063 }
1064
2b9d6589 1065 if (!strcmp(name, peer)) {
9fff138e 1066 VLOG_ERR_BUF(errp, "%s: patch peer must not be self", name);
2b9d6589
BP
1067 return EINVAL;
1068 }
1069
86383816 1070 ovs_mutex_lock(&dev->mutex);
a1908399
AW
1071 if (!dev->peer || strcmp(dev->peer, peer)) {
1072 free(dev->peer);
1073 dev->peer = xstrdup(peer);
1074 netdev_change_seq_changed(dev_);
1075 }
86383816
BP
1076 ovs_mutex_unlock(&dev->mutex);
1077
2b9d6589
BP
1078 return 0;
1079}
6d9e6eb4
BP
1080
1081static int
89c09c1c 1082netdev_vport_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
0a740f48 1083{
b5d57fc8 1084 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
1085
1086 ovs_mutex_lock(&dev->mutex);
d6e3feb5 1087 /* Passing only collected counters */
1088 stats->tx_packets = dev->stats.tx_packets;
1089 stats->tx_bytes = dev->stats.tx_bytes;
1090 stats->rx_packets = dev->stats.rx_packets;
1091 stats->rx_bytes = dev->stats.rx_bytes;
86383816
BP
1092 ovs_mutex_unlock(&dev->mutex);
1093
6d9e6eb4
BP
1094 return 0;
1095}
a36de779 1096
875ab130 1097static enum netdev_pt_mode
89c09c1c 1098netdev_vport_get_pt_mode(const struct netdev *netdev)
875ab130
BP
1099{
1100 struct netdev_vport *dev = netdev_vport_cast(netdev);
1101
1102 return dev->tnl_cfg.pt_mode;
1103}
1104
1105
2b9d6589 1106\f
01b25786
PB
1107#ifdef __linux__
1108static int
5e530e26 1109netdev_vport_get_ifindex(const struct netdev *netdev_)
01b25786
PB
1110{
1111 char buf[NETDEV_VPORT_NAME_BUFSIZE];
1112 const char *name = netdev_vport_get_dpif_port(netdev_, buf, sizeof(buf));
1113
1114 return linux_get_ifindex(name);
1115}
1116
01b25786 1117#define NETDEV_VPORT_GET_IFINDEX netdev_vport_get_ifindex
01b25786
PB
1118#else /* !__linux__ */
1119#define NETDEV_VPORT_GET_IFINDEX NULL
01b25786
PB
1120#endif /* __linux__ */
1121
89c09c1c
BP
1122#define VPORT_FUNCTIONS_COMMON \
1123 .run = netdev_vport_run, \
1124 .wait = netdev_vport_wait, \
1125 .alloc = netdev_vport_alloc, \
1126 .construct = netdev_vport_construct, \
1127 .destruct = netdev_vport_destruct, \
1128 .dealloc = netdev_vport_dealloc, \
1129 .set_etheraddr = netdev_vport_set_etheraddr, \
1130 .get_etheraddr = netdev_vport_get_etheraddr, \
1131 .get_stats = netdev_vport_get_stats, \
1132 .get_pt_mode = netdev_vport_get_pt_mode, \
5fc5c50f 1133 .update_flags = netdev_vport_update_flags
89c09c1c
BP
1134
1135#define TUNNEL_FUNCTIONS_COMMON \
1136 VPORT_FUNCTIONS_COMMON, \
1137 .get_config = get_tunnel_config, \
1138 .set_config = set_tunnel_config, \
1139 .get_tunnel_config = get_netdev_tunnel_config, \
1140 .get_status = tunnel_get_status
db078f85 1141
2b9d6589 1142void
c060c4cf 1143netdev_vport_tunnel_register(void)
2b9d6589 1144{
a5d4fadd
JG
1145 /* The name of the dpif_port should be short enough to accomodate adding
1146 * a port number to the end if one is necessary. */
189de33f 1147 static struct vport_class vport_classes[] = {
89c09c1c
BP
1148 { "genev_sys",
1149 {
1150 TUNNEL_FUNCTIONS_COMMON,
1151 .type = "geneve",
1152 .build_header = netdev_geneve_build_header,
1153 .push_header = netdev_tnl_push_udp_header,
1154 .pop_header = netdev_geneve_pop_header,
1155 .get_ifindex = NETDEV_VPORT_GET_IFINDEX,
189de33f
EC
1156 },
1157 {{NULL, NULL, 0, 0}}
89c09c1c
BP
1158 },
1159 { "gre_sys",
1160 {
1161 TUNNEL_FUNCTIONS_COMMON,
1162 .type = "gre",
1163 .build_header = netdev_gre_build_header,
1164 .push_header = netdev_gre_push_header,
5e63eaa9
EB
1165 .pop_header = netdev_gre_pop_header,
1166 .get_ifindex = NETDEV_VPORT_GET_IFINDEX,
189de33f
EC
1167 },
1168 {{NULL, NULL, 0, 0}}
89c09c1c
BP
1169 },
1170 { "vxlan_sys",
1171 {
1172 TUNNEL_FUNCTIONS_COMMON,
1173 .type = "vxlan",
1174 .build_header = netdev_vxlan_build_header,
1175 .push_header = netdev_tnl_push_udp_header,
1176 .pop_header = netdev_vxlan_pop_header,
1177 .get_ifindex = NETDEV_VPORT_GET_IFINDEX
189de33f
EC
1178 },
1179 {{NULL, NULL, 0, 0}}
89c09c1c
BP
1180 },
1181 { "lisp_sys",
1182 {
1183 TUNNEL_FUNCTIONS_COMMON,
1184 .type = "lisp"
189de33f
EC
1185 },
1186 {{NULL, NULL, 0, 0}}
89c09c1c
BP
1187 },
1188 { "stt_sys",
1189 {
1190 TUNNEL_FUNCTIONS_COMMON,
1191 .type = "stt"
189de33f
EC
1192 },
1193 {{NULL, NULL, 0, 0}}
89c09c1c
BP
1194 },
1195 { "erspan_sys",
1196 {
1197 TUNNEL_FUNCTIONS_COMMON,
1198 .type = "erspan",
1199 .build_header = netdev_erspan_build_header,
1200 .push_header = netdev_erspan_push_header,
1201 .pop_header = netdev_erspan_pop_header
189de33f
EC
1202 },
1203 {{NULL, NULL, 0, 0}}
89c09c1c
BP
1204 },
1205 { "ip6erspan_sys",
1206 {
1207 TUNNEL_FUNCTIONS_COMMON,
1208 .type = "ip6erspan",
1209 .build_header = netdev_erspan_build_header,
1210 .push_header = netdev_erspan_push_header,
1211 .pop_header = netdev_erspan_pop_header
189de33f
EC
1212 },
1213 {{NULL, NULL, 0, 0}}
89c09c1c
BP
1214 },
1215 { "ip6gre_sys",
1216 {
1217 TUNNEL_FUNCTIONS_COMMON,
1218 .type = "ip6gre",
1219 .build_header = netdev_gre_build_header,
1220 .push_header = netdev_gre_push_header,
1221 .pop_header = netdev_gre_pop_header
189de33f
EC
1222 },
1223 {{NULL, NULL, 0, 0}}
89c09c1c 1224 },
c3827f61 1225 };
86383816 1226 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
c3827f61 1227
86383816
BP
1228 if (ovsthread_once_start(&once)) {
1229 int i;
c3827f61 1230
7c54c27f 1231 for (i = 0; i < ARRAY_SIZE(vport_classes); i++) {
189de33f 1232 simap_init(&vport_classes[i].global_cfg_tracker);
7c54c27f
BP
1233 netdev_register_provider(&vport_classes[i].netdev_class);
1234 }
a36de779
PS
1235
1236 unixctl_command_register("tnl/egress_port_range", "min max", 0, 2,
6b241d64 1237 netdev_tnl_egress_port_range, NULL);
a36de779 1238
86383816 1239 ovsthread_once_done(&once);
c3827f61 1240 }
2b9d6589 1241}
c060c4cf
EJ
1242
1243void
1244netdev_vport_patch_register(void)
1245{
189de33f 1246 static struct vport_class patch_class = {
89c09c1c
BP
1247 NULL,
1248 { VPORT_FUNCTIONS_COMMON,
1249 .type = "patch",
1250 .get_config = get_patch_config,
1251 .set_config = set_patch_config,
189de33f
EC
1252 },
1253 {{NULL, NULL, 0, 0}}
89c09c1c 1254 };
189de33f 1255 simap_init(&patch_class.global_cfg_tracker);
c060c4cf
EJ
1256 netdev_register_provider(&patch_class.netdev_class);
1257}