datapath: Add support for Geneve tunneling.
[cascardo/ovs.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 <net/if.h>
25 #include <sys/ioctl.h>
26
27 #include "byte-order.h"
28 #include "daemon.h"
29 #include "dirs.h"
30 #include "dpif.h"
31 #include "hash.h"
32 #include "hmap.h"
33 #include "list.h"
34 #include "netdev-provider.h"
35 #include "ofpbuf.h"
36 #include "packets.h"
37 #include "poll-loop.h"
38 #include "route-table.h"
39 #include "shash.h"
40 #include "socket-util.h"
41 #include "vlog.h"
42
43 VLOG_DEFINE_THIS_MODULE(netdev_vport);
44
45 #define GENEVE_DST_PORT 6081
46 #define VXLAN_DST_PORT 4789
47 #define LISP_DST_PORT 4341
48
49 #define DEFAULT_TTL 64
50
51 struct netdev_vport {
52     struct netdev up;
53
54     /* Protects all members below. */
55     struct ovs_mutex mutex;
56
57     uint8_t etheraddr[ETH_ADDR_LEN];
58     struct netdev_stats stats;
59
60     /* Tunnels. */
61     struct netdev_tunnel_config tnl_cfg;
62     char egress_iface[IFNAMSIZ];
63     bool carrier_status;
64
65     /* Patch Ports. */
66     char *peer;
67 };
68
69 struct vport_class {
70     const char *dpif_port;
71     struct netdev_class netdev_class;
72 };
73
74 /* Last read of the route-table's change number. */
75 static uint64_t rt_change_seqno;
76
77 static int netdev_vport_construct(struct netdev *);
78 static int get_patch_config(const struct netdev *netdev, struct smap *args);
79 static int get_tunnel_config(const struct netdev *, struct smap *args);
80 static bool tunnel_check_status_change__(struct netdev_vport *);
81
82 static bool
83 is_vport_class(const struct netdev_class *class)
84 {
85     return class->construct == netdev_vport_construct;
86 }
87
88 bool
89 netdev_vport_is_vport_class(const struct netdev_class *class)
90 {
91     return is_vport_class(class);
92 }
93
94 static const struct vport_class *
95 vport_class_cast(const struct netdev_class *class)
96 {
97     ovs_assert(is_vport_class(class));
98     return CONTAINER_OF(class, struct vport_class, netdev_class);
99 }
100
101 static struct netdev_vport *
102 netdev_vport_cast(const struct netdev *netdev)
103 {
104     ovs_assert(is_vport_class(netdev_get_class(netdev)));
105     return CONTAINER_OF(netdev, struct netdev_vport, up);
106 }
107
108 static const struct netdev_tunnel_config *
109 get_netdev_tunnel_config(const struct netdev *netdev)
110 {
111     return &netdev_vport_cast(netdev)->tnl_cfg;
112 }
113
114 bool
115 netdev_vport_is_patch(const struct netdev *netdev)
116 {
117     const struct netdev_class *class = netdev_get_class(netdev);
118
119     return class->get_config == get_patch_config;
120 }
121
122 bool
123 netdev_vport_is_layer3(const struct netdev *dev)
124 {
125     const char *type = netdev_get_type(dev);
126
127     return (!strcmp("lisp", type));
128 }
129
130 static bool
131 netdev_vport_needs_dst_port(const struct netdev *dev)
132 {
133     const struct netdev_class *class = netdev_get_class(dev);
134     const char *type = netdev_get_type(dev);
135
136     return (class->get_config == get_tunnel_config &&
137             (!strcmp("geneve", type) || !strcmp("vxlan", type) ||
138              !strcmp("lisp", type)));
139 }
140
141 const char *
142 netdev_vport_class_get_dpif_port(const struct netdev_class *class)
143 {
144     return is_vport_class(class) ? vport_class_cast(class)->dpif_port : NULL;
145 }
146
147 const char *
148 netdev_vport_get_dpif_port(const struct netdev *netdev,
149                            char namebuf[], size_t bufsize)
150 {
151     const struct netdev_class *class = netdev_get_class(netdev);
152     const char *dpif_port = netdev_vport_class_get_dpif_port(class);
153
154     if (!dpif_port) {
155         return netdev_get_name(netdev);
156     }
157
158     if (netdev_vport_needs_dst_port(netdev)) {
159         const struct netdev_vport *vport = netdev_vport_cast(netdev);
160
161         /*
162          * Note: IFNAMSIZ is 16 bytes long. Implementations should choose
163          * a dpif port name that is short enough to fit including any
164          * port numbers but assert just in case.
165          */
166         BUILD_ASSERT(NETDEV_VPORT_NAME_BUFSIZE >= IFNAMSIZ);
167         ovs_assert(strlen(dpif_port) + 6 < IFNAMSIZ);
168         snprintf(namebuf, bufsize, "%s_%d", dpif_port,
169                  ntohs(vport->tnl_cfg.dst_port));
170         return namebuf;
171     } else {
172         return dpif_port;
173     }
174 }
175
176 char *
177 netdev_vport_get_dpif_port_strdup(const struct netdev *netdev)
178 {
179     char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
180
181     return xstrdup(netdev_vport_get_dpif_port(netdev, namebuf,
182                                               sizeof namebuf));
183 }
184
185 /* Whenever the route-table change number is incremented,
186  * netdev_vport_route_changed() should be called to update
187  * the corresponding tunnel interface status. */
188 static void
189 netdev_vport_route_changed(void)
190 {
191     struct netdev **vports;
192     size_t i, n_vports;
193
194     vports = netdev_get_vports(&n_vports);
195     for (i = 0; i < n_vports; i++) {
196         struct netdev *netdev_ = vports[i];
197         struct netdev_vport *netdev = netdev_vport_cast(netdev_);
198
199         ovs_mutex_lock(&netdev->mutex);
200         /* Finds all tunnel vports. */
201         if (netdev->tnl_cfg.ip_dst) {
202             if (tunnel_check_status_change__(netdev)) {
203                 netdev_change_seq_changed(netdev_);
204             }
205         }
206         netdev_close(netdev_);
207         ovs_mutex_unlock(&netdev->mutex);
208     }
209
210     free(vports);
211 }
212
213 static struct netdev *
214 netdev_vport_alloc(void)
215 {
216     struct netdev_vport *netdev = xzalloc(sizeof *netdev);
217     return &netdev->up;
218 }
219
220 static int
221 netdev_vport_construct(struct netdev *netdev_)
222 {
223     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
224
225     ovs_mutex_init(&netdev->mutex);
226     eth_addr_random(netdev->etheraddr);
227
228     route_table_register();
229
230     return 0;
231 }
232
233 static void
234 netdev_vport_destruct(struct netdev *netdev_)
235 {
236     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
237
238     route_table_unregister();
239     free(netdev->peer);
240     ovs_mutex_destroy(&netdev->mutex);
241 }
242
243 static void
244 netdev_vport_dealloc(struct netdev *netdev_)
245 {
246     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
247     free(netdev);
248 }
249
250 static int
251 netdev_vport_set_etheraddr(struct netdev *netdev_,
252                            const uint8_t mac[ETH_ADDR_LEN])
253 {
254     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
255
256     ovs_mutex_lock(&netdev->mutex);
257     memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
258     ovs_mutex_unlock(&netdev->mutex);
259     netdev_change_seq_changed(netdev_);
260
261     return 0;
262 }
263
264 static int
265 netdev_vport_get_etheraddr(const struct netdev *netdev_,
266                            uint8_t mac[ETH_ADDR_LEN])
267 {
268     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
269
270     ovs_mutex_lock(&netdev->mutex);
271     memcpy(mac, netdev->etheraddr, ETH_ADDR_LEN);
272     ovs_mutex_unlock(&netdev->mutex);
273
274     return 0;
275 }
276
277 /* Checks if the tunnel status has changed and returns a boolean.
278  * Updates the tunnel status if it has changed. */
279 static bool
280 tunnel_check_status_change__(struct netdev_vport *netdev)
281     OVS_REQUIRES(netdev->mutex)
282 {
283     char iface[IFNAMSIZ];
284     bool status = false;
285     ovs_be32 route;
286
287     iface[0] = '\0';
288     route = netdev->tnl_cfg.ip_dst;
289     if (route_table_get_name(route, iface)) {
290         struct netdev *egress_netdev;
291
292         if (!netdev_open(iface, "system", &egress_netdev)) {
293             status = netdev_get_carrier(egress_netdev);
294             netdev_close(egress_netdev);
295         }
296     }
297
298     if (strcmp(netdev->egress_iface, iface)
299         || netdev->carrier_status != status) {
300         ovs_strlcpy(netdev->egress_iface, iface, IFNAMSIZ);
301         netdev->carrier_status = status;
302
303         return true;
304     }
305
306     return false;
307 }
308
309 static int
310 tunnel_get_status(const struct netdev *netdev_, struct smap *smap)
311 {
312     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
313
314     if (netdev->egress_iface[0]) {
315         smap_add(smap, "tunnel_egress_iface", netdev->egress_iface);
316
317         smap_add(smap, "tunnel_egress_iface_carrier",
318                  netdev->carrier_status ? "up" : "down");
319     }
320
321     return 0;
322 }
323
324 static int
325 netdev_vport_update_flags(struct netdev *netdev OVS_UNUSED,
326                           enum netdev_flags off,
327                           enum netdev_flags on OVS_UNUSED,
328                           enum netdev_flags *old_flagsp)
329 {
330     if (off & (NETDEV_UP | NETDEV_PROMISC)) {
331         return EOPNOTSUPP;
332     }
333
334     *old_flagsp = NETDEV_UP | NETDEV_PROMISC;
335     return 0;
336 }
337
338 static void
339 netdev_vport_run(void)
340 {
341     uint64_t seq;
342
343     route_table_run();
344     seq = route_table_get_change_seq();
345     if (rt_change_seqno != seq) {
346         rt_change_seqno = seq;
347         netdev_vport_route_changed();
348     }
349 }
350
351 static void
352 netdev_vport_wait(void)
353 {
354     uint64_t seq;
355
356     route_table_wait();
357     seq = route_table_get_change_seq();
358     if (rt_change_seqno != seq) {
359         poll_immediate_wake();
360     }
361 }
362 \f
363 /* Code specific to tunnel types. */
364
365 static ovs_be64
366 parse_key(const struct smap *args, const char *name,
367           bool *present, bool *flow)
368 {
369     const char *s;
370
371     *present = false;
372     *flow = false;
373
374     s = smap_get(args, name);
375     if (!s) {
376         s = smap_get(args, "key");
377         if (!s) {
378             return 0;
379         }
380     }
381
382     *present = true;
383
384     if (!strcmp(s, "flow")) {
385         *flow = true;
386         return 0;
387     } else {
388         return htonll(strtoull(s, NULL, 0));
389     }
390 }
391
392 static int
393 set_tunnel_config(struct netdev *dev_, const struct smap *args)
394 {
395     struct netdev_vport *dev = netdev_vport_cast(dev_);
396     const char *name = netdev_get_name(dev_);
397     const char *type = netdev_get_type(dev_);
398     bool ipsec_mech_set, needs_dst_port, has_csum;
399     struct netdev_tunnel_config tnl_cfg;
400     struct smap_node *node;
401
402     has_csum = strstr(type, "gre");
403     ipsec_mech_set = false;
404     memset(&tnl_cfg, 0, sizeof tnl_cfg);
405
406     needs_dst_port = netdev_vport_needs_dst_port(dev_);
407     tnl_cfg.ipsec = strstr(type, "ipsec");
408     tnl_cfg.dont_fragment = true;
409
410     SMAP_FOR_EACH (node, args) {
411         if (!strcmp(node->key, "remote_ip")) {
412             struct in_addr in_addr;
413             if (!strcmp(node->value, "flow")) {
414                 tnl_cfg.ip_dst_flow = true;
415                 tnl_cfg.ip_dst = htonl(0);
416             } else if (lookup_ip(node->value, &in_addr)) {
417                 VLOG_WARN("%s: bad %s 'remote_ip'", name, type);
418             } else if (ip_is_multicast(in_addr.s_addr)) {
419                 VLOG_WARN("%s: multicast remote_ip="IP_FMT" not allowed",
420                           name, IP_ARGS(in_addr.s_addr));
421                 return EINVAL;
422             } else {
423                 tnl_cfg.ip_dst = in_addr.s_addr;
424             }
425         } else if (!strcmp(node->key, "local_ip")) {
426             struct in_addr in_addr;
427             if (!strcmp(node->value, "flow")) {
428                 tnl_cfg.ip_src_flow = true;
429                 tnl_cfg.ip_src = htonl(0);
430             } else if (lookup_ip(node->value, &in_addr)) {
431                 VLOG_WARN("%s: bad %s 'local_ip'", name, type);
432             } else {
433                 tnl_cfg.ip_src = in_addr.s_addr;
434             }
435         } else if (!strcmp(node->key, "tos")) {
436             if (!strcmp(node->value, "inherit")) {
437                 tnl_cfg.tos_inherit = true;
438             } else {
439                 char *endptr;
440                 int tos;
441                 tos = strtol(node->value, &endptr, 0);
442                 if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
443                     tnl_cfg.tos = tos;
444                 } else {
445                     VLOG_WARN("%s: invalid TOS %s", name, node->value);
446                 }
447             }
448         } else if (!strcmp(node->key, "ttl")) {
449             if (!strcmp(node->value, "inherit")) {
450                 tnl_cfg.ttl_inherit = true;
451             } else {
452                 tnl_cfg.ttl = atoi(node->value);
453             }
454         } else if (!strcmp(node->key, "dst_port") && needs_dst_port) {
455             tnl_cfg.dst_port = htons(atoi(node->value));
456         } else if (!strcmp(node->key, "csum") && has_csum) {
457             if (!strcmp(node->value, "true")) {
458                 tnl_cfg.csum = true;
459             }
460         } else if (!strcmp(node->key, "df_default")) {
461             if (!strcmp(node->value, "false")) {
462                 tnl_cfg.dont_fragment = false;
463             }
464         } else if (!strcmp(node->key, "peer_cert") && tnl_cfg.ipsec) {
465             if (smap_get(args, "certificate")) {
466                 ipsec_mech_set = true;
467             } else {
468                 const char *use_ssl_cert;
469
470                 /* If the "use_ssl_cert" is true, then "certificate" and
471                  * "private_key" will be pulled from the SSL table.  The
472                  * use of this option is strongly discouraged, since it
473                  * will like be removed when multiple SSL configurations
474                  * are supported by OVS.
475                  */
476                 use_ssl_cert = smap_get(args, "use_ssl_cert");
477                 if (!use_ssl_cert || strcmp(use_ssl_cert, "true")) {
478                     VLOG_ERR("%s: 'peer_cert' requires 'certificate' argument",
479                              name);
480                     return EINVAL;
481                 }
482                 ipsec_mech_set = true;
483             }
484         } else if (!strcmp(node->key, "psk") && tnl_cfg.ipsec) {
485             ipsec_mech_set = true;
486         } else if (tnl_cfg.ipsec
487                 && (!strcmp(node->key, "certificate")
488                     || !strcmp(node->key, "private_key")
489                     || !strcmp(node->key, "use_ssl_cert"))) {
490             /* Ignore options not used by the netdev. */
491         } else if (!strcmp(node->key, "key") ||
492                    !strcmp(node->key, "in_key") ||
493                    !strcmp(node->key, "out_key")) {
494             /* Handled separately below. */
495         } else {
496             VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
497         }
498     }
499
500     /* Add a default destination port for tunnel ports if none specified. */
501     if (!strcmp(type, "geneve") && !tnl_cfg.dst_port) {
502         tnl_cfg.dst_port = htons(GENEVE_DST_PORT);
503     }
504
505     if (!strcmp(type, "vxlan") && !tnl_cfg.dst_port) {
506         tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
507     }
508
509     if (!strcmp(type, "lisp") && !tnl_cfg.dst_port) {
510         tnl_cfg.dst_port = htons(LISP_DST_PORT);
511     }
512
513     if (tnl_cfg.ipsec) {
514         static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
515         static pid_t pid = 0;
516
517 #ifndef _WIN32
518         ovs_mutex_lock(&mutex);
519         if (pid <= 0) {
520             char *file_name = xasprintf("%s/%s", ovs_rundir(),
521                                         "ovs-monitor-ipsec.pid");
522             pid = read_pidfile(file_name);
523             free(file_name);
524         }
525         ovs_mutex_unlock(&mutex);
526 #endif
527
528         if (pid < 0) {
529             VLOG_ERR("%s: IPsec requires the ovs-monitor-ipsec daemon",
530                      name);
531             return EINVAL;
532         }
533
534         if (smap_get(args, "peer_cert") && smap_get(args, "psk")) {
535             VLOG_ERR("%s: cannot define both 'peer_cert' and 'psk'", name);
536             return EINVAL;
537         }
538
539         if (!ipsec_mech_set) {
540             VLOG_ERR("%s: IPsec requires an 'peer_cert' or psk' argument",
541                      name);
542             return EINVAL;
543         }
544     }
545
546     if (!tnl_cfg.ip_dst && !tnl_cfg.ip_dst_flow) {
547         VLOG_ERR("%s: %s type requires valid 'remote_ip' argument",
548                  name, type);
549         return EINVAL;
550     }
551     if (tnl_cfg.ip_src_flow && !tnl_cfg.ip_dst_flow) {
552         VLOG_ERR("%s: %s type requires 'remote_ip=flow' with 'local_ip=flow'",
553                  name, type);
554         return EINVAL;
555     }
556     if (!tnl_cfg.ttl) {
557         tnl_cfg.ttl = DEFAULT_TTL;
558     }
559
560     tnl_cfg.in_key = parse_key(args, "in_key",
561                                &tnl_cfg.in_key_present,
562                                &tnl_cfg.in_key_flow);
563
564     tnl_cfg.out_key = parse_key(args, "out_key",
565                                &tnl_cfg.out_key_present,
566                                &tnl_cfg.out_key_flow);
567
568     ovs_mutex_lock(&dev->mutex);
569     dev->tnl_cfg = tnl_cfg;
570     tunnel_check_status_change__(dev);
571     netdev_change_seq_changed(dev_);
572     ovs_mutex_unlock(&dev->mutex);
573
574     return 0;
575 }
576
577 static int
578 get_tunnel_config(const struct netdev *dev, struct smap *args)
579 {
580     struct netdev_vport *netdev = netdev_vport_cast(dev);
581     struct netdev_tunnel_config tnl_cfg;
582
583     ovs_mutex_lock(&netdev->mutex);
584     tnl_cfg = netdev->tnl_cfg;
585     ovs_mutex_unlock(&netdev->mutex);
586
587     if (tnl_cfg.ip_dst) {
588         smap_add_format(args, "remote_ip", IP_FMT, IP_ARGS(tnl_cfg.ip_dst));
589     } else if (tnl_cfg.ip_dst_flow) {
590         smap_add(args, "remote_ip", "flow");
591     }
592
593     if (tnl_cfg.ip_src) {
594         smap_add_format(args, "local_ip", IP_FMT, IP_ARGS(tnl_cfg.ip_src));
595     } else if (tnl_cfg.ip_src_flow) {
596         smap_add(args, "local_ip", "flow");
597     }
598
599     if (tnl_cfg.in_key_flow && tnl_cfg.out_key_flow) {
600         smap_add(args, "key", "flow");
601     } else if (tnl_cfg.in_key_present && tnl_cfg.out_key_present
602                && tnl_cfg.in_key == tnl_cfg.out_key) {
603         smap_add_format(args, "key", "%"PRIu64, ntohll(tnl_cfg.in_key));
604     } else {
605         if (tnl_cfg.in_key_flow) {
606             smap_add(args, "in_key", "flow");
607         } else if (tnl_cfg.in_key_present) {
608             smap_add_format(args, "in_key", "%"PRIu64,
609                             ntohll(tnl_cfg.in_key));
610         }
611
612         if (tnl_cfg.out_key_flow) {
613             smap_add(args, "out_key", "flow");
614         } else if (tnl_cfg.out_key_present) {
615             smap_add_format(args, "out_key", "%"PRIu64,
616                             ntohll(tnl_cfg.out_key));
617         }
618     }
619
620     if (tnl_cfg.ttl_inherit) {
621         smap_add(args, "ttl", "inherit");
622     } else if (tnl_cfg.ttl != DEFAULT_TTL) {
623         smap_add_format(args, "ttl", "%"PRIu8, tnl_cfg.ttl);
624     }
625
626     if (tnl_cfg.tos_inherit) {
627         smap_add(args, "tos", "inherit");
628     } else if (tnl_cfg.tos) {
629         smap_add_format(args, "tos", "0x%x", tnl_cfg.tos);
630     }
631
632     if (tnl_cfg.dst_port) {
633         uint16_t dst_port = ntohs(tnl_cfg.dst_port);
634         const char *type = netdev_get_type(dev);
635
636         if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) ||
637             (!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
638             (!strcmp("lisp", type) && dst_port != LISP_DST_PORT)) {
639             smap_add_format(args, "dst_port", "%d", dst_port);
640         }
641     }
642
643     if (tnl_cfg.csum) {
644         smap_add(args, "csum", "true");
645     }
646
647     if (!tnl_cfg.dont_fragment) {
648         smap_add(args, "df_default", "false");
649     }
650
651     return 0;
652 }
653 \f
654 /* Code specific to patch ports. */
655
656 /* If 'netdev' is a patch port, returns the name of its peer as a malloc()'d
657  * string that the caller must free.
658  *
659  * If 'netdev' is not a patch port, returns NULL. */
660 char *
661 netdev_vport_patch_peer(const struct netdev *netdev_)
662 {
663     char *peer = NULL;
664
665     if (netdev_vport_is_patch(netdev_)) {
666         struct netdev_vport *netdev = netdev_vport_cast(netdev_);
667
668         ovs_mutex_lock(&netdev->mutex);
669         if (netdev->peer) {
670             peer = xstrdup(netdev->peer);
671         }
672         ovs_mutex_unlock(&netdev->mutex);
673     }
674
675     return peer;
676 }
677
678 void
679 netdev_vport_inc_rx(const struct netdev *netdev,
680                     const struct dpif_flow_stats *stats)
681 {
682     if (is_vport_class(netdev_get_class(netdev))) {
683         struct netdev_vport *dev = netdev_vport_cast(netdev);
684
685         ovs_mutex_lock(&dev->mutex);
686         dev->stats.rx_packets += stats->n_packets;
687         dev->stats.rx_bytes += stats->n_bytes;
688         ovs_mutex_unlock(&dev->mutex);
689     }
690 }
691
692 void
693 netdev_vport_inc_tx(const struct netdev *netdev,
694                     const struct dpif_flow_stats *stats)
695 {
696     if (is_vport_class(netdev_get_class(netdev))) {
697         struct netdev_vport *dev = netdev_vport_cast(netdev);
698
699         ovs_mutex_lock(&dev->mutex);
700         dev->stats.tx_packets += stats->n_packets;
701         dev->stats.tx_bytes += stats->n_bytes;
702         ovs_mutex_unlock(&dev->mutex);
703     }
704 }
705
706 static int
707 get_patch_config(const struct netdev *dev_, struct smap *args)
708 {
709     struct netdev_vport *dev = netdev_vport_cast(dev_);
710
711     ovs_mutex_lock(&dev->mutex);
712     if (dev->peer) {
713         smap_add(args, "peer", dev->peer);
714     }
715     ovs_mutex_unlock(&dev->mutex);
716
717     return 0;
718 }
719
720 static int
721 set_patch_config(struct netdev *dev_, const struct smap *args)
722 {
723     struct netdev_vport *dev = netdev_vport_cast(dev_);
724     const char *name = netdev_get_name(dev_);
725     const char *peer;
726
727     peer = smap_get(args, "peer");
728     if (!peer) {
729         VLOG_ERR("%s: patch type requires valid 'peer' argument", name);
730         return EINVAL;
731     }
732
733     if (smap_count(args) > 1) {
734         VLOG_ERR("%s: patch type takes only a 'peer' argument", name);
735         return EINVAL;
736     }
737
738     if (!strcmp(name, peer)) {
739         VLOG_ERR("%s: patch peer must not be self", name);
740         return EINVAL;
741     }
742
743     ovs_mutex_lock(&dev->mutex);
744     free(dev->peer);
745     dev->peer = xstrdup(peer);
746     netdev_change_seq_changed(dev_);
747     ovs_mutex_unlock(&dev->mutex);
748
749     return 0;
750 }
751
752 static int
753 get_stats(const struct netdev *netdev, struct netdev_stats *stats)
754 {
755     struct netdev_vport *dev = netdev_vport_cast(netdev);
756
757     ovs_mutex_lock(&dev->mutex);
758     *stats = dev->stats;
759     ovs_mutex_unlock(&dev->mutex);
760
761     return 0;
762 }
763 \f
764 #define VPORT_FUNCTIONS(GET_CONFIG, SET_CONFIG,             \
765                         GET_TUNNEL_CONFIG, GET_STATUS)      \
766     NULL,                                                   \
767     netdev_vport_run,                                       \
768     netdev_vport_wait,                                      \
769                                                             \
770     netdev_vport_alloc,                                     \
771     netdev_vport_construct,                                 \
772     netdev_vport_destruct,                                  \
773     netdev_vport_dealloc,                                   \
774     GET_CONFIG,                                             \
775     SET_CONFIG,                                             \
776     GET_TUNNEL_CONFIG,                                      \
777                                                             \
778     NULL,                       /* send */                  \
779     NULL,                       /* send_wait */             \
780                                                             \
781     netdev_vport_set_etheraddr,                             \
782     netdev_vport_get_etheraddr,                             \
783     NULL,                       /* get_mtu */               \
784     NULL,                       /* set_mtu */               \
785     NULL,                       /* get_ifindex */           \
786     NULL,                       /* get_carrier */           \
787     NULL,                       /* get_carrier_resets */    \
788     NULL,                       /* get_miimon */            \
789     get_stats,                                              \
790     NULL,                       /* set_stats */             \
791                                                             \
792     NULL,                       /* get_features */          \
793     NULL,                       /* set_advertisements */    \
794                                                             \
795     NULL,                       /* set_policing */          \
796     NULL,                       /* get_qos_types */         \
797     NULL,                       /* get_qos_capabilities */  \
798     NULL,                       /* get_qos */               \
799     NULL,                       /* set_qos */               \
800     NULL,                       /* get_queue */             \
801     NULL,                       /* set_queue */             \
802     NULL,                       /* delete_queue */          \
803     NULL,                       /* get_queue_stats */       \
804     NULL,                       /* queue_dump_start */      \
805     NULL,                       /* queue_dump_next */       \
806     NULL,                       /* queue_dump_done */       \
807     NULL,                       /* dump_queue_stats */      \
808                                                             \
809     NULL,                       /* get_in4 */               \
810     NULL,                       /* set_in4 */               \
811     NULL,                       /* get_in6 */               \
812     NULL,                       /* add_router */            \
813     NULL,                       /* get_next_hop */          \
814     GET_STATUS,                                             \
815     NULL,                       /* arp_lookup */            \
816                                                             \
817     netdev_vport_update_flags,                              \
818                                                             \
819     NULL,                   /* rx_alloc */                  \
820     NULL,                   /* rx_construct */              \
821     NULL,                   /* rx_destruct */               \
822     NULL,                   /* rx_dealloc */                \
823     NULL,                   /* rx_recv */                   \
824     NULL,                   /* rx_wait */                   \
825     NULL,                   /* rx_drain */
826
827 #define TUNNEL_CLASS(NAME, DPIF_PORT)                       \
828     { DPIF_PORT,                                            \
829         { NAME, VPORT_FUNCTIONS(get_tunnel_config,          \
830                                 set_tunnel_config,          \
831                                 get_netdev_tunnel_config,   \
832                                 tunnel_get_status) }}
833
834 void
835 netdev_vport_tunnel_register(void)
836 {
837     /* The name of the dpif_port should be short enough to accomodate adding
838      * a port number to the end if one is necessary. */
839     static const struct vport_class vport_classes[] = {
840         TUNNEL_CLASS("geneve", "genev_sys"),
841         TUNNEL_CLASS("gre", "gre_sys"),
842         TUNNEL_CLASS("ipsec_gre", "gre_sys"),
843         TUNNEL_CLASS("gre64", "gre64_sys"),
844         TUNNEL_CLASS("ipsec_gre64", "gre64_sys"),
845         TUNNEL_CLASS("vxlan", "vxlan_sys"),
846         TUNNEL_CLASS("lisp", "lisp_sys")
847     };
848     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
849
850     if (ovsthread_once_start(&once)) {
851         int i;
852
853         for (i = 0; i < ARRAY_SIZE(vport_classes); i++) {
854             netdev_register_provider(&vport_classes[i].netdev_class);
855         }
856         ovsthread_once_done(&once);
857     }
858 }
859
860 void
861 netdev_vport_patch_register(void)
862 {
863     static const struct vport_class patch_class =
864         { NULL,
865             { "patch", VPORT_FUNCTIONS(get_patch_config,
866                                        set_patch_config,
867                                        NULL,
868                                        NULL) }};
869     netdev_register_provider(&patch_class.netdev_class);
870 }