netdev_pltap,netdev_tunnel: moved to new API
[sliver-openvswitch.git] / lib / netdev-tunnel.c
1 /*
2  * Copyright (c) 2010, 2011, 2012 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 <unistd.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <errno.h>
24
25 #include "flow.h"
26 #include "list.h"
27 #include "netdev-provider.h"
28 #include "odp-util.h"
29 #include "ofp-print.h"
30 #include "ofpbuf.h"
31 #include "packets.h"
32 #include "poll-loop.h"
33 #include "shash.h"
34 #include "sset.h"
35 #include "unixctl.h"
36 #include "socket-util.h"
37 #include "vlog.h"
38
39 VLOG_DEFINE_THIS_MODULE(netdev_tunnel);
40
41 struct netdev_tunnel {
42     struct netdev up;
43     uint8_t hwaddr[ETH_ADDR_LEN];
44     struct netdev_stats stats;
45     enum netdev_flags flags;
46     int sockfd;
47     struct sockaddr_in local_addr;
48     struct sockaddr_in remote_addr;
49     bool valid_remote_ip;
50     bool valid_remote_port;
51     bool connected;
52     unsigned int change_seq;
53 };
54
55 struct netdev_rx_tunnel {
56     struct netdev_rx up;
57     int fd;
58 };
59
60 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
61
62 static struct shash tunnel_netdevs = SHASH_INITIALIZER(&tunnel_netdevs);
63
64 static int netdev_tunnel_construct(struct netdev *netdevp_);
65 static void netdev_tunnel_update_seq(struct netdev_tunnel *);
66
67 static bool
68 is_netdev_tunnel_class(const struct netdev_class *class)
69 {
70     return class->construct == netdev_tunnel_construct;
71 }
72
73 static struct netdev_tunnel *
74 netdev_tunnel_cast(const struct netdev *netdev)
75 {
76     ovs_assert(is_netdev_tunnel_class(netdev_get_class(netdev)));
77     return CONTAINER_OF(netdev, struct netdev_tunnel, up);
78 }
79
80 static struct netdev_rx_tunnel *
81 netdev_rx_tunnel_cast(const struct netdev_rx *rx)
82 {
83     ovs_assert(is_netdev_tunnel_class(netdev_get_class(rx->netdev)));
84     return CONTAINER_OF(rx, struct netdev_rx_tunnel, up);
85 }
86
87 static struct netdev *
88 netdev_tunnel_alloc(void)
89 {
90     struct netdev_tunnel *netdev = xzalloc(sizeof *netdev);
91     return &netdev->up;
92 }
93
94 static int
95 netdev_tunnel_construct(struct netdev *netdev_)
96 {
97     static unsigned int n = 0;
98     struct netdev_tunnel *netdev = netdev_tunnel_cast(netdev_);
99
100     netdev->hwaddr[0] = 0xfe;
101     netdev->hwaddr[1] = 0xff;
102     netdev->hwaddr[2] = 0xff;
103     netdev->hwaddr[3] = n >> 16;
104     netdev->hwaddr[4] = n >> 8;
105     netdev->hwaddr[5] = n;
106     netdev->flags = 0;
107     netdev->change_seq = 1;
108     memset(&netdev->remote_addr, 0, sizeof(netdev->remote_addr));
109     netdev->valid_remote_ip = false;
110     netdev->valid_remote_port = false;
111     netdev->connected = false;
112
113
114     netdev->sockfd = inet_open_passive(SOCK_DGRAM, "", 0, &netdev->local_addr, 0);
115     if (netdev->sockfd < 0) {
116         return netdev->sockfd;
117     }
118
119
120     shash_add(&tunnel_netdevs, netdev_get_name(netdev_), netdev);
121
122     n++;
123
124     VLOG_DBG("tunnel_create: name=%s, fd=%d, port=%d",
125         netdev_get_name(netdev_), netdev->sockfd, netdev->local_addr.sin_port);
126
127     return 0;
128
129 }
130
131 static void
132 netdev_tunnel_destruct(struct netdev *netdev_)
133 {
134     struct netdev_tunnel *netdev = netdev_tunnel_cast(netdev_);
135
136     if (netdev->sockfd != -1)
137         close(netdev->sockfd);
138
139     shash_find_and_delete(&tunnel_netdevs,
140                           netdev_get_name(netdev_));
141 }
142
143 static void
144 netdev_tunnel_dealloc(struct netdev *netdev_)
145 {
146     struct netdev_tunnel *netdev = netdev_tunnel_cast(netdev_);
147     free(netdev);
148 }
149
150 static int
151 netdev_tunnel_get_config(const struct netdev *dev_, struct smap *args)
152 {
153     struct netdev_tunnel *netdev = netdev_tunnel_cast(dev_);
154
155     if (netdev->valid_remote_ip)
156         smap_add_format(args, "remote_ip", IP_FMT,
157                 IP_ARGS(netdev->remote_addr.sin_addr.s_addr));
158     if (netdev->valid_remote_port)
159         smap_add_format(args, "remote_port", "%"PRIu16,
160                 ntohs(netdev->remote_addr.sin_port));
161     return 0;
162 }
163
164 static int
165 netdev_tunnel_connect(struct netdev_tunnel *dev)
166 {
167     char buf[1024];
168     if (dev->sockfd < 0)
169         return EBADF;
170     if (!dev->valid_remote_ip || !dev->valid_remote_port)
171         return 0;
172     dev->remote_addr.sin_family = AF_INET;
173     if (connect(dev->sockfd, (struct sockaddr*) &dev->remote_addr, sizeof(dev->remote_addr)) < 0) {
174         return errno;
175     }
176     dev->connected = true;
177     netdev_tunnel_update_seq(dev);
178     VLOG_DBG("%s: connected to (%s, %d)", netdev_get_name(&dev->up),
179         inet_ntop(AF_INET, &dev->remote_addr.sin_addr, buf, 1024), ntohs(dev->remote_addr.sin_port));
180     return 0;
181 }
182
183 static int
184 netdev_tunnel_set_config(struct netdev *dev_, const struct smap *args)
185 {
186     struct netdev_tunnel *netdev = netdev_tunnel_cast(dev_);
187     struct shash_node *node;
188
189     VLOG_DBG("tunnel_set_config(%s)", netdev_get_name(dev_));
190     SMAP_FOR_EACH(node, args) {
191         VLOG_DBG("arg: %s->%s", node->name, (char*)node->data);
192         if (!strcmp(node->name, "remote_ip")) {
193             struct in_addr addr;
194             if (lookup_ip(node->data, &addr)) {
195                 VLOG_WARN("%s: bad 'remote_ip'", node->name);
196             } else {
197                 netdev->remote_addr.sin_addr = addr;
198                 netdev->valid_remote_ip = true;
199             }
200         } else if (!strcmp(node->name, "remote_port")) {
201             netdev->remote_addr.sin_port = htons(atoi(node->data));
202             netdev->valid_remote_port = true;
203         } else {
204             VLOG_WARN("%s: unknown argument '%s'", 
205                 netdev_get_name(dev_), node->name);
206         }
207     }
208     return netdev_tunnel_connect(netdev);        
209 }
210
211 static struct netdev_rx *
212 netdev_tunnel_rx_alloc(void)
213 {
214     struct netdev_rx_tunnel *rx = xzalloc(sizeof *rx);
215     return &rx->up;
216 }
217
218 static int
219 netdev_tunnel_rx_construct(struct netdev_rx *rx_)
220 {   
221     struct netdev_rx_tunnel *rx = netdev_rx_tunnel_cast(rx_);
222     struct netdev *netdev_ = rx->up.netdev;
223     struct netdev_tunnel *netdev =
224         netdev_tunnel_cast(netdev_);
225     rx->fd = netdev->sockfd;
226     return 0;
227 }
228
229 static void
230 netdev_tunnel_rx_destruct(struct netdev_rx *rx_ OVS_UNUSED)
231 {
232 }
233
234 static void
235 netdev_tunnel_rx_dealloc(struct netdev_rx *rx_)
236 {
237     struct netdev_rx_tunnel *rx = netdev_rx_tunnel_cast(rx_);
238
239     free(rx);
240 }
241
242 static int
243 netdev_tunnel_rx_recv(struct netdev_rx *rx_, void *buffer, size_t size)
244 {
245     struct netdev_rx_tunnel *rx = netdev_rx_tunnel_cast(rx_);
246     struct netdev_tunnel *netdev =
247         netdev_tunnel_cast(rx_->netdev);
248     if (!netdev->connected)
249         return -EAGAIN;
250     for (;;) {
251         ssize_t retval;
252         retval = recv(rx->fd, buffer, size, MSG_TRUNC);
253             VLOG_DBG("%s: recv(%"PRIxPTR", %zu, MSG_TRUNC) = %zd",
254                     netdev_rx_get_name(rx_), (uintptr_t)buffer, size, retval);
255         if (retval >= 0) {
256             netdev->stats.rx_packets++;
257             netdev->stats.rx_bytes += retval;
258             if (retval <= size) {
259                     return retval;
260             } else {
261                 netdev->stats.rx_errors++;
262                 netdev->stats.rx_length_errors++;
263                 return -EMSGSIZE;
264             }
265         } else if (errno != EINTR) {
266             if (errno != EAGAIN) {
267                 VLOG_WARN_RL(&rl, "error receiveing Ethernet packet on %s: %s",
268                     netdev_rx_get_name(rx_), ovs_strerror(errno));
269                     netdev->stats.rx_errors++;
270             }
271             return -errno;
272         }
273     }
274 }
275
276 static void
277 netdev_tunnel_rx_wait(struct netdev_rx *rx_)
278 {
279     struct netdev_rx_tunnel *rx = 
280         netdev_rx_tunnel_cast(rx_);
281     if (rx->fd >= 0) {
282         poll_fd_wait(rx->fd, POLLIN);
283     }
284 }
285
286 static int
287 netdev_tunnel_send(struct netdev *netdev_, const void *buffer, size_t size)
288 {
289     struct netdev_tunnel *dev = 
290         netdev_tunnel_cast(netdev_);
291     if (!dev->connected)
292         return EAGAIN;
293     for (;;) {
294         ssize_t retval;
295         retval = send(dev->sockfd, buffer, size, 0);
296         VLOG_DBG("%s: send(%"PRIxPTR", %zu) = %zd",
297                  netdev_get_name(netdev_), (uintptr_t)buffer, size, retval);
298         if (retval >= 0) {
299             dev->stats.tx_packets++;
300             dev->stats.tx_bytes += retval;
301             if (retval != size) {
302                 VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%zd bytes of "
303                              "%zu) on %s", retval, size, netdev_get_name(netdev_));
304                 dev->stats.tx_errors++;
305             }
306             return 0;
307         } else if (errno != EINTR) {
308             if (errno != EAGAIN) {
309                 VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: %s",
310                     netdev_get_name(netdev_), ovs_strerror(errno));
311                 dev->stats.tx_errors++;
312             }
313             return errno;
314         }
315     }
316 }
317
318 static void
319 netdev_tunnel_send_wait(struct netdev *netdev_)
320 {
321     struct netdev_tunnel *dev = netdev_tunnel_cast(netdev_);
322     if (dev->sockfd >= 0) {
323         poll_fd_wait(dev->sockfd, POLLOUT);
324     }
325 }
326
327 static int
328 netdev_tunnel_rx_drain(struct netdev_rx *rx_)
329 {
330     struct netdev_tunnel *netdev =
331         netdev_tunnel_cast(rx_->netdev);
332     struct netdev_rx_tunnel *rx = 
333         netdev_rx_tunnel_cast(rx_);
334     char buffer[128];
335     int error;
336
337     if (!netdev->connected)
338         return 0;
339     for (;;) {
340         error = recv(rx->fd, buffer, 128, MSG_TRUNC);
341         if (error) {
342             if (error == -EAGAIN)
343                 break;
344             else if (error != -EMSGSIZE)
345                 return error;
346         }
347     }
348     return 0;
349 }
350
351 static int
352 netdev_tunnel_set_etheraddr(struct netdev *netdev,
353                            const uint8_t mac[ETH_ADDR_LEN])
354 {
355     struct netdev_tunnel *dev = netdev_tunnel_cast(netdev);
356
357     if (!eth_addr_equals(dev->hwaddr, mac)) {
358         memcpy(dev->hwaddr, mac, ETH_ADDR_LEN);
359         netdev_tunnel_update_seq(dev);
360     }
361
362     return 0;
363 }
364
365 static int
366 netdev_tunnel_get_etheraddr(const struct netdev *netdev,
367                            uint8_t mac[ETH_ADDR_LEN])
368 {
369     const struct netdev_tunnel *dev = netdev_tunnel_cast(netdev);
370
371     memcpy(mac, dev->hwaddr, ETH_ADDR_LEN);
372     return 0;
373 }
374
375
376 static int
377 netdev_tunnel_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
378 {
379     const struct netdev_tunnel *dev = netdev_tunnel_cast(netdev);
380
381     *stats = dev->stats;
382     return 0;
383 }
384
385 static int
386 netdev_tunnel_set_stats(struct netdev *netdev, const struct netdev_stats *stats)
387 {
388     struct netdev_tunnel *dev = netdev_tunnel_cast(netdev);
389
390     dev->stats = *stats;
391     return 0;
392 }
393
394 static int
395 netdev_tunnel_update_flags(struct netdev *dev_,
396                           enum netdev_flags off, enum netdev_flags on,
397                           enum netdev_flags *old_flagsp)
398 {
399     struct netdev_tunnel *netdev =
400         netdev_tunnel_cast(dev_);
401
402     if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) {
403         return EINVAL;
404     }
405
406     // XXX should we actually do something with these flags?
407     *old_flagsp = netdev->flags;
408     netdev->flags |= on;
409     netdev->flags &= ~off;
410     if (*old_flagsp != netdev->flags) {
411         netdev_tunnel_update_seq(netdev);
412     }
413     return 0;
414 }
415
416 static unsigned int
417 netdev_tunnel_change_seq(const struct netdev *netdev)
418 {
419     return netdev_tunnel_cast(netdev)->change_seq;
420 }
421 \f
422 /* Helper functions. */
423
424 static void
425 netdev_tunnel_update_seq(struct netdev_tunnel *dev)
426 {
427     dev->change_seq++;
428     if (!dev->change_seq) {
429         dev->change_seq++;
430     }
431 }
432
433 static void
434 netdev_tunnel_get_port(struct unixctl_conn *conn,
435                      int argc OVS_UNUSED, const char *argv[], void *aux OVS_UNUSED)
436 {
437     struct netdev_tunnel *tunnel_dev;
438     char buf[6];
439
440     tunnel_dev = shash_find_data(&tunnel_netdevs, argv[1]);
441     if (!tunnel_dev) {
442         unixctl_command_reply_error(conn, "no such tunnel netdev");
443         return;
444     }
445
446     sprintf(buf, "%d", ntohs(tunnel_dev->local_addr.sin_port));
447     unixctl_command_reply(conn, buf);
448 }
449
450 static void
451 netdev_tunnel_get_tx_bytes(struct unixctl_conn *conn,
452                      int argc OVS_UNUSED, const char *argv[], void *aux OVS_UNUSED)
453 {
454     struct netdev_tunnel *tunnel_dev;
455     char buf[128];
456
457     tunnel_dev = shash_find_data(&tunnel_netdevs, argv[1]);
458     if (!tunnel_dev) {
459         unixctl_command_reply_error(conn, "no such tunnel netdev");
460         return;
461     }
462
463     sprintf(buf, "%"PRIu64, tunnel_dev->stats.tx_bytes);
464     unixctl_command_reply(conn, buf);
465 }
466
467 static void
468 netdev_tunnel_get_rx_bytes(struct unixctl_conn *conn,
469                      int argc OVS_UNUSED, const char *argv[], void *aux OVS_UNUSED)
470 {
471     struct netdev_tunnel *tunnel_dev;
472     char buf[128];
473
474     tunnel_dev = shash_find_data(&tunnel_netdevs, argv[1]);
475     if (!tunnel_dev) {
476         unixctl_command_reply_error(conn, "no such tunnel netdev");
477         return;
478     }
479
480     sprintf(buf, "%"PRIu64, tunnel_dev->stats.rx_bytes);
481     unixctl_command_reply(conn, buf);
482 }
483
484
485 static int
486 netdev_tunnel_init(void)
487 {
488     unixctl_command_register("netdev-tunnel/get-port", "NAME",
489                              1, 1, netdev_tunnel_get_port, NULL);
490     unixctl_command_register("netdev-tunnel/get-tx-bytes", "NAME",
491                              1, 1, netdev_tunnel_get_tx_bytes, NULL);
492     unixctl_command_register("netdev-tunnel/get-rx-bytes", "NAME",
493                              1, 1, netdev_tunnel_get_rx_bytes, NULL);
494     return 0;
495 }
496
497 const struct netdev_class netdev_tunnel_class = {
498     "tunnel",
499     netdev_tunnel_init,         /* init */
500     NULL,                       /* run */
501     NULL,                       /* wait */
502
503     netdev_tunnel_alloc,
504     netdev_tunnel_construct,
505     netdev_tunnel_destruct,
506     netdev_tunnel_dealloc,
507     netdev_tunnel_get_config,
508     netdev_tunnel_set_config, 
509     NULL,                                   /* get_tunnel_config */
510
511     netdev_tunnel_send, 
512     netdev_tunnel_send_wait,  
513
514     netdev_tunnel_set_etheraddr,
515     netdev_tunnel_get_etheraddr,
516     NULL,                                   /* get_mtu */
517     NULL,                                   /* set_mtu */
518     NULL,                       /* get_ifindex */
519     NULL,                                   /* get_carrier */
520     NULL,                       /* get_carrier_resets */
521     NULL,                       /* get_miimon */
522     netdev_tunnel_get_stats,
523     netdev_tunnel_set_stats,
524
525     NULL,                       /* get_features */
526     NULL,                       /* set_advertisements */
527
528     NULL,                       /* set_policing */
529     NULL,                       /* get_qos_types */
530     NULL,                       /* get_qos_capabilities */
531     NULL,                       /* get_qos */
532     NULL,                       /* set_qos */
533     NULL,                       /* get_queue */
534     NULL,                       /* set_queue */
535     NULL,                       /* delete_queue */
536     NULL,                       /* get_queue_stats */
537     NULL,                       /* dump_queues */
538     NULL,                       /* dump_queue_stats */
539
540     NULL,                       /* get_in4 */
541     NULL,                       /* set_in4 */
542     NULL,                       /* get_in6 */
543     NULL,                       /* add_router */
544     NULL,                       /* get_next_hop */
545     NULL,                       /* get_drv_info */
546     NULL,                       /* arp_lookup */
547
548     netdev_tunnel_update_flags,
549
550     netdev_tunnel_change_seq,
551
552     netdev_tunnel_rx_alloc,
553     netdev_tunnel_rx_construct,
554     netdev_tunnel_rx_destruct,
555     netdev_tunnel_rx_dealloc,
556     netdev_tunnel_rx_recv,
557     netdev_tunnel_rx_wait,
558     netdev_tunnel_rx_drain,
559 };