]> git.proxmox.com Git - mirror_ovs.git/blame - lib/netdev-vport.c
dpif-netdev: Don't run port names through netdev_vport_get_dpif_port().
[mirror_ovs.git] / lib / netdev-vport.c
CommitLineData
777ece09 1/*
9284baa2 2 * Copyright (c) 2010, 2011, 2012, 2013 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"
5059eff3
JP
28#include "daemon.h"
29#include "dirs.h"
0a740f48 30#include "dpif.h"
ea83a2fc
EJ
31#include "hash.h"
32#include "hmap.h"
777ece09 33#include "list.h"
2b9d6589 34#include "netdev-provider.h"
ea83a2fc 35#include "ofpbuf.h"
2b9d6589 36#include "packets.h"
a132aa96 37#include "route-table.h"
777ece09
JG
38#include "shash.h"
39#include "socket-util.h"
777ece09
JG
40#include "vlog.h"
41
d98e6007 42VLOG_DEFINE_THIS_MODULE(netdev_vport);
5136ce49 43
4f2abb7b 44#define VXLAN_DST_PORT 4789
a6ae068b
LJ
45#define LISP_DST_PORT 4341
46
f431bf7d
EJ
47#define DEFAULT_TTL 64
48
b5d57fc8
BP
49struct netdev_vport {
50 struct netdev up;
ac4d3bcb 51 unsigned int change_seq;
35b769cb 52 uint8_t etheraddr[ETH_ADDR_LEN];
b9ad7294 53 struct netdev_stats stats;
0a740f48
EJ
54
55 /* Tunnels. */
f431bf7d 56 struct netdev_tunnel_config tnl_cfg;
0a740f48
EJ
57
58 /* Patch Ports. */
0a740f48 59 char *peer;
2b9d6589
BP
60};
61
2b9d6589 62struct vport_class {
b9ad7294 63 const char *dpif_port;
c3827f61 64 struct netdev_class netdev_class;
2b9d6589
BP
65};
66
2b9d6589 67static int netdev_vport_create(const struct netdev_class *, const char *,
b5d57fc8
BP
68 struct netdev **);
69static int get_patch_config(const struct netdev *, struct smap *args);
70static int get_tunnel_config(const struct netdev *, struct smap *args);
71static void netdev_vport_poll_notify(struct netdev_vport *);
2b9d6589
BP
72
73static bool
74is_vport_class(const struct netdev_class *class)
777ece09 75{
2b9d6589
BP
76 return class->create == netdev_vport_create;
77}
777ece09 78
2b9d6589
BP
79static const struct vport_class *
80vport_class_cast(const struct netdev_class *class)
81{
cb22974d 82 ovs_assert(is_vport_class(class));
2b9d6589
BP
83 return CONTAINER_OF(class, struct vport_class, netdev_class);
84}
85
b5d57fc8
BP
86static struct netdev_vport *
87netdev_vport_cast(const struct netdev *netdev)
2b9d6589 88{
b5d57fc8
BP
89 ovs_assert(is_vport_class(netdev_get_class(netdev)));
90 return CONTAINER_OF(netdev, struct netdev_vport, up);
df67d7ae
EJ
91}
92
f431bf7d 93static const struct netdev_tunnel_config *
b5d57fc8 94get_netdev_tunnel_config(const struct netdev *netdev)
f431bf7d 95{
b5d57fc8 96 return &netdev_vport_cast(netdev)->tnl_cfg;
f431bf7d
EJ
97}
98
0a740f48
EJ
99bool
100netdev_vport_is_patch(const struct netdev *netdev)
101{
b5d57fc8 102 const struct netdev_class *class = netdev_get_class(netdev);
f18a39b7 103
c060c4cf 104 return class->get_config == get_patch_config;
0a740f48
EJ
105}
106
56b11f0b 107static bool
b5d57fc8 108netdev_vport_needs_dst_port(const struct netdev *dev)
56b11f0b 109{
b5d57fc8
BP
110 const struct netdev_class *class = netdev_get_class(dev);
111 const char *type = netdev_get_type(dev);
56b11f0b 112
a6ae068b
LJ
113 return (class->get_config == get_tunnel_config &&
114 (!strcmp("vxlan", type) || !strcmp("lisp", type)));
56b11f0b
KM
115}
116
94a53842
AW
117const char *
118netdev_vport_class_get_dpif_port(const struct netdev_class *class)
119{
120 return is_vport_class(class) ? vport_class_cast(class)->dpif_port : NULL;
121}
122
de281153
EJ
123const char *
124netdev_vport_get_dpif_port(const struct netdev *netdev)
125{
b9ad7294 126 const char *dpif_port;
c19e6535 127
b5d57fc8
BP
128 if (netdev_vport_needs_dst_port(netdev)) {
129 const struct netdev_vport *vport = netdev_vport_cast(netdev);
130 const char *type = netdev_get_type(netdev);
a6ae068b 131 static char dpif_port_combined[IFNAMSIZ];
56b11f0b
KM
132
133 /*
134 * Note: IFNAMSIZ is 16 bytes long. The maximum length of a VXLAN
a6ae068b
LJ
135 * or LISP port name below is 15 or 14 bytes respectively. Still,
136 * assert here on the size of strlen(type) in case that changes
137 * in the future.
56b11f0b
KM
138 */
139 ovs_assert(strlen(type) + 10 < IFNAMSIZ);
a6ae068b 140 snprintf(dpif_port_combined, IFNAMSIZ, "%s_sys_%d", type,
56b11f0b 141 ntohs(vport->tnl_cfg.dst_port));
a6ae068b 142 return dpif_port_combined;
56b11f0b 143 } else {
b5d57fc8 144 const struct netdev_class *class = netdev_get_class(netdev);
94a53842 145 dpif_port = netdev_vport_class_get_dpif_port(class);
56b11f0b
KM
146 }
147
b9ad7294 148 return dpif_port ? dpif_port : netdev_get_name(netdev);
2b9d6589 149}
777ece09 150
2b9d6589 151static int
c3827f61 152netdev_vport_create(const struct netdev_class *netdev_class, const char *name,
b5d57fc8 153 struct netdev **netdevp)
2b9d6589 154{
b5d57fc8 155 struct netdev_vport *dev;
6d9e6eb4 156
f431bf7d 157 dev = xzalloc(sizeof *dev);
b5d57fc8 158 netdev_init(&dev->up, name, netdev_class);
de5cdb90 159 dev->change_seq = 1;
35b769cb 160 eth_addr_random(dev->etheraddr);
6d9e6eb4 161
b5d57fc8 162 *netdevp = &dev->up;
de5cdb90 163 route_table_register();
6d9e6eb4 164
de5cdb90 165 return 0;
777ece09
JG
166}
167
2b9d6589 168static void
b5d57fc8 169netdev_vport_destroy(struct netdev *netdev_)
2b9d6589 170{
b5d57fc8 171 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
2b9d6589 172
a132aa96 173 route_table_unregister();
b5d57fc8 174 free(netdev->peer);
2b9d6589
BP
175 free(netdev);
176}
177
2b9d6589 178static int
b5d57fc8 179netdev_vport_set_etheraddr(struct netdev *netdev_,
777ece09
JG
180 const uint8_t mac[ETH_ADDR_LEN])
181{
b5d57fc8
BP
182 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
183 memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
184 netdev_vport_poll_notify(netdev);
35b769cb 185 return 0;
777ece09
JG
186}
187
2b9d6589 188static int
777ece09
JG
189netdev_vport_get_etheraddr(const struct netdev *netdev,
190 uint8_t mac[ETH_ADDR_LEN])
191{
b5d57fc8 192 memcpy(mac, netdev_vport_cast(netdev)->etheraddr, ETH_ADDR_LEN);
35b769cb 193 return 0;
777ece09
JG
194}
195
ea763e0e 196static int
275707c3 197tunnel_get_status(const struct netdev *netdev, struct smap *smap)
ea763e0e 198{
3dea0874 199 char iface[IFNAMSIZ];
275707c3 200 ovs_be32 route;
ea763e0e 201
b5d57fc8 202 route = netdev_vport_cast(netdev)->tnl_cfg.ip_dst;
275707c3 203 if (route_table_get_name(route, iface)) {
a404826e
AE
204 struct netdev *egress_netdev;
205
79f1cbe9 206 smap_add(smap, "tunnel_egress_iface", iface);
a404826e 207
18812dff 208 if (!netdev_open(iface, "system", &egress_netdev)) {
79f1cbe9
EJ
209 smap_add(smap, "tunnel_egress_iface_carrier",
210 netdev_get_carrier(egress_netdev) ? "up" : "down");
a404826e
AE
211 netdev_close(egress_netdev);
212 }
ea763e0e
EJ
213 }
214
215 return 0;
216}
217
2b9d6589 218static int
b5d57fc8
BP
219netdev_vport_update_flags(struct netdev *netdev OVS_UNUSED,
220 enum netdev_flags off,
221 enum netdev_flags on OVS_UNUSED,
222 enum netdev_flags *old_flagsp)
777ece09
JG
223{
224 if (off & (NETDEV_UP | NETDEV_PROMISC)) {
225 return EOPNOTSUPP;
226 }
227
228 *old_flagsp = NETDEV_UP | NETDEV_PROMISC;
229 return 0;
230}
231
ac4d3bcb
EJ
232static unsigned int
233netdev_vport_change_seq(const struct netdev *netdev)
234{
b5d57fc8 235 return netdev_vport_cast(netdev)->change_seq;
ac4d3bcb
EJ
236}
237
ea83a2fc
EJ
238static void
239netdev_vport_run(void)
240{
a132aa96 241 route_table_run();
ea83a2fc
EJ
242}
243
244static void
245netdev_vport_wait(void)
246{
a132aa96 247 route_table_wait();
ea83a2fc
EJ
248}
249\f
2b9d6589 250/* Helper functions. */
777ece09 251
2b9d6589 252static void
b5d57fc8 253netdev_vport_poll_notify(struct netdev_vport *ndv)
777ece09 254{
ac4d3bcb
EJ
255 ndv->change_seq++;
256 if (!ndv->change_seq) {
257 ndv->change_seq++;
258 }
777ece09 259}
2b9d6589 260\f
0a740f48 261/* Code specific to tunnel types. */
2b9d6589 262
f431bf7d
EJ
263static ovs_be64
264parse_key(const struct smap *args, const char *name,
265 bool *present, bool *flow)
c19e6535
BP
266{
267 const char *s;
268
f431bf7d
EJ
269 *present = false;
270 *flow = false;
271
79f1cbe9 272 s = smap_get(args, name);
c19e6535 273 if (!s) {
79f1cbe9 274 s = smap_get(args, "key");
c19e6535 275 if (!s) {
f431bf7d 276 return 0;
c19e6535
BP
277 }
278 }
279
f431bf7d
EJ
280 *present = true;
281
c19e6535 282 if (!strcmp(s, "flow")) {
f431bf7d
EJ
283 *flow = true;
284 return 0;
c19e6535 285 } else {
f431bf7d 286 return htonll(strtoull(s, NULL, 0));
c19e6535
BP
287 }
288}
289
2b9d6589 290static int
b5d57fc8 291set_tunnel_config(struct netdev *dev_, const struct smap *args)
2b9d6589 292{
b5d57fc8
BP
293 struct netdev_vport *dev = netdev_vport_cast(dev_);
294 const char *name = netdev_get_name(dev_);
295 const char *type = netdev_get_type(dev_);
f431bf7d
EJ
296 bool ipsec_mech_set, needs_dst_port, has_csum;
297 struct netdev_tunnel_config tnl_cfg;
79f1cbe9 298 struct smap_node *node;
f431bf7d 299
f431bf7d
EJ
300 has_csum = strstr(type, "gre");
301 ipsec_mech_set = false;
302 memset(&tnl_cfg, 0, sizeof tnl_cfg);
2b9d6589 303
a6ae068b 304 needs_dst_port = netdev_vport_needs_dst_port(dev_);
f431bf7d 305 tnl_cfg.ipsec = strstr(type, "ipsec");
f431bf7d 306 tnl_cfg.dont_fragment = true;
e16a28b5 307
79f1cbe9
EJ
308 SMAP_FOR_EACH (node, args) {
309 if (!strcmp(node->key, "remote_ip")) {
2b9d6589 310 struct in_addr in_addr;
0ad90c84
JR
311 if (!strcmp(node->value, "flow")) {
312 tnl_cfg.ip_dst_flow = true;
313 tnl_cfg.ip_dst = htonl(0);
314 } else if (lookup_ip(node->value, &in_addr)) {
c3827f61 315 VLOG_WARN("%s: bad %s 'remote_ip'", name, type);
85c9de19
PS
316 } else if (ip_is_multicast(in_addr.s_addr)) {
317 VLOG_WARN("%s: multicast remote_ip="IP_FMT" not allowed",
318 name, IP_ARGS(in_addr.s_addr));
319 return EINVAL;
2b9d6589 320 } else {
f431bf7d 321 tnl_cfg.ip_dst = in_addr.s_addr;
2b9d6589 322 }
79f1cbe9 323 } else if (!strcmp(node->key, "local_ip")) {
2b9d6589 324 struct in_addr in_addr;
0ad90c84
JR
325 if (!strcmp(node->value, "flow")) {
326 tnl_cfg.ip_src_flow = true;
327 tnl_cfg.ip_src = htonl(0);
328 } else if (lookup_ip(node->value, &in_addr)) {
c3827f61 329 VLOG_WARN("%s: bad %s 'local_ip'", name, type);
2b9d6589 330 } else {
f431bf7d 331 tnl_cfg.ip_src = in_addr.s_addr;
2b9d6589 332 }
79f1cbe9
EJ
333 } else if (!strcmp(node->key, "tos")) {
334 if (!strcmp(node->value, "inherit")) {
f431bf7d 335 tnl_cfg.tos_inherit = true;
2b9d6589 336 } else {
3fca7064
PS
337 char *endptr;
338 int tos;
79f1cbe9 339 tos = strtol(node->value, &endptr, 0);
91aff446 340 if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
f431bf7d 341 tnl_cfg.tos = tos;
91aff446
BP
342 } else {
343 VLOG_WARN("%s: invalid TOS %s", name, node->value);
3fca7064 344 }
2b9d6589 345 }
79f1cbe9
EJ
346 } else if (!strcmp(node->key, "ttl")) {
347 if (!strcmp(node->value, "inherit")) {
f431bf7d 348 tnl_cfg.ttl_inherit = true;
2b9d6589 349 } else {
f431bf7d 350 tnl_cfg.ttl = atoi(node->value);
2b9d6589 351 }
79f827fa 352 } else if (!strcmp(node->key, "dst_port") && needs_dst_port) {
f431bf7d 353 tnl_cfg.dst_port = htons(atoi(node->value));
f431bf7d 354 } else if (!strcmp(node->key, "csum") && has_csum) {
79f1cbe9 355 if (!strcmp(node->value, "true")) {
f431bf7d 356 tnl_cfg.csum = true;
2b9d6589 357 }
79f1cbe9
EJ
358 } else if (!strcmp(node->key, "df_default")) {
359 if (!strcmp(node->value, "false")) {
f431bf7d 360 tnl_cfg.dont_fragment = false;
66409d1b 361 }
f431bf7d 362 } else if (!strcmp(node->key, "peer_cert") && tnl_cfg.ipsec) {
79f1cbe9 363 if (smap_get(args, "certificate")) {
3c52fa7b
JP
364 ipsec_mech_set = true;
365 } else {
ef7ee76a
JP
366 const char *use_ssl_cert;
367
368 /* If the "use_ssl_cert" is true, then "certificate" and
369 * "private_key" will be pulled from the SSL table. The
370 * use of this option is strongly discouraged, since it
371 * will like be removed when multiple SSL configurations
372 * are supported by OVS.
373 */
79f1cbe9 374 use_ssl_cert = smap_get(args, "use_ssl_cert");
ef7ee76a 375 if (!use_ssl_cert || strcmp(use_ssl_cert, "true")) {
8283e514
JP
376 VLOG_ERR("%s: 'peer_cert' requires 'certificate' argument",
377 name);
b9ad7294 378 return EINVAL;
ef7ee76a
JP
379 }
380 ipsec_mech_set = true;
3c52fa7b 381 }
f431bf7d 382 } else if (!strcmp(node->key, "psk") && tnl_cfg.ipsec) {
2b9d6589 383 ipsec_mech_set = true;
f431bf7d 384 } else if (tnl_cfg.ipsec
79f1cbe9
EJ
385 && (!strcmp(node->key, "certificate")
386 || !strcmp(node->key, "private_key")
387 || !strcmp(node->key, "use_ssl_cert"))) {
3c52fa7b 388 /* Ignore options not used by the netdev. */
79f1cbe9
EJ
389 } else if (!strcmp(node->key, "key") ||
390 !strcmp(node->key, "in_key") ||
391 !strcmp(node->key, "out_key")) {
c19e6535 392 /* Handled separately below. */
2b9d6589 393 } else {
79f1cbe9 394 VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
2b9d6589
BP
395 }
396 }
397
79f827fa 398 /* Add a default destination port for VXLAN if none specified. */
a6ae068b 399 if (!strcmp(type, "vxlan") && !tnl_cfg.dst_port) {
f431bf7d 400 tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
79f827fa
KM
401 }
402
a6ae068b
LJ
403 /* Add a default destination port for LISP if none specified. */
404 if (!strcmp(type, "lisp") && !tnl_cfg.dst_port) {
405 tnl_cfg.dst_port = htons(LISP_DST_PORT);
406 }
407
f431bf7d 408 if (tnl_cfg.ipsec) {
2a586a5c 409 static pid_t pid = 0;
900f7601 410 if (pid <= 0) {
2a586a5c
AS
411 char *file_name = xasprintf("%s/%s", ovs_rundir(),
412 "ovs-monitor-ipsec.pid");
413 pid = read_pidfile(file_name);
414 free(file_name);
415 }
416
e7009c36 417 if (pid < 0) {
8283e514
JP
418 VLOG_ERR("%s: IPsec requires the ovs-monitor-ipsec daemon",
419 name);
b9ad7294 420 return EINVAL;
e7009c36 421 }
5059eff3 422
79f1cbe9 423 if (smap_get(args, "peer_cert") && smap_get(args, "psk")) {
8283e514 424 VLOG_ERR("%s: cannot define both 'peer_cert' and 'psk'", name);
b9ad7294 425 return EINVAL;
3c52fa7b
JP
426 }
427
428 if (!ipsec_mech_set) {
8283e514
JP
429 VLOG_ERR("%s: IPsec requires an 'peer_cert' or psk' argument",
430 name);
b9ad7294 431 return EINVAL;
3c52fa7b 432 }
2b9d6589
BP
433 }
434
0ad90c84 435 if (!tnl_cfg.ip_dst && !tnl_cfg.ip_dst_flow) {
8283e514
JP
436 VLOG_ERR("%s: %s type requires valid 'remote_ip' argument",
437 name, type);
b9ad7294 438 return EINVAL;
2b9d6589 439 }
0ad90c84
JR
440 if (tnl_cfg.ip_src_flow && !tnl_cfg.ip_dst_flow) {
441 VLOG_ERR("%s: %s type requires 'remote_ip=flow' with 'local_ip=flow'",
442 name, type);
443 return EINVAL;
444 }
f431bf7d
EJ
445 if (!tnl_cfg.ttl) {
446 tnl_cfg.ttl = DEFAULT_TTL;
447 }
448
449 tnl_cfg.in_key = parse_key(args, "in_key",
450 &tnl_cfg.in_key_present,
451 &tnl_cfg.in_key_flow);
f431bf7d
EJ
452
453 tnl_cfg.out_key = parse_key(args, "out_key",
454 &tnl_cfg.out_key_present,
455 &tnl_cfg.out_key_flow);
2b9d6589 456
0a740f48 457 dev->tnl_cfg = tnl_cfg;
b9ad7294 458 netdev_vport_poll_notify(dev);
f431bf7d 459
c19e6535
BP
460 return 0;
461}
462
2b9d6589 463static int
b5d57fc8 464get_tunnel_config(const struct netdev *dev, struct smap *args)
6d9e6eb4 465{
b9ad7294 466 const struct netdev_tunnel_config *tnl_cfg =
b5d57fc8 467 &netdev_vport_cast(dev)->tnl_cfg;
6d9e6eb4 468
b9ad7294
EJ
469 if (tnl_cfg->ip_dst) {
470 smap_add_format(args, "remote_ip", IP_FMT, IP_ARGS(tnl_cfg->ip_dst));
0ad90c84
JR
471 } else if (tnl_cfg->ip_dst_flow) {
472 smap_add(args, "remote_ip", "flow");
0a740f48
EJ
473 }
474
b9ad7294
EJ
475 if (tnl_cfg->ip_src) {
476 smap_add_format(args, "local_ip", IP_FMT, IP_ARGS(tnl_cfg->ip_src));
0ad90c84
JR
477 } else if (tnl_cfg->ip_src_flow) {
478 smap_add(args, "local_ip", "flow");
7f804ea5 479 }
c19e6535 480
b9ad7294 481 if (tnl_cfg->in_key_flow && tnl_cfg->out_key_flow) {
6d9e6eb4 482 smap_add(args, "key", "flow");
b9ad7294
EJ
483 } else if (tnl_cfg->in_key_present && tnl_cfg->out_key_present
484 && tnl_cfg->in_key == tnl_cfg->out_key) {
485 smap_add_format(args, "key", "%"PRIu64, ntohll(tnl_cfg->in_key));
6d9e6eb4 486 } else {
b9ad7294
EJ
487 if (tnl_cfg->in_key_flow) {
488 smap_add(args, "in_key", "flow");
489 } else if (tnl_cfg->in_key_present) {
490 smap_add_format(args, "in_key", "%"PRIu64,
491 ntohll(tnl_cfg->in_key));
492 }
6d9e6eb4 493
b9ad7294
EJ
494 if (tnl_cfg->out_key_flow) {
495 smap_add(args, "out_key", "flow");
496 } else if (tnl_cfg->out_key_present) {
497 smap_add_format(args, "out_key", "%"PRIu64,
498 ntohll(tnl_cfg->out_key));
6d9e6eb4
BP
499 }
500 }
501
b9ad7294 502 if (tnl_cfg->ttl_inherit) {
62827e6a 503 smap_add(args, "ttl", "inherit");
b9ad7294
EJ
504 } else if (tnl_cfg->ttl != DEFAULT_TTL) {
505 smap_add_format(args, "ttl", "%"PRIu8, tnl_cfg->ttl);
c19e6535
BP
506 }
507
b9ad7294 508 if (tnl_cfg->tos_inherit) {
6d9e6eb4 509 smap_add(args, "tos", "inherit");
b9ad7294
EJ
510 } else if (tnl_cfg->tos) {
511 smap_add_format(args, "tos", "0x%x", tnl_cfg->tos);
6d9e6eb4
BP
512 }
513
b9ad7294
EJ
514 if (tnl_cfg->dst_port) {
515 uint16_t dst_port = ntohs(tnl_cfg->dst_port);
b5d57fc8 516 const char *type = netdev_get_type(dev);
9eeb949b
KM
517
518 if ((!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
519 (!strcmp("lisp", type) && dst_port != LISP_DST_PORT)) {
79f827fa
KM
520 smap_add_format(args, "dst_port", "%d", dst_port);
521 }
522 }
523
b9ad7294 524 if (tnl_cfg->csum) {
6d9e6eb4
BP
525 smap_add(args, "csum", "true");
526 }
8a9ff93a 527
b9ad7294 528 if (!tnl_cfg->dont_fragment) {
66409d1b
AE
529 smap_add(args, "df_default", "false");
530 }
6d9e6eb4
BP
531
532 return 0;
533}
0a740f48
EJ
534\f
535/* Code specific to patch ports. */
536
537const char *
538netdev_vport_patch_peer(const struct netdev *netdev)
539{
b5d57fc8
BP
540 return (netdev_vport_is_patch(netdev)
541 ? netdev_vport_cast(netdev)->peer
542 : NULL);
0a740f48
EJ
543}
544
545void
b9ad7294 546netdev_vport_inc_rx(const struct netdev *netdev,
0a740f48
EJ
547 const struct dpif_flow_stats *stats)
548{
b5d57fc8
BP
549 if (is_vport_class(netdev_get_class(netdev))) {
550 struct netdev_vport *dev = netdev_vport_cast(netdev);
0a740f48
EJ
551 dev->stats.rx_packets += stats->n_packets;
552 dev->stats.rx_bytes += stats->n_bytes;
553 }
554}
555
556void
b9ad7294
EJ
557netdev_vport_inc_tx(const struct netdev *netdev,
558 const struct dpif_flow_stats *stats)
0a740f48 559{
b5d57fc8
BP
560 if (is_vport_class(netdev_get_class(netdev))) {
561 struct netdev_vport *dev = netdev_vport_cast(netdev);
0a740f48
EJ
562 dev->stats.tx_packets += stats->n_packets;
563 dev->stats.tx_bytes += stats->n_bytes;
564 }
565}
566
567static int
b5d57fc8 568get_patch_config(const struct netdev *dev_, struct smap *args)
0a740f48 569{
b5d57fc8 570 struct netdev_vport *dev = netdev_vport_cast(dev_);
0a740f48
EJ
571
572 if (dev->peer) {
573 smap_add(args, "peer", dev->peer);
574 }
575 return 0;
576}
6d9e6eb4
BP
577
578static int
b5d57fc8 579set_patch_config(struct netdev *dev_, const struct smap *args)
2b9d6589 580{
b5d57fc8
BP
581 struct netdev_vport *dev = netdev_vport_cast(dev_);
582 const char *name = netdev_get_name(dev_);
2b9d6589
BP
583 const char *peer;
584
79f1cbe9 585 peer = smap_get(args, "peer");
2b9d6589 586 if (!peer) {
8283e514 587 VLOG_ERR("%s: patch type requires valid 'peer' argument", name);
2b9d6589
BP
588 return EINVAL;
589 }
590
79f1cbe9 591 if (smap_count(args) > 1) {
8283e514 592 VLOG_ERR("%s: patch type takes only a 'peer' argument", name);
2b9d6589
BP
593 return EINVAL;
594 }
595
2b9d6589 596 if (!strcmp(name, peer)) {
8283e514 597 VLOG_ERR("%s: patch peer must not be self", name);
2b9d6589
BP
598 return EINVAL;
599 }
600
0a740f48
EJ
601 free(dev->peer);
602 dev->peer = xstrdup(peer);
2b9d6589
BP
603
604 return 0;
605}
6d9e6eb4
BP
606
607static int
b9ad7294 608get_stats(const struct netdev *netdev, struct netdev_stats *stats)
0a740f48 609{
b5d57fc8 610 struct netdev_vport *dev = netdev_vport_cast(netdev);
0a740f48 611 memcpy(stats, &dev->stats, sizeof *stats);
6d9e6eb4
BP
612 return 0;
613}
2b9d6589 614\f
0a740f48 615#define VPORT_FUNCTIONS(GET_CONFIG, SET_CONFIG, \
b9ad7294 616 GET_TUNNEL_CONFIG, GET_STATUS) \
b46ccdf5 617 NULL, \
ea83a2fc
EJ
618 netdev_vport_run, \
619 netdev_vport_wait, \
2b9d6589
BP
620 \
621 netdev_vport_create, \
622 netdev_vport_destroy, \
0a740f48
EJ
623 GET_CONFIG, \
624 SET_CONFIG, \
f431bf7d 625 GET_TUNNEL_CONFIG, \
2b9d6589 626 \
796223f5 627 NULL, /* rx_open */ \
2b9d6589 628 \
552e20d0 629 NULL, /* send */ \
2b9d6589
BP
630 NULL, /* send_wait */ \
631 \
632 netdev_vport_set_etheraddr, \
633 netdev_vport_get_etheraddr, \
14622f22
BP
634 NULL, /* get_mtu */ \
635 NULL, /* set_mtu */ \
2b9d6589 636 NULL, /* get_ifindex */ \
85da620e 637 NULL, /* get_carrier */ \
65c3058c 638 NULL, /* get_carrier_resets */ \
63331829 639 NULL, /* get_miimon */ \
b9ad7294 640 get_stats, \
2f31a822 641 NULL, /* set_stats */ \
2b9d6589
BP
642 \
643 NULL, /* get_features */ \
644 NULL, /* set_advertisements */ \
2b9d6589
BP
645 \
646 NULL, /* set_policing */ \
647 NULL, /* get_qos_types */ \
648 NULL, /* get_qos_capabilities */ \
649 NULL, /* get_qos */ \
650 NULL, /* set_qos */ \
651 NULL, /* get_queue */ \
652 NULL, /* set_queue */ \
653 NULL, /* delete_queue */ \
654 NULL, /* get_queue_stats */ \
655 NULL, /* dump_queues */ \
656 NULL, /* dump_queue_stats */ \
657 \
658 NULL, /* get_in4 */ \
659 NULL, /* set_in4 */ \
660 NULL, /* get_in6 */ \
661 NULL, /* add_router */ \
662 NULL, /* get_next_hop */ \
ea763e0e 663 GET_STATUS, \
2b9d6589
BP
664 NULL, /* arp_lookup */ \
665 \
666 netdev_vport_update_flags, \
667 \
ac4d3bcb 668 netdev_vport_change_seq
2b9d6589 669
c060c4cf
EJ
670#define TUNNEL_CLASS(NAME, DPIF_PORT) \
671 { DPIF_PORT, \
0a740f48
EJ
672 { NAME, VPORT_FUNCTIONS(get_tunnel_config, \
673 set_tunnel_config, \
674 get_netdev_tunnel_config, \
0a740f48 675 tunnel_get_status) }}
db078f85 676
2b9d6589 677void
c060c4cf 678netdev_vport_tunnel_register(void)
2b9d6589 679{
c3827f61 680 static const struct vport_class vport_classes[] = {
c060c4cf
EJ
681 TUNNEL_CLASS("gre", "gre_system"),
682 TUNNEL_CLASS("ipsec_gre", "gre_system"),
683 TUNNEL_CLASS("gre64", "gre64_system"),
684 TUNNEL_CLASS("ipsec_gre64", "gre64_system"),
a6ae068b
LJ
685 TUNNEL_CLASS("vxlan", "vxlan_system"),
686 TUNNEL_CLASS("lisp", "lisp_system")
c3827f61 687 };
7c54c27f 688 static bool inited;
c3827f61
BP
689
690 int i;
691
7c54c27f
BP
692 if (!inited) {
693 inited = true;
694 for (i = 0; i < ARRAY_SIZE(vport_classes); i++) {
695 netdev_register_provider(&vport_classes[i].netdev_class);
696 }
c3827f61 697 }
2b9d6589 698}
c060c4cf
EJ
699
700void
701netdev_vport_patch_register(void)
702{
703 static const struct vport_class patch_class =
704 { NULL,
705 { "patch", VPORT_FUNCTIONS(get_patch_config,
706 set_patch_config,
707 NULL,
708 NULL) }};
709 netdev_register_provider(&patch_class.netdev_class);
710}