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