]> git.proxmox.com Git - mirror_ovs.git/blame - lib/netdev-vport.c
dpif-netdev: Store actions data and size contiguously.
[mirror_ovs.git] / lib / netdev-vport.c
CommitLineData
777ece09 1/*
b2f771ef 2 * Copyright (c) 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
777ece09
JG
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
6fcfff1b 10 * Unless required by applicable law or agreed to in writing, software
777ece09
JG
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
2b9d6589
BP
18
19#include "netdev-vport.h"
20
777ece09
JG
21#include <errno.h>
22#include <fcntl.h>
ea83a2fc 23#include <sys/socket.h>
2b9d6589 24#include <net/if.h>
777ece09
JG
25#include <sys/ioctl.h>
26
b9298d3f 27#include "byte-order.h"
a36de779 28#include "csum.h"
5059eff3
JP
29#include "daemon.h"
30#include "dirs.h"
0a740f48 31#include "dpif.h"
e14deea0 32#include "dp-packet.h"
a36de779
PS
33#include "dynamic-string.h"
34#include "flow.h"
ea83a2fc
EJ
35#include "hash.h"
36#include "hmap.h"
777ece09 37#include "list.h"
2b9d6589 38#include "netdev-provider.h"
a36de779 39#include "odp-netlink.h"
cf62fa4c 40#include "dp-packet.h"
d9b4ebc5 41#include "ovs-router.h"
2b9d6589 42#include "packets.h"
41ca1e0a 43#include "poll-loop.h"
a132aa96 44#include "route-table.h"
777ece09
JG
45#include "shash.h"
46#include "socket-util.h"
e6211adc 47#include "openvswitch/vlog.h"
a36de779
PS
48#include "unaligned.h"
49#include "unixctl.h"
50#include "util.h"
777ece09 51
d98e6007 52VLOG_DEFINE_THIS_MODULE(netdev_vport);
a36de779 53static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5);
5136ce49 54
c1fc1411 55#define GENEVE_DST_PORT 6081
4f2abb7b 56#define VXLAN_DST_PORT 4789
a6ae068b
LJ
57#define LISP_DST_PORT 4341
58
a36de779
PS
59#define VXLAN_HLEN (sizeof(struct eth_header) + \
60 sizeof(struct ip_header) + \
61 sizeof(struct udp_header) + \
62 sizeof(struct vxlanhdr))
63
e5a1caee
JG
64#define GENEVE_BASE_HLEN (sizeof(struct eth_header) + \
65 sizeof(struct ip_header) + \
66 sizeof(struct udp_header) + \
67 sizeof(struct genevehdr))
68
f431bf7d
EJ
69#define DEFAULT_TTL 64
70
b5d57fc8
BP
71struct netdev_vport {
72 struct netdev up;
86383816
BP
73
74 /* Protects all members below. */
75 struct ovs_mutex mutex;
76
35b769cb 77 uint8_t etheraddr[ETH_ADDR_LEN];
b9ad7294 78 struct netdev_stats stats;
0a740f48
EJ
79
80 /* Tunnels. */
f431bf7d 81 struct netdev_tunnel_config tnl_cfg;
41ca1e0a
AW
82 char egress_iface[IFNAMSIZ];
83 bool carrier_status;
0a740f48
EJ
84
85 /* Patch Ports. */
0a740f48 86 char *peer;
2b9d6589
BP
87};
88
2b9d6589 89struct vport_class {
b9ad7294 90 const char *dpif_port;
c3827f61 91 struct netdev_class netdev_class;
2b9d6589
BP
92};
93
41ca1e0a
AW
94/* Last read of the route-table's change number. */
95static uint64_t rt_change_seqno;
96
9dc63482 97static int netdev_vport_construct(struct netdev *);
86383816 98static int get_patch_config(const struct netdev *netdev, struct smap *args);
b5d57fc8 99static int get_tunnel_config(const struct netdev *, struct smap *args);
41ca1e0a 100static bool tunnel_check_status_change__(struct netdev_vport *);
2b9d6589 101
a36de779
PS
102static uint16_t tnl_udp_port_min = 32768;
103static uint16_t tnl_udp_port_max = 61000;
104
2b9d6589
BP
105static bool
106is_vport_class(const struct netdev_class *class)
777ece09 107{
9dc63482 108 return class->construct == netdev_vport_construct;
2b9d6589 109}
777ece09 110
41ca1e0a
AW
111bool
112netdev_vport_is_vport_class(const struct netdev_class *class)
113{
114 return is_vport_class(class);
115}
116
2b9d6589
BP
117static const struct vport_class *
118vport_class_cast(const struct netdev_class *class)
119{
cb22974d 120 ovs_assert(is_vport_class(class));
2b9d6589
BP
121 return CONTAINER_OF(class, struct vport_class, netdev_class);
122}
123
b5d57fc8
BP
124static struct netdev_vport *
125netdev_vport_cast(const struct netdev *netdev)
2b9d6589 126{
b5d57fc8
BP
127 ovs_assert(is_vport_class(netdev_get_class(netdev)));
128 return CONTAINER_OF(netdev, struct netdev_vport, up);
df67d7ae
EJ
129}
130
f431bf7d 131static const struct netdev_tunnel_config *
b5d57fc8 132get_netdev_tunnel_config(const struct netdev *netdev)
f431bf7d 133{
b5d57fc8 134 return &netdev_vport_cast(netdev)->tnl_cfg;
f431bf7d
EJ
135}
136
0a740f48
EJ
137bool
138netdev_vport_is_patch(const struct netdev *netdev)
139{
b5d57fc8 140 const struct netdev_class *class = netdev_get_class(netdev);
f18a39b7 141
c060c4cf 142 return class->get_config == get_patch_config;
0a740f48
EJ
143}
144
a6363cfd
LJ
145bool
146netdev_vport_is_layer3(const struct netdev *dev)
147{
148 const char *type = netdev_get_type(dev);
149
150 return (!strcmp("lisp", type));
151}
152
56b11f0b 153static bool
b5d57fc8 154netdev_vport_needs_dst_port(const struct netdev *dev)
56b11f0b 155{
b5d57fc8
BP
156 const struct netdev_class *class = netdev_get_class(dev);
157 const char *type = netdev_get_type(dev);
56b11f0b 158
a6ae068b 159 return (class->get_config == get_tunnel_config &&
c1fc1411
JG
160 (!strcmp("geneve", type) || !strcmp("vxlan", type) ||
161 !strcmp("lisp", type)));
56b11f0b
KM
162}
163
94a53842
AW
164const char *
165netdev_vport_class_get_dpif_port(const struct netdev_class *class)
166{
167 return is_vport_class(class) ? vport_class_cast(class)->dpif_port : NULL;
168}
169
de281153 170const char *
3aa30359
BP
171netdev_vport_get_dpif_port(const struct netdev *netdev,
172 char namebuf[], size_t bufsize)
de281153 173{
a5d4fadd
JG
174 const struct netdev_class *class = netdev_get_class(netdev);
175 const char *dpif_port = netdev_vport_class_get_dpif_port(class);
176
177 if (!dpif_port) {
178 return netdev_get_name(netdev);
179 }
180
b5d57fc8
BP
181 if (netdev_vport_needs_dst_port(netdev)) {
182 const struct netdev_vport *vport = netdev_vport_cast(netdev);
56b11f0b
KM
183
184 /*
a5d4fadd
JG
185 * Note: IFNAMSIZ is 16 bytes long. Implementations should choose
186 * a dpif port name that is short enough to fit including any
187 * port numbers but assert just in case.
56b11f0b 188 */
3aa30359 189 BUILD_ASSERT(NETDEV_VPORT_NAME_BUFSIZE >= IFNAMSIZ);
a5d4fadd
JG
190 ovs_assert(strlen(dpif_port) + 6 < IFNAMSIZ);
191 snprintf(namebuf, bufsize, "%s_%d", dpif_port,
56b11f0b 192 ntohs(vport->tnl_cfg.dst_port));
3aa30359 193 return namebuf;
56b11f0b 194 } else {
a5d4fadd 195 return dpif_port;
56b11f0b 196 }
2b9d6589 197}
777ece09 198
3aa30359
BP
199char *
200netdev_vport_get_dpif_port_strdup(const struct netdev *netdev)
201{
202 char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
203
204 return xstrdup(netdev_vport_get_dpif_port(netdev, namebuf,
205 sizeof namebuf));
206}
207
41ca1e0a
AW
208/* Whenever the route-table change number is incremented,
209 * netdev_vport_route_changed() should be called to update
210 * the corresponding tunnel interface status. */
211static void
212netdev_vport_route_changed(void)
213{
214 struct netdev **vports;
215 size_t i, n_vports;
216
217 vports = netdev_get_vports(&n_vports);
218 for (i = 0; i < n_vports; i++) {
219 struct netdev *netdev_ = vports[i];
220 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
221
222 ovs_mutex_lock(&netdev->mutex);
223 /* Finds all tunnel vports. */
224 if (netdev->tnl_cfg.ip_dst) {
225 if (tunnel_check_status_change__(netdev)) {
226 netdev_change_seq_changed(netdev_);
227 }
228 }
41ca1e0a 229 ovs_mutex_unlock(&netdev->mutex);
b2f771ef
BP
230
231 netdev_close(netdev_);
41ca1e0a
AW
232 }
233
234 free(vports);
235}
236
9dc63482
BP
237static struct netdev *
238netdev_vport_alloc(void)
239{
240 struct netdev_vport *netdev = xzalloc(sizeof *netdev);
241 return &netdev->up;
242}
243
2b9d6589 244static int
9dc63482 245netdev_vport_construct(struct netdev *netdev_)
2b9d6589 246{
a36de779
PS
247 struct netdev_vport *dev = netdev_vport_cast(netdev_);
248 const char *type = netdev_get_type(netdev_);
6d9e6eb4 249
a36de779
PS
250 ovs_mutex_init(&dev->mutex);
251 eth_addr_random(dev->etheraddr);
252
253 /* Add a default destination port for tunnel ports if none specified. */
254 if (!strcmp(type, "geneve")) {
255 dev->tnl_cfg.dst_port = htons(GENEVE_DST_PORT);
256 } else if (!strcmp(type, "vxlan")) {
257 dev->tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
258 } else if (!strcmp(type, "lisp")) {
259 dev->tnl_cfg.dst_port = htons(LISP_DST_PORT);
260 }
6d9e6eb4 261
de5cdb90 262 return 0;
777ece09
JG
263}
264
2b9d6589 265static void
9dc63482 266netdev_vport_destruct(struct netdev *netdev_)
2b9d6589 267{
b5d57fc8 268 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
2b9d6589 269
b5d57fc8 270 free(netdev->peer);
86383816 271 ovs_mutex_destroy(&netdev->mutex);
9dc63482
BP
272}
273
274static void
275netdev_vport_dealloc(struct netdev *netdev_)
276{
277 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
2b9d6589
BP
278 free(netdev);
279}
280
2b9d6589 281static int
b5d57fc8 282netdev_vport_set_etheraddr(struct netdev *netdev_,
777ece09
JG
283 const uint8_t mac[ETH_ADDR_LEN])
284{
b5d57fc8 285 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
86383816
BP
286
287 ovs_mutex_lock(&netdev->mutex);
b5d57fc8 288 memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
86383816 289 ovs_mutex_unlock(&netdev->mutex);
3e912ffc 290 netdev_change_seq_changed(netdev_);
86383816 291
35b769cb 292 return 0;
777ece09
JG
293}
294
2b9d6589 295static int
86383816 296netdev_vport_get_etheraddr(const struct netdev *netdev_,
777ece09
JG
297 uint8_t mac[ETH_ADDR_LEN])
298{
86383816
BP
299 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
300
301 ovs_mutex_lock(&netdev->mutex);
302 memcpy(mac, netdev->etheraddr, ETH_ADDR_LEN);
303 ovs_mutex_unlock(&netdev->mutex);
304
35b769cb 305 return 0;
777ece09
JG
306}
307
41ca1e0a
AW
308/* Checks if the tunnel status has changed and returns a boolean.
309 * Updates the tunnel status if it has changed. */
310static bool
311tunnel_check_status_change__(struct netdev_vport *netdev)
312 OVS_REQUIRES(netdev->mutex)
ea763e0e 313{
3dea0874 314 char iface[IFNAMSIZ];
41ca1e0a 315 bool status = false;
275707c3 316 ovs_be32 route;
d9b4ebc5 317 ovs_be32 gw;
ea763e0e 318
41ca1e0a 319 iface[0] = '\0';
86383816 320 route = netdev->tnl_cfg.ip_dst;
d9b4ebc5 321 if (ovs_router_lookup(route, iface, &gw)) {
a404826e
AE
322 struct netdev *egress_netdev;
323
18812dff 324 if (!netdev_open(iface, "system", &egress_netdev)) {
41ca1e0a 325 status = netdev_get_carrier(egress_netdev);
a404826e
AE
326 netdev_close(egress_netdev);
327 }
ea763e0e
EJ
328 }
329
41ca1e0a
AW
330 if (strcmp(netdev->egress_iface, iface)
331 || netdev->carrier_status != status) {
332 ovs_strlcpy(netdev->egress_iface, iface, IFNAMSIZ);
333 netdev->carrier_status = status;
334
335 return true;
336 }
337
338 return false;
339}
340
341static int
342tunnel_get_status(const struct netdev *netdev_, struct smap *smap)
343{
344 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
345
346 if (netdev->egress_iface[0]) {
347 smap_add(smap, "tunnel_egress_iface", netdev->egress_iface);
348
349 smap_add(smap, "tunnel_egress_iface_carrier",
350 netdev->carrier_status ? "up" : "down");
351 }
352
ea763e0e
EJ
353 return 0;
354}
355
2b9d6589 356static int
b5d57fc8
BP
357netdev_vport_update_flags(struct netdev *netdev OVS_UNUSED,
358 enum netdev_flags off,
359 enum netdev_flags on OVS_UNUSED,
360 enum netdev_flags *old_flagsp)
777ece09
JG
361{
362 if (off & (NETDEV_UP | NETDEV_PROMISC)) {
363 return EOPNOTSUPP;
364 }
365
366 *old_flagsp = NETDEV_UP | NETDEV_PROMISC;
367 return 0;
368}
369
ea83a2fc
EJ
370static void
371netdev_vport_run(void)
372{
41ca1e0a
AW
373 uint64_t seq;
374
a132aa96 375 route_table_run();
41ca1e0a
AW
376 seq = route_table_get_change_seq();
377 if (rt_change_seqno != seq) {
378 rt_change_seqno = seq;
379 netdev_vport_route_changed();
380 }
ea83a2fc
EJ
381}
382
383static void
384netdev_vport_wait(void)
385{
41ca1e0a
AW
386 uint64_t seq;
387
a132aa96 388 route_table_wait();
41ca1e0a
AW
389 seq = route_table_get_change_seq();
390 if (rt_change_seqno != seq) {
391 poll_immediate_wake();
392 }
ea83a2fc
EJ
393}
394\f
0a740f48 395/* Code specific to tunnel types. */
2b9d6589 396
f431bf7d
EJ
397static ovs_be64
398parse_key(const struct smap *args, const char *name,
399 bool *present, bool *flow)
c19e6535
BP
400{
401 const char *s;
402
f431bf7d
EJ
403 *present = false;
404 *flow = false;
405
79f1cbe9 406 s = smap_get(args, name);
c19e6535 407 if (!s) {
79f1cbe9 408 s = smap_get(args, "key");
c19e6535 409 if (!s) {
f431bf7d 410 return 0;
c19e6535
BP
411 }
412 }
413
f431bf7d
EJ
414 *present = true;
415
c19e6535 416 if (!strcmp(s, "flow")) {
f431bf7d
EJ
417 *flow = true;
418 return 0;
c19e6535 419 } else {
f431bf7d 420 return htonll(strtoull(s, NULL, 0));
c19e6535
BP
421 }
422}
423
2b9d6589 424static int
b5d57fc8 425set_tunnel_config(struct netdev *dev_, const struct smap *args)
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_);
f431bf7d
EJ
430 bool ipsec_mech_set, needs_dst_port, has_csum;
431 struct netdev_tunnel_config tnl_cfg;
79f1cbe9 432 struct smap_node *node;
f431bf7d 433
4752cc0c
JG
434 has_csum = strstr(type, "gre") || strstr(type, "geneve") ||
435 strstr(type, "vxlan");
f431bf7d
EJ
436 ipsec_mech_set = false;
437 memset(&tnl_cfg, 0, sizeof tnl_cfg);
2b9d6589 438
a36de779
PS
439 /* Add a default destination port for tunnel ports if none specified. */
440 if (!strcmp(type, "geneve")) {
441 tnl_cfg.dst_port = htons(GENEVE_DST_PORT);
442 }
443
444 if (!strcmp(type, "vxlan")) {
445 tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
446 }
447
448 if (!strcmp(type, "lisp")) {
449 tnl_cfg.dst_port = htons(LISP_DST_PORT);
450 }
451
a6ae068b 452 needs_dst_port = netdev_vport_needs_dst_port(dev_);
f431bf7d 453 tnl_cfg.ipsec = strstr(type, "ipsec");
f431bf7d 454 tnl_cfg.dont_fragment = true;
e16a28b5 455
79f1cbe9
EJ
456 SMAP_FOR_EACH (node, args) {
457 if (!strcmp(node->key, "remote_ip")) {
2b9d6589 458 struct in_addr in_addr;
0ad90c84
JR
459 if (!strcmp(node->value, "flow")) {
460 tnl_cfg.ip_dst_flow = true;
461 tnl_cfg.ip_dst = htonl(0);
462 } else if (lookup_ip(node->value, &in_addr)) {
c3827f61 463 VLOG_WARN("%s: bad %s 'remote_ip'", name, type);
85c9de19
PS
464 } else if (ip_is_multicast(in_addr.s_addr)) {
465 VLOG_WARN("%s: multicast remote_ip="IP_FMT" not allowed",
466 name, IP_ARGS(in_addr.s_addr));
467 return EINVAL;
2b9d6589 468 } else {
f431bf7d 469 tnl_cfg.ip_dst = in_addr.s_addr;
2b9d6589 470 }
79f1cbe9 471 } else if (!strcmp(node->key, "local_ip")) {
2b9d6589 472 struct in_addr in_addr;
0ad90c84
JR
473 if (!strcmp(node->value, "flow")) {
474 tnl_cfg.ip_src_flow = true;
475 tnl_cfg.ip_src = htonl(0);
476 } else if (lookup_ip(node->value, &in_addr)) {
c3827f61 477 VLOG_WARN("%s: bad %s 'local_ip'", name, type);
2b9d6589 478 } else {
f431bf7d 479 tnl_cfg.ip_src = in_addr.s_addr;
2b9d6589 480 }
79f1cbe9
EJ
481 } else if (!strcmp(node->key, "tos")) {
482 if (!strcmp(node->value, "inherit")) {
f431bf7d 483 tnl_cfg.tos_inherit = true;
2b9d6589 484 } else {
3fca7064
PS
485 char *endptr;
486 int tos;
79f1cbe9 487 tos = strtol(node->value, &endptr, 0);
91aff446 488 if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
f431bf7d 489 tnl_cfg.tos = tos;
91aff446
BP
490 } else {
491 VLOG_WARN("%s: invalid TOS %s", name, node->value);
3fca7064 492 }
2b9d6589 493 }
79f1cbe9
EJ
494 } else if (!strcmp(node->key, "ttl")) {
495 if (!strcmp(node->value, "inherit")) {
f431bf7d 496 tnl_cfg.ttl_inherit = true;
2b9d6589 497 } else {
f431bf7d 498 tnl_cfg.ttl = atoi(node->value);
2b9d6589 499 }
79f827fa 500 } else if (!strcmp(node->key, "dst_port") && needs_dst_port) {
f431bf7d 501 tnl_cfg.dst_port = htons(atoi(node->value));
f431bf7d 502 } else if (!strcmp(node->key, "csum") && has_csum) {
79f1cbe9 503 if (!strcmp(node->value, "true")) {
f431bf7d 504 tnl_cfg.csum = true;
2b9d6589 505 }
79f1cbe9
EJ
506 } else if (!strcmp(node->key, "df_default")) {
507 if (!strcmp(node->value, "false")) {
f431bf7d 508 tnl_cfg.dont_fragment = false;
66409d1b 509 }
f431bf7d 510 } else if (!strcmp(node->key, "peer_cert") && tnl_cfg.ipsec) {
79f1cbe9 511 if (smap_get(args, "certificate")) {
3c52fa7b
JP
512 ipsec_mech_set = true;
513 } else {
ef7ee76a
JP
514 const char *use_ssl_cert;
515
516 /* If the "use_ssl_cert" is true, then "certificate" and
517 * "private_key" will be pulled from the SSL table. The
518 * use of this option is strongly discouraged, since it
519 * will like be removed when multiple SSL configurations
520 * are supported by OVS.
521 */
79f1cbe9 522 use_ssl_cert = smap_get(args, "use_ssl_cert");
ef7ee76a 523 if (!use_ssl_cert || strcmp(use_ssl_cert, "true")) {
8283e514
JP
524 VLOG_ERR("%s: 'peer_cert' requires 'certificate' argument",
525 name);
b9ad7294 526 return EINVAL;
ef7ee76a
JP
527 }
528 ipsec_mech_set = true;
3c52fa7b 529 }
f431bf7d 530 } else if (!strcmp(node->key, "psk") && tnl_cfg.ipsec) {
2b9d6589 531 ipsec_mech_set = true;
f431bf7d 532 } else if (tnl_cfg.ipsec
79f1cbe9
EJ
533 && (!strcmp(node->key, "certificate")
534 || !strcmp(node->key, "private_key")
535 || !strcmp(node->key, "use_ssl_cert"))) {
3c52fa7b 536 /* Ignore options not used by the netdev. */
79f1cbe9
EJ
537 } else if (!strcmp(node->key, "key") ||
538 !strcmp(node->key, "in_key") ||
539 !strcmp(node->key, "out_key")) {
c19e6535 540 /* Handled separately below. */
526df7d8
TG
541 } else if (!strcmp(node->key, "exts")) {
542 char *str = xstrdup(node->value);
543 char *ext, *save_ptr = NULL;
544
545 tnl_cfg.exts = 0;
546
547 ext = strtok_r(str, ",", &save_ptr);
548 while (ext) {
549 if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
550 tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
551 } else {
552 VLOG_WARN("%s: unknown extension '%s'", name, ext);
553 }
554
555 ext = strtok_r(NULL, ",", &save_ptr);
556 }
557
558 free(str);
2b9d6589 559 } else {
79f1cbe9 560 VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
2b9d6589
BP
561 }
562 }
563
f431bf7d 564 if (tnl_cfg.ipsec) {
9366380a 565 static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
2a586a5c 566 static pid_t pid = 0;
6027d03d 567
c89809c9 568#ifndef _WIN32
9366380a 569 ovs_mutex_lock(&mutex);
900f7601 570 if (pid <= 0) {
2a586a5c
AS
571 char *file_name = xasprintf("%s/%s", ovs_rundir(),
572 "ovs-monitor-ipsec.pid");
573 pid = read_pidfile(file_name);
574 free(file_name);
575 }
9366380a 576 ovs_mutex_unlock(&mutex);
c89809c9 577#endif
2a586a5c 578
e7009c36 579 if (pid < 0) {
8283e514
JP
580 VLOG_ERR("%s: IPsec requires the ovs-monitor-ipsec daemon",
581 name);
b9ad7294 582 return EINVAL;
e7009c36 583 }
5059eff3 584
79f1cbe9 585 if (smap_get(args, "peer_cert") && smap_get(args, "psk")) {
8283e514 586 VLOG_ERR("%s: cannot define both 'peer_cert' and 'psk'", name);
b9ad7294 587 return EINVAL;
3c52fa7b
JP
588 }
589
590 if (!ipsec_mech_set) {
8283e514
JP
591 VLOG_ERR("%s: IPsec requires an 'peer_cert' or psk' argument",
592 name);
b9ad7294 593 return EINVAL;
3c52fa7b 594 }
2b9d6589
BP
595 }
596
0ad90c84 597 if (!tnl_cfg.ip_dst && !tnl_cfg.ip_dst_flow) {
8283e514
JP
598 VLOG_ERR("%s: %s type requires valid 'remote_ip' argument",
599 name, type);
b9ad7294 600 return EINVAL;
2b9d6589 601 }
0ad90c84
JR
602 if (tnl_cfg.ip_src_flow && !tnl_cfg.ip_dst_flow) {
603 VLOG_ERR("%s: %s type requires 'remote_ip=flow' with 'local_ip=flow'",
604 name, type);
605 return EINVAL;
606 }
f431bf7d
EJ
607 if (!tnl_cfg.ttl) {
608 tnl_cfg.ttl = DEFAULT_TTL;
609 }
610
611 tnl_cfg.in_key = parse_key(args, "in_key",
612 &tnl_cfg.in_key_present,
613 &tnl_cfg.in_key_flow);
f431bf7d
EJ
614
615 tnl_cfg.out_key = parse_key(args, "out_key",
616 &tnl_cfg.out_key_present,
617 &tnl_cfg.out_key_flow);
2b9d6589 618
86383816 619 ovs_mutex_lock(&dev->mutex);
a1908399
AW
620 if (memcmp(&dev->tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) {
621 dev->tnl_cfg = tnl_cfg;
622 tunnel_check_status_change__(dev);
623 netdev_change_seq_changed(dev_);
624 }
86383816 625 ovs_mutex_unlock(&dev->mutex);
f431bf7d 626
c19e6535
BP
627 return 0;
628}
629
2b9d6589 630static int
b5d57fc8 631get_tunnel_config(const struct netdev *dev, struct smap *args)
6d9e6eb4 632{
86383816
BP
633 struct netdev_vport *netdev = netdev_vport_cast(dev);
634 struct netdev_tunnel_config tnl_cfg;
635
636 ovs_mutex_lock(&netdev->mutex);
637 tnl_cfg = netdev->tnl_cfg;
638 ovs_mutex_unlock(&netdev->mutex);
6d9e6eb4 639
86383816
BP
640 if (tnl_cfg.ip_dst) {
641 smap_add_format(args, "remote_ip", IP_FMT, IP_ARGS(tnl_cfg.ip_dst));
642 } else if (tnl_cfg.ip_dst_flow) {
0ad90c84 643 smap_add(args, "remote_ip", "flow");
0a740f48
EJ
644 }
645
86383816
BP
646 if (tnl_cfg.ip_src) {
647 smap_add_format(args, "local_ip", IP_FMT, IP_ARGS(tnl_cfg.ip_src));
648 } else if (tnl_cfg.ip_src_flow) {
0ad90c84 649 smap_add(args, "local_ip", "flow");
7f804ea5 650 }
c19e6535 651
86383816 652 if (tnl_cfg.in_key_flow && tnl_cfg.out_key_flow) {
6d9e6eb4 653 smap_add(args, "key", "flow");
86383816
BP
654 } else if (tnl_cfg.in_key_present && tnl_cfg.out_key_present
655 && tnl_cfg.in_key == tnl_cfg.out_key) {
656 smap_add_format(args, "key", "%"PRIu64, ntohll(tnl_cfg.in_key));
6d9e6eb4 657 } else {
86383816 658 if (tnl_cfg.in_key_flow) {
b9ad7294 659 smap_add(args, "in_key", "flow");
86383816 660 } else if (tnl_cfg.in_key_present) {
b9ad7294 661 smap_add_format(args, "in_key", "%"PRIu64,
86383816 662 ntohll(tnl_cfg.in_key));
b9ad7294 663 }
6d9e6eb4 664
86383816 665 if (tnl_cfg.out_key_flow) {
b9ad7294 666 smap_add(args, "out_key", "flow");
86383816 667 } else if (tnl_cfg.out_key_present) {
b9ad7294 668 smap_add_format(args, "out_key", "%"PRIu64,
86383816 669 ntohll(tnl_cfg.out_key));
6d9e6eb4
BP
670 }
671 }
672
86383816 673 if (tnl_cfg.ttl_inherit) {
62827e6a 674 smap_add(args, "ttl", "inherit");
86383816
BP
675 } else if (tnl_cfg.ttl != DEFAULT_TTL) {
676 smap_add_format(args, "ttl", "%"PRIu8, tnl_cfg.ttl);
c19e6535
BP
677 }
678
86383816 679 if (tnl_cfg.tos_inherit) {
6d9e6eb4 680 smap_add(args, "tos", "inherit");
86383816
BP
681 } else if (tnl_cfg.tos) {
682 smap_add_format(args, "tos", "0x%x", tnl_cfg.tos);
6d9e6eb4
BP
683 }
684
86383816
BP
685 if (tnl_cfg.dst_port) {
686 uint16_t dst_port = ntohs(tnl_cfg.dst_port);
b5d57fc8 687 const char *type = netdev_get_type(dev);
9eeb949b 688
c1fc1411
JG
689 if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) ||
690 (!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
9eeb949b 691 (!strcmp("lisp", type) && dst_port != LISP_DST_PORT)) {
79f827fa
KM
692 smap_add_format(args, "dst_port", "%d", dst_port);
693 }
694 }
695
86383816 696 if (tnl_cfg.csum) {
6d9e6eb4
BP
697 smap_add(args, "csum", "true");
698 }
8a9ff93a 699
86383816 700 if (!tnl_cfg.dont_fragment) {
66409d1b
AE
701 smap_add(args, "df_default", "false");
702 }
6d9e6eb4
BP
703
704 return 0;
705}
0a740f48
EJ
706\f
707/* Code specific to patch ports. */
708
161b6042
BP
709/* If 'netdev' is a patch port, returns the name of its peer as a malloc()'d
710 * string that the caller must free.
711 *
712 * If 'netdev' is not a patch port, returns NULL. */
713char *
714netdev_vport_patch_peer(const struct netdev *netdev_)
0a740f48 715{
161b6042
BP
716 char *peer = NULL;
717
718 if (netdev_vport_is_patch(netdev_)) {
719 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
86383816
BP
720
721 ovs_mutex_lock(&netdev->mutex);
161b6042
BP
722 if (netdev->peer) {
723 peer = xstrdup(netdev->peer);
724 }
86383816 725 ovs_mutex_unlock(&netdev->mutex);
161b6042
BP
726 }
727
728 return peer;
0a740f48
EJ
729}
730
731void
b9ad7294 732netdev_vport_inc_rx(const struct netdev *netdev,
9e04d6f6 733 const struct dpif_flow_stats *stats)
0a740f48 734{
b5d57fc8
BP
735 if (is_vport_class(netdev_get_class(netdev))) {
736 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
737
738 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
739 dev->stats.rx_packets += stats->n_packets;
740 dev->stats.rx_bytes += stats->n_bytes;
86383816 741 ovs_mutex_unlock(&dev->mutex);
0a740f48
EJ
742 }
743}
744
745void
b9ad7294
EJ
746netdev_vport_inc_tx(const struct netdev *netdev,
747 const struct dpif_flow_stats *stats)
0a740f48 748{
b5d57fc8
BP
749 if (is_vport_class(netdev_get_class(netdev))) {
750 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
751
752 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
753 dev->stats.tx_packets += stats->n_packets;
754 dev->stats.tx_bytes += stats->n_bytes;
86383816 755 ovs_mutex_unlock(&dev->mutex);
0a740f48
EJ
756 }
757}
758
759static int
b5d57fc8 760get_patch_config(const struct netdev *dev_, struct smap *args)
0a740f48 761{
b5d57fc8 762 struct netdev_vport *dev = netdev_vport_cast(dev_);
0a740f48 763
86383816 764 ovs_mutex_lock(&dev->mutex);
0a740f48
EJ
765 if (dev->peer) {
766 smap_add(args, "peer", dev->peer);
767 }
86383816
BP
768 ovs_mutex_unlock(&dev->mutex);
769
0a740f48
EJ
770 return 0;
771}
6d9e6eb4
BP
772
773static int
b5d57fc8 774set_patch_config(struct netdev *dev_, const struct smap *args)
2b9d6589 775{
b5d57fc8
BP
776 struct netdev_vport *dev = netdev_vport_cast(dev_);
777 const char *name = netdev_get_name(dev_);
2b9d6589
BP
778 const char *peer;
779
79f1cbe9 780 peer = smap_get(args, "peer");
2b9d6589 781 if (!peer) {
8283e514 782 VLOG_ERR("%s: patch type requires valid 'peer' argument", name);
2b9d6589
BP
783 return EINVAL;
784 }
785
79f1cbe9 786 if (smap_count(args) > 1) {
8283e514 787 VLOG_ERR("%s: patch type takes only a 'peer' argument", name);
2b9d6589
BP
788 return EINVAL;
789 }
790
2b9d6589 791 if (!strcmp(name, peer)) {
8283e514 792 VLOG_ERR("%s: patch peer must not be self", name);
2b9d6589
BP
793 return EINVAL;
794 }
795
86383816 796 ovs_mutex_lock(&dev->mutex);
a1908399
AW
797 if (!dev->peer || strcmp(dev->peer, peer)) {
798 free(dev->peer);
799 dev->peer = xstrdup(peer);
800 netdev_change_seq_changed(dev_);
801 }
86383816
BP
802 ovs_mutex_unlock(&dev->mutex);
803
2b9d6589
BP
804 return 0;
805}
6d9e6eb4
BP
806
807static int
b9ad7294 808get_stats(const struct netdev *netdev, struct netdev_stats *stats)
0a740f48 809{
b5d57fc8 810 struct netdev_vport *dev = netdev_vport_cast(netdev);
86383816
BP
811
812 ovs_mutex_lock(&dev->mutex);
813 *stats = dev->stats;
814 ovs_mutex_unlock(&dev->mutex);
815
6d9e6eb4
BP
816 return 0;
817}
a36de779
PS
818
819\f
820/* Tunnel push pop ops. */
821
822static struct ip_header *
823ip_hdr(void *eth)
824{
825 return (void *)((char *)eth + sizeof (struct eth_header));
826}
827
828static struct gre_base_hdr *
829gre_hdr(struct ip_header *ip)
830{
831 return (void *)((char *)ip + sizeof (struct ip_header));
832}
833
834static void *
cf62fa4c 835ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl)
a36de779
PS
836{
837 struct ip_header *nh;
838 void *l4;
839
cf62fa4c
PS
840 nh = dp_packet_l3(packet);
841 l4 = dp_packet_l4(packet);
a36de779
PS
842
843 if (!nh || !l4) {
844 return NULL;
845 }
846
847 tnl->ip_src = get_16aligned_be32(&nh->ip_src);
848 tnl->ip_dst = get_16aligned_be32(&nh->ip_dst);
849 tnl->ip_tos = nh->ip_tos;
66252457 850 tnl->ip_ttl = nh->ip_ttl;
a36de779
PS
851
852 return l4;
853}
854
855/* Pushes the 'size' bytes of 'header' into the headroom of 'packet',
856 * reallocating the packet if necessary. 'header' should contain an Ethernet
857 * header, followed by an IPv4 header (without options), and an L4 header.
858 *
859 * This function sets the IP header's ip_tot_len field (which should be zeroed
860 * as part of 'header') and puts its value into '*ip_tot_size' as well. Also
861 * updates IP header checksum.
862 *
863 * Return pointer to the L4 header added to 'packet'. */
864static void *
cf62fa4c 865push_ip_header(struct dp_packet *packet,
a36de779
PS
866 const void *header, int size, int *ip_tot_size)
867{
868 struct eth_header *eth;
869 struct ip_header *ip;
870
cf62fa4c
PS
871 eth = dp_packet_push_uninit(packet, size);
872 *ip_tot_size = dp_packet_size(packet) - sizeof (struct eth_header);
a36de779
PS
873
874 memcpy(eth, header, size);
875 ip = ip_hdr(eth);
876 ip->ip_tot_len = htons(*ip_tot_size);
877
878
879 ip->ip_csum = recalc_csum16(ip->ip_csum, 0, ip->ip_tot_len);
880
881 return ip + 1;
882}
883
e066f78f
JG
884static void *
885udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl)
886{
887 struct udp_header *udp;
888
889 udp = ip_extract_tnl_md(packet, tnl);
890 if (!udp) {
891 return NULL;
892 }
893
8e45fe7c
JG
894 if (udp->udp_csum) {
895 uint32_t csum = packet_csum_pseudoheader(dp_packet_l3(packet));
896
897 csum = csum_continue(csum, udp, dp_packet_size(packet) -
898 ((const unsigned char *)udp -
899 (const unsigned char *)dp_packet_l2(packet)));
900 if (csum_finish(csum)) {
901 return NULL;
902 }
903 tnl->flags |= FLOW_TNL_F_CSUM;
904 }
905
e066f78f
JG
906 tnl->tp_src = udp->udp_src;
907 tnl->tp_dst = udp->udp_dst;
908
909 return udp + 1;
910}
911
912static ovs_be16
913get_src_port(struct dp_packet *packet)
914{
915 uint32_t hash;
916
917 hash = dp_packet_get_dp_hash(packet);
918
919 return htons((((uint64_t) hash * (tnl_udp_port_max - tnl_udp_port_min)) >> 32) +
920 tnl_udp_port_min);
921}
922
d625fbd1
JG
923static void
924push_udp_header(struct dp_packet *packet,
925 const struct ovs_action_push_tnl *data)
e066f78f
JG
926{
927 struct udp_header *udp;
928 int ip_tot_size;
929
d625fbd1 930 udp = push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
e066f78f
JG
931
932 /* set udp src port */
933 udp->udp_src = get_src_port(packet);
934 udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header));
8e45fe7c
JG
935
936 if (udp->udp_csum) {
937 uint32_t csum = packet_csum_pseudoheader(ip_hdr(dp_packet_data(packet)));
938
939 csum = csum_continue(csum, udp,
940 ip_tot_size - sizeof (struct ip_header));
941 udp->udp_csum = csum_finish(csum);
942
943 if (!udp->udp_csum) {
944 udp->udp_csum = htons(0xffff);
945 }
946 }
e066f78f
JG
947}
948
949static void *
950udp_build_header(struct netdev_tunnel_config *tnl_cfg,
8e45fe7c 951 const struct flow *tnl_flow,
e066f78f
JG
952 struct ovs_action_push_tnl *data)
953{
954 struct ip_header *ip;
955 struct udp_header *udp;
956
957 ip = ip_hdr(data->header);
958 ip->ip_proto = IPPROTO_UDP;
959
960 udp = (struct udp_header *) (ip + 1);
961 udp->udp_dst = tnl_cfg->dst_port;
962
8e45fe7c
JG
963 if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) {
964 /* Write a value in now to mark that we should compute the checksum
965 * later. 0xffff is handy because it is transparent to the
966 * calculation. */
967 udp->udp_csum = htons(0xffff);
968 }
969
e066f78f
JG
970 return udp + 1;
971}
972
a36de779
PS
973static int
974gre_header_len(ovs_be16 flags)
975{
976 int hlen = sizeof(struct eth_header) +
977 sizeof(struct ip_header) + 4;
978
979 if (flags & htons(GRE_CSUM)) {
980 hlen += 4;
981 }
982 if (flags & htons(GRE_KEY)) {
983 hlen += 4;
984 }
985 if (flags & htons(GRE_SEQ)) {
986 hlen += 4;
987 }
988 return hlen;
989}
990
991static int
cf62fa4c 992parse_gre_header(struct dp_packet *packet,
a36de779
PS
993 struct flow_tnl *tnl)
994{
995 const struct gre_base_hdr *greh;
996 ovs_16aligned_be32 *options;
997 int hlen;
998
999 greh = ip_extract_tnl_md(packet, tnl);
1000 if (!greh) {
1001 return -EINVAL;
1002 }
1003
1004 if (greh->flags & ~(htons(GRE_CSUM | GRE_KEY | GRE_SEQ))) {
1005 return -EINVAL;
1006 }
1007
6432e527
JG
1008 if (greh->protocol != htons(ETH_TYPE_TEB)) {
1009 return -EINVAL;
1010 }
1011
a36de779 1012 hlen = gre_header_len(greh->flags);
cf62fa4c 1013 if (hlen > dp_packet_size(packet)) {
a36de779
PS
1014 return -EINVAL;
1015 }
1016
1017 options = (ovs_16aligned_be32 *)(greh + 1);
1018 if (greh->flags & htons(GRE_CSUM)) {
1019 ovs_be16 pkt_csum;
1020
cf62fa4c 1021 pkt_csum = csum(greh, dp_packet_size(packet) -
a36de779 1022 ((const unsigned char *)greh -
cf62fa4c 1023 (const unsigned char *)dp_packet_l2(packet)));
a36de779
PS
1024 if (pkt_csum) {
1025 return -EINVAL;
1026 }
1027 tnl->flags = FLOW_TNL_F_CSUM;
1028 options++;
1029 }
1030
1031 if (greh->flags & htons(GRE_KEY)) {
1032 tnl->tun_id = (OVS_FORCE ovs_be64) ((OVS_FORCE uint64_t)(get_16aligned_be32(options)) << 32);
1033 tnl->flags |= FLOW_TNL_F_KEY;
1034 options++;
1035 }
1036
1037 if (greh->flags & htons(GRE_SEQ)) {
1038 options++;
1039 }
1040
1041 return hlen;
1042}
1043
d625fbd1
JG
1044static int
1045netdev_gre_pop_header(struct dp_packet *packet)
a36de779 1046{
cf62fa4c 1047 struct pkt_metadata *md = &packet->md;
a36de779
PS
1048 struct flow_tnl *tnl = &md->tunnel;
1049 int hlen = sizeof(struct eth_header) +
1050 sizeof(struct ip_header) + 4;
1051
1052 memset(md, 0, sizeof *md);
cf62fa4c 1053 if (hlen > dp_packet_size(packet)) {
d625fbd1 1054 return EINVAL;
a36de779
PS
1055 }
1056
1057 hlen = parse_gre_header(packet, tnl);
1058 if (hlen < 0) {
d625fbd1 1059 return -hlen;
a36de779
PS
1060 }
1061
cf62fa4c 1062 dp_packet_reset_packet(packet, hlen);
a36de779 1063
a36de779
PS
1064 return 0;
1065}
1066
1067static void
d625fbd1
JG
1068netdev_gre_push_header(struct dp_packet *packet,
1069 const struct ovs_action_push_tnl *data)
a36de779
PS
1070{
1071 struct gre_base_hdr *greh;
1072 int ip_tot_size;
1073
d625fbd1 1074 greh = push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
a36de779
PS
1075
1076 if (greh->flags & htons(GRE_CSUM)) {
d804d31e
JG
1077 ovs_be16 *csum_opt = (ovs_be16 *) (greh + 1);
1078 *csum_opt = csum(greh, ip_tot_size - sizeof (struct ip_header));
a36de779
PS
1079 }
1080}
1081
a36de779
PS
1082static int
1083netdev_gre_build_header(const struct netdev *netdev,
c876a4bb
RL
1084 struct ovs_action_push_tnl *data,
1085 const struct flow *tnl_flow)
a36de779
PS
1086{
1087 struct netdev_vport *dev = netdev_vport_cast(netdev);
1088 struct netdev_tunnel_config *tnl_cfg;
1089 struct ip_header *ip;
1090 struct gre_base_hdr *greh;
1091 ovs_16aligned_be32 *options;
1092 int hlen;
1093
1094 /* XXX: RCUfy tnl_cfg. */
1095 ovs_mutex_lock(&dev->mutex);
1096 tnl_cfg = &dev->tnl_cfg;
1097
1098 ip = ip_hdr(data->header);
1099 ip->ip_proto = IPPROTO_GRE;
1100
1101 greh = gre_hdr(ip);
1102 greh->protocol = htons(ETH_TYPE_TEB);
1103 greh->flags = 0;
1104
1105 options = (ovs_16aligned_be32 *) (greh + 1);
61cf6b70 1106 if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) {
a36de779
PS
1107 greh->flags |= htons(GRE_CSUM);
1108 put_16aligned_be32(options, 0);
1109 options++;
1110 }
1111
1112 if (tnl_cfg->out_key_present) {
1113 greh->flags |= htons(GRE_KEY);
1114 put_16aligned_be32(options, (OVS_FORCE ovs_be32)
c876a4bb 1115 ((OVS_FORCE uint64_t) tnl_flow->tunnel.tun_id >> 32));
a36de779
PS
1116 options++;
1117 }
1118
1119 ovs_mutex_unlock(&dev->mutex);
1120
1121 hlen = (uint8_t *) options - (uint8_t *) greh;
1122
1123 data->header_len = sizeof(struct eth_header) +
1124 sizeof(struct ip_header) + hlen;
1125 data->tnl_type = OVS_VPORT_TYPE_GRE;
1126 return 0;
1127}
1128
d625fbd1
JG
1129static int
1130netdev_vxlan_pop_header(struct dp_packet *packet)
a36de779 1131{
cf62fa4c 1132 struct pkt_metadata *md = &packet->md;
a36de779 1133 struct flow_tnl *tnl = &md->tunnel;
a36de779
PS
1134 struct vxlanhdr *vxh;
1135
1136 memset(md, 0, sizeof *md);
cf62fa4c 1137 if (VXLAN_HLEN > dp_packet_size(packet)) {
d625fbd1 1138 return EINVAL;
a36de779
PS
1139 }
1140
e066f78f
JG
1141 vxh = udp_extract_tnl_md(packet, tnl);
1142 if (!vxh) {
d625fbd1 1143 return EINVAL;
a36de779 1144 }
a36de779
PS
1145
1146 if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
1147 (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
1148 VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
1149 ntohl(get_16aligned_be32(&vxh->vx_flags)),
1150 ntohl(get_16aligned_be32(&vxh->vx_vni)));
d625fbd1 1151 return EINVAL;
a36de779 1152 }
a36de779 1153 tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
83fbb69b 1154 tnl->flags |= FLOW_TNL_F_KEY;
a36de779 1155
cf62fa4c 1156 dp_packet_reset_packet(packet, VXLAN_HLEN);
a36de779 1157
a36de779
PS
1158 return 0;
1159}
1160
1161static int
1162netdev_vxlan_build_header(const struct netdev *netdev,
c876a4bb
RL
1163 struct ovs_action_push_tnl *data,
1164 const struct flow *tnl_flow)
a36de779
PS
1165{
1166 struct netdev_vport *dev = netdev_vport_cast(netdev);
1167 struct netdev_tunnel_config *tnl_cfg;
a36de779
PS
1168 struct vxlanhdr *vxh;
1169
1170 /* XXX: RCUfy tnl_cfg. */
1171 ovs_mutex_lock(&dev->mutex);
1172 tnl_cfg = &dev->tnl_cfg;
1173
8e45fe7c 1174 vxh = udp_build_header(tnl_cfg, tnl_flow, data);
a36de779 1175
a36de779 1176 put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
c876a4bb 1177 put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
a36de779
PS
1178
1179 ovs_mutex_unlock(&dev->mutex);
1180 data->header_len = VXLAN_HLEN;
1181 data->tnl_type = OVS_VPORT_TYPE_VXLAN;
1182 return 0;
1183}
1184
a36de779 1185static int
d625fbd1 1186netdev_geneve_pop_header(struct dp_packet *packet)
e5a1caee
JG
1187{
1188 struct pkt_metadata *md = &packet->md;
1189 struct flow_tnl *tnl = &md->tunnel;
1190 struct genevehdr *gnh;
1191 unsigned int hlen;
1192
1193 memset(md, 0, sizeof *md);
1194 if (GENEVE_BASE_HLEN > dp_packet_size(packet)) {
1195 VLOG_WARN_RL(&err_rl, "geneve packet too small: min header=%u packet size=%u\n",
1196 (unsigned int)GENEVE_BASE_HLEN, dp_packet_size(packet));
d625fbd1 1197 return EINVAL;
e5a1caee
JG
1198 }
1199
1200 gnh = udp_extract_tnl_md(packet, tnl);
1201 if (!gnh) {
d625fbd1 1202 return EINVAL;
e5a1caee
JG
1203 }
1204
1205 hlen = GENEVE_BASE_HLEN + gnh->opt_len * 4;
1206 if (hlen > dp_packet_size(packet)) {
1207 VLOG_WARN_RL(&err_rl, "geneve packet too small: header len=%u packet size=%u\n",
1208 hlen, dp_packet_size(packet));
d625fbd1 1209 return EINVAL;
e5a1caee
JG
1210 }
1211
1212 if (gnh->ver != 0) {
1213 VLOG_WARN_RL(&err_rl, "unknown geneve version: %"PRIu8"\n", gnh->ver);
d625fbd1 1214 return EINVAL;
e5a1caee
JG
1215 }
1216
1217 if (gnh->opt_len && gnh->critical) {
1218 VLOG_WARN_RL(&err_rl, "unknown geneve critical options: %"PRIu8" bytes\n",
1219 gnh->opt_len * 4);
d625fbd1 1220 return EINVAL;
e5a1caee
JG
1221 }
1222
1223 if (gnh->proto_type != htons(ETH_TYPE_TEB)) {
1224 VLOG_WARN_RL(&err_rl, "unknown geneve encapsulated protocol: %#x\n",
1225 ntohs(gnh->proto_type));
d625fbd1 1226 return EINVAL;
e5a1caee
JG
1227 }
1228
1229 tnl->flags |= gnh->oam ? FLOW_TNL_F_OAM : 0;
1230 tnl->tun_id = htonll(ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
1231 tnl->flags |= FLOW_TNL_F_KEY;
1232
1233 dp_packet_reset_packet(packet, hlen);
e5a1caee 1234
e5a1caee
JG
1235 return 0;
1236}
1237
1238static int
1239netdev_geneve_build_header(const struct netdev *netdev,
1240 struct ovs_action_push_tnl *data,
1241 const struct flow *tnl_flow)
1242{
1243 struct netdev_vport *dev = netdev_vport_cast(netdev);
1244 struct netdev_tunnel_config *tnl_cfg;
1245 struct genevehdr *gnh;
1246
1247 /* XXX: RCUfy tnl_cfg. */
1248 ovs_mutex_lock(&dev->mutex);
1249 tnl_cfg = &dev->tnl_cfg;
1250
8e45fe7c 1251 gnh = udp_build_header(tnl_cfg, tnl_flow, data);
e5a1caee
JG
1252
1253 gnh->oam = !!(tnl_flow->tunnel.flags & FLOW_TNL_F_OAM);
1254 gnh->proto_type = htons(ETH_TYPE_TEB);
1255 put_16aligned_be32(&gnh->vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
1256
1257 ovs_mutex_unlock(&dev->mutex);
1258 data->header_len = GENEVE_BASE_HLEN;
1259 data->tnl_type = OVS_VPORT_TYPE_GENEVE;
1260 return 0;
1261}
1262
a36de779
PS
1263static void
1264netdev_vport_range(struct unixctl_conn *conn, int argc,
1265 const char *argv[], void *aux OVS_UNUSED)
1266{
1267 int val1, val2;
1268
1269 if (argc < 3) {
1270 struct ds ds = DS_EMPTY_INITIALIZER;
1271
1272 ds_put_format(&ds, "Tunnel UDP source port range: %"PRIu16"-%"PRIu16"\n",
1273 tnl_udp_port_min, tnl_udp_port_max);
1274
1275 unixctl_command_reply(conn, ds_cstr(&ds));
1276 ds_destroy(&ds);
1277 return;
1278 }
1279
1280 if (argc != 3) {
1281 return;
1282 }
1283
1284 val1 = atoi(argv[1]);
1285 if (val1 <= 0 || val1 > UINT16_MAX) {
1286 unixctl_command_reply(conn, "Invalid min.");
1287 return;
1288 }
1289 val2 = atoi(argv[2]);
1290 if (val2 <= 0 || val2 > UINT16_MAX) {
1291 unixctl_command_reply(conn, "Invalid max.");
1292 return;
1293 }
1294
1295 if (val1 > val2) {
1296 tnl_udp_port_min = val2;
1297 tnl_udp_port_max = val1;
1298 } else {
1299 tnl_udp_port_min = val1;
1300 tnl_udp_port_max = val2;
1301 }
1302 seq_change(tnl_conf_seq);
1303
1304 unixctl_command_reply(conn, "OK");
1305}
1306
2b9d6589 1307\f
0a740f48 1308#define VPORT_FUNCTIONS(GET_CONFIG, SET_CONFIG, \
a36de779
PS
1309 GET_TUNNEL_CONFIG, GET_STATUS, \
1310 BUILD_HEADER, \
1311 PUSH_HEADER, POP_HEADER) \
b46ccdf5 1312 NULL, \
ea83a2fc
EJ
1313 netdev_vport_run, \
1314 netdev_vport_wait, \
2b9d6589 1315 \
9dc63482
BP
1316 netdev_vport_alloc, \
1317 netdev_vport_construct, \
1318 netdev_vport_destruct, \
1319 netdev_vport_dealloc, \
0a740f48
EJ
1320 GET_CONFIG, \
1321 SET_CONFIG, \
f431bf7d 1322 GET_TUNNEL_CONFIG, \
a36de779
PS
1323 BUILD_HEADER, \
1324 PUSH_HEADER, \
1325 POP_HEADER, \
7dec44fe 1326 NULL, /* get_numa_id */ \
5496878c 1327 NULL, /* set_multiq */ \
2b9d6589 1328 \
552e20d0 1329 NULL, /* send */ \
2b9d6589
BP
1330 NULL, /* send_wait */ \
1331 \
1332 netdev_vport_set_etheraddr, \
1333 netdev_vport_get_etheraddr, \
14622f22
BP
1334 NULL, /* get_mtu */ \
1335 NULL, /* set_mtu */ \
2b9d6589 1336 NULL, /* get_ifindex */ \
85da620e 1337 NULL, /* get_carrier */ \
65c3058c 1338 NULL, /* get_carrier_resets */ \
63331829 1339 NULL, /* get_miimon */ \
b9ad7294 1340 get_stats, \
2b9d6589
BP
1341 \
1342 NULL, /* get_features */ \
1343 NULL, /* set_advertisements */ \
2b9d6589
BP
1344 \
1345 NULL, /* set_policing */ \
1346 NULL, /* get_qos_types */ \
1347 NULL, /* get_qos_capabilities */ \
1348 NULL, /* get_qos */ \
1349 NULL, /* set_qos */ \
1350 NULL, /* get_queue */ \
1351 NULL, /* set_queue */ \
1352 NULL, /* delete_queue */ \
1353 NULL, /* get_queue_stats */ \
89454bf4
BP
1354 NULL, /* queue_dump_start */ \
1355 NULL, /* queue_dump_next */ \
1356 NULL, /* queue_dump_done */ \
2b9d6589
BP
1357 NULL, /* dump_queue_stats */ \
1358 \
1359 NULL, /* get_in4 */ \
1360 NULL, /* set_in4 */ \
1361 NULL, /* get_in6 */ \
1362 NULL, /* add_router */ \
1363 NULL, /* get_next_hop */ \
ea763e0e 1364 GET_STATUS, \
2b9d6589
BP
1365 NULL, /* arp_lookup */ \
1366 \
1367 netdev_vport_update_flags, \
1368 \
9dc63482
BP
1369 NULL, /* rx_alloc */ \
1370 NULL, /* rx_construct */ \
1371 NULL, /* rx_destruct */ \
1372 NULL, /* rx_dealloc */ \
1373 NULL, /* rx_recv */ \
1374 NULL, /* rx_wait */ \
1375 NULL, /* rx_drain */
2b9d6589 1376
a36de779
PS
1377
1378#define TUNNEL_CLASS(NAME, DPIF_PORT, BUILD_HEADER, PUSH_HEADER, POP_HEADER) \
1379 { DPIF_PORT, \
1380 { NAME, VPORT_FUNCTIONS(get_tunnel_config, \
1381 set_tunnel_config, \
1382 get_netdev_tunnel_config, \
1383 tunnel_get_status, \
1384 BUILD_HEADER, PUSH_HEADER, POP_HEADER) }}
db078f85 1385
2b9d6589 1386void
c060c4cf 1387netdev_vport_tunnel_register(void)
2b9d6589 1388{
a5d4fadd
JG
1389 /* The name of the dpif_port should be short enough to accomodate adding
1390 * a port number to the end if one is necessary. */
c3827f61 1391 static const struct vport_class vport_classes[] = {
e5a1caee 1392 TUNNEL_CLASS("geneve", "genev_sys", netdev_geneve_build_header,
d625fbd1 1393 push_udp_header,
e5a1caee 1394 netdev_geneve_pop_header),
a36de779
PS
1395 TUNNEL_CLASS("gre", "gre_sys", netdev_gre_build_header,
1396 netdev_gre_push_header,
1397 netdev_gre_pop_header),
1398 TUNNEL_CLASS("ipsec_gre", "gre_sys", NULL, NULL, NULL),
1399 TUNNEL_CLASS("gre64", "gre64_sys", NULL, NULL, NULL),
1400 TUNNEL_CLASS("ipsec_gre64", "gre64_sys", NULL, NULL, NULL),
1401 TUNNEL_CLASS("vxlan", "vxlan_sys", netdev_vxlan_build_header,
d625fbd1 1402 push_udp_header,
a36de779
PS
1403 netdev_vxlan_pop_header),
1404 TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL)
c3827f61 1405 };
86383816 1406 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
c3827f61 1407
86383816
BP
1408 if (ovsthread_once_start(&once)) {
1409 int i;
c3827f61 1410
7c54c27f
BP
1411 for (i = 0; i < ARRAY_SIZE(vport_classes); i++) {
1412 netdev_register_provider(&vport_classes[i].netdev_class);
1413 }
a36de779
PS
1414
1415 unixctl_command_register("tnl/egress_port_range", "min max", 0, 2,
1416 netdev_vport_range, NULL);
1417
86383816 1418 ovsthread_once_done(&once);
c3827f61 1419 }
2b9d6589 1420}
c060c4cf
EJ
1421
1422void
1423netdev_vport_patch_register(void)
1424{
1425 static const struct vport_class patch_class =
1426 { NULL,
1427 { "patch", VPORT_FUNCTIONS(get_patch_config,
1428 set_patch_config,
1429 NULL,
a36de779 1430 NULL, NULL, NULL, NULL) }};
c060c4cf
EJ
1431 netdev_register_provider(&patch_class.netdev_class);
1432}