]> git.proxmox.com Git - mirror_ovs.git/blame - lib/netdev-vport.c
vxlan: Use sk_release_kernel() instead of sock_release().
[mirror_ovs.git] / lib / netdev-vport.c
CommitLineData
777ece09 1/*
e0edde6f 2 * Copyright (c) 2010, 2011, 2012 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>
077257b8 24#include <linux/openvswitch.h>
ea83a2fc 25#include <linux/rtnetlink.h>
2b9d6589 26#include <net/if.h>
777ece09
JG
27#include <sys/ioctl.h>
28
b9298d3f 29#include "byte-order.h"
5059eff3
JP
30#include "daemon.h"
31#include "dirs.h"
c19e6535 32#include "dpif-linux.h"
ea83a2fc
EJ
33#include "hash.h"
34#include "hmap.h"
777ece09 35#include "list.h"
d3980822 36#include "netdev-linux.h"
2b9d6589 37#include "netdev-provider.h"
ea83a2fc 38#include "netlink.h"
45c8d3a1 39#include "netlink-notifier.h"
ea83a2fc
EJ
40#include "netlink-socket.h"
41#include "ofpbuf.h"
2b9d6589
BP
42#include "openvswitch/tunnel.h"
43#include "packets.h"
a132aa96 44#include "route-table.h"
777ece09
JG
45#include "shash.h"
46#include "socket-util.h"
69ebca1e 47#include "unaligned.h"
777ece09
JG
48#include "vlog.h"
49
d98e6007 50VLOG_DEFINE_THIS_MODULE(netdev_vport);
5136ce49 51
79f827fa
KM
52/* Default to the OTV port, per the VXLAN IETF draft. */
53#define VXLAN_DST_PORT 8472
54
2b9d6589
BP
55struct netdev_dev_vport {
56 struct netdev_dev netdev_dev;
c19e6535 57 struct ofpbuf *options;
7feba1ac
BP
58 int dp_ifindex; /* -1 if unknown. */
59 uint32_t port_no; /* UINT32_MAX if unknown. */
ac4d3bcb 60 unsigned int change_seq;
2b9d6589
BP
61};
62
63struct netdev_vport {
64 struct netdev netdev;
65};
66
2b9d6589 67struct vport_class {
df2c07f4 68 enum ovs_vport_type type;
c3827f61 69 struct netdev_class netdev_class;
6d9e6eb4 70 int (*parse_config)(const char *name, const char *type,
79f1cbe9 71 const struct smap *args, struct ofpbuf *options);
6d9e6eb4 72 int (*unparse_config)(const char *name, const char *type,
c19e6535 73 const struct nlattr *options, size_t options_len,
79f1cbe9 74 struct smap *args);
2b9d6589
BP
75};
76
777ece09
JG
77static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
78
2b9d6589 79static int netdev_vport_create(const struct netdev_class *, const char *,
de5cdb90 80 struct netdev_dev **);
2b9d6589 81static void netdev_vport_poll_notify(const struct netdev *);
c19e6535
BP
82static int tnl_port_config_from_nlattr(const struct nlattr *options,
83 size_t options_len,
df2c07f4 84 struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1]);
2b9d6589 85
ea763e0e 86static const char *netdev_vport_get_tnl_iface(const struct netdev *netdev);
ea83a2fc 87
2b9d6589
BP
88static bool
89is_vport_class(const struct netdev_class *class)
777ece09 90{
2b9d6589
BP
91 return class->create == netdev_vport_create;
92}
777ece09 93
2b9d6589
BP
94static const struct vport_class *
95vport_class_cast(const struct netdev_class *class)
96{
97 assert(is_vport_class(class));
98 return CONTAINER_OF(class, struct vport_class, netdev_class);
99}
100
101static struct netdev_dev_vport *
102netdev_dev_vport_cast(const struct netdev_dev *netdev_dev)
103{
104 assert(is_vport_class(netdev_dev_get_class(netdev_dev)));
105 return CONTAINER_OF(netdev_dev, struct netdev_dev_vport, netdev_dev);
106}
107
108static struct netdev_vport *
109netdev_vport_cast(const struct netdev *netdev)
110{
111 struct netdev_dev *netdev_dev = netdev_get_dev(netdev);
112 assert(is_vport_class(netdev_dev_get_class(netdev_dev)));
113 return CONTAINER_OF(netdev, struct netdev_vport, netdev);
114}
115
c19e6535 116/* If 'netdev' is a vport netdev, returns an ofpbuf that contains Netlink
df2c07f4 117 * options to include in OVS_VPORT_ATTR_OPTIONS for configuring that vport.
c19e6535
BP
118 * Otherwise returns NULL. */
119const struct ofpbuf *
120netdev_vport_get_options(const struct netdev *netdev)
121{
122 const struct netdev_dev *dev = netdev_get_dev(netdev);
123
124 return (is_vport_class(netdev_dev_get_class(dev))
125 ? netdev_dev_vport_cast(dev)->options
126 : NULL);
127}
128
df2c07f4 129enum ovs_vport_type
c19e6535 130netdev_vport_get_vport_type(const struct netdev *netdev)
2b9d6589 131{
c3827f61 132 const struct netdev_dev *dev = netdev_get_dev(netdev);
c19e6535
BP
133 const struct netdev_class *class = netdev_dev_get_class(dev);
134
135 return (is_vport_class(class) ? vport_class_cast(class)->type
df2c07f4 136 : class == &netdev_internal_class ? OVS_VPORT_TYPE_INTERNAL
52fa1bcf
BP
137 : (class == &netdev_linux_class ||
138 class == &netdev_tap_class) ? OVS_VPORT_TYPE_NETDEV
df2c07f4 139 : OVS_VPORT_TYPE_UNSPEC);
c19e6535
BP
140}
141
142const char *
143netdev_vport_get_netdev_type(const struct dpif_linux_vport *vport)
144{
df2c07f4 145 struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1];
c19e6535
BP
146
147 switch (vport->type) {
df2c07f4 148 case OVS_VPORT_TYPE_UNSPEC:
c19e6535
BP
149 break;
150
df2c07f4 151 case OVS_VPORT_TYPE_NETDEV:
c19e6535
BP
152 return "system";
153
df2c07f4 154 case OVS_VPORT_TYPE_INTERNAL:
c19e6535 155 return "internal";
c3827f61 156
df2c07f4 157 case OVS_VPORT_TYPE_PATCH:
c19e6535
BP
158 return "patch";
159
df2c07f4 160 case OVS_VPORT_TYPE_GRE:
c19e6535
BP
161 if (tnl_port_config_from_nlattr(vport->options, vport->options_len,
162 a)) {
163 break;
164 }
df2c07f4 165 return (nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_IPSEC
c19e6535
BP
166 ? "ipsec_gre" : "gre");
167
2de795ad
PS
168 case OVS_VPORT_TYPE_GRE64:
169 if (tnl_port_config_from_nlattr(vport->options, vport->options_len,
170 a)) {
171 break;
172 }
173 return (nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_IPSEC
174 ? "ipsec_gre64" : "gre64");
175
df2c07f4 176 case OVS_VPORT_TYPE_CAPWAP:
c19e6535
BP
177 return "capwap";
178
79f827fa
KM
179 case OVS_VPORT_TYPE_VXLAN:
180 return ("vxlan");
181
3c82d068 182 case OVS_VPORT_TYPE_FT_GRE:
df2c07f4 183 case __OVS_VPORT_TYPE_MAX:
c19e6535 184 break;
777ece09 185 }
c19e6535
BP
186
187 VLOG_WARN_RL(&rl, "dp%d: port `%s' has unsupported type %u",
254f2dc8 188 vport->dp_ifindex, vport->name, (unsigned int) vport->type);
c19e6535 189 return "unknown";
2b9d6589 190}
777ece09 191
2b9d6589 192static int
c3827f61 193netdev_vport_create(const struct netdev_class *netdev_class, const char *name,
c3827f61 194 struct netdev_dev **netdev_devp)
2b9d6589 195{
de5cdb90 196 struct netdev_dev_vport *dev;
6d9e6eb4 197
de5cdb90
BP
198 dev = xmalloc(sizeof *dev);
199 netdev_dev_init(&dev->netdev_dev, name, netdev_class);
200 dev->options = NULL;
201 dev->dp_ifindex = -1;
202 dev->port_no = UINT32_MAX;
203 dev->change_seq = 1;
6d9e6eb4 204
de5cdb90
BP
205 *netdev_devp = &dev->netdev_dev;
206 route_table_register();
6d9e6eb4 207
de5cdb90 208 return 0;
777ece09
JG
209}
210
2b9d6589
BP
211static void
212netdev_vport_destroy(struct netdev_dev *netdev_dev_)
213{
214 struct netdev_dev_vport *netdev_dev = netdev_dev_vport_cast(netdev_dev_);
215
896b3272 216 ofpbuf_delete(netdev_dev->options);
a132aa96 217 route_table_unregister();
2b9d6589
BP
218 free(netdev_dev);
219}
220
221static int
7b6b0ef4 222netdev_vport_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp)
2b9d6589
BP
223{
224 struct netdev_vport *netdev;
225
226 netdev = xmalloc(sizeof *netdev);
227 netdev_init(&netdev->netdev, netdev_dev_);
228
229 *netdevp = &netdev->netdev;
230 return 0;
231}
232
233static void
234netdev_vport_close(struct netdev *netdev_)
235{
236 struct netdev_vport *netdev = netdev_vport_cast(netdev_);
237 free(netdev);
238}
239
de5cdb90 240static int
79f1cbe9 241netdev_vport_get_config(struct netdev_dev *dev_, struct smap *args)
de5cdb90
BP
242{
243 const struct netdev_class *netdev_class = netdev_dev_get_class(dev_);
244 const struct vport_class *vport_class = vport_class_cast(netdev_class);
245 struct netdev_dev_vport *dev = netdev_dev_vport_cast(dev_);
246 const char *name = netdev_dev_get_name(dev_);
247 int error;
248
249 if (!dev->options) {
250 struct dpif_linux_vport reply;
251 struct ofpbuf *buf;
252
253 error = dpif_linux_vport_get(name, &reply, &buf);
254 if (error) {
255 VLOG_ERR_RL(&rl, "%s: vport query failed (%s)",
256 name, strerror(error));
257 return error;
258 }
259
260 dev->options = ofpbuf_clone_data(reply.options, reply.options_len);
261 dev->dp_ifindex = reply.dp_ifindex;
262 dev->port_no = reply.port_no;
263 ofpbuf_delete(buf);
264 }
265
266 error = vport_class->unparse_config(name, netdev_class->type,
267 dev->options->data,
268 dev->options->size,
269 args);
270 if (error) {
271 VLOG_ERR_RL(&rl, "%s: failed to parse kernel config (%s)",
272 name, strerror(error));
273 }
274 return error;
275}
276
2b9d6589 277static int
79f1cbe9 278netdev_vport_set_config(struct netdev_dev *dev_, const struct smap *args)
2b9d6589 279{
c3827f61
BP
280 const struct netdev_class *netdev_class = netdev_dev_get_class(dev_);
281 const struct vport_class *vport_class = vport_class_cast(netdev_class);
282 struct netdev_dev_vport *dev = netdev_dev_vport_cast(dev_);
c19e6535
BP
283 const char *name = netdev_dev_get_name(dev_);
284 struct ofpbuf *options;
c3827f61
BP
285 int error;
286
c19e6535
BP
287 options = ofpbuf_new(64);
288 error = vport_class->parse_config(name, netdev_dev_get_type(dev_),
289 args, options);
290 if (!error
de5cdb90
BP
291 && (!dev->options
292 || options->size != dev->options->size
c19e6535
BP
293 || memcmp(options->data, dev->options->data, options->size))) {
294 struct dpif_linux_vport vport;
295
296 dpif_linux_vport_init(&vport);
df2c07f4 297 vport.cmd = OVS_VPORT_CMD_SET;
c19e6535
BP
298 vport.name = name;
299 vport.options = options->data;
300 vport.options_len = options->size;
301 error = dpif_linux_vport_transact(&vport, NULL, NULL);
c3827f61
BP
302 if (!error || error == ENODEV) {
303 /* Either reconfiguration succeeded or this vport is not installed
304 * in the kernel (e.g. it hasn't been added to a dpif yet with
305 * dpif_port_add()). */
c19e6535
BP
306 ofpbuf_delete(dev->options);
307 dev->options = options;
308 options = NULL;
309 error = 0;
c3827f61 310 }
2b9d6589 311 }
c19e6535
BP
312 ofpbuf_delete(options);
313
c3827f61 314 return error;
2b9d6589
BP
315}
316
7feba1ac
BP
317static int
318netdev_vport_send(struct netdev *netdev, const void *data, size_t size)
319{
320 struct netdev_dev *dev_ = netdev_get_dev(netdev);
321 struct netdev_dev_vport *dev = netdev_dev_vport_cast(dev_);
322
323 if (dev->dp_ifindex == -1) {
324 const char *name = netdev_get_name(netdev);
325 struct dpif_linux_vport reply;
326 struct ofpbuf *buf;
327 int error;
328
329 error = dpif_linux_vport_get(name, &reply, &buf);
330 if (error) {
331 VLOG_ERR_RL(&rl, "%s: failed to query vport for send (%s)",
332 name, strerror(error));
333 return error;
334 }
335 dev->dp_ifindex = reply.dp_ifindex;
336 dev->port_no = reply.port_no;
337 ofpbuf_delete(buf);
338 }
339
340 return dpif_linux_vport_send(dev->dp_ifindex, dev->port_no, data, size);
341}
342
2b9d6589 343static int
777ece09
JG
344netdev_vport_set_etheraddr(struct netdev *netdev,
345 const uint8_t mac[ETH_ADDR_LEN])
346{
c19e6535
BP
347 struct dpif_linux_vport vport;
348 int error;
777ece09 349
c19e6535 350 dpif_linux_vport_init(&vport);
df2c07f4 351 vport.cmd = OVS_VPORT_CMD_SET;
c19e6535
BP
352 vport.name = netdev_get_name(netdev);
353 vport.address = mac;
777ece09 354
c19e6535
BP
355 error = dpif_linux_vport_transact(&vport, NULL, NULL);
356 if (!error) {
357 netdev_vport_poll_notify(netdev);
777ece09 358 }
c19e6535 359 return error;
777ece09
JG
360}
361
2b9d6589 362static int
777ece09
JG
363netdev_vport_get_etheraddr(const struct netdev *netdev,
364 uint8_t mac[ETH_ADDR_LEN])
365{
c19e6535
BP
366 struct dpif_linux_vport reply;
367 struct ofpbuf *buf;
368 int error;
777ece09 369
c19e6535
BP
370 error = dpif_linux_vport_get(netdev_get_name(netdev), &reply, &buf);
371 if (!error) {
372 if (reply.address) {
373 memcpy(mac, reply.address, ETH_ADDR_LEN);
374 } else {
375 error = EOPNOTSUPP;
376 }
377 ofpbuf_delete(buf);
777ece09 378 }
c19e6535 379 return error;
777ece09
JG
380}
381
69ebca1e
BP
382/* Copies 'src' into 'dst', performing format conversion in the process.
383 *
384 * 'src' is allowed to be misaligned. */
f613a0d7
PS
385static void
386netdev_stats_from_ovs_vport_stats(struct netdev_stats *dst,
387 const struct ovs_vport_stats *src)
388{
69ebca1e
BP
389 dst->rx_packets = get_unaligned_u64(&src->rx_packets);
390 dst->tx_packets = get_unaligned_u64(&src->tx_packets);
391 dst->rx_bytes = get_unaligned_u64(&src->rx_bytes);
392 dst->tx_bytes = get_unaligned_u64(&src->tx_bytes);
393 dst->rx_errors = get_unaligned_u64(&src->rx_errors);
394 dst->tx_errors = get_unaligned_u64(&src->tx_errors);
395 dst->rx_dropped = get_unaligned_u64(&src->rx_dropped);
396 dst->tx_dropped = get_unaligned_u64(&src->tx_dropped);
f613a0d7
PS
397 dst->multicast = 0;
398 dst->collisions = 0;
399 dst->rx_length_errors = 0;
400 dst->rx_over_errors = 0;
401 dst->rx_crc_errors = 0;
402 dst->rx_frame_errors = 0;
403 dst->rx_fifo_errors = 0;
404 dst->rx_missed_errors = 0;
405 dst->tx_aborted_errors = 0;
406 dst->tx_carrier_errors = 0;
407 dst->tx_fifo_errors = 0;
408 dst->tx_heartbeat_errors = 0;
409 dst->tx_window_errors = 0;
410}
411
412/* Copies 'src' into 'dst', performing format conversion in the process. */
413static void
414netdev_stats_to_ovs_vport_stats(struct ovs_vport_stats *dst,
415 const struct netdev_stats *src)
416{
69ebca1e
BP
417 dst->rx_packets = src->rx_packets;
418 dst->tx_packets = src->tx_packets;
419 dst->rx_bytes = src->rx_bytes;
420 dst->tx_bytes = src->tx_bytes;
421 dst->rx_errors = src->rx_errors;
422 dst->tx_errors = src->tx_errors;
423 dst->rx_dropped = src->rx_dropped;
424 dst->tx_dropped = src->tx_dropped;
f613a0d7
PS
425}
426
777ece09
JG
427int
428netdev_vport_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
429{
c19e6535
BP
430 struct dpif_linux_vport reply;
431 struct ofpbuf *buf;
432 int error;
777ece09 433
c19e6535
BP
434 error = dpif_linux_vport_get(netdev_get_name(netdev), &reply, &buf);
435 if (error) {
436 return error;
437 } else if (!reply.stats) {
438 ofpbuf_delete(buf);
439 return EOPNOTSUPP;
440 }
441
f613a0d7 442 netdev_stats_from_ovs_vport_stats(stats, reply.stats);
c19e6535
BP
443
444 ofpbuf_delete(buf);
777ece09
JG
445
446 return 0;
447}
448
f4b6076a
JG
449int
450netdev_vport_set_stats(struct netdev *netdev, const struct netdev_stats *stats)
451{
f613a0d7 452 struct ovs_vport_stats rtnl_stats;
c19e6535 453 struct dpif_linux_vport vport;
f4b6076a
JG
454 int err;
455
f613a0d7 456 netdev_stats_to_ovs_vport_stats(&rtnl_stats, stats);
c19e6535
BP
457
458 dpif_linux_vport_init(&vport);
df2c07f4 459 vport.cmd = OVS_VPORT_CMD_SET;
c19e6535
BP
460 vport.name = netdev_get_name(netdev);
461 vport.stats = &rtnl_stats;
462
463 err = dpif_linux_vport_transact(&vport, NULL, NULL);
f4b6076a
JG
464
465 /* If the vport layer doesn't know about the device, that doesn't mean it
466 * doesn't exist (after all were able to open it when netdev_open() was
467 * called), it just means that it isn't attached and we'll be getting
468 * stats a different way. */
469 if (err == ENODEV) {
470 err = EOPNOTSUPP;
471 }
472
473 return err;
474}
475
ea763e0e 476static int
79f1cbe9 477netdev_vport_get_drv_info(const struct netdev *netdev, struct smap *smap)
ea763e0e
EJ
478{
479 const char *iface = netdev_vport_get_tnl_iface(netdev);
480
481 if (iface) {
a404826e
AE
482 struct netdev *egress_netdev;
483
79f1cbe9 484 smap_add(smap, "tunnel_egress_iface", iface);
a404826e 485
18812dff 486 if (!netdev_open(iface, "system", &egress_netdev)) {
79f1cbe9
EJ
487 smap_add(smap, "tunnel_egress_iface_carrier",
488 netdev_get_carrier(egress_netdev) ? "up" : "down");
a404826e
AE
489 netdev_close(egress_netdev);
490 }
ea763e0e
EJ
491 }
492
493 return 0;
494}
495
2b9d6589 496static int
777ece09
JG
497netdev_vport_update_flags(struct netdev *netdev OVS_UNUSED,
498 enum netdev_flags off, enum netdev_flags on OVS_UNUSED,
499 enum netdev_flags *old_flagsp)
500{
501 if (off & (NETDEV_UP | NETDEV_PROMISC)) {
502 return EOPNOTSUPP;
503 }
504
505 *old_flagsp = NETDEV_UP | NETDEV_PROMISC;
506 return 0;
507}
508
ac4d3bcb
EJ
509static unsigned int
510netdev_vport_change_seq(const struct netdev *netdev)
511{
512 return netdev_dev_vport_cast(netdev_get_dev(netdev))->change_seq;
513}
514
ea83a2fc
EJ
515static void
516netdev_vport_run(void)
517{
a132aa96 518 route_table_run();
ea83a2fc
EJ
519}
520
521static void
522netdev_vport_wait(void)
523{
a132aa96 524 route_table_wait();
ea83a2fc
EJ
525}
526\f
527/* get_tnl_iface() implementation. */
ea83a2fc
EJ
528static const char *
529netdev_vport_get_tnl_iface(const struct netdev *netdev)
530{
df2c07f4 531 struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1];
d84d4b88 532 ovs_be32 route;
ea83a2fc 533 struct netdev_dev_vport *ndv;
b46ccdf5 534 static char name[IFNAMSIZ];
ea83a2fc
EJ
535
536 ndv = netdev_dev_vport_cast(netdev_get_dev(netdev));
c19e6535
BP
537 if (tnl_port_config_from_nlattr(ndv->options->data, ndv->options->size,
538 a)) {
539 return NULL;
540 }
df2c07f4 541 route = nl_attr_get_be32(a[OVS_TUNNEL_ATTR_DST_IPV4]);
ea83a2fc 542
b46ccdf5
EJ
543 if (route_table_get_name(route, name)) {
544 return name;
ea83a2fc
EJ
545 }
546
547 return NULL;
548}
2b9d6589
BP
549\f
550/* Helper functions. */
777ece09 551
2b9d6589 552static void
777ece09
JG
553netdev_vport_poll_notify(const struct netdev *netdev)
554{
ac4d3bcb
EJ
555 struct netdev_dev_vport *ndv;
556
557 ndv = netdev_dev_vport_cast(netdev_get_dev(netdev));
777ece09 558
ac4d3bcb
EJ
559 ndv->change_seq++;
560 if (!ndv->change_seq) {
561 ndv->change_seq++;
562 }
777ece09 563}
2b9d6589
BP
564\f
565/* Code specific to individual vport types. */
566
c19e6535 567static void
79f1cbe9 568set_key(const struct smap *args, const char *name, uint16_t type,
c19e6535
BP
569 struct ofpbuf *options)
570{
571 const char *s;
572
79f1cbe9 573 s = smap_get(args, name);
c19e6535 574 if (!s) {
79f1cbe9 575 s = smap_get(args, "key");
c19e6535
BP
576 if (!s) {
577 s = "0";
578 }
579 }
580
581 if (!strcmp(s, "flow")) {
582 /* This is the default if no attribute is present. */
583 } else {
584 nl_msg_put_be64(options, type, htonll(strtoull(s, NULL, 0)));
585 }
586}
587
2b9d6589 588static int
6d9e6eb4 589parse_tunnel_config(const char *name, const char *type,
79f1cbe9 590 const struct smap *args, struct ofpbuf *options)
2b9d6589 591{
e16a28b5
JP
592 bool is_gre = false;
593 bool is_ipsec = false;
79f827fa
KM
594 bool needs_dst_port = false;
595 bool found_dst_port = false;
79f1cbe9 596 struct smap_node *node;
2b9d6589 597 bool ipsec_mech_set = false;
c19e6535 598 ovs_be32 daddr = htonl(0);
b37e6334 599 ovs_be32 saddr = htonl(0);
c19e6535 600 uint32_t flags;
2b9d6589 601
1280bf0e
PS
602 if (!strcmp(type, "capwap")) {
603 VLOG_WARN_ONCE("CAPWAP tunnel support is deprecated.");
604 }
605
05a9d485 606 flags = TNL_F_DF_DEFAULT;
2de795ad 607 if (!strcmp(type, "gre") || !strcmp(type, "gre64")) {
e16a28b5 608 is_gre = true;
2de795ad 609 } else if (!strcmp(type, "ipsec_gre") || !strcmp(type, "ipsec_gre64")) {
e16a28b5
JP
610 is_gre = true;
611 is_ipsec = true;
c19e6535 612 flags |= TNL_F_IPSEC;
79f827fa
KM
613 } else if (!strcmp(type, "vxlan")) {
614 needs_dst_port = true;
e16a28b5
JP
615 }
616
79f1cbe9
EJ
617 SMAP_FOR_EACH (node, args) {
618 if (!strcmp(node->key, "remote_ip")) {
2b9d6589 619 struct in_addr in_addr;
79f1cbe9 620 if (lookup_ip(node->value, &in_addr)) {
c3827f61 621 VLOG_WARN("%s: bad %s 'remote_ip'", name, type);
2b9d6589 622 } else {
c19e6535 623 daddr = in_addr.s_addr;
2b9d6589 624 }
79f1cbe9 625 } else if (!strcmp(node->key, "local_ip")) {
2b9d6589 626 struct in_addr in_addr;
79f1cbe9 627 if (lookup_ip(node->value, &in_addr)) {
c3827f61 628 VLOG_WARN("%s: bad %s 'local_ip'", name, type);
2b9d6589 629 } else {
b37e6334 630 saddr = in_addr.s_addr;
2b9d6589 631 }
79f1cbe9
EJ
632 } else if (!strcmp(node->key, "tos")) {
633 if (!strcmp(node->value, "inherit")) {
c19e6535 634 flags |= TNL_F_TOS_INHERIT;
2b9d6589 635 } else {
3fca7064
PS
636 char *endptr;
637 int tos;
79f1cbe9 638 tos = strtol(node->value, &endptr, 0);
91aff446 639 if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
3fca7064 640 nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TOS, tos);
91aff446
BP
641 } else {
642 VLOG_WARN("%s: invalid TOS %s", name, node->value);
3fca7064 643 }
2b9d6589 644 }
79f1cbe9
EJ
645 } else if (!strcmp(node->key, "ttl")) {
646 if (!strcmp(node->value, "inherit")) {
c19e6535 647 flags |= TNL_F_TTL_INHERIT;
2b9d6589 648 } else {
79f1cbe9 649 nl_msg_put_u8(options, OVS_TUNNEL_ATTR_TTL, atoi(node->value));
2b9d6589 650 }
79f827fa
KM
651 } else if (!strcmp(node->key, "dst_port") && needs_dst_port) {
652 nl_msg_put_u16(options, OVS_TUNNEL_ATTR_DST_PORT,
653 atoi(node->value));
654 found_dst_port = true;
79f1cbe9
EJ
655 } else if (!strcmp(node->key, "csum") && is_gre) {
656 if (!strcmp(node->value, "true")) {
c19e6535 657 flags |= TNL_F_CSUM;
2b9d6589 658 }
79f1cbe9
EJ
659 } else if (!strcmp(node->key, "df_inherit")) {
660 if (!strcmp(node->value, "true")) {
66409d1b
AE
661 flags |= TNL_F_DF_INHERIT;
662 }
79f1cbe9
EJ
663 } else if (!strcmp(node->key, "df_default")) {
664 if (!strcmp(node->value, "false")) {
66409d1b
AE
665 flags &= ~TNL_F_DF_DEFAULT;
666 }
79f1cbe9 667 } else if (!strcmp(node->key, "pmtud")) {
85b53b31 668 if (!strcmp(node->value, "true")) {
85340733
AA
669 VLOG_WARN_ONCE("%s: The tunnel Path MTU discovery is "
670 "deprecated and may be removed in February "
671 "2013. Please email dev@openvswitch.org with "
672 "concerns.", name);
85b53b31 673 flags |= TNL_F_PMTUD;
2b9d6589 674 }
79f1cbe9
EJ
675 } else if (!strcmp(node->key, "peer_cert") && is_ipsec) {
676 if (smap_get(args, "certificate")) {
3c52fa7b
JP
677 ipsec_mech_set = true;
678 } else {
ef7ee76a
JP
679 const char *use_ssl_cert;
680
681 /* If the "use_ssl_cert" is true, then "certificate" and
682 * "private_key" will be pulled from the SSL table. The
683 * use of this option is strongly discouraged, since it
684 * will like be removed when multiple SSL configurations
685 * are supported by OVS.
686 */
79f1cbe9 687 use_ssl_cert = smap_get(args, "use_ssl_cert");
ef7ee76a 688 if (!use_ssl_cert || strcmp(use_ssl_cert, "true")) {
8283e514
JP
689 VLOG_ERR("%s: 'peer_cert' requires 'certificate' argument",
690 name);
ef7ee76a
JP
691 return EINVAL;
692 }
693 ipsec_mech_set = true;
3c52fa7b 694 }
79f1cbe9 695 } else if (!strcmp(node->key, "psk") && is_ipsec) {
2b9d6589 696 ipsec_mech_set = true;
ea83a2fc 697 } else if (is_ipsec
79f1cbe9
EJ
698 && (!strcmp(node->key, "certificate")
699 || !strcmp(node->key, "private_key")
700 || !strcmp(node->key, "use_ssl_cert"))) {
3c52fa7b 701 /* Ignore options not used by the netdev. */
79f1cbe9
EJ
702 } else if (!strcmp(node->key, "key") ||
703 !strcmp(node->key, "in_key") ||
704 !strcmp(node->key, "out_key")) {
c19e6535 705 /* Handled separately below. */
2b9d6589 706 } else {
79f1cbe9 707 VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
2b9d6589
BP
708 }
709 }
710
79f827fa
KM
711 /* Add a default destination port for VXLAN if none specified. */
712 if (needs_dst_port && !found_dst_port) {
713 nl_msg_put_u16(options, OVS_TUNNEL_ATTR_DST_PORT, VXLAN_DST_PORT);
714 }
715
3c52fa7b 716 if (is_ipsec) {
2a586a5c 717 static pid_t pid = 0;
900f7601 718 if (pid <= 0) {
2a586a5c
AS
719 char *file_name = xasprintf("%s/%s", ovs_rundir(),
720 "ovs-monitor-ipsec.pid");
721 pid = read_pidfile(file_name);
722 free(file_name);
723 }
724
e7009c36 725 if (pid < 0) {
8283e514
JP
726 VLOG_ERR("%s: IPsec requires the ovs-monitor-ipsec daemon",
727 name);
e7009c36
JP
728 return EINVAL;
729 }
5059eff3 730
79f1cbe9 731 if (smap_get(args, "peer_cert") && smap_get(args, "psk")) {
8283e514 732 VLOG_ERR("%s: cannot define both 'peer_cert' and 'psk'", name);
3c52fa7b
JP
733 return EINVAL;
734 }
735
736 if (!ipsec_mech_set) {
8283e514
JP
737 VLOG_ERR("%s: IPsec requires an 'peer_cert' or psk' argument",
738 name);
3c52fa7b
JP
739 return EINVAL;
740 }
2b9d6589
BP
741 }
742
40a75177
VG
743 set_key(args, "in_key", OVS_TUNNEL_ATTR_IN_KEY, options);
744 set_key(args, "out_key", OVS_TUNNEL_ATTR_OUT_KEY, options);
c19e6535
BP
745
746 if (!daddr) {
8283e514
JP
747 VLOG_ERR("%s: %s type requires valid 'remote_ip' argument",
748 name, type);
2b9d6589
BP
749 return EINVAL;
750 }
df2c07f4 751 nl_msg_put_be32(options, OVS_TUNNEL_ATTR_DST_IPV4, daddr);
c19e6535 752
b37e6334
BP
753 if (saddr) {
754 if (ip_is_multicast(daddr)) {
755 VLOG_WARN("%s: remote_ip is multicast, ignoring local_ip", name);
756 } else {
757 nl_msg_put_be32(options, OVS_TUNNEL_ATTR_SRC_IPV4, saddr);
758 }
759 }
760
df2c07f4 761 nl_msg_put_u32(options, OVS_TUNNEL_ATTR_FLAGS, flags);
2b9d6589
BP
762
763 return 0;
764}
765
c19e6535
BP
766static int
767tnl_port_config_from_nlattr(const struct nlattr *options, size_t options_len,
df2c07f4
JP
768 struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1])
769{
770 static const struct nl_policy ovs_tunnel_policy[] = {
771 [OVS_TUNNEL_ATTR_FLAGS] = { .type = NL_A_U32 },
772 [OVS_TUNNEL_ATTR_DST_IPV4] = { .type = NL_A_BE32 },
773 [OVS_TUNNEL_ATTR_SRC_IPV4] = { .type = NL_A_BE32, .optional = true },
774 [OVS_TUNNEL_ATTR_IN_KEY] = { .type = NL_A_BE64, .optional = true },
775 [OVS_TUNNEL_ATTR_OUT_KEY] = { .type = NL_A_BE64, .optional = true },
776 [OVS_TUNNEL_ATTR_TOS] = { .type = NL_A_U8, .optional = true },
777 [OVS_TUNNEL_ATTR_TTL] = { .type = NL_A_U8, .optional = true },
79f827fa 778 [OVS_TUNNEL_ATTR_DST_PORT] = { .type = NL_A_U16, .optional = true },
c19e6535
BP
779 };
780 struct ofpbuf buf;
781
782 ofpbuf_use_const(&buf, options, options_len);
df2c07f4
JP
783 if (!nl_policy_parse(&buf, 0, ovs_tunnel_policy,
784 a, ARRAY_SIZE(ovs_tunnel_policy))) {
c19e6535
BP
785 return EINVAL;
786 }
787 return 0;
788}
789
790static uint64_t
791get_be64_or_zero(const struct nlattr *a)
792{
793 return a ? ntohll(nl_attr_get_be64(a)) : 0;
794}
795
2b9d6589 796static int
6d9e6eb4 797unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED,
c19e6535 798 const struct nlattr *options, size_t options_len,
79f1cbe9 799 struct smap *args)
6d9e6eb4 800{
df2c07f4 801 struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1];
c19e6535
BP
802 ovs_be32 daddr;
803 uint32_t flags;
804 int error;
6d9e6eb4 805
c19e6535
BP
806 error = tnl_port_config_from_nlattr(options, options_len, a);
807 if (error) {
808 return error;
809 }
810
c19e6535 811
df2c07f4 812 daddr = nl_attr_get_be32(a[OVS_TUNNEL_ATTR_DST_IPV4]);
79f1cbe9 813 smap_add_format(args, "remote_ip", IP_FMT, IP_ARGS(&daddr));
c19e6535 814
df2c07f4
JP
815 if (a[OVS_TUNNEL_ATTR_SRC_IPV4]) {
816 ovs_be32 saddr = nl_attr_get_be32(a[OVS_TUNNEL_ATTR_SRC_IPV4]);
79f1cbe9 817 smap_add_format(args, "local_ip", IP_FMT, IP_ARGS(&saddr));
6d9e6eb4
BP
818 }
819
df2c07f4 820 if (!a[OVS_TUNNEL_ATTR_IN_KEY] && !a[OVS_TUNNEL_ATTR_OUT_KEY]) {
6d9e6eb4 821 smap_add(args, "key", "flow");
6d9e6eb4 822 } else {
df2c07f4
JP
823 uint64_t in_key = get_be64_or_zero(a[OVS_TUNNEL_ATTR_IN_KEY]);
824 uint64_t out_key = get_be64_or_zero(a[OVS_TUNNEL_ATTR_OUT_KEY]);
c19e6535
BP
825
826 if (in_key && in_key == out_key) {
79f1cbe9 827 smap_add_format(args, "key", "%"PRIu64, in_key);
c19e6535 828 } else {
df2c07f4 829 if (!a[OVS_TUNNEL_ATTR_IN_KEY]) {
c19e6535
BP
830 smap_add(args, "in_key", "flow");
831 } else if (in_key) {
79f1cbe9 832 smap_add_format(args, "in_key", "%"PRIu64, in_key);
c19e6535 833 }
6d9e6eb4 834
df2c07f4 835 if (!a[OVS_TUNNEL_ATTR_OUT_KEY]) {
c19e6535
BP
836 smap_add(args, "out_key", "flow");
837 } else if (out_key) {
79f1cbe9 838 smap_add_format(args, "out_key", "%"PRIu64, out_key);
c19e6535 839 }
6d9e6eb4
BP
840 }
841 }
842
05a9d485 843 flags = nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]);
c19e6535 844 if (flags & TNL_F_TTL_INHERIT) {
62827e6a 845 smap_add(args, "ttl", "inherit");
df2c07f4
JP
846 } else if (a[OVS_TUNNEL_ATTR_TTL]) {
847 int ttl = nl_attr_get_u8(a[OVS_TUNNEL_ATTR_TTL]);
62827e6a 848 smap_add_format(args, "ttl", "%d", ttl);
c19e6535
BP
849 }
850
851 if (flags & TNL_F_TOS_INHERIT) {
6d9e6eb4 852 smap_add(args, "tos", "inherit");
df2c07f4
JP
853 } else if (a[OVS_TUNNEL_ATTR_TOS]) {
854 int tos = nl_attr_get_u8(a[OVS_TUNNEL_ATTR_TOS]);
79f1cbe9 855 smap_add_format(args, "tos", "0x%x", tos);
6d9e6eb4
BP
856 }
857
79f827fa
KM
858 if (a[OVS_TUNNEL_ATTR_DST_PORT]) {
859 uint16_t dst_port = nl_attr_get_u16(a[OVS_TUNNEL_ATTR_DST_PORT]);
860 if (dst_port != VXLAN_DST_PORT) {
861 smap_add_format(args, "dst_port", "%d", dst_port);
862 }
863 }
864
c19e6535 865 if (flags & TNL_F_CSUM) {
6d9e6eb4
BP
866 smap_add(args, "csum", "true");
867 }
66409d1b
AE
868 if (flags & TNL_F_DF_INHERIT) {
869 smap_add(args, "df_inherit", "true");
870 }
871 if (!(flags & TNL_F_DF_DEFAULT)) {
872 smap_add(args, "df_default", "false");
873 }
85b53b31
AA
874 if (flags & TNL_F_PMTUD) {
875 smap_add(args, "pmtud", "true");
6d9e6eb4
BP
876 }
877
878 return 0;
879}
880
881static int
882parse_patch_config(const char *name, const char *type OVS_UNUSED,
79f1cbe9 883 const struct smap *args, struct ofpbuf *options)
2b9d6589 884{
2b9d6589
BP
885 const char *peer;
886
79f1cbe9 887 peer = smap_get(args, "peer");
2b9d6589 888 if (!peer) {
8283e514 889 VLOG_ERR("%s: patch type requires valid 'peer' argument", name);
2b9d6589
BP
890 return EINVAL;
891 }
892
79f1cbe9 893 if (smap_count(args) > 1) {
8283e514 894 VLOG_ERR("%s: patch type takes only a 'peer' argument", name);
2b9d6589
BP
895 return EINVAL;
896 }
897
c19e6535 898 if (strlen(peer) >= IFNAMSIZ) {
8283e514 899 VLOG_ERR("%s: patch 'peer' arg too long", name);
2b9d6589
BP
900 return EINVAL;
901 }
902
903 if (!strcmp(name, peer)) {
8283e514 904 VLOG_ERR("%s: patch peer must not be self", name);
2b9d6589
BP
905 return EINVAL;
906 }
907
df2c07f4 908 nl_msg_put_string(options, OVS_PATCH_ATTR_PEER, peer);
2b9d6589
BP
909
910 return 0;
911}
6d9e6eb4
BP
912
913static int
914unparse_patch_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED,
c19e6535 915 const struct nlattr *options, size_t options_len,
79f1cbe9 916 struct smap *args)
6d9e6eb4 917{
df2c07f4
JP
918 static const struct nl_policy ovs_patch_policy[] = {
919 [OVS_PATCH_ATTR_PEER] = { .type = NL_A_STRING,
c19e6535
BP
920 .max_len = IFNAMSIZ,
921 .optional = false }
922 };
923
df2c07f4 924 struct nlattr *a[ARRAY_SIZE(ovs_patch_policy)];
c19e6535
BP
925 struct ofpbuf buf;
926
927 ofpbuf_use_const(&buf, options, options_len);
df2c07f4
JP
928 if (!nl_policy_parse(&buf, 0, ovs_patch_policy,
929 a, ARRAY_SIZE(ovs_patch_policy))) {
c19e6535 930 return EINVAL;
6d9e6eb4
BP
931 }
932
df2c07f4 933 smap_add(args, "peer", nl_attr_get_string(a[OVS_PATCH_ATTR_PEER]));
6d9e6eb4
BP
934 return 0;
935}
2b9d6589 936\f
ea763e0e 937#define VPORT_FUNCTIONS(GET_STATUS) \
b46ccdf5 938 NULL, \
ea83a2fc
EJ
939 netdev_vport_run, \
940 netdev_vport_wait, \
2b9d6589
BP
941 \
942 netdev_vport_create, \
943 netdev_vport_destroy, \
de5cdb90 944 netdev_vport_get_config, \
6d9e6eb4 945 netdev_vport_set_config, \
2b9d6589
BP
946 \
947 netdev_vport_open, \
948 netdev_vport_close, \
949 \
7b6b0ef4 950 NULL, /* listen */ \
2b9d6589
BP
951 NULL, /* recv */ \
952 NULL, /* recv_wait */ \
953 NULL, /* drain */ \
954 \
7feba1ac 955 netdev_vport_send, /* send */ \
2b9d6589
BP
956 NULL, /* send_wait */ \
957 \
958 netdev_vport_set_etheraddr, \
959 netdev_vport_get_etheraddr, \
14622f22
BP
960 NULL, /* get_mtu */ \
961 NULL, /* set_mtu */ \
2b9d6589 962 NULL, /* get_ifindex */ \
85da620e 963 NULL, /* get_carrier */ \
65c3058c 964 NULL, /* get_carrier_resets */ \
63331829 965 NULL, /* get_miimon */ \
2b9d6589
BP
966 netdev_vport_get_stats, \
967 netdev_vport_set_stats, \
968 \
969 NULL, /* get_features */ \
970 NULL, /* set_advertisements */ \
2b9d6589
BP
971 \
972 NULL, /* set_policing */ \
973 NULL, /* get_qos_types */ \
974 NULL, /* get_qos_capabilities */ \
975 NULL, /* get_qos */ \
976 NULL, /* set_qos */ \
977 NULL, /* get_queue */ \
978 NULL, /* set_queue */ \
979 NULL, /* delete_queue */ \
980 NULL, /* get_queue_stats */ \
981 NULL, /* dump_queues */ \
982 NULL, /* dump_queue_stats */ \
983 \
984 NULL, /* get_in4 */ \
985 NULL, /* set_in4 */ \
986 NULL, /* get_in6 */ \
987 NULL, /* add_router */ \
988 NULL, /* get_next_hop */ \
ea763e0e 989 GET_STATUS, \
2b9d6589
BP
990 NULL, /* arp_lookup */ \
991 \
992 netdev_vport_update_flags, \
993 \
ac4d3bcb 994 netdev_vport_change_seq
2b9d6589 995
2b9d6589
BP
996void
997netdev_vport_register(void)
998{
c3827f61 999 static const struct vport_class vport_classes[] = {
df2c07f4 1000 { OVS_VPORT_TYPE_GRE,
2c2ea5a8 1001 { "gre", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
de5cdb90 1002 parse_tunnel_config, unparse_tunnel_config },
c283069c 1003
df2c07f4 1004 { OVS_VPORT_TYPE_GRE,
2c2ea5a8 1005 { "ipsec_gre", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
de5cdb90 1006 parse_tunnel_config, unparse_tunnel_config },
c283069c 1007
2de795ad
PS
1008 { OVS_VPORT_TYPE_GRE64,
1009 { "gre64", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
1010 parse_tunnel_config, unparse_tunnel_config },
1011
1012 { OVS_VPORT_TYPE_GRE64,
1013 { "ipsec_gre64", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
1014 parse_tunnel_config, unparse_tunnel_config },
1015
df2c07f4 1016 { OVS_VPORT_TYPE_CAPWAP,
2c2ea5a8 1017 { "capwap", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
de5cdb90 1018 parse_tunnel_config, unparse_tunnel_config },
c283069c 1019
79f827fa
KM
1020 { OVS_VPORT_TYPE_VXLAN,
1021 { "vxlan", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
1022 parse_tunnel_config, unparse_tunnel_config },
1023
df2c07f4 1024 { OVS_VPORT_TYPE_PATCH,
c283069c 1025 { "patch", VPORT_FUNCTIONS(NULL) },
de5cdb90 1026 parse_patch_config, unparse_patch_config }
c3827f61
BP
1027 };
1028
1029 int i;
1030
1031 for (i = 0; i < ARRAY_SIZE(vport_classes); i++) {
1032 netdev_register_provider(&vport_classes[i].netdev_class);
1033 }
2b9d6589 1034}