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