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