]> git.proxmox.com Git - mirror_ovs.git/blame - lib/netdev-vport.c
netdev: Clean up class initialization.
[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;
0ffff497 431 bool needs_dst_port, has_csum, has_seq;
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");
0ffff497 439 has_seq = strstr(type, "gre");
f431bf7d 440 memset(&tnl_cfg, 0, sizeof tnl_cfg);
2b9d6589 441
a36de779
PS
442 /* Add a default destination port for tunnel ports if none specified. */
443 if (!strcmp(type, "geneve")) {
444 tnl_cfg.dst_port = htons(GENEVE_DST_PORT);
445 }
446
447 if (!strcmp(type, "vxlan")) {
448 tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
449 }
450
451 if (!strcmp(type, "lisp")) {
452 tnl_cfg.dst_port = htons(LISP_DST_PORT);
453 }
454
4237026e
PS
455 if (!strcmp(type, "stt")) {
456 tnl_cfg.dst_port = htons(STT_DST_PORT);
457 }
458
a6ae068b 459 needs_dst_port = netdev_vport_needs_dst_port(dev_);
f431bf7d 460 tnl_cfg.dont_fragment = true;
e16a28b5 461
79f1cbe9
EJ
462 SMAP_FOR_EACH (node, args) {
463 if (!strcmp(node->key, "remote_ip")) {
3ae91c01
JB
464 err = parse_tunnel_ip(node->value, false, &tnl_cfg.ip_dst_flow,
465 &tnl_cfg.ipv6_dst, &dst_proto);
466 switch (err) {
467 case ENOENT:
9fff138e 468 ds_put_format(&errors, "%s: bad %s 'remote_ip'\n", name, type);
3ae91c01
JB
469 break;
470 case EINVAL:
9fff138e
DDP
471 ds_put_format(&errors,
472 "%s: multicast remote_ip=%s not allowed\n",
473 name, node->value);
474 goto out;
2b9d6589 475 }
79f1cbe9 476 } else if (!strcmp(node->key, "local_ip")) {
3ae91c01
JB
477 err = parse_tunnel_ip(node->value, true, &tnl_cfg.ip_src_flow,
478 &tnl_cfg.ipv6_src, &src_proto);
479 switch (err) {
480 case ENOENT:
9fff138e 481 ds_put_format(&errors, "%s: bad %s 'local_ip'\n", name, type);
3ae91c01 482 break;
2b9d6589 483 }
79f1cbe9
EJ
484 } else if (!strcmp(node->key, "tos")) {
485 if (!strcmp(node->value, "inherit")) {
f431bf7d 486 tnl_cfg.tos_inherit = true;
2b9d6589 487 } else {
3fca7064
PS
488 char *endptr;
489 int tos;
79f1cbe9 490 tos = strtol(node->value, &endptr, 0);
91aff446 491 if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
f431bf7d 492 tnl_cfg.tos = tos;
91aff446 493 } else {
9fff138e
DDP
494 ds_put_format(&errors, "%s: invalid TOS %s\n", name,
495 node->value);
3fca7064 496 }
2b9d6589 497 }
79f1cbe9
EJ
498 } else if (!strcmp(node->key, "ttl")) {
499 if (!strcmp(node->value, "inherit")) {
f431bf7d 500 tnl_cfg.ttl_inherit = true;
2b9d6589 501 } else {
f431bf7d 502 tnl_cfg.ttl = atoi(node->value);
2b9d6589 503 }
79f827fa 504 } else if (!strcmp(node->key, "dst_port") && needs_dst_port) {
f431bf7d 505 tnl_cfg.dst_port = htons(atoi(node->value));
f431bf7d 506 } else if (!strcmp(node->key, "csum") && has_csum) {
79f1cbe9 507 if (!strcmp(node->value, "true")) {
f431bf7d 508 tnl_cfg.csum = true;
2b9d6589 509 }
0ffff497
WT
510 } else if (!strcmp(node->key, "seq") && has_seq) {
511 if (!strcmp(node->value, "true")) {
512 tnl_cfg.set_seq = true;
513 }
79f1cbe9
EJ
514 } else if (!strcmp(node->key, "df_default")) {
515 if (!strcmp(node->value, "false")) {
f431bf7d 516 tnl_cfg.dont_fragment = false;
66409d1b 517 }
79f1cbe9
EJ
518 } else if (!strcmp(node->key, "key") ||
519 !strcmp(node->key, "in_key") ||
875ab130
BP
520 !strcmp(node->key, "out_key") ||
521 !strcmp(node->key, "packet_type")) {
c19e6535 522 /* Handled separately below. */
875ab130 523 } else if (!strcmp(node->key, "exts") && !strcmp(type, "vxlan")) {
526df7d8
TG
524 char *str = xstrdup(node->value);
525 char *ext, *save_ptr = NULL;
526
527 tnl_cfg.exts = 0;
528
529 ext = strtok_r(str, ",", &save_ptr);
530 while (ext) {
531 if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
532 tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
439f39cb
GS
533 } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) {
534 tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
526df7d8 535 } else {
9fff138e
DDP
536 ds_put_format(&errors, "%s: unknown extension '%s'\n",
537 name, ext);
526df7d8
TG
538 }
539
540 ext = strtok_r(NULL, ",", &save_ptr);
541 }
542
543 free(str);
bf4bbd0d
PS
544 } else if (!strcmp(node->key, "egress_pkt_mark")) {
545 tnl_cfg.egress_pkt_mark = strtoul(node->value, NULL, 10);
546 tnl_cfg.set_egress_pkt_mark = true;
7dc18ae9 547 } else if (!strcmp(node->key, "erspan_idx")) {
068794b4
GR
548 if (!strcmp(node->value, "flow")) {
549 tnl_cfg.erspan_idx_flow = true;
550 } else {
551 tnl_cfg.erspan_idx_flow = false;
552 tnl_cfg.erspan_idx = strtol(node->value, NULL, 16);
553
554 if (tnl_cfg.erspan_idx & ~ERSPAN_IDX_MASK) {
555 ds_put_format(&errors, "%s: invalid erspan index: %s\n",
556 name, node->value);
557 err = EINVAL;
558 goto out;
559 }
7dc18ae9
WT
560 }
561 } else if (!strcmp(node->key, "erspan_ver")) {
068794b4
GR
562 if (!strcmp(node->value, "flow")) {
563 tnl_cfg.erspan_ver_flow = true;
564 tnl_cfg.erspan_idx_flow = true;
565 tnl_cfg.erspan_dir_flow = true;
566 tnl_cfg.erspan_hwid_flow = true;
567 } else {
568 tnl_cfg.erspan_ver_flow = false;
569 tnl_cfg.erspan_ver = atoi(node->value);
570
571 if (tnl_cfg.erspan_ver != 1 && tnl_cfg.erspan_ver != 2) {
572 ds_put_format(&errors, "%s: invalid erspan version: %s\n",
573 name, node->value);
574 err = EINVAL;
575 goto out;
576 }
7dc18ae9
WT
577 }
578 } else if (!strcmp(node->key, "erspan_dir")) {
068794b4
GR
579 if (!strcmp(node->value, "flow")) {
580 tnl_cfg.erspan_dir_flow = true;
581 } else {
582 tnl_cfg.erspan_dir_flow = false;
583 tnl_cfg.erspan_dir = atoi(node->value);
584
585 if (tnl_cfg.erspan_dir != 0 && tnl_cfg.erspan_dir != 1) {
586 ds_put_format(&errors, "%s: invalid erspan direction: %s\n",
587 name, node->value);
588 err = EINVAL;
589 goto out;
590 }
7dc18ae9
WT
591 }
592 } else if (!strcmp(node->key, "erspan_hwid")) {
068794b4
GR
593 if (!strcmp(node->value, "flow")) {
594 tnl_cfg.erspan_hwid_flow = true;
595 } else {
596 tnl_cfg.erspan_hwid_flow = false;
597 tnl_cfg.erspan_hwid = strtol(node->value, NULL, 16);
598
599 if (tnl_cfg.erspan_hwid & ~(ERSPAN_HWID_MASK >> 4)) {
600 ds_put_format(&errors, "%s: invalid erspan hardware ID: %s\n",
601 name, node->value);
602 err = EINVAL;
603 goto out;
604 }
7dc18ae9 605 }
2b9d6589 606 } else {
439f39cb
GS
607 ds_put_format(&errors, "%s: unknown %s argument '%s'\n", name,
608 type, node->key);
2b9d6589
BP
609 }
610 }
611
875ab130
BP
612 enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg);
613 const char *full_type = (strcmp(type, "vxlan") ? type
ea4cb65c
EG
614 : (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GPE)
615 ? "VXLAN-GPE" : "VXLAN (without GPE"));
875ab130
BP
616 const char *packet_type = smap_get(args, "packet_type");
617 if (!packet_type) {
618 tnl_cfg.pt_mode = default_pt_mode(layers);
619 } else if (!strcmp(packet_type, "legacy_l2")) {
620 tnl_cfg.pt_mode = NETDEV_PT_LEGACY_L2;
621 if (!(layers & TNL_L2)) {
622 ds_put_format(&errors, "%s: legacy_l2 configured on %s tunnel "
623 "that cannot carry L2 traffic\n",
624 name, full_type);
625 err = EINVAL;
626 goto out;
627 }
628 } else if (!strcmp(packet_type, "legacy_l3")) {
629 tnl_cfg.pt_mode = NETDEV_PT_LEGACY_L3;
630 if (!(layers & TNL_L3)) {
631 ds_put_format(&errors, "%s: legacy_l3 configured on %s tunnel "
632 "that cannot carry L3 traffic\n",
633 name, full_type);
634 err = EINVAL;
635 goto out;
636 }
637 } else if (!strcmp(packet_type, "ptap")) {
638 tnl_cfg.pt_mode = NETDEV_PT_AWARE;
639 } else {
640 ds_put_format(&errors, "%s: unknown packet_type '%s'\n",
641 name, packet_type);
642 err = EINVAL;
643 goto out;
439f39cb
GS
644 }
645
3ae91c01 646 if (!ipv6_addr_is_set(&tnl_cfg.ipv6_dst) && !tnl_cfg.ip_dst_flow) {
9fff138e
DDP
647 ds_put_format(&errors,
648 "%s: %s type requires valid 'remote_ip' argument\n",
649 name, type);
650 err = EINVAL;
651 goto out;
2b9d6589 652 }
0ad90c84 653 if (tnl_cfg.ip_src_flow && !tnl_cfg.ip_dst_flow) {
9fff138e
DDP
654 ds_put_format(&errors,
655 "%s: %s type requires 'remote_ip=flow' "
656 "with 'local_ip=flow'\n",
657 name, type);
658 err = EINVAL;
659 goto out;
0ad90c84 660 }
3ae91c01 661 if (src_proto && dst_proto && src_proto != dst_proto) {
9fff138e
DDP
662 ds_put_format(&errors,
663 "%s: 'remote_ip' and 'local_ip' "
664 "has to be of the same address family\n",
665 name);
666 err = EINVAL;
667 goto out;
3ae91c01 668 }
f431bf7d
EJ
669 if (!tnl_cfg.ttl) {
670 tnl_cfg.ttl = DEFAULT_TTL;
671 }
672
673 tnl_cfg.in_key = parse_key(args, "in_key",
674 &tnl_cfg.in_key_present,
675 &tnl_cfg.in_key_flow);
f431bf7d
EJ
676
677 tnl_cfg.out_key = parse_key(args, "out_key",
678 &tnl_cfg.out_key_present,
679 &tnl_cfg.out_key_flow);
2b9d6589 680
86383816 681 ovs_mutex_lock(&dev->mutex);
a1908399
AW
682 if (memcmp(&dev->tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) {
683 dev->tnl_cfg = tnl_cfg;
684 tunnel_check_status_change__(dev);
685 netdev_change_seq_changed(dev_);
686 }
86383816 687 ovs_mutex_unlock(&dev->mutex);
f431bf7d 688
9fff138e
DDP
689 err = 0;
690
691out:
c296d3f8
DDP
692 if (errors.length) {
693 ds_chomp(&errors, '\n');
694 VLOG_WARN("%s", ds_cstr(&errors));
695 if (err) {
696 *errp = ds_steal_cstr(&errors);
697 }
9fff138e
DDP
698 }
699
700 ds_destroy(&errors);
701
702 return err;
c19e6535
BP
703}
704
2b9d6589 705static int
b5d57fc8 706get_tunnel_config(const struct netdev *dev, struct smap *args)
6d9e6eb4 707{
86383816 708 struct netdev_vport *netdev = netdev_vport_cast(dev);
63171f04 709 const char *type = netdev_get_type(dev);
86383816
BP
710 struct netdev_tunnel_config tnl_cfg;
711
712 ovs_mutex_lock(&netdev->mutex);
713 tnl_cfg = netdev->tnl_cfg;
714 ovs_mutex_unlock(&netdev->mutex);
6d9e6eb4 715
3ae91c01
JB
716 if (ipv6_addr_is_set(&tnl_cfg.ipv6_dst)) {
717 smap_add_ipv6(args, "remote_ip", &tnl_cfg.ipv6_dst);
86383816 718 } else if (tnl_cfg.ip_dst_flow) {
0ad90c84 719 smap_add(args, "remote_ip", "flow");
0a740f48
EJ
720 }
721
3ae91c01
JB
722 if (ipv6_addr_is_set(&tnl_cfg.ipv6_src)) {
723 smap_add_ipv6(args, "local_ip", &tnl_cfg.ipv6_src);
86383816 724 } else if (tnl_cfg.ip_src_flow) {
0ad90c84 725 smap_add(args, "local_ip", "flow");
7f804ea5 726 }
c19e6535 727
86383816 728 if (tnl_cfg.in_key_flow && tnl_cfg.out_key_flow) {
6d9e6eb4 729 smap_add(args, "key", "flow");
86383816
BP
730 } else if (tnl_cfg.in_key_present && tnl_cfg.out_key_present
731 && tnl_cfg.in_key == tnl_cfg.out_key) {
732 smap_add_format(args, "key", "%"PRIu64, ntohll(tnl_cfg.in_key));
6d9e6eb4 733 } else {
86383816 734 if (tnl_cfg.in_key_flow) {
b9ad7294 735 smap_add(args, "in_key", "flow");
86383816 736 } else if (tnl_cfg.in_key_present) {
b9ad7294 737 smap_add_format(args, "in_key", "%"PRIu64,
86383816 738 ntohll(tnl_cfg.in_key));
b9ad7294 739 }
6d9e6eb4 740
86383816 741 if (tnl_cfg.out_key_flow) {
b9ad7294 742 smap_add(args, "out_key", "flow");
86383816 743 } else if (tnl_cfg.out_key_present) {
b9ad7294 744 smap_add_format(args, "out_key", "%"PRIu64,
86383816 745 ntohll(tnl_cfg.out_key));
6d9e6eb4
BP
746 }
747 }
748
86383816 749 if (tnl_cfg.ttl_inherit) {
62827e6a 750 smap_add(args, "ttl", "inherit");
86383816
BP
751 } else if (tnl_cfg.ttl != DEFAULT_TTL) {
752 smap_add_format(args, "ttl", "%"PRIu8, tnl_cfg.ttl);
c19e6535
BP
753 }
754
86383816 755 if (tnl_cfg.tos_inherit) {
6d9e6eb4 756 smap_add(args, "tos", "inherit");
86383816
BP
757 } else if (tnl_cfg.tos) {
758 smap_add_format(args, "tos", "0x%x", tnl_cfg.tos);
6d9e6eb4
BP
759 }
760
86383816
BP
761 if (tnl_cfg.dst_port) {
762 uint16_t dst_port = ntohs(tnl_cfg.dst_port);
9eeb949b 763
c1fc1411
JG
764 if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) ||
765 (!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
4237026e
PS
766 (!strcmp("lisp", type) && dst_port != LISP_DST_PORT) ||
767 (!strcmp("stt", type) && dst_port != STT_DST_PORT)) {
79f827fa
KM
768 smap_add_format(args, "dst_port", "%d", dst_port);
769 }
770 }
771
86383816 772 if (tnl_cfg.csum) {
6d9e6eb4
BP
773 smap_add(args, "csum", "true");
774 }
8a9ff93a 775
0ffff497
WT
776 if (tnl_cfg.set_seq) {
777 smap_add(args, "seq", "true");
778 }
779
875ab130
BP
780 enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg);
781 if (tnl_cfg.pt_mode != default_pt_mode(layers)) {
782 smap_add(args, "packet_type",
783 tnl_cfg.pt_mode == NETDEV_PT_LEGACY_L2 ? "legacy_l2"
784 : tnl_cfg.pt_mode == NETDEV_PT_LEGACY_L3 ? "legacy_l3"
785 : "ptap");
63171f04
JS
786 }
787
86383816 788 if (!tnl_cfg.dont_fragment) {
66409d1b
AE
789 smap_add(args, "df_default", "false");
790 }
6d9e6eb4 791
bf4bbd0d
PS
792 if (tnl_cfg.set_egress_pkt_mark) {
793 smap_add_format(args, "egress_pkt_mark",
794 "%"PRIu32, tnl_cfg.egress_pkt_mark);
795 }
7dc18ae9 796
068794b4
GR
797 if (!strcmp("erspan", type) || !strcmp("ip6erspan", type)) {
798 if (tnl_cfg.erspan_ver_flow) {
799 /* since version number is not determined,
800 * assume print all other as flow
801 */
802 smap_add(args, "erspan_ver", "flow");
803 smap_add(args, "erspan_idx", "flow");
804 smap_add(args, "erspan_dir", "flow");
805 smap_add(args, "erspan_hwid", "flow");
806 } else {
807 smap_add_format(args, "erspan_ver", "%d", tnl_cfg.erspan_ver);
808
809 if (tnl_cfg.erspan_ver == 1) {
810 if (tnl_cfg.erspan_idx_flow) {
811 smap_add(args, "erspan_idx", "flow");
812 } else {
813 smap_add_format(args, "erspan_idx", "0x%x",
814 tnl_cfg.erspan_idx);
815 }
816 } else if (tnl_cfg.erspan_ver == 2) {
817 if (tnl_cfg.erspan_dir_flow) {
818 smap_add(args, "erspan_dir", "flow");
819 } else {
820 smap_add_format(args, "erspan_dir", "%d",
821 tnl_cfg.erspan_dir);
822 }
823 if (tnl_cfg.erspan_hwid_flow) {
824 smap_add(args, "erspan_hwid", "flow");
825 } else {
826 smap_add_format(args, "erspan_hwid", "0x%x",
827 tnl_cfg.erspan_hwid);
828 }
829 }
830 }
7dc18ae9
WT
831 }
832
6d9e6eb4
BP
833 return 0;
834}
0a740f48
EJ
835\f
836/* Code specific to patch ports. */
837
161b6042
BP
838/* If 'netdev' is a patch port, returns the name of its peer as a malloc()'d
839 * string that the caller must free.
840 *
841 * If 'netdev' is not a patch port, returns NULL. */
842char *
843netdev_vport_patch_peer(const struct netdev *netdev_)
0a740f48 844{
161b6042
BP
845 char *peer = NULL;
846
847 if (netdev_vport_is_patch(netdev_)) {
848 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
86383816
BP
849
850 ovs_mutex_lock(&netdev->mutex);
161b6042
BP
851 if (netdev->peer) {
852 peer = xstrdup(netdev->peer);
853 }
86383816 854 ovs_mutex_unlock(&netdev->mutex);
161b6042
BP
855 }
856
857 return peer;
0a740f48
EJ
858}
859
860void
b9ad7294 861netdev_vport_inc_rx(const struct netdev *netdev,
9e04d6f6 862 const struct dpif_flow_stats *stats)
0a740f48 863{
b5d57fc8
BP
864 if (is_vport_class(netdev_get_class(netdev))) {
865 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
866
867 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
868 dev->stats.rx_packets += stats->n_packets;
869 dev->stats.rx_bytes += stats->n_bytes;
86383816 870 ovs_mutex_unlock(&dev->mutex);
0a740f48
EJ
871 }
872}
873
874void
b9ad7294
EJ
875netdev_vport_inc_tx(const struct netdev *netdev,
876 const struct dpif_flow_stats *stats)
0a740f48 877{
b5d57fc8
BP
878 if (is_vport_class(netdev_get_class(netdev))) {
879 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
880
881 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
882 dev->stats.tx_packets += stats->n_packets;
883 dev->stats.tx_bytes += stats->n_bytes;
86383816 884 ovs_mutex_unlock(&dev->mutex);
0a740f48
EJ
885 }
886}
887
888static int
b5d57fc8 889get_patch_config(const struct netdev *dev_, struct smap *args)
0a740f48 890{
b5d57fc8 891 struct netdev_vport *dev = netdev_vport_cast(dev_);
0a740f48 892
86383816 893 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
894 if (dev->peer) {
895 smap_add(args, "peer", dev->peer);
896 }
86383816
BP
897 ovs_mutex_unlock(&dev->mutex);
898
0a740f48
EJ
899 return 0;
900}
6d9e6eb4
BP
901
902static int
9fff138e 903set_patch_config(struct netdev *dev_, const struct smap *args, char **errp)
2b9d6589 904{
b5d57fc8
BP
905 struct netdev_vport *dev = netdev_vport_cast(dev_);
906 const char *name = netdev_get_name(dev_);
2b9d6589
BP
907 const char *peer;
908
79f1cbe9 909 peer = smap_get(args, "peer");
2b9d6589 910 if (!peer) {
9fff138e
DDP
911 VLOG_ERR_BUF(errp, "%s: patch type requires valid 'peer' argument",
912 name);
2b9d6589
BP
913 return EINVAL;
914 }
915
79f1cbe9 916 if (smap_count(args) > 1) {
9fff138e
DDP
917 VLOG_ERR_BUF(errp, "%s: patch type takes only a 'peer' argument",
918 name);
2b9d6589
BP
919 return EINVAL;
920 }
921
2b9d6589 922 if (!strcmp(name, peer)) {
9fff138e 923 VLOG_ERR_BUF(errp, "%s: patch peer must not be self", name);
2b9d6589
BP
924 return EINVAL;
925 }
926
86383816 927 ovs_mutex_lock(&dev->mutex);
a1908399
AW
928 if (!dev->peer || strcmp(dev->peer, peer)) {
929 free(dev->peer);
930 dev->peer = xstrdup(peer);
931 netdev_change_seq_changed(dev_);
932 }
86383816
BP
933 ovs_mutex_unlock(&dev->mutex);
934
2b9d6589
BP
935 return 0;
936}
6d9e6eb4
BP
937
938static int
89c09c1c 939netdev_vport_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
0a740f48 940{
b5d57fc8 941 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
942
943 ovs_mutex_lock(&dev->mutex);
d6e3feb5 944 /* Passing only collected counters */
945 stats->tx_packets = dev->stats.tx_packets;
946 stats->tx_bytes = dev->stats.tx_bytes;
947 stats->rx_packets = dev->stats.rx_packets;
948 stats->rx_bytes = dev->stats.rx_bytes;
86383816
BP
949 ovs_mutex_unlock(&dev->mutex);
950
6d9e6eb4
BP
951 return 0;
952}
a36de779 953
875ab130 954static enum netdev_pt_mode
89c09c1c 955netdev_vport_get_pt_mode(const struct netdev *netdev)
875ab130
BP
956{
957 struct netdev_vport *dev = netdev_vport_cast(netdev);
958
959 return dev->tnl_cfg.pt_mode;
960}
961
962
2b9d6589 963\f
01b25786
PB
964#ifdef __linux__
965static int
5e530e26 966netdev_vport_get_ifindex(const struct netdev *netdev_)
01b25786
PB
967{
968 char buf[NETDEV_VPORT_NAME_BUFSIZE];
969 const char *name = netdev_vport_get_dpif_port(netdev_, buf, sizeof(buf));
970
971 return linux_get_ifindex(name);
972}
973
01b25786 974#define NETDEV_VPORT_GET_IFINDEX netdev_vport_get_ifindex
89c09c1c 975#define NETDEV_FLOW_OFFLOAD_API , LINUX_FLOW_OFFLOAD_API
01b25786
PB
976#else /* !__linux__ */
977#define NETDEV_VPORT_GET_IFINDEX NULL
89c09c1c 978#define NETDEV_FLOW_OFFLOAD_API
01b25786
PB
979#endif /* __linux__ */
980
89c09c1c
BP
981#define VPORT_FUNCTIONS_COMMON \
982 .run = netdev_vport_run, \
983 .wait = netdev_vport_wait, \
984 .alloc = netdev_vport_alloc, \
985 .construct = netdev_vport_construct, \
986 .destruct = netdev_vport_destruct, \
987 .dealloc = netdev_vport_dealloc, \
988 .set_etheraddr = netdev_vport_set_etheraddr, \
989 .get_etheraddr = netdev_vport_get_etheraddr, \
990 .get_stats = netdev_vport_get_stats, \
991 .get_pt_mode = netdev_vport_get_pt_mode, \
992 .update_flags = netdev_vport_update_flags \
993 NETDEV_FLOW_OFFLOAD_API
994
995#define TUNNEL_FUNCTIONS_COMMON \
996 VPORT_FUNCTIONS_COMMON, \
997 .get_config = get_tunnel_config, \
998 .set_config = set_tunnel_config, \
999 .get_tunnel_config = get_netdev_tunnel_config, \
1000 .get_status = tunnel_get_status
db078f85 1001
2b9d6589 1002void
c060c4cf 1003netdev_vport_tunnel_register(void)
2b9d6589 1004{
a5d4fadd
JG
1005 /* The name of the dpif_port should be short enough to accomodate adding
1006 * a port number to the end if one is necessary. */
c3827f61 1007 static const struct vport_class vport_classes[] = {
89c09c1c
BP
1008 { "genev_sys",
1009 {
1010 TUNNEL_FUNCTIONS_COMMON,
1011 .type = "geneve",
1012 .build_header = netdev_geneve_build_header,
1013 .push_header = netdev_tnl_push_udp_header,
1014 .pop_header = netdev_geneve_pop_header,
1015 .get_ifindex = NETDEV_VPORT_GET_IFINDEX,
1016 }
1017 },
1018 { "gre_sys",
1019 {
1020 TUNNEL_FUNCTIONS_COMMON,
1021 .type = "gre",
1022 .build_header = netdev_gre_build_header,
1023 .push_header = netdev_gre_push_header,
1024 .pop_header = netdev_gre_pop_header
1025 }
1026 },
1027 { "vxlan_sys",
1028 {
1029 TUNNEL_FUNCTIONS_COMMON,
1030 .type = "vxlan",
1031 .build_header = netdev_vxlan_build_header,
1032 .push_header = netdev_tnl_push_udp_header,
1033 .pop_header = netdev_vxlan_pop_header,
1034 .get_ifindex = NETDEV_VPORT_GET_IFINDEX
1035 }
1036 },
1037 { "lisp_sys",
1038 {
1039 TUNNEL_FUNCTIONS_COMMON,
1040 .type = "lisp"
1041 }
1042 },
1043 { "stt_sys",
1044 {
1045 TUNNEL_FUNCTIONS_COMMON,
1046 .type = "stt"
1047 }
1048 },
1049 { "erspan_sys",
1050 {
1051 TUNNEL_FUNCTIONS_COMMON,
1052 .type = "erspan",
1053 .build_header = netdev_erspan_build_header,
1054 .push_header = netdev_erspan_push_header,
1055 .pop_header = netdev_erspan_pop_header
1056 }
1057 },
1058 { "ip6erspan_sys",
1059 {
1060 TUNNEL_FUNCTIONS_COMMON,
1061 .type = "ip6erspan",
1062 .build_header = netdev_erspan_build_header,
1063 .push_header = netdev_erspan_push_header,
1064 .pop_header = netdev_erspan_pop_header
1065 }
1066 },
1067 { "ip6gre_sys",
1068 {
1069 TUNNEL_FUNCTIONS_COMMON,
1070 .type = "ip6gre",
1071 .build_header = netdev_gre_build_header,
1072 .push_header = netdev_gre_push_header,
1073 .pop_header = netdev_gre_pop_header
1074 }
1075 },
c3827f61 1076 };
86383816 1077 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
c3827f61 1078
86383816
BP
1079 if (ovsthread_once_start(&once)) {
1080 int i;
c3827f61 1081
7c54c27f
BP
1082 for (i = 0; i < ARRAY_SIZE(vport_classes); i++) {
1083 netdev_register_provider(&vport_classes[i].netdev_class);
1084 }
a36de779
PS
1085
1086 unixctl_command_register("tnl/egress_port_range", "min max", 0, 2,
6b241d64 1087 netdev_tnl_egress_port_range, NULL);
a36de779 1088
86383816 1089 ovsthread_once_done(&once);
c3827f61 1090 }
2b9d6589 1091}
c060c4cf
EJ
1092
1093void
1094netdev_vport_patch_register(void)
1095{
89c09c1c
BP
1096 static const struct vport_class patch_class = {
1097 NULL,
1098 { VPORT_FUNCTIONS_COMMON,
1099 .type = "patch",
1100 .get_config = get_patch_config,
1101 .set_config = set_patch_config,
1102 }
1103 };
c060c4cf
EJ
1104 netdev_register_provider(&patch_class.netdev_class);
1105}