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