netdev-vport: Build on all platforms.
[sliver-openvswitch.git] / lib / netdev-vport.c
1 /*
2  * Copyright (c) 2010, 2011, 2012, 2013 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18
19 #include "netdev-vport.h"
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <sys/socket.h>
24 #include <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 "route-table.h"
38 #include "shash.h"
39 #include "socket-util.h"
40 #include "vlog.h"
41
42 VLOG_DEFINE_THIS_MODULE(netdev_vport);
43
44 /* Default to the OTV port, per the VXLAN IETF draft. */
45 #define VXLAN_DST_PORT 8472
46
47 #define DEFAULT_TTL 64
48
49 struct netdev_dev_vport {
50     struct netdev_dev netdev_dev;
51     unsigned int change_seq;
52     uint8_t etheraddr[ETH_ADDR_LEN];
53     struct netdev_stats stats;
54
55     /* Tunnels. */
56     struct netdev_tunnel_config tnl_cfg;
57
58     /* Patch Ports. */
59     char *peer;
60 };
61
62 struct vport_class {
63     const char *dpif_port;
64     struct netdev_class netdev_class;
65 };
66
67 static int netdev_vport_create(const struct netdev_class *, const char *,
68                                struct netdev_dev **);
69 static int get_patch_config(struct netdev_dev *, struct smap *args);
70 static void netdev_vport_poll_notify(struct netdev_dev_vport *);
71
72 static bool
73 is_vport_class(const struct netdev_class *class)
74 {
75     return class->create == netdev_vport_create;
76 }
77
78 static const struct vport_class *
79 vport_class_cast(const struct netdev_class *class)
80 {
81     ovs_assert(is_vport_class(class));
82     return CONTAINER_OF(class, struct vport_class, netdev_class);
83 }
84
85 static struct netdev_dev_vport *
86 netdev_dev_vport_cast(const struct netdev_dev *netdev_dev)
87 {
88     ovs_assert(is_vport_class(netdev_dev_get_class(netdev_dev)));
89     return CONTAINER_OF(netdev_dev, struct netdev_dev_vport, netdev_dev);
90 }
91
92 static struct netdev_dev_vport *
93 netdev_vport_get_dev(const struct netdev *netdev)
94 {
95     return netdev_dev_vport_cast(netdev_get_dev(netdev));
96 }
97
98 static const struct netdev_tunnel_config *
99 get_netdev_tunnel_config(const struct netdev_dev *netdev_dev)
100 {
101     return &netdev_dev_vport_cast(netdev_dev)->tnl_cfg;
102 }
103
104 bool
105 netdev_vport_is_patch(const struct netdev *netdev)
106 {
107     const struct netdev_dev *dev = netdev_get_dev(netdev);
108     const struct netdev_class *class = netdev_dev_get_class(dev);
109
110     return class->get_config == get_patch_config;
111 }
112
113 const char *
114 netdev_vport_get_dpif_port(const struct netdev *netdev)
115 {
116     const struct netdev_dev *dev = netdev_get_dev(netdev);
117     const struct netdev_class *class = netdev_dev_get_class(dev);
118     const char *dpif_port;
119
120     dpif_port = (is_vport_class(class)
121                  ? vport_class_cast(class)->dpif_port
122                  : NULL);
123     return dpif_port ? dpif_port : netdev_get_name(netdev);
124 }
125
126 static int
127 netdev_vport_create(const struct netdev_class *netdev_class, const char *name,
128                     struct netdev_dev **netdev_devp)
129 {
130     struct netdev_dev_vport *dev;
131
132     dev = xzalloc(sizeof *dev);
133     netdev_dev_init(&dev->netdev_dev, name, netdev_class);
134     dev->change_seq = 1;
135     eth_addr_random(dev->etheraddr);
136
137     *netdev_devp = &dev->netdev_dev;
138     route_table_register();
139
140     return 0;
141 }
142
143 static void
144 netdev_vport_destroy(struct netdev_dev *netdev_dev_)
145 {
146     struct netdev_dev_vport *netdev_dev = netdev_dev_vport_cast(netdev_dev_);
147
148     route_table_unregister();
149     free(netdev_dev->peer);
150     free(netdev_dev);
151 }
152
153 static int
154 netdev_vport_open(struct netdev_dev *netdev_dev, struct netdev **netdevp)
155 {
156     *netdevp = xmalloc(sizeof **netdevp);
157     netdev_init(*netdevp, netdev_dev);
158     return 0;
159 }
160
161 static void
162 netdev_vport_close(struct netdev *netdev)
163 {
164     free(netdev);
165 }
166
167 static int
168 netdev_vport_set_etheraddr(struct netdev *netdev,
169                            const uint8_t mac[ETH_ADDR_LEN])
170 {
171     struct netdev_dev_vport *dev = netdev_vport_get_dev(netdev);
172     memcpy(dev->etheraddr, mac, ETH_ADDR_LEN);
173     netdev_vport_poll_notify(dev);
174     return 0;
175 }
176
177 static int
178 netdev_vport_get_etheraddr(const struct netdev *netdev,
179                            uint8_t mac[ETH_ADDR_LEN])
180 {
181     memcpy(mac, netdev_vport_get_dev(netdev)->etheraddr, ETH_ADDR_LEN);
182     return 0;
183 }
184
185 static int
186 tunnel_get_status(const struct netdev *netdev, struct smap *smap)
187 {
188     static char iface[IFNAMSIZ];
189     ovs_be32 route;
190
191     route = netdev_vport_get_dev(netdev)->tnl_cfg.ip_dst;
192     if (route_table_get_name(route, iface)) {
193         struct netdev *egress_netdev;
194
195         smap_add(smap, "tunnel_egress_iface", iface);
196
197         if (!netdev_open(iface, "system", &egress_netdev)) {
198             smap_add(smap, "tunnel_egress_iface_carrier",
199                      netdev_get_carrier(egress_netdev) ? "up" : "down");
200             netdev_close(egress_netdev);
201         }
202     }
203
204     return 0;
205 }
206
207 static int
208 netdev_vport_update_flags(struct netdev *netdev OVS_UNUSED,
209                         enum netdev_flags off, enum netdev_flags on OVS_UNUSED,
210                         enum netdev_flags *old_flagsp)
211 {
212     if (off & (NETDEV_UP | NETDEV_PROMISC)) {
213         return EOPNOTSUPP;
214     }
215
216     *old_flagsp = NETDEV_UP | NETDEV_PROMISC;
217     return 0;
218 }
219
220 static unsigned int
221 netdev_vport_change_seq(const struct netdev *netdev)
222 {
223     return netdev_vport_get_dev(netdev)->change_seq;
224 }
225
226 static void
227 netdev_vport_run(void)
228 {
229     route_table_run();
230 }
231
232 static void
233 netdev_vport_wait(void)
234 {
235     route_table_wait();
236 }
237 \f
238 /* Helper functions. */
239
240 static void
241 netdev_vport_poll_notify(struct netdev_dev_vport *ndv)
242 {
243     ndv->change_seq++;
244     if (!ndv->change_seq) {
245         ndv->change_seq++;
246     }
247 }
248 \f
249 /* Code specific to tunnel types. */
250
251 static ovs_be64
252 parse_key(const struct smap *args, const char *name,
253           bool *present, bool *flow)
254 {
255     const char *s;
256
257     *present = false;
258     *flow = false;
259
260     s = smap_get(args, name);
261     if (!s) {
262         s = smap_get(args, "key");
263         if (!s) {
264             return 0;
265         }
266     }
267
268     *present = true;
269
270     if (!strcmp(s, "flow")) {
271         *flow = true;
272         return 0;
273     } else {
274         return htonll(strtoull(s, NULL, 0));
275     }
276 }
277
278 static int
279 set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
280 {
281     struct netdev_dev_vport *dev = netdev_dev_vport_cast(dev_);
282     const char *name = netdev_dev_get_name(dev_);
283     const char *type = netdev_dev_get_type(dev_);
284     bool ipsec_mech_set, needs_dst_port, has_csum;
285     struct netdev_tunnel_config tnl_cfg;
286     struct smap_node *node;
287
288     has_csum = strstr(type, "gre");
289     ipsec_mech_set = false;
290     memset(&tnl_cfg, 0, sizeof tnl_cfg);
291
292     if (!strcmp(type, "capwap")) {
293         VLOG_WARN_ONCE("CAPWAP tunnel support is deprecated.");
294     }
295
296     needs_dst_port = !strcmp(type, "vxlan");
297     tnl_cfg.ipsec = strstr(type, "ipsec");
298     tnl_cfg.dont_fragment = true;
299
300     SMAP_FOR_EACH (node, args) {
301         if (!strcmp(node->key, "remote_ip")) {
302             struct in_addr in_addr;
303             if (lookup_ip(node->value, &in_addr)) {
304                 VLOG_WARN("%s: bad %s 'remote_ip'", name, type);
305             } else {
306                 tnl_cfg.ip_dst = in_addr.s_addr;
307             }
308         } else if (!strcmp(node->key, "local_ip")) {
309             struct in_addr in_addr;
310             if (lookup_ip(node->value, &in_addr)) {
311                 VLOG_WARN("%s: bad %s 'local_ip'", name, type);
312             } else {
313                 tnl_cfg.ip_src = in_addr.s_addr;
314             }
315         } else if (!strcmp(node->key, "tos")) {
316             if (!strcmp(node->value, "inherit")) {
317                 tnl_cfg.tos_inherit = true;
318             } else {
319                 char *endptr;
320                 int tos;
321                 tos = strtol(node->value, &endptr, 0);
322                 if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
323                     tnl_cfg.tos = tos;
324                 } else {
325                     VLOG_WARN("%s: invalid TOS %s", name, node->value);
326                 }
327             }
328         } else if (!strcmp(node->key, "ttl")) {
329             if (!strcmp(node->value, "inherit")) {
330                 tnl_cfg.ttl_inherit = true;
331             } else {
332                 tnl_cfg.ttl = atoi(node->value);
333             }
334         } else if (!strcmp(node->key, "dst_port") && needs_dst_port) {
335             tnl_cfg.dst_port = htons(atoi(node->value));
336         } else if (!strcmp(node->key, "csum") && has_csum) {
337             if (!strcmp(node->value, "true")) {
338                 tnl_cfg.csum = true;
339             }
340         } else if (!strcmp(node->key, "df_default")) {
341             if (!strcmp(node->value, "false")) {
342                 tnl_cfg.dont_fragment = false;
343             }
344         } else if (!strcmp(node->key, "peer_cert") && tnl_cfg.ipsec) {
345             if (smap_get(args, "certificate")) {
346                 ipsec_mech_set = true;
347             } else {
348                 const char *use_ssl_cert;
349
350                 /* If the "use_ssl_cert" is true, then "certificate" and
351                  * "private_key" will be pulled from the SSL table.  The
352                  * use of this option is strongly discouraged, since it
353                  * will like be removed when multiple SSL configurations
354                  * are supported by OVS.
355                  */
356                 use_ssl_cert = smap_get(args, "use_ssl_cert");
357                 if (!use_ssl_cert || strcmp(use_ssl_cert, "true")) {
358                     VLOG_ERR("%s: 'peer_cert' requires 'certificate' argument",
359                              name);
360                     return EINVAL;
361                 }
362                 ipsec_mech_set = true;
363             }
364         } else if (!strcmp(node->key, "psk") && tnl_cfg.ipsec) {
365             ipsec_mech_set = true;
366         } else if (tnl_cfg.ipsec
367                 && (!strcmp(node->key, "certificate")
368                     || !strcmp(node->key, "private_key")
369                     || !strcmp(node->key, "use_ssl_cert"))) {
370             /* Ignore options not used by the netdev. */
371         } else if (!strcmp(node->key, "key") ||
372                    !strcmp(node->key, "in_key") ||
373                    !strcmp(node->key, "out_key")) {
374             /* Handled separately below. */
375         } else {
376             VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
377         }
378     }
379
380     /* Add a default destination port for VXLAN if none specified. */
381     if (needs_dst_port && !tnl_cfg.dst_port) {
382         tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
383     }
384
385     if (tnl_cfg.ipsec) {
386         static pid_t pid = 0;
387         if (pid <= 0) {
388             char *file_name = xasprintf("%s/%s", ovs_rundir(),
389                                         "ovs-monitor-ipsec.pid");
390             pid = read_pidfile(file_name);
391             free(file_name);
392         }
393
394         if (pid < 0) {
395             VLOG_ERR("%s: IPsec requires the ovs-monitor-ipsec daemon",
396                      name);
397             return EINVAL;
398         }
399
400         if (smap_get(args, "peer_cert") && smap_get(args, "psk")) {
401             VLOG_ERR("%s: cannot define both 'peer_cert' and 'psk'", name);
402             return EINVAL;
403         }
404
405         if (!ipsec_mech_set) {
406             VLOG_ERR("%s: IPsec requires an 'peer_cert' or psk' argument",
407                      name);
408             return EINVAL;
409         }
410     }
411
412     if (!tnl_cfg.ip_dst) {
413         VLOG_ERR("%s: %s type requires valid 'remote_ip' argument",
414                  name, type);
415         return EINVAL;
416     }
417
418     if (tnl_cfg.ip_src) {
419         if (ip_is_multicast(tnl_cfg.ip_dst)) {
420             VLOG_WARN("%s: remote_ip is multicast, ignoring local_ip", name);
421             tnl_cfg.ip_src = 0;
422         }
423     }
424
425     if (!tnl_cfg.ttl) {
426         tnl_cfg.ttl = DEFAULT_TTL;
427     }
428
429     tnl_cfg.in_key = parse_key(args, "in_key",
430                                &tnl_cfg.in_key_present,
431                                &tnl_cfg.in_key_flow);
432
433     tnl_cfg.out_key = parse_key(args, "out_key",
434                                &tnl_cfg.out_key_present,
435                                &tnl_cfg.out_key_flow);
436
437     dev->tnl_cfg = tnl_cfg;
438     netdev_vport_poll_notify(dev);
439
440     return 0;
441 }
442
443 static int
444 get_tunnel_config(struct netdev_dev *dev, struct smap *args)
445 {
446     const struct netdev_tunnel_config *tnl_cfg =
447         &netdev_dev_vport_cast(dev)->tnl_cfg;
448
449     if (tnl_cfg->ip_dst) {
450         smap_add_format(args, "remote_ip", IP_FMT, IP_ARGS(tnl_cfg->ip_dst));
451     }
452
453     if (tnl_cfg->ip_src) {
454         smap_add_format(args, "local_ip", IP_FMT, IP_ARGS(tnl_cfg->ip_src));
455     }
456
457     if (tnl_cfg->in_key_flow && tnl_cfg->out_key_flow) {
458         smap_add(args, "key", "flow");
459     } else if (tnl_cfg->in_key_present && tnl_cfg->out_key_present
460                && tnl_cfg->in_key == tnl_cfg->out_key) {
461         smap_add_format(args, "key", "%"PRIu64, ntohll(tnl_cfg->in_key));
462     } else {
463         if (tnl_cfg->in_key_flow) {
464             smap_add(args, "in_key", "flow");
465         } else if (tnl_cfg->in_key_present) {
466             smap_add_format(args, "in_key", "%"PRIu64,
467                             ntohll(tnl_cfg->in_key));
468         }
469
470         if (tnl_cfg->out_key_flow) {
471             smap_add(args, "out_key", "flow");
472         } else if (tnl_cfg->out_key_present) {
473             smap_add_format(args, "out_key", "%"PRIu64,
474                             ntohll(tnl_cfg->out_key));
475         }
476     }
477
478     if (tnl_cfg->ttl_inherit) {
479         smap_add(args, "ttl", "inherit");
480     } else if (tnl_cfg->ttl != DEFAULT_TTL) {
481         smap_add_format(args, "ttl", "%"PRIu8, tnl_cfg->ttl);
482     }
483
484     if (tnl_cfg->tos_inherit) {
485         smap_add(args, "tos", "inherit");
486     } else if (tnl_cfg->tos) {
487         smap_add_format(args, "tos", "0x%x", tnl_cfg->tos);
488     }
489
490     if (tnl_cfg->dst_port) {
491         uint16_t dst_port = ntohs(tnl_cfg->dst_port);
492         if (dst_port != VXLAN_DST_PORT) {
493             smap_add_format(args, "dst_port", "%d", dst_port);
494         }
495     }
496
497     if (tnl_cfg->csum) {
498         smap_add(args, "csum", "true");
499     }
500
501     if (!tnl_cfg->dont_fragment) {
502         smap_add(args, "df_default", "false");
503     }
504
505     return 0;
506 }
507 \f
508 /* Code specific to patch ports. */
509
510 const char *
511 netdev_vport_patch_peer(const struct netdev *netdev)
512 {
513     return netdev_vport_is_patch(netdev)
514         ? netdev_vport_get_dev(netdev)->peer
515         : NULL;
516 }
517
518 void
519 netdev_vport_inc_rx(const struct netdev *netdev,
520                           const struct dpif_flow_stats *stats)
521 {
522     if (is_vport_class(netdev_dev_get_class(netdev_get_dev(netdev)))) {
523         struct netdev_dev_vport *dev = netdev_vport_get_dev(netdev);
524         dev->stats.rx_packets += stats->n_packets;
525         dev->stats.rx_bytes += stats->n_bytes;
526     }
527 }
528
529 void
530 netdev_vport_inc_tx(const struct netdev *netdev,
531                     const struct dpif_flow_stats *stats)
532 {
533     if (is_vport_class(netdev_dev_get_class(netdev_get_dev(netdev)))) {
534         struct netdev_dev_vport *dev = netdev_vport_get_dev(netdev);
535         dev->stats.tx_packets += stats->n_packets;
536         dev->stats.tx_bytes += stats->n_bytes;
537     }
538 }
539
540 static int
541 get_patch_config(struct netdev_dev *dev_, struct smap *args)
542 {
543     struct netdev_dev_vport *dev = netdev_dev_vport_cast(dev_);
544
545     if (dev->peer) {
546         smap_add(args, "peer", dev->peer);
547     }
548     return 0;
549 }
550
551 static int
552 set_patch_config(struct netdev_dev *dev_, const struct smap *args)
553 {
554     struct netdev_dev_vport *dev = netdev_dev_vport_cast(dev_);
555     const char *name = netdev_dev_get_name(dev_);
556     const char *peer;
557
558     peer = smap_get(args, "peer");
559     if (!peer) {
560         VLOG_ERR("%s: patch type requires valid 'peer' argument", name);
561         return EINVAL;
562     }
563
564     if (smap_count(args) > 1) {
565         VLOG_ERR("%s: patch type takes only a 'peer' argument", name);
566         return EINVAL;
567     }
568
569     if (!strcmp(name, peer)) {
570         VLOG_ERR("%s: patch peer must not be self", name);
571         return EINVAL;
572     }
573
574     free(dev->peer);
575     dev->peer = xstrdup(peer);
576
577     return 0;
578 }
579
580 static int
581 get_stats(const struct netdev *netdev, struct netdev_stats *stats)
582 {
583     struct netdev_dev_vport *dev = netdev_vport_get_dev(netdev);
584     memcpy(stats, &dev->stats, sizeof *stats);
585     return 0;
586 }
587 \f
588 #define VPORT_FUNCTIONS(GET_CONFIG, SET_CONFIG,             \
589                         GET_TUNNEL_CONFIG, GET_STATUS)      \
590     NULL,                                                   \
591     netdev_vport_run,                                       \
592     netdev_vport_wait,                                      \
593                                                             \
594     netdev_vport_create,                                    \
595     netdev_vport_destroy,                                   \
596     GET_CONFIG,                                             \
597     SET_CONFIG,                                             \
598     GET_TUNNEL_CONFIG,                                      \
599                                                             \
600     netdev_vport_open,                                      \
601     netdev_vport_close,                                     \
602                                                             \
603     NULL,                       /* listen */                \
604     NULL,                       /* recv */                  \
605     NULL,                       /* recv_wait */             \
606     NULL,                       /* drain */                 \
607                                                             \
608     NULL,                       /* send */                  \
609     NULL,                       /* send_wait */             \
610                                                             \
611     netdev_vport_set_etheraddr,                             \
612     netdev_vport_get_etheraddr,                             \
613     NULL,                       /* get_mtu */               \
614     NULL,                       /* set_mtu */               \
615     NULL,                       /* get_ifindex */           \
616     NULL,                       /* get_carrier */           \
617     NULL,                       /* get_carrier_resets */    \
618     NULL,                       /* get_miimon */            \
619     get_stats,                                              \
620     NULL,                       /* set_stats */             \
621                                                             \
622     NULL,                       /* get_features */          \
623     NULL,                       /* set_advertisements */    \
624                                                             \
625     NULL,                       /* set_policing */          \
626     NULL,                       /* get_qos_types */         \
627     NULL,                       /* get_qos_capabilities */  \
628     NULL,                       /* get_qos */               \
629     NULL,                       /* set_qos */               \
630     NULL,                       /* get_queue */             \
631     NULL,                       /* set_queue */             \
632     NULL,                       /* delete_queue */          \
633     NULL,                       /* get_queue_stats */       \
634     NULL,                       /* dump_queues */           \
635     NULL,                       /* dump_queue_stats */      \
636                                                             \
637     NULL,                       /* get_in4 */               \
638     NULL,                       /* set_in4 */               \
639     NULL,                       /* get_in6 */               \
640     NULL,                       /* add_router */            \
641     NULL,                       /* get_next_hop */          \
642     GET_STATUS,                                             \
643     NULL,                       /* arp_lookup */            \
644                                                             \
645     netdev_vport_update_flags,                              \
646                                                             \
647     netdev_vport_change_seq
648
649 #define TUNNEL_CLASS(NAME, DPIF_PORT)                       \
650     { DPIF_PORT,                                            \
651         { NAME, VPORT_FUNCTIONS(get_tunnel_config,          \
652                                 set_tunnel_config,          \
653                                 get_netdev_tunnel_config,   \
654                                 tunnel_get_status) }}
655
656 void
657 netdev_vport_tunnel_register(void)
658 {
659     static const struct vport_class vport_classes[] = {
660         TUNNEL_CLASS("gre", "gre_system"),
661         TUNNEL_CLASS("ipsec_gre", "gre_system"),
662         TUNNEL_CLASS("gre64", "gre64_system"),
663         TUNNEL_CLASS("ipsec_gre64", "gre64_system"),
664         TUNNEL_CLASS("capwap", "capwap_system"),
665         TUNNEL_CLASS("vxlan", "vxlan_system")
666     };
667
668     int i;
669
670     for (i = 0; i < ARRAY_SIZE(vport_classes); i++) {
671         netdev_register_provider(&vport_classes[i].netdev_class);
672     }
673 }
674
675 void
676 netdev_vport_patch_register(void)
677 {
678     static const struct vport_class patch_class =
679         { NULL,
680             { "patch", VPORT_FUNCTIONS(get_patch_config,
681                                        set_patch_config,
682                                        NULL,
683                                        NULL) }};
684     netdev_register_provider(&patch_class.netdev_class);
685 }