comply with new ofpbuf interface
[sliver-openvswitch.git] / lib / netdev-pltap.c
1 /*
2  * Copyright (c) 2012 Giuseppe Lettieri
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 <sys/types.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <arpa/inet.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <net/if.h>
26 #include <net/if_arp.h>
27 #include <linux/if_tun.h>
28 #include <netinet/in.h>
29 #include <errno.h>
30
31 #include "flow.h"
32 #include "list.h"
33 #include "dpif-netdev.h"
34 #include "netdev-provider.h"
35 #include "odp-util.h"
36 #include "ofp-print.h"
37 #include "ofpbuf.h"
38 #include "packets.h"
39 #include "poll-loop.h"
40 #include "shash.h"
41 #include "sset.h"
42 #include "unixctl.h"
43 #include "socket-util.h"
44 #include "vlog.h"
45 #include "tunalloc.h"
46
47 VLOG_DEFINE_THIS_MODULE(netdev_pltap);
48
49 /* Protects 'sync_list'. */
50 static struct ovs_mutex sync_list_mutex = OVS_MUTEX_INITIALIZER;
51
52 static struct list sync_list OVS_GUARDED_BY(sync_list_mutex)
53     = LIST_INITIALIZER(&sync_list);
54
55 struct netdev_pltap {
56     struct netdev up;
57
58     /* In sync_list. */
59     struct list sync_list OVS_GUARDED_BY(sync_list_mutex);
60
61     /* Protects all members below. */
62     struct ovs_mutex mutex OVS_ACQ_AFTER(sync_list_mutex);
63
64     char *real_name;
65     struct netdev_stats stats;
66     enum netdev_flags new_flags;
67     enum netdev_flags flags;
68     int fd;
69     struct sockaddr_in local_addr;
70     int local_netmask;
71     bool valid_local_ip;
72     bool valid_local_netmask;
73     bool sync_flags_needed;
74     unsigned int change_seq;
75 };
76
77
78 struct netdev_rxq_pltap {
79     struct netdev_rxq up;    
80     int fd;
81 };
82
83 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
84
85 /* Protects 'pltap_netdevs' */
86 static struct ovs_mutex pltap_netdevs_mutex = OVS_MUTEX_INITIALIZER;
87 static struct shash pltap_netdevs OVS_GUARDED_BY(pltap_netdevs_mutex)
88     = SHASH_INITIALIZER(&pltap_netdevs);
89
90 static int netdev_pltap_construct(struct netdev *netdev_);
91
92 static void netdev_pltap_update_seq(struct netdev_pltap *) 
93     OVS_REQUIRES(dev->mutex);
94 static int get_flags(struct netdev_pltap *dev, enum netdev_flags *flags)
95     OVS_REQUIRES(dev->mutex);
96
97 static bool
98 netdev_pltap_finalized(struct netdev_pltap *dev)
99     OVS_REQUIRES(dev->mutex)
100 {
101     return dev->valid_local_ip && dev->valid_local_netmask;
102 }
103
104 static bool
105 is_netdev_pltap_class(const struct netdev_class *class)
106 {
107     return class->construct == netdev_pltap_construct;
108 }
109
110 static struct netdev_pltap *
111 netdev_pltap_cast(const struct netdev *netdev)
112 {
113     ovs_assert(is_netdev_pltap_class(netdev_get_class(netdev)));
114     return CONTAINER_OF(netdev, struct netdev_pltap, up);
115 }
116
117 static struct netdev_rxq_pltap*
118 netdev_rxq_pltap_cast(const struct netdev_rxq *rx)
119 {
120     ovs_assert(is_netdev_pltap_class(netdev_get_class(rx->netdev)));
121     return CONTAINER_OF(rx, struct netdev_rxq_pltap, up);
122 }
123
124 static void sync_needed(struct netdev_pltap *dev)
125     OVS_REQUIRES(dev->mutex, sync_list_mutex)
126 {
127     if (dev->sync_flags_needed)
128         return;
129
130     dev->sync_flags_needed = true;
131     list_insert(&sync_list, &dev->sync_list);
132 }
133
134 static void sync_done(struct netdev_pltap *dev)
135     OVS_REQUIRES(dev->mutex, sync_list_mutex)
136 {
137     if (!dev->sync_flags_needed)
138         return;
139
140     (void) list_remove(&dev->sync_list);
141     dev->sync_flags_needed = false;
142 }
143
144 static struct netdev *
145 netdev_pltap_alloc(void)
146 {
147     struct netdev_pltap *netdev = xzalloc(sizeof *netdev);
148     return &netdev->up;
149 }
150
151 static int
152 netdev_pltap_construct(struct netdev *netdev_)
153 {
154     struct netdev_pltap *netdev = netdev_pltap_cast(netdev_);
155     int error;
156
157     ovs_mutex_init(&netdev->mutex);
158     netdev->real_name = xzalloc(IFNAMSIZ + 1);
159     memset(&netdev->local_addr, 0, sizeof(netdev->local_addr));
160     netdev->valid_local_ip = false;
161     netdev->valid_local_netmask = false;
162     netdev->flags = 0;
163     netdev->sync_flags_needed = false;
164     netdev->change_seq = 1;
165
166
167     /* Open tap device. */
168     netdev->fd = tun_alloc(IFF_TAP, netdev->real_name);
169     if (netdev->fd < 0) {
170         error = errno;
171         VLOG_WARN("tun_alloc(IFF_TAP, %s) failed: %s",
172             netdev_get_name(netdev_), ovs_strerror(error));
173         return error;
174     }
175     VLOG_DBG("real_name = %s", netdev->real_name);
176
177     /* Make non-blocking. */
178     error = set_nonblocking(netdev->fd);
179     if (error) {
180         return error;
181     }
182
183     ovs_mutex_lock(&pltap_netdevs_mutex);
184     shash_add(&pltap_netdevs, netdev_get_name(netdev_), netdev);
185     ovs_mutex_unlock(&pltap_netdevs_mutex);
186     return 0;
187 }
188
189 static void
190 netdev_pltap_destruct(struct netdev *netdev_)
191 {
192     struct netdev_pltap *netdev = netdev_pltap_cast(netdev_);
193
194     ovs_mutex_lock(&pltap_netdevs_mutex);
195     if (netdev->fd != -1)
196         close(netdev->fd);
197
198     if (netdev->sync_flags_needed) {
199         ovs_mutex_lock(&sync_list_mutex);
200         (void) list_remove(&netdev->sync_list);
201         ovs_mutex_unlock(&sync_list_mutex);
202     }
203
204     shash_find_and_delete(&pltap_netdevs,
205                           netdev_get_name(netdev_));
206     ovs_mutex_unlock(&pltap_netdevs_mutex);
207     ovs_mutex_destroy(&netdev->mutex);
208 }
209
210 static void
211 netdev_pltap_dealloc(struct netdev *netdev_)
212 {
213     struct netdev_pltap *netdev = netdev_pltap_cast(netdev_);
214     free(netdev);
215 }
216
217 static int netdev_pltap_up(struct netdev_pltap *dev) OVS_REQUIRES(dev->mutex);
218
219 static struct netdev_rxq *
220 netdev_pltap_rxq_alloc(void)
221 {
222     struct netdev_rxq_pltap *rx = xzalloc(sizeof *rx);
223     return &rx->up;
224 }
225
226 static int
227 netdev_pltap_rxq_construct(struct netdev_rxq *rx_)
228 {
229     struct netdev_rxq_pltap *rx = netdev_rxq_pltap_cast(rx_);
230     struct netdev *netdev_ = rx->up.netdev;
231     struct netdev_pltap *netdev =
232         netdev_pltap_cast(netdev_);
233     int error = 0;
234
235     ovs_mutex_lock(&netdev->mutex);
236     rx->fd = netdev->fd;
237     if (!netdev_pltap_finalized(netdev))
238         goto out;
239     error = netdev_pltap_up(netdev);
240     if (error) {
241         goto out;
242     }
243 out:
244     ovs_mutex_unlock(&netdev->mutex);
245     return error;
246 }
247
248 static void
249 netdev_pltap_rxq_destruct(struct netdev_rxq *rx_ OVS_UNUSED)
250 {
251 }
252
253 static void
254 netdev_pltap_rxq_dealloc(struct netdev_rxq *rx_)
255 {
256     struct netdev_rxq_pltap *rx = netdev_rxq_pltap_cast(rx_);
257
258     free(rx);
259 }
260
261 static int vsys_transaction(const char *script,
262         const char **preply, char *format, ...)
263 {
264     char *msg = NULL, *reply = NULL;
265     const size_t reply_size = 1024;
266     int ifd = -1, ofd = -1, maxfd;
267     size_t bytes_to_write, bytes_to_read,
268            bytes_written = 0, bytes_read = 0;
269     int error = 0;
270     char *ofname = NULL, *ifname = NULL;
271     va_list args;
272
273     va_start(args, format);
274     msg = xvasprintf(format, args);
275     va_end(args);
276     reply = (char*)xmalloc(reply_size);
277     if (!msg || !reply) {
278         VLOG_ERR("Out of memory");
279         error = ENOMEM;
280         goto cleanup;
281     }
282
283     ofname = xasprintf("/vsys/%s.out", script);
284     ifname = xasprintf("/vsys/%s.in", script);
285     if (!ofname || !ifname) {
286         VLOG_ERR("Out of memory");
287         error = ENOMEM;
288         goto cleanup;
289     }
290
291     ofd = open(ofname, O_RDONLY | O_NONBLOCK);
292     if (ofd < 0) {
293         VLOG_ERR("Cannot open %s: %s", ofname, ovs_strerror(errno));
294         error = errno;
295         goto cleanup;
296     }
297     ifd = open(ifname, O_WRONLY | O_NONBLOCK);
298     if (ifd < 0) {
299         VLOG_ERR("Cannot open %s: %s", ifname, ovs_strerror(errno));
300         error = errno;
301         goto cleanup;
302     }
303     maxfd = (ifd < ofd) ? ofd : ifd;
304
305     bytes_to_write = strlen(msg);
306     bytes_to_read = reply_size;
307     while (bytes_to_write || bytes_to_read) {
308         fd_set readset, writeset, errorset;
309
310         FD_ZERO(&readset);
311         FD_ZERO(&writeset);
312         FD_ZERO(&errorset);
313         if (bytes_to_write) {
314             FD_SET(ifd, &writeset);
315             FD_SET(ifd, &errorset);
316         }
317         FD_SET(ofd, &readset);
318         FD_SET(ofd, &errorset);
319         if (select(maxfd + 1, &readset, &writeset, &errorset, NULL) < 0) {
320             if (errno == EINTR)
321                 continue;
322             VLOG_ERR("selec error: %s", ovs_strerror(errno));
323             error = errno;
324             goto cleanup;
325         }
326         if (FD_ISSET(ifd, &errorset) || FD_ISSET(ofd, &errorset)) {
327             VLOG_ERR("error condition on ifd or ofd");
328             goto cleanup;
329         }
330         if (FD_ISSET(ifd, &writeset)) {
331             ssize_t n = write(ifd, msg + bytes_written, bytes_to_write);    
332             if (n < 0) {
333                 if (errno != EAGAIN && errno != EINTR) {
334                     VLOG_ERR("write on %s: %s", ifname, ovs_strerror(errno));
335                     error = errno;
336                     goto cleanup;
337                 }
338             } else {
339                 bytes_written += n;
340                 bytes_to_write -= n;
341                 if (bytes_to_write == 0)
342                     close(ifd);
343             }
344         }
345         if (FD_ISSET(ofd, &readset)) {
346             ssize_t n = read(ofd, reply + bytes_read, bytes_to_read);    
347             if (n < 0) {
348                 if (errno != EAGAIN && errno != EINTR) {
349                     VLOG_ERR("read on %s: %s", ofname, ovs_strerror(errno));
350                     error = errno;
351                     goto cleanup;
352                 }
353             } else if (n == 0) {
354                 bytes_to_read = 0;
355             } else {
356                 bytes_read += n;
357                 bytes_to_read -= n;
358             }
359         }
360     }
361     if (bytes_read) {
362         reply[bytes_read] = '\0';
363         if (preply) {
364                 *preply = reply;
365                 reply = NULL; /* prevent freeing the reply msg */
366         } else {
367                 VLOG_ERR("%s returned: %s", script, reply);
368         }
369         error = EAGAIN;
370         goto cleanup;
371     }
372
373 cleanup:
374     free(msg);
375     free(reply);
376     free(ofname);
377     free(ifname);
378     close(ifd);
379     close(ofd);
380     return error;
381 }
382
383 static int
384 netdev_pltap_up(struct netdev_pltap *dev)
385     OVS_REQUIRES(dev->mutex)
386 {
387     if (!netdev_pltap_finalized(dev)) {
388         return 0;
389     }
390     
391     return vsys_transaction("vif_up", NULL, "%s\n"IP_FMT"\n%d\n",
392                dev->real_name,
393                IP_ARGS(dev->local_addr.sin_addr.s_addr),
394                dev->local_netmask);
395 }
396
397 static int
398 netdev_pltap_down(struct netdev_pltap *dev)
399     OVS_REQUIRES(dev->mutex)
400 {
401     if (!netdev_pltap_finalized(dev)) {
402         return 0;
403     }
404     
405     return vsys_transaction("vif_down", NULL, "%s\n", dev->real_name);
406 }
407
408 static int
409 netdev_pltap_promisc(struct netdev_pltap *dev, bool promisc)
410     OVS_REQUIRES(dev-mutex)
411 {
412     if (!netdev_pltap_finalized(dev)) {
413         return 0;
414     }
415
416     return vsys_transaction("promisc", NULL, "%s\n%s",
417                dev->real_name,
418                (promisc ? "" : "-\n"));
419 }
420
421 static void
422 netdev_pltap_sync_flags(struct netdev_pltap *dev)
423     OVS_REQUIRES(sync_list_mutex)
424 {
425
426     ovs_mutex_lock(&dev->mutex);
427
428     if (dev->fd < 0 || !netdev_pltap_finalized(dev)) {
429         goto out;
430     }
431     
432     VLOG_DBG("sync_flags(%s): current: %s %s  target: %s %s",
433         dev->real_name,
434         (dev->flags & NETDEV_UP ? "UP" : "-"),
435         (dev->flags & NETDEV_PROMISC ? "PROMISC" : "-"),
436         (dev->new_flags & NETDEV_UP ? "UP" : "-"),
437         (dev->new_flags & NETDEV_PROMISC ? "PROMISC" : "-"));
438
439     if ((dev->new_flags & NETDEV_UP) && !(dev->flags & NETDEV_UP)) {
440         (void) netdev_pltap_up(dev);
441     } else if (!(dev->new_flags & NETDEV_UP) && (dev->flags & NETDEV_UP)) {
442         (void) netdev_pltap_down(dev);
443     }
444
445     if ((dev->new_flags & NETDEV_PROMISC) ^ (dev->flags & NETDEV_PROMISC)) {
446         (void) netdev_pltap_promisc(dev, dev->new_flags & NETDEV_PROMISC);
447     }
448
449     netdev_pltap_update_seq(dev);
450
451 out:
452     sync_done(dev);
453     ovs_mutex_unlock(&dev->mutex);
454 }
455
456
457 static int
458 netdev_pltap_get_config(const struct netdev *dev_, struct smap *args)
459 {
460     struct netdev_pltap *netdev = netdev_pltap_cast(dev_);
461
462     ovs_mutex_lock(&netdev->mutex);
463     if (netdev->valid_local_ip)
464         smap_add_format(args, "local_ip", IP_FMT,
465             IP_ARGS(netdev->local_addr.sin_addr.s_addr));
466     if (netdev->valid_local_netmask)
467         smap_add_format(args, "local_netmask", "%"PRIu32,
468             ntohs(netdev->local_netmask));
469     ovs_mutex_unlock(&netdev->mutex);
470     return 0;
471 }
472
473 static int
474 netdev_pltap_set_config(struct netdev *dev_, const struct smap *args)
475 {
476     struct netdev_pltap *netdev = netdev_pltap_cast(dev_);
477     struct shash_node *node;
478
479     ovs_mutex_lock(&sync_list_mutex);
480     ovs_mutex_lock(&netdev->mutex);
481     VLOG_DBG("pltap_set_config(%s)", netdev_get_name(dev_));
482     SMAP_FOR_EACH(node, args) {
483         VLOG_DBG("arg: %s->%s", node->name, (char*)node->data);
484         if (!strcmp(node->name, "local_ip")) {
485             struct in_addr addr;
486             if (lookup_ip(node->data, &addr)) {
487                 VLOG_WARN("%s: bad 'local_ip'", node->name);
488             } else {
489                 netdev->local_addr.sin_addr = addr;
490                 netdev->valid_local_ip = true;
491             }
492         } else if (!strcmp(node->name, "local_netmask")) {
493             netdev->local_netmask = atoi(node->data);
494             // XXX check valididy
495             netdev->valid_local_netmask = true;
496         } else {
497             VLOG_WARN("%s: unknown argument '%s'", 
498                 netdev_get_name(dev_), node->name);
499         }
500     }
501     if (netdev_pltap_finalized(netdev)) {
502         netdev->new_flags |= NETDEV_UP;
503         sync_needed(netdev);
504     }
505     ovs_mutex_unlock(&netdev->mutex);
506     ovs_mutex_unlock(&sync_list_mutex);
507     return 0;
508 }
509
510 static int
511 netdev_pltap_rxq_recv(struct netdev_rxq *rx_, struct ofpbuf **packet, int *c)
512 {
513     struct netdev_rxq_pltap *rx = netdev_rxq_pltap_cast(rx_);
514     struct tun_pi pi;
515     struct iovec iov[2] = {
516         { .iov_base = &pi, .iov_len = sizeof(pi) },
517     };
518     struct ofpbuf *buffer = NULL;
519     size_t size;
520     int error = 0;
521
522     buffer = ofpbuf_new_with_headroom(VLAN_ETH_HEADER_LEN + ETH_PAYLOAD_MAX,
523         DP_NETDEV_HEADROOM);
524     size = ofpbuf_tailroom(buffer);
525     iov[1].iov_base = ofpbuf_data(buffer);
526     iov[1].iov_len = size;
527     for (;;) {
528         ssize_t retval;
529         retval = readv(rx->fd, iov, 2);
530         if (retval >= 0) {
531             if (retval <= size) {
532             ofpbuf_set_size(buffer, ofpbuf_size(buffer) + retval);
533                 goto out;
534             } else {
535                 error = EMSGSIZE;
536             goto out;
537             }
538         } else if (errno != EINTR) {
539             if (errno != EAGAIN) {
540                 VLOG_WARN_RL(&rl, "error receiveing Ethernet packet on %s: %s",
541                     netdev_rxq_get_name(rx_), ovs_strerror(errno));
542             }
543             error = errno;
544             goto out;
545         }
546     }
547 out:
548     if (error) {
549         ofpbuf_delete(buffer);
550     } else {
551         dp_packet_pad(buffer);
552         packet[0] = buffer;
553         *c = 1;
554     }
555
556     return error;
557 }
558
559 static void
560 netdev_pltap_rxq_wait(struct netdev_rxq *rx_)
561 {
562     struct netdev_rxq_pltap *rx = netdev_rxq_pltap_cast(rx_);
563     struct netdev_pltap *netdev =
564         netdev_pltap_cast(rx->up.netdev);
565     if (rx->fd >= 0 && netdev_pltap_finalized(netdev)) {
566         poll_fd_wait(rx->fd, POLLIN);
567     }
568 }
569
570 static int
571 netdev_pltap_send(struct netdev *netdev_, struct ofpbuf *pkt, bool may_steal)
572 {
573     const void *buffer = ofpbuf_data(pkt);
574     size_t size = ofpbuf_size(pkt);
575     struct netdev_pltap *dev = 
576         netdev_pltap_cast(netdev_);
577     int error = 0;
578     struct tun_pi pi = { 0, 0x86 };
579     struct iovec iov[2] = {
580         { .iov_base = &pi, .iov_len = sizeof(pi) },
581         { .iov_base = (char*) buffer, .iov_len = size }
582     };
583     if (dev->fd < 0) {
584         error = EAGAIN;
585         goto out;
586     }
587     for (;;) {
588         ssize_t retval;
589         retval = writev(dev->fd, iov, 2);
590         if (retval >= 0) {
591             if (retval != size + sizeof(pi)) {
592                 VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%"PRIdSIZE" bytes of %"PRIuSIZE") on %s",
593                         retval, size + sizeof(pi), netdev_get_name(netdev_));
594             }
595             goto out;
596         } else if (errno != EINTR) {
597             if (errno != EAGAIN) {
598                 VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: %s",
599                         netdev_get_name(netdev_), ovs_strerror(errno));
600             }
601             error = errno;
602             goto out;
603         }
604     }
605 out:
606     if (may_steal) {
607         ofpbuf_delete(pkt);
608     }
609     return error;
610 }
611
612 static void
613 netdev_pltap_send_wait(struct netdev *netdev_)
614 {
615     struct netdev_pltap *dev = 
616         netdev_pltap_cast(netdev_);
617     if (dev->fd >= 0 && netdev_pltap_finalized(dev)) {
618         poll_fd_wait(dev->fd, POLLOUT);
619     }
620 }
621
622 static int
623 netdev_pltap_rxq_drain(struct netdev_rxq *rx_)
624 {
625     struct netdev_rxq_pltap *rx = netdev_rxq_pltap_cast(rx_);
626     char buffer[128];
627     int error;
628
629     if (rx->fd < 0)
630         return EAGAIN;
631     for (;;) {
632         error = recv(rx->fd, buffer, 128, MSG_TRUNC);
633         if (error) {
634             if (error == -EAGAIN)
635                 break;
636             else if (error != -EMSGSIZE)
637                 return error;
638         }
639     }
640     return 0;
641 }
642
643 static int
644 netdev_pltap_set_etheraddr(struct netdev *netdevi OVS_UNUSED,
645                            const uint8_t mac[ETH_ADDR_LEN] OVS_UNUSED)
646 {
647     return ENOTSUP;
648 }
649
650
651 // XXX from netdev-linux.c
652 static int
653 get_etheraddr(struct netdev_pltap *dev, uint8_t ea[ETH_ADDR_LEN])
654     OVS_REQUIRES(dev->mutex)
655 {
656     struct ifreq ifr;
657     int hwaddr_family;
658     int error;
659
660     memset(&ifr, 0, sizeof ifr);
661     ovs_strzcpy(ifr.ifr_name, dev->real_name, sizeof ifr.ifr_name);
662     error = af_inet_ifreq_ioctl(dev->real_name, &ifr,
663         SIOCGIFHWADDR, "SIOCGIFHWADDR");
664     if (error) {
665         return error;
666     }
667     hwaddr_family = ifr.ifr_hwaddr.sa_family;
668     if (hwaddr_family != AF_UNSPEC && hwaddr_family != ARPHRD_ETHER) {
669         VLOG_WARN("%s device has unknown hardware address family %d",
670                   dev->real_name, hwaddr_family);
671     }
672     memcpy(ea, ifr.ifr_hwaddr.sa_data, ETH_ADDR_LEN);
673     return 0;
674 }
675
676 static int
677 get_flags(struct netdev_pltap *dev, enum netdev_flags *flags)
678     OVS_REQUIRES(dev->mutex)
679 {
680     struct ifreq ifr;
681     int error;
682
683     error = af_inet_ifreq_ioctl(dev->real_name, &ifr,
684         SIOCGIFFLAGS, "SIOCGIFFLAGS");
685     if (error) {
686         return error;
687     }
688     *flags = 0;
689     if (ifr.ifr_flags & IFF_UP)
690         *flags |= NETDEV_UP;
691     if (ifr.ifr_flags & IFF_PROMISC)
692         *flags |= NETDEV_PROMISC;
693     return 0;
694 }
695
696 static int
697 netdev_pltap_get_etheraddr(const struct netdev *netdev,
698                            uint8_t mac[ETH_ADDR_LEN])
699 {
700     struct netdev_pltap *dev = 
701         netdev_pltap_cast(netdev);
702     int error = 0;
703
704     ovs_mutex_lock(&dev->mutex);
705     if (dev->fd < 0) {
706         error = EAGAIN;
707         goto out;
708     }
709     error = get_etheraddr(dev, mac);
710
711 out:
712     ovs_mutex_unlock(&dev->mutex);
713     return error;
714 }
715
716
717 // XXX can we read stats in planetlab?
718 static int
719 netdev_pltap_get_stats(const struct netdev *netdev OVS_UNUSED, struct netdev_stats *stats OVS_UNUSED)
720 {
721     return ENOTSUP;
722 }
723
724 static int
725 netdev_pltap_set_stats(struct netdev *netdev OVS_UNUSED, const struct netdev_stats *stats OVS_UNUSED)
726 {
727     return ENOTSUP;
728 }
729
730
731 static int
732 netdev_pltap_update_flags(struct netdev *dev_,
733                           enum netdev_flags off, enum netdev_flags on,
734                           enum netdev_flags *old_flagsp)
735 {
736     struct netdev_pltap *netdev =
737         netdev_pltap_cast(dev_);
738     int error = 0;
739
740     ovs_mutex_lock(&sync_list_mutex);
741     ovs_mutex_lock(&netdev->mutex);
742     if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) {
743         error = EINVAL;
744         goto out;
745     }
746
747     if (netdev_pltap_finalized(netdev)) {
748         error = get_flags(netdev, &netdev->flags);
749     }
750     *old_flagsp = netdev->flags;
751     netdev->new_flags |= on;
752     netdev->new_flags &= ~off;
753     if (netdev->flags != netdev->new_flags) {
754         /* we cannot sync here, since we may be in a signal handler */
755         sync_needed(netdev);
756     }
757
758 out:
759     ovs_mutex_unlock(&netdev->mutex);
760     ovs_mutex_unlock(&sync_list_mutex);
761     return error;
762 }
763
764 static unsigned int
765 netdev_pltap_change_seq(const struct netdev *netdev)
766 {
767     struct netdev_pltap *dev =
768         netdev_pltap_cast(netdev);
769     unsigned int change_seq;
770
771     ovs_mutex_lock(&dev->mutex);
772     change_seq = dev->change_seq;
773     ovs_mutex_unlock(&dev->mutex);
774
775     return change_seq;
776 }
777 \f
778 /* Helper functions. */
779
780 static void
781 netdev_pltap_update_seq(struct netdev_pltap *dev)
782     OVS_REQUIRES(dev->mutex)
783 {
784     dev->change_seq++;
785     if (!dev->change_seq) {
786         dev->change_seq++;
787     }
788 }
789
790 static void
791 netdev_pltap_get_real_name(struct unixctl_conn *conn,
792                      int argc OVS_UNUSED, const char *argv[], void *aux OVS_UNUSED)
793 {
794     struct netdev_pltap *pltap_dev;
795
796     ovs_mutex_lock(&pltap_netdevs_mutex);
797     pltap_dev = shash_find_data(&pltap_netdevs, argv[1]);
798     if (!pltap_dev) {
799         unixctl_command_reply_error(conn, "no such pltap netdev");
800         goto out;
801     }
802     if (pltap_dev->fd < 0) {
803         unixctl_command_reply_error(conn, "no real device attached");
804         goto out;       
805     }
806
807     unixctl_command_reply(conn, pltap_dev->real_name);
808
809 out:
810     ovs_mutex_unlock(&pltap_netdevs_mutex);
811 }
812
813 static int
814 netdev_pltap_init(void)
815 {
816     unixctl_command_register("netdev-pltap/get-tapname", "port",
817                              1, 1, netdev_pltap_get_real_name, NULL);
818     return 0;
819 }
820
821 static void
822 netdev_pltap_run(void)
823 {
824     struct netdev_pltap *iter, *next;
825     ovs_mutex_lock(&sync_list_mutex);
826     LIST_FOR_EACH_SAFE(iter, next, sync_list, &sync_list) {
827         netdev_pltap_sync_flags(iter);
828     }
829     ovs_mutex_unlock(&sync_list_mutex);
830 }
831
832 static void
833 netdev_pltap_wait(void)
834 {
835     ovs_mutex_lock(&sync_list_mutex);
836     if (!list_is_empty(&sync_list)) {
837         VLOG_DBG("netdev_pltap: scheduling sync");
838         poll_immediate_wake();
839     }
840     ovs_mutex_unlock(&sync_list_mutex);
841 }
842
843 const struct netdev_class netdev_pltap_class = {
844     "pltap",
845     netdev_pltap_init,
846     netdev_pltap_run,  
847     netdev_pltap_wait,            
848
849     netdev_pltap_alloc,
850     netdev_pltap_construct,
851     netdev_pltap_destruct,
852     netdev_pltap_dealloc,
853     netdev_pltap_get_config,
854     netdev_pltap_set_config, 
855     NULL,                                   /* get_tunnel_config */
856
857     netdev_pltap_send, 
858     netdev_pltap_send_wait,  
859
860     netdev_pltap_set_etheraddr,
861     netdev_pltap_get_etheraddr,
862     NULL,                                   /* get_mtu */
863     NULL,                                   /* set_mtu */
864     NULL,                       /* get_ifindex */
865     NULL,                                   /* get_carrier */
866     NULL,                       /* get_carrier_resets */
867     NULL,                       /* get_miimon */
868     netdev_pltap_get_stats,
869     netdev_pltap_set_stats,
870
871     NULL,                       /* get_features */
872     NULL,                       /* set_advertisements */
873
874     NULL,                       /* set_policing */
875     NULL,                       /* get_qos_types */
876     NULL,                       /* get_qos_capabilities */
877     NULL,                       /* get_qos */
878     NULL,                       /* set_qos */
879     NULL,                       /* get_queue */
880     NULL,                       /* set_queue */
881     NULL,                       /* delete_queue */
882     NULL,                       /* get_queue_stats */
883     NULL,                       /* queue_dump_start */
884     NULL,                       /* queue_dump_next */
885     NULL,                       /* queue_dump_done */
886     NULL,                       /* dump_queue_stats */
887
888     NULL,                       /* get_in4 */
889     NULL,                       /* set_in4 */
890     NULL,                       /* get_in6 */
891     NULL,                       /* add_router */
892     NULL,                       /* get_next_hop */
893     NULL,                       /* get_drv_info */
894     NULL,                       /* arp_lookup */
895
896     netdev_pltap_update_flags,
897
898     netdev_pltap_rxq_alloc,
899     netdev_pltap_rxq_construct,
900     netdev_pltap_rxq_destruct,
901     netdev_pltap_rxq_dealloc,
902     netdev_pltap_rxq_recv,
903     netdev_pltap_rxq_wait,
904     netdev_pltap_rxq_drain,
905 };