]> git.proxmox.com Git - mirror_ovs.git/blame - lib/netdev-vport.c
ovs-vswitchd: Better document that ovs-vswitchd manages its own datapaths.
[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"
aca40d4f 44#include "smap.h"
777ece09 45#include "socket-util.h"
a36de779
PS
46#include "unaligned.h"
47#include "unixctl.h"
aca40d4f 48#include "openvswitch/vlog.h"
01b25786
PB
49#include "netdev-tc-offloads.h"
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 *);
2b9d6589 69
6b241d64
PS
70struct vport_class {
71 const char *dpif_port;
72 struct netdev_class netdev_class;
73};
777ece09 74
41ca1e0a
AW
75bool
76netdev_vport_is_vport_class(const struct netdev_class *class)
77{
78 return is_vport_class(class);
79}
80
2b9d6589
BP
81static const struct vport_class *
82vport_class_cast(const struct netdev_class *class)
83{
cb22974d 84 ovs_assert(is_vport_class(class));
2b9d6589
BP
85 return CONTAINER_OF(class, struct vport_class, netdev_class);
86}
87
f431bf7d 88static const struct netdev_tunnel_config *
b5d57fc8 89get_netdev_tunnel_config(const struct netdev *netdev)
f431bf7d 90{
b5d57fc8 91 return &netdev_vport_cast(netdev)->tnl_cfg;
f431bf7d
EJ
92}
93
0a740f48
EJ
94bool
95netdev_vport_is_patch(const struct netdev *netdev)
96{
b5d57fc8 97 const struct netdev_class *class = netdev_get_class(netdev);
f18a39b7 98
c060c4cf 99 return class->get_config == get_patch_config;
0a740f48
EJ
100}
101
56b11f0b 102static bool
b5d57fc8 103netdev_vport_needs_dst_port(const struct netdev *dev)
56b11f0b 104{
b5d57fc8
BP
105 const struct netdev_class *class = netdev_get_class(dev);
106 const char *type = netdev_get_type(dev);
56b11f0b 107
a6ae068b 108 return (class->get_config == get_tunnel_config &&
c1fc1411 109 (!strcmp("geneve", type) || !strcmp("vxlan", type) ||
4237026e 110 !strcmp("lisp", type) || !strcmp("stt", type)) );
56b11f0b
KM
111}
112
94a53842
AW
113const char *
114netdev_vport_class_get_dpif_port(const struct netdev_class *class)
115{
116 return is_vport_class(class) ? vport_class_cast(class)->dpif_port : NULL;
117}
118
de281153 119const char *
3aa30359
BP
120netdev_vport_get_dpif_port(const struct netdev *netdev,
121 char namebuf[], size_t bufsize)
de281153 122{
a5d4fadd
JG
123 const struct netdev_class *class = netdev_get_class(netdev);
124 const char *dpif_port = netdev_vport_class_get_dpif_port(class);
125
126 if (!dpif_port) {
127 return netdev_get_name(netdev);
128 }
129
b5d57fc8
BP
130 if (netdev_vport_needs_dst_port(netdev)) {
131 const struct netdev_vport *vport = netdev_vport_cast(netdev);
56b11f0b
KM
132
133 /*
a5d4fadd
JG
134 * Note: IFNAMSIZ is 16 bytes long. Implementations should choose
135 * a dpif port name that is short enough to fit including any
136 * port numbers but assert just in case.
56b11f0b 137 */
3aa30359 138 BUILD_ASSERT(NETDEV_VPORT_NAME_BUFSIZE >= IFNAMSIZ);
a5d4fadd
JG
139 ovs_assert(strlen(dpif_port) + 6 < IFNAMSIZ);
140 snprintf(namebuf, bufsize, "%s_%d", dpif_port,
56b11f0b 141 ntohs(vport->tnl_cfg.dst_port));
3aa30359 142 return namebuf;
56b11f0b 143 } else {
a5d4fadd 144 return dpif_port;
56b11f0b 145 }
2b9d6589 146}
777ece09 147
41ca1e0a
AW
148/* Whenever the route-table change number is incremented,
149 * netdev_vport_route_changed() should be called to update
150 * the corresponding tunnel interface status. */
151static void
152netdev_vport_route_changed(void)
153{
154 struct netdev **vports;
155 size_t i, n_vports;
156
157 vports = netdev_get_vports(&n_vports);
158 for (i = 0; i < n_vports; i++) {
159 struct netdev *netdev_ = vports[i];
160 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
161
162 ovs_mutex_lock(&netdev->mutex);
163 /* Finds all tunnel vports. */
3ae91c01 164 if (ipv6_addr_is_set(&netdev->tnl_cfg.ipv6_dst)) {
41ca1e0a
AW
165 if (tunnel_check_status_change__(netdev)) {
166 netdev_change_seq_changed(netdev_);
167 }
168 }
41ca1e0a 169 ovs_mutex_unlock(&netdev->mutex);
b2f771ef
BP
170
171 netdev_close(netdev_);
41ca1e0a
AW
172 }
173
174 free(vports);
175}
176
9dc63482
BP
177static struct netdev *
178netdev_vport_alloc(void)
179{
180 struct netdev_vport *netdev = xzalloc(sizeof *netdev);
181 return &netdev->up;
182}
183
6b241d64 184int
9dc63482 185netdev_vport_construct(struct netdev *netdev_)
2b9d6589 186{
a36de779
PS
187 struct netdev_vport *dev = netdev_vport_cast(netdev_);
188 const char *type = netdev_get_type(netdev_);
6d9e6eb4 189
a36de779 190 ovs_mutex_init(&dev->mutex);
74ff3298 191 eth_addr_random(&dev->etheraddr);
a36de779
PS
192
193 /* Add a default destination port for tunnel ports if none specified. */
194 if (!strcmp(type, "geneve")) {
195 dev->tnl_cfg.dst_port = htons(GENEVE_DST_PORT);
196 } else if (!strcmp(type, "vxlan")) {
197 dev->tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
198 } else if (!strcmp(type, "lisp")) {
199 dev->tnl_cfg.dst_port = htons(LISP_DST_PORT);
4237026e
PS
200 } else if (!strcmp(type, "stt")) {
201 dev->tnl_cfg.dst_port = htons(STT_DST_PORT);
a36de779 202 }
6d9e6eb4 203
0890056e
PS
204 dev->tnl_cfg.dont_fragment = true;
205 dev->tnl_cfg.ttl = DEFAULT_TTL;
de5cdb90 206 return 0;
777ece09
JG
207}
208
2b9d6589 209static void
9dc63482 210netdev_vport_destruct(struct netdev *netdev_)
2b9d6589 211{
b5d57fc8 212 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
2b9d6589 213
b5d57fc8 214 free(netdev->peer);
86383816 215 ovs_mutex_destroy(&netdev->mutex);
9dc63482
BP
216}
217
218static void
219netdev_vport_dealloc(struct netdev *netdev_)
220{
221 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
2b9d6589
BP
222 free(netdev);
223}
224
2b9d6589 225static int
74ff3298 226netdev_vport_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac)
777ece09 227{
b5d57fc8 228 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
86383816
BP
229
230 ovs_mutex_lock(&netdev->mutex);
74ff3298 231 netdev->etheraddr = mac;
86383816 232 ovs_mutex_unlock(&netdev->mutex);
3e912ffc 233 netdev_change_seq_changed(netdev_);
86383816 234
35b769cb 235 return 0;
777ece09
JG
236}
237
2b9d6589 238static int
74ff3298 239netdev_vport_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac)
777ece09 240{
86383816
BP
241 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
242
243 ovs_mutex_lock(&netdev->mutex);
74ff3298 244 *mac = netdev->etheraddr;
86383816
BP
245 ovs_mutex_unlock(&netdev->mutex);
246
35b769cb 247 return 0;
777ece09
JG
248}
249
41ca1e0a
AW
250/* Checks if the tunnel status has changed and returns a boolean.
251 * Updates the tunnel status if it has changed. */
252static bool
253tunnel_check_status_change__(struct netdev_vport *netdev)
254 OVS_REQUIRES(netdev->mutex)
ea763e0e 255{
3dea0874 256 char iface[IFNAMSIZ];
41ca1e0a 257 bool status = false;
3ae91c01
JB
258 struct in6_addr *route;
259 struct in6_addr gw;
ed52ca57 260 uint32_t mark;
ea763e0e 261
41ca1e0a 262 iface[0] = '\0';
3ae91c01 263 route = &netdev->tnl_cfg.ipv6_dst;
ed52ca57
PS
264 mark = netdev->tnl_cfg.egress_pkt_mark;
265 if (ovs_router_lookup(mark, route, iface, NULL, &gw)) {
a404826e
AE
266 struct netdev *egress_netdev;
267
6c607a64 268 if (!netdev_open(iface, NULL, &egress_netdev)) {
41ca1e0a 269 status = netdev_get_carrier(egress_netdev);
a404826e
AE
270 netdev_close(egress_netdev);
271 }
ea763e0e
EJ
272 }
273
41ca1e0a
AW
274 if (strcmp(netdev->egress_iface, iface)
275 || netdev->carrier_status != status) {
f9ac0f03 276 ovs_strlcpy_arrays(netdev->egress_iface, iface);
41ca1e0a
AW
277 netdev->carrier_status = status;
278
279 return true;
280 }
281
282 return false;
283}
284
285static int
286tunnel_get_status(const struct netdev *netdev_, struct smap *smap)
287{
288 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
289
290 if (netdev->egress_iface[0]) {
291 smap_add(smap, "tunnel_egress_iface", netdev->egress_iface);
292
293 smap_add(smap, "tunnel_egress_iface_carrier",
294 netdev->carrier_status ? "up" : "down");
295 }
296
ea763e0e
EJ
297 return 0;
298}
299
2b9d6589 300static int
b5d57fc8
BP
301netdev_vport_update_flags(struct netdev *netdev OVS_UNUSED,
302 enum netdev_flags off,
303 enum netdev_flags on OVS_UNUSED,
304 enum netdev_flags *old_flagsp)
777ece09
JG
305{
306 if (off & (NETDEV_UP | NETDEV_PROMISC)) {
307 return EOPNOTSUPP;
308 }
309
310 *old_flagsp = NETDEV_UP | NETDEV_PROMISC;
311 return 0;
312}
313
ea83a2fc 314static void
1c33f0c3 315netdev_vport_run(const struct netdev_class *netdev_class OVS_UNUSED)
ea83a2fc 316{
41ca1e0a
AW
317 uint64_t seq;
318
a132aa96 319 route_table_run();
41ca1e0a
AW
320 seq = route_table_get_change_seq();
321 if (rt_change_seqno != seq) {
322 rt_change_seqno = seq;
323 netdev_vport_route_changed();
324 }
ea83a2fc
EJ
325}
326
327static void
1c33f0c3 328netdev_vport_wait(const struct netdev_class *netdev_class OVS_UNUSED)
ea83a2fc 329{
41ca1e0a
AW
330 uint64_t seq;
331
a132aa96 332 route_table_wait();
41ca1e0a
AW
333 seq = route_table_get_change_seq();
334 if (rt_change_seqno != seq) {
335 poll_immediate_wake();
336 }
ea83a2fc
EJ
337}
338\f
0a740f48 339/* Code specific to tunnel types. */
2b9d6589 340
f431bf7d
EJ
341static ovs_be64
342parse_key(const struct smap *args, const char *name,
343 bool *present, bool *flow)
c19e6535
BP
344{
345 const char *s;
346
f431bf7d
EJ
347 *present = false;
348 *flow = false;
349
79f1cbe9 350 s = smap_get(args, name);
c19e6535 351 if (!s) {
79f1cbe9 352 s = smap_get(args, "key");
c19e6535 353 if (!s) {
f431bf7d 354 return 0;
c19e6535
BP
355 }
356 }
357
f431bf7d
EJ
358 *present = true;
359
c19e6535 360 if (!strcmp(s, "flow")) {
f431bf7d
EJ
361 *flow = true;
362 return 0;
c19e6535 363 } else {
f431bf7d 364 return htonll(strtoull(s, NULL, 0));
c19e6535
BP
365 }
366}
367
3ae91c01
JB
368static int
369parse_tunnel_ip(const char *value, bool accept_mcast, bool *flow,
370 struct in6_addr *ipv6, uint16_t *protocol)
371{
372 if (!strcmp(value, "flow")) {
373 *flow = true;
374 *protocol = 0;
375 return 0;
376 }
377 if (addr_is_ipv6(value)) {
378 if (lookup_ipv6(value, ipv6)) {
379 return ENOENT;
380 }
381 if (!accept_mcast && ipv6_addr_is_multicast(ipv6)) {
382 return EINVAL;
383 }
384 *protocol = ETH_TYPE_IPV6;
385 } else {
386 struct in_addr ip;
387 if (lookup_ip(value, &ip)) {
388 return ENOENT;
389 }
390 if (!accept_mcast && ip_is_multicast(ip.s_addr)) {
391 return EINVAL;
392 }
393 in6_addr_set_mapped_ipv4(ipv6, ip.s_addr);
394 *protocol = ETH_TYPE_IP;
395 }
396 return 0;
397}
398
875ab130
BP
399enum tunnel_layers {
400 TNL_L2 = 1 << 0, /* 1 if a tunnel type can carry Ethernet traffic. */
401 TNL_L3 = 1 << 1 /* 1 if a tunnel type can carry L3 traffic. */
402};
403static enum tunnel_layers
404tunnel_supported_layers(const char *type,
405 const struct netdev_tunnel_config *tnl_cfg)
406{
407 if (!strcmp(type, "lisp")) {
408 return TNL_L3;
409 } else if (!strcmp(type, "gre")) {
410 return TNL_L2 | TNL_L3;
ea4cb65c
EG
411 } else if (!strcmp(type, "vxlan")
412 && tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GPE)) {
875ab130
BP
413 return TNL_L2 | TNL_L3;
414 } else {
415 return TNL_L2;
416 }
417}
418static enum netdev_pt_mode
419default_pt_mode(enum tunnel_layers layers)
420{
421 return layers == TNL_L3 ? NETDEV_PT_LEGACY_L3 : NETDEV_PT_LEGACY_L2;
422}
423
2b9d6589 424static int
9fff138e 425set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp)
2b9d6589 426{
b5d57fc8
BP
427 struct netdev_vport *dev = netdev_vport_cast(dev_);
428 const char *name = netdev_get_name(dev_);
429 const char *type = netdev_get_type(dev_);
9fff138e 430 struct ds errors = DS_EMPTY_INITIALIZER;
875ab130 431 bool needs_dst_port, has_csum;
3ae91c01 432 uint16_t dst_proto = 0, src_proto = 0;
f431bf7d 433 struct netdev_tunnel_config tnl_cfg;
79f1cbe9 434 struct smap_node *node;
9fff138e 435 int err;
f431bf7d 436
4752cc0c 437 has_csum = strstr(type, "gre") || strstr(type, "geneve") ||
4237026e 438 strstr(type, "stt") || strstr(type, "vxlan");
f431bf7d 439 memset(&tnl_cfg, 0, sizeof tnl_cfg);
2b9d6589 440
a36de779
PS
441 /* Add a default destination port for tunnel ports if none specified. */
442 if (!strcmp(type, "geneve")) {
443 tnl_cfg.dst_port = htons(GENEVE_DST_PORT);
444 }
445
446 if (!strcmp(type, "vxlan")) {
447 tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
448 }
449
450 if (!strcmp(type, "lisp")) {
451 tnl_cfg.dst_port = htons(LISP_DST_PORT);
452 }
453
4237026e
PS
454 if (!strcmp(type, "stt")) {
455 tnl_cfg.dst_port = htons(STT_DST_PORT);
456 }
457
a6ae068b 458 needs_dst_port = netdev_vport_needs_dst_port(dev_);
f431bf7d 459 tnl_cfg.dont_fragment = true;
e16a28b5 460
79f1cbe9
EJ
461 SMAP_FOR_EACH (node, args) {
462 if (!strcmp(node->key, "remote_ip")) {
3ae91c01
JB
463 err = parse_tunnel_ip(node->value, false, &tnl_cfg.ip_dst_flow,
464 &tnl_cfg.ipv6_dst, &dst_proto);
465 switch (err) {
466 case ENOENT:
9fff138e 467 ds_put_format(&errors, "%s: bad %s 'remote_ip'\n", name, type);
3ae91c01
JB
468 break;
469 case EINVAL:
9fff138e
DDP
470 ds_put_format(&errors,
471 "%s: multicast remote_ip=%s not allowed\n",
472 name, node->value);
473 goto out;
2b9d6589 474 }
79f1cbe9 475 } else if (!strcmp(node->key, "local_ip")) {
3ae91c01
JB
476 err = parse_tunnel_ip(node->value, true, &tnl_cfg.ip_src_flow,
477 &tnl_cfg.ipv6_src, &src_proto);
478 switch (err) {
479 case ENOENT:
9fff138e 480 ds_put_format(&errors, "%s: bad %s 'local_ip'\n", name, type);
3ae91c01 481 break;
2b9d6589 482 }
79f1cbe9
EJ
483 } else if (!strcmp(node->key, "tos")) {
484 if (!strcmp(node->value, "inherit")) {
f431bf7d 485 tnl_cfg.tos_inherit = true;
2b9d6589 486 } else {
3fca7064
PS
487 char *endptr;
488 int tos;
79f1cbe9 489 tos = strtol(node->value, &endptr, 0);
91aff446 490 if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
f431bf7d 491 tnl_cfg.tos = tos;
91aff446 492 } else {
9fff138e
DDP
493 ds_put_format(&errors, "%s: invalid TOS %s\n", name,
494 node->value);
3fca7064 495 }
2b9d6589 496 }
79f1cbe9
EJ
497 } else if (!strcmp(node->key, "ttl")) {
498 if (!strcmp(node->value, "inherit")) {
f431bf7d 499 tnl_cfg.ttl_inherit = true;
2b9d6589 500 } else {
f431bf7d 501 tnl_cfg.ttl = atoi(node->value);
2b9d6589 502 }
79f827fa 503 } else if (!strcmp(node->key, "dst_port") && needs_dst_port) {
f431bf7d 504 tnl_cfg.dst_port = htons(atoi(node->value));
f431bf7d 505 } else if (!strcmp(node->key, "csum") && has_csum) {
79f1cbe9 506 if (!strcmp(node->value, "true")) {
f431bf7d 507 tnl_cfg.csum = true;
2b9d6589 508 }
79f1cbe9
EJ
509 } else if (!strcmp(node->key, "df_default")) {
510 if (!strcmp(node->value, "false")) {
f431bf7d 511 tnl_cfg.dont_fragment = false;
66409d1b 512 }
79f1cbe9
EJ
513 } else if (!strcmp(node->key, "key") ||
514 !strcmp(node->key, "in_key") ||
875ab130
BP
515 !strcmp(node->key, "out_key") ||
516 !strcmp(node->key, "packet_type")) {
c19e6535 517 /* Handled separately below. */
875ab130 518 } else if (!strcmp(node->key, "exts") && !strcmp(type, "vxlan")) {
526df7d8
TG
519 char *str = xstrdup(node->value);
520 char *ext, *save_ptr = NULL;
521
522 tnl_cfg.exts = 0;
523
524 ext = strtok_r(str, ",", &save_ptr);
525 while (ext) {
526 if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
527 tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
439f39cb
GS
528 } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) {
529 tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
526df7d8 530 } else {
9fff138e
DDP
531 ds_put_format(&errors, "%s: unknown extension '%s'\n",
532 name, ext);
526df7d8
TG
533 }
534
535 ext = strtok_r(NULL, ",", &save_ptr);
536 }
537
538 free(str);
bf4bbd0d
PS
539 } else if (!strcmp(node->key, "egress_pkt_mark")) {
540 tnl_cfg.egress_pkt_mark = strtoul(node->value, NULL, 10);
541 tnl_cfg.set_egress_pkt_mark = true;
2b9d6589 542 } else {
439f39cb
GS
543 ds_put_format(&errors, "%s: unknown %s argument '%s'\n", name,
544 type, node->key);
2b9d6589
BP
545 }
546 }
547
875ab130
BP
548 enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg);
549 const char *full_type = (strcmp(type, "vxlan") ? type
ea4cb65c
EG
550 : (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GPE)
551 ? "VXLAN-GPE" : "VXLAN (without GPE"));
875ab130
BP
552 const char *packet_type = smap_get(args, "packet_type");
553 if (!packet_type) {
554 tnl_cfg.pt_mode = default_pt_mode(layers);
555 } else if (!strcmp(packet_type, "legacy_l2")) {
556 tnl_cfg.pt_mode = NETDEV_PT_LEGACY_L2;
557 if (!(layers & TNL_L2)) {
558 ds_put_format(&errors, "%s: legacy_l2 configured on %s tunnel "
559 "that cannot carry L2 traffic\n",
560 name, full_type);
561 err = EINVAL;
562 goto out;
563 }
564 } else if (!strcmp(packet_type, "legacy_l3")) {
565 tnl_cfg.pt_mode = NETDEV_PT_LEGACY_L3;
566 if (!(layers & TNL_L3)) {
567 ds_put_format(&errors, "%s: legacy_l3 configured on %s tunnel "
568 "that cannot carry L3 traffic\n",
569 name, full_type);
570 err = EINVAL;
571 goto out;
572 }
573 } else if (!strcmp(packet_type, "ptap")) {
574 tnl_cfg.pt_mode = NETDEV_PT_AWARE;
575 } else {
576 ds_put_format(&errors, "%s: unknown packet_type '%s'\n",
577 name, packet_type);
578 err = EINVAL;
579 goto out;
439f39cb
GS
580 }
581
3ae91c01 582 if (!ipv6_addr_is_set(&tnl_cfg.ipv6_dst) && !tnl_cfg.ip_dst_flow) {
9fff138e
DDP
583 ds_put_format(&errors,
584 "%s: %s type requires valid 'remote_ip' argument\n",
585 name, type);
586 err = EINVAL;
587 goto out;
2b9d6589 588 }
0ad90c84 589 if (tnl_cfg.ip_src_flow && !tnl_cfg.ip_dst_flow) {
9fff138e
DDP
590 ds_put_format(&errors,
591 "%s: %s type requires 'remote_ip=flow' "
592 "with 'local_ip=flow'\n",
593 name, type);
594 err = EINVAL;
595 goto out;
0ad90c84 596 }
3ae91c01 597 if (src_proto && dst_proto && src_proto != dst_proto) {
9fff138e
DDP
598 ds_put_format(&errors,
599 "%s: 'remote_ip' and 'local_ip' "
600 "has to be of the same address family\n",
601 name);
602 err = EINVAL;
603 goto out;
3ae91c01 604 }
f431bf7d
EJ
605 if (!tnl_cfg.ttl) {
606 tnl_cfg.ttl = DEFAULT_TTL;
607 }
608
609 tnl_cfg.in_key = parse_key(args, "in_key",
610 &tnl_cfg.in_key_present,
611 &tnl_cfg.in_key_flow);
f431bf7d
EJ
612
613 tnl_cfg.out_key = parse_key(args, "out_key",
614 &tnl_cfg.out_key_present,
615 &tnl_cfg.out_key_flow);
2b9d6589 616
86383816 617 ovs_mutex_lock(&dev->mutex);
a1908399
AW
618 if (memcmp(&dev->tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) {
619 dev->tnl_cfg = tnl_cfg;
620 tunnel_check_status_change__(dev);
621 netdev_change_seq_changed(dev_);
622 }
86383816 623 ovs_mutex_unlock(&dev->mutex);
f431bf7d 624
9fff138e
DDP
625 err = 0;
626
627out:
c296d3f8
DDP
628 if (errors.length) {
629 ds_chomp(&errors, '\n');
630 VLOG_WARN("%s", ds_cstr(&errors));
631 if (err) {
632 *errp = ds_steal_cstr(&errors);
633 }
9fff138e
DDP
634 }
635
636 ds_destroy(&errors);
637
638 return err;
c19e6535
BP
639}
640
2b9d6589 641static int
b5d57fc8 642get_tunnel_config(const struct netdev *dev, struct smap *args)
6d9e6eb4 643{
86383816 644 struct netdev_vport *netdev = netdev_vport_cast(dev);
63171f04 645 const char *type = netdev_get_type(dev);
86383816
BP
646 struct netdev_tunnel_config tnl_cfg;
647
648 ovs_mutex_lock(&netdev->mutex);
649 tnl_cfg = netdev->tnl_cfg;
650 ovs_mutex_unlock(&netdev->mutex);
6d9e6eb4 651
3ae91c01
JB
652 if (ipv6_addr_is_set(&tnl_cfg.ipv6_dst)) {
653 smap_add_ipv6(args, "remote_ip", &tnl_cfg.ipv6_dst);
86383816 654 } else if (tnl_cfg.ip_dst_flow) {
0ad90c84 655 smap_add(args, "remote_ip", "flow");
0a740f48
EJ
656 }
657
3ae91c01
JB
658 if (ipv6_addr_is_set(&tnl_cfg.ipv6_src)) {
659 smap_add_ipv6(args, "local_ip", &tnl_cfg.ipv6_src);
86383816 660 } else if (tnl_cfg.ip_src_flow) {
0ad90c84 661 smap_add(args, "local_ip", "flow");
7f804ea5 662 }
c19e6535 663
86383816 664 if (tnl_cfg.in_key_flow && tnl_cfg.out_key_flow) {
6d9e6eb4 665 smap_add(args, "key", "flow");
86383816
BP
666 } else if (tnl_cfg.in_key_present && tnl_cfg.out_key_present
667 && tnl_cfg.in_key == tnl_cfg.out_key) {
668 smap_add_format(args, "key", "%"PRIu64, ntohll(tnl_cfg.in_key));
6d9e6eb4 669 } else {
86383816 670 if (tnl_cfg.in_key_flow) {
b9ad7294 671 smap_add(args, "in_key", "flow");
86383816 672 } else if (tnl_cfg.in_key_present) {
b9ad7294 673 smap_add_format(args, "in_key", "%"PRIu64,
86383816 674 ntohll(tnl_cfg.in_key));
b9ad7294 675 }
6d9e6eb4 676
86383816 677 if (tnl_cfg.out_key_flow) {
b9ad7294 678 smap_add(args, "out_key", "flow");
86383816 679 } else if (tnl_cfg.out_key_present) {
b9ad7294 680 smap_add_format(args, "out_key", "%"PRIu64,
86383816 681 ntohll(tnl_cfg.out_key));
6d9e6eb4
BP
682 }
683 }
684
86383816 685 if (tnl_cfg.ttl_inherit) {
62827e6a 686 smap_add(args, "ttl", "inherit");
86383816
BP
687 } else if (tnl_cfg.ttl != DEFAULT_TTL) {
688 smap_add_format(args, "ttl", "%"PRIu8, tnl_cfg.ttl);
c19e6535
BP
689 }
690
86383816 691 if (tnl_cfg.tos_inherit) {
6d9e6eb4 692 smap_add(args, "tos", "inherit");
86383816
BP
693 } else if (tnl_cfg.tos) {
694 smap_add_format(args, "tos", "0x%x", tnl_cfg.tos);
6d9e6eb4
BP
695 }
696
86383816
BP
697 if (tnl_cfg.dst_port) {
698 uint16_t dst_port = ntohs(tnl_cfg.dst_port);
9eeb949b 699
c1fc1411
JG
700 if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) ||
701 (!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
4237026e
PS
702 (!strcmp("lisp", type) && dst_port != LISP_DST_PORT) ||
703 (!strcmp("stt", type) && dst_port != STT_DST_PORT)) {
79f827fa
KM
704 smap_add_format(args, "dst_port", "%d", dst_port);
705 }
706 }
707
86383816 708 if (tnl_cfg.csum) {
6d9e6eb4
BP
709 smap_add(args, "csum", "true");
710 }
8a9ff93a 711
875ab130
BP
712 enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg);
713 if (tnl_cfg.pt_mode != default_pt_mode(layers)) {
714 smap_add(args, "packet_type",
715 tnl_cfg.pt_mode == NETDEV_PT_LEGACY_L2 ? "legacy_l2"
716 : tnl_cfg.pt_mode == NETDEV_PT_LEGACY_L3 ? "legacy_l3"
717 : "ptap");
63171f04
JS
718 }
719
86383816 720 if (!tnl_cfg.dont_fragment) {
66409d1b
AE
721 smap_add(args, "df_default", "false");
722 }
6d9e6eb4 723
bf4bbd0d
PS
724 if (tnl_cfg.set_egress_pkt_mark) {
725 smap_add_format(args, "egress_pkt_mark",
726 "%"PRIu32, tnl_cfg.egress_pkt_mark);
727 }
6d9e6eb4
BP
728 return 0;
729}
0a740f48
EJ
730\f
731/* Code specific to patch ports. */
732
161b6042
BP
733/* If 'netdev' is a patch port, returns the name of its peer as a malloc()'d
734 * string that the caller must free.
735 *
736 * If 'netdev' is not a patch port, returns NULL. */
737char *
738netdev_vport_patch_peer(const struct netdev *netdev_)
0a740f48 739{
161b6042
BP
740 char *peer = NULL;
741
742 if (netdev_vport_is_patch(netdev_)) {
743 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
86383816
BP
744
745 ovs_mutex_lock(&netdev->mutex);
161b6042
BP
746 if (netdev->peer) {
747 peer = xstrdup(netdev->peer);
748 }
86383816 749 ovs_mutex_unlock(&netdev->mutex);
161b6042
BP
750 }
751
752 return peer;
0a740f48
EJ
753}
754
755void
b9ad7294 756netdev_vport_inc_rx(const struct netdev *netdev,
9e04d6f6 757 const struct dpif_flow_stats *stats)
0a740f48 758{
b5d57fc8
BP
759 if (is_vport_class(netdev_get_class(netdev))) {
760 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
761
762 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
763 dev->stats.rx_packets += stats->n_packets;
764 dev->stats.rx_bytes += stats->n_bytes;
86383816 765 ovs_mutex_unlock(&dev->mutex);
0a740f48
EJ
766 }
767}
768
769void
b9ad7294
EJ
770netdev_vport_inc_tx(const struct netdev *netdev,
771 const struct dpif_flow_stats *stats)
0a740f48 772{
b5d57fc8
BP
773 if (is_vport_class(netdev_get_class(netdev))) {
774 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
775
776 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
777 dev->stats.tx_packets += stats->n_packets;
778 dev->stats.tx_bytes += stats->n_bytes;
86383816 779 ovs_mutex_unlock(&dev->mutex);
0a740f48
EJ
780 }
781}
782
783static int
b5d57fc8 784get_patch_config(const struct netdev *dev_, struct smap *args)
0a740f48 785{
b5d57fc8 786 struct netdev_vport *dev = netdev_vport_cast(dev_);
0a740f48 787
86383816 788 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
789 if (dev->peer) {
790 smap_add(args, "peer", dev->peer);
791 }
86383816
BP
792 ovs_mutex_unlock(&dev->mutex);
793
0a740f48
EJ
794 return 0;
795}
6d9e6eb4
BP
796
797static int
9fff138e 798set_patch_config(struct netdev *dev_, const struct smap *args, char **errp)
2b9d6589 799{
b5d57fc8
BP
800 struct netdev_vport *dev = netdev_vport_cast(dev_);
801 const char *name = netdev_get_name(dev_);
2b9d6589
BP
802 const char *peer;
803
79f1cbe9 804 peer = smap_get(args, "peer");
2b9d6589 805 if (!peer) {
9fff138e
DDP
806 VLOG_ERR_BUF(errp, "%s: patch type requires valid 'peer' argument",
807 name);
2b9d6589
BP
808 return EINVAL;
809 }
810
79f1cbe9 811 if (smap_count(args) > 1) {
9fff138e
DDP
812 VLOG_ERR_BUF(errp, "%s: patch type takes only a 'peer' argument",
813 name);
2b9d6589
BP
814 return EINVAL;
815 }
816
2b9d6589 817 if (!strcmp(name, peer)) {
9fff138e 818 VLOG_ERR_BUF(errp, "%s: patch peer must not be self", name);
2b9d6589
BP
819 return EINVAL;
820 }
821
86383816 822 ovs_mutex_lock(&dev->mutex);
a1908399
AW
823 if (!dev->peer || strcmp(dev->peer, peer)) {
824 free(dev->peer);
825 dev->peer = xstrdup(peer);
826 netdev_change_seq_changed(dev_);
827 }
86383816
BP
828 ovs_mutex_unlock(&dev->mutex);
829
2b9d6589
BP
830 return 0;
831}
6d9e6eb4
BP
832
833static int
b9ad7294 834get_stats(const struct netdev *netdev, struct netdev_stats *stats)
0a740f48 835{
b5d57fc8 836 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
837
838 ovs_mutex_lock(&dev->mutex);
d6e3feb5 839 /* Passing only collected counters */
840 stats->tx_packets = dev->stats.tx_packets;
841 stats->tx_bytes = dev->stats.tx_bytes;
842 stats->rx_packets = dev->stats.rx_packets;
843 stats->rx_bytes = dev->stats.rx_bytes;
86383816
BP
844 ovs_mutex_unlock(&dev->mutex);
845
6d9e6eb4
BP
846 return 0;
847}
a36de779 848
875ab130
BP
849static enum netdev_pt_mode
850get_pt_mode(const struct netdev *netdev)
851{
852 struct netdev_vport *dev = netdev_vport_cast(netdev);
853
854 return dev->tnl_cfg.pt_mode;
855}
856
857
2b9d6589 858\f
01b25786
PB
859#ifdef __linux__
860static int
5e530e26 861netdev_vport_get_ifindex(const struct netdev *netdev_)
01b25786
PB
862{
863 char buf[NETDEV_VPORT_NAME_BUFSIZE];
864 const char *name = netdev_vport_get_dpif_port(netdev_, buf, sizeof(buf));
865
866 return linux_get_ifindex(name);
867}
868
01b25786
PB
869#define NETDEV_VPORT_GET_IFINDEX netdev_vport_get_ifindex
870#define NETDEV_FLOW_OFFLOAD_API LINUX_FLOW_OFFLOAD_API
871#else /* !__linux__ */
872#define NETDEV_VPORT_GET_IFINDEX NULL
873#define NETDEV_FLOW_OFFLOAD_API NO_OFFLOAD_API
874#endif /* __linux__ */
875
0a740f48 876#define VPORT_FUNCTIONS(GET_CONFIG, SET_CONFIG, \
a36de779
PS
877 GET_TUNNEL_CONFIG, GET_STATUS, \
878 BUILD_HEADER, \
01b25786
PB
879 PUSH_HEADER, POP_HEADER, \
880 GET_IFINDEX) \
b46ccdf5 881 NULL, \
ea83a2fc
EJ
882 netdev_vport_run, \
883 netdev_vport_wait, \
2b9d6589 884 \
9dc63482
BP
885 netdev_vport_alloc, \
886 netdev_vport_construct, \
887 netdev_vport_destruct, \
888 netdev_vport_dealloc, \
0a740f48
EJ
889 GET_CONFIG, \
890 SET_CONFIG, \
f431bf7d 891 GET_TUNNEL_CONFIG, \
a36de779
PS
892 BUILD_HEADER, \
893 PUSH_HEADER, \
894 POP_HEADER, \
7dec44fe 895 NULL, /* get_numa_id */ \
050c60bf 896 NULL, /* set_tx_multiq */ \
2b9d6589 897 \
552e20d0 898 NULL, /* send */ \
2b9d6589
BP
899 NULL, /* send_wait */ \
900 \
901 netdev_vport_set_etheraddr, \
902 netdev_vport_get_etheraddr, \
14622f22
BP
903 NULL, /* get_mtu */ \
904 NULL, /* set_mtu */ \
01b25786 905 GET_IFINDEX, \
85da620e 906 NULL, /* get_carrier */ \
65c3058c 907 NULL, /* get_carrier_resets */ \
63331829 908 NULL, /* get_miimon */ \
b9ad7294 909 get_stats, \
971f4b39 910 NULL, /* get_custom_stats */ \
2b9d6589
BP
911 \
912 NULL, /* get_features */ \
913 NULL, /* set_advertisements */ \
875ab130 914 get_pt_mode, \
2b9d6589
BP
915 \
916 NULL, /* set_policing */ \
917 NULL, /* get_qos_types */ \
918 NULL, /* get_qos_capabilities */ \
919 NULL, /* get_qos */ \
920 NULL, /* set_qos */ \
921 NULL, /* get_queue */ \
922 NULL, /* set_queue */ \
923 NULL, /* delete_queue */ \
924 NULL, /* get_queue_stats */ \
89454bf4
BP
925 NULL, /* queue_dump_start */ \
926 NULL, /* queue_dump_next */ \
927 NULL, /* queue_dump_done */ \
2b9d6589
BP
928 NULL, /* dump_queue_stats */ \
929 \
2b9d6589 930 NULL, /* set_in4 */ \
a8704b50 931 NULL, /* get_addr_list */ \
2b9d6589
BP
932 NULL, /* add_router */ \
933 NULL, /* get_next_hop */ \
ea763e0e 934 GET_STATUS, \
2b9d6589
BP
935 NULL, /* arp_lookup */ \
936 \
937 netdev_vport_update_flags, \
790fb3b7 938 NULL, /* reconfigure */ \
2b9d6589 939 \
9dc63482
BP
940 NULL, /* rx_alloc */ \
941 NULL, /* rx_construct */ \
942 NULL, /* rx_destruct */ \
943 NULL, /* rx_dealloc */ \
944 NULL, /* rx_recv */ \
945 NULL, /* rx_wait */ \
18ebd48c
PB
946 NULL, /* rx_drain */ \
947 \
01b25786 948 NETDEV_FLOW_OFFLOAD_API
2b9d6589 949
a36de779 950
01b25786
PB
951#define TUNNEL_CLASS(NAME, DPIF_PORT, BUILD_HEADER, PUSH_HEADER, POP_HEADER, \
952 GET_IFINDEX) \
a36de779 953 { DPIF_PORT, \
118c77b1
IM
954 { NAME, false, \
955 VPORT_FUNCTIONS(get_tunnel_config, \
956 set_tunnel_config, \
957 get_netdev_tunnel_config, \
958 tunnel_get_status, \
01b25786
PB
959 BUILD_HEADER, PUSH_HEADER, POP_HEADER, \
960 GET_IFINDEX) }}
db078f85 961
2b9d6589 962void
c060c4cf 963netdev_vport_tunnel_register(void)
2b9d6589 964{
a5d4fadd
JG
965 /* The name of the dpif_port should be short enough to accomodate adding
966 * a port number to the end if one is necessary. */
c3827f61 967 static const struct vport_class vport_classes[] = {
e5a1caee 968 TUNNEL_CLASS("geneve", "genev_sys", netdev_geneve_build_header,
6b241d64 969 netdev_tnl_push_udp_header,
01b25786 970 netdev_geneve_pop_header,
2eb0e01d 971 NETDEV_VPORT_GET_IFINDEX),
a36de779
PS
972 TUNNEL_CLASS("gre", "gre_sys", netdev_gre_build_header,
973 netdev_gre_push_header,
01b25786
PB
974 netdev_gre_pop_header,
975 NULL),
a36de779 976 TUNNEL_CLASS("vxlan", "vxlan_sys", netdev_vxlan_build_header,
6b241d64 977 netdev_tnl_push_udp_header,
01b25786
PB
978 netdev_vxlan_pop_header,
979 NETDEV_VPORT_GET_IFINDEX),
980 TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL, NULL),
981 TUNNEL_CLASS("stt", "stt_sys", NULL, NULL, NULL, NULL),
c3827f61 982 };
86383816 983 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
c3827f61 984
86383816
BP
985 if (ovsthread_once_start(&once)) {
986 int i;
c3827f61 987
7c54c27f
BP
988 for (i = 0; i < ARRAY_SIZE(vport_classes); i++) {
989 netdev_register_provider(&vport_classes[i].netdev_class);
990 }
a36de779
PS
991
992 unixctl_command_register("tnl/egress_port_range", "min max", 0, 2,
6b241d64 993 netdev_tnl_egress_port_range, NULL);
a36de779 994
86383816 995 ovsthread_once_done(&once);
c3827f61 996 }
2b9d6589 997}
c060c4cf
EJ
998
999void
1000netdev_vport_patch_register(void)
1001{
1002 static const struct vport_class patch_class =
1003 { NULL,
118c77b1
IM
1004 { "patch", false,
1005 VPORT_FUNCTIONS(get_patch_config,
1006 set_patch_config,
1007 NULL,
01b25786 1008 NULL, NULL, NULL, NULL, NULL) }};
c060c4cf
EJ
1009 netdev_register_provider(&patch_class.netdev_class);
1010}