2 * Copyright (c) 2012 Giuseppe Lettieri
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <linux/if_tun.h>
31 #include "netdev-provider.h"
33 #include "ofp-print.h"
36 #include "poll-loop.h"
40 #include "socket-util.h"
44 VLOG_DEFINE_THIS_MODULE(netdev_pltap);
46 struct netdev_dev_pltap {
47 struct netdev_dev netdev_dev;
48 uint8_t hwaddr[ETH_ADDR_LEN];
51 struct netdev_stats stats;
52 enum netdev_flags flags;
54 struct sockaddr_in local_addr;
57 bool valid_local_netmask;
59 unsigned int change_seq;
66 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
68 static struct shash pltap_netdev_devs = SHASH_INITIALIZER(&pltap_netdev_devs);
70 static int netdev_pltap_create(const struct netdev_class *, const char *,
71 struct netdev_dev **);
73 static struct shash pltap_creating = SHASH_INITIALIZER(&pltap_creating);
75 static void netdev_pltap_update_seq(struct netdev_dev_pltap *);
78 is_pltap_class(const struct netdev_class *class)
80 return class->create == netdev_pltap_create;
83 static struct netdev_dev_pltap *
84 netdev_dev_pltap_cast(const struct netdev_dev *netdev_dev)
86 assert(is_pltap_class(netdev_dev_get_class(netdev_dev)));
87 return CONTAINER_OF(netdev_dev, struct netdev_dev_pltap, netdev_dev);
90 static struct netdev_pltap *
91 netdev_pltap_cast(const struct netdev *netdev)
93 struct netdev_dev *netdev_dev = netdev_get_dev(netdev);
94 assert(is_pltap_class(netdev_dev_get_class(netdev_dev)));
95 return CONTAINER_OF(netdev, struct netdev_pltap, netdev);
99 netdev_pltap_create(const struct netdev_class *class OVS_UNUSED, const char *name,
100 struct netdev_dev **netdev_devp)
102 struct netdev_dev_pltap *netdev_dev;
105 netdev_dev = xzalloc(sizeof *netdev_dev);
107 netdev_dev->real_name = xzalloc(IFNAMSIZ + 1);
108 netdev_dev->error = NULL;
109 memset(&netdev_dev->local_addr, 0, sizeof(netdev_dev->local_addr));
110 netdev_dev->valid_local_ip = false;
111 netdev_dev->valid_local_netmask = false;
112 netdev_dev->finalized = false;
115 /* Open tap device. */
116 netdev_dev->fd = tun_alloc(IFF_TAP, netdev_dev->real_name);
117 if (netdev_dev->fd < 0) {
119 VLOG_WARN("tun_alloc(IFF_TAP, %s) failed: %s", name, strerror(error));
122 VLOG_DBG("real_name = %s", netdev_dev->real_name);
124 /* Make non-blocking. */
125 error = set_nonblocking(netdev_dev->fd);
130 netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_pltap_class);
131 shash_add(&pltap_netdev_devs, name, netdev_dev);
132 *netdev_devp = &netdev_dev->netdev_dev;
141 netdev_pltap_destroy(struct netdev_dev *netdev_dev_)
143 struct netdev_dev_pltap *netdev_dev = netdev_dev_pltap_cast(netdev_dev_);
145 if (netdev_dev->fd != -1)
146 close(netdev_dev->fd);
148 shash_find_and_delete(&pltap_netdev_devs,
149 netdev_dev_get_name(netdev_dev_));
154 netdev_pltap_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp)
156 struct netdev_pltap *netdev;
158 netdev = xmalloc(sizeof *netdev);
159 netdev_init(&netdev->netdev, netdev_dev_);
161 *netdevp = &netdev->netdev;
166 netdev_pltap_close(struct netdev *netdev_)
168 struct netdev_pltap *netdev = netdev_pltap_cast(netdev_);
173 netdev_pltap_create_finalize(struct netdev_dev_pltap *dev)
175 int ifd = -1, ofd = -1, maxfd;
176 size_t bytes_to_write, bytes_to_read = 1024,
177 bytes_written = 0, bytes_read = 0;
179 char *msg = NULL, *reply = NULL;
183 if (!dev->valid_local_ip || !dev->valid_local_netmask)
186 ofd = open("/vsys/vif_up.out", O_RDONLY | O_NONBLOCK);
188 VLOG_ERR("Cannot open vif_up.out: %s", strerror(errno));
192 ifd = open("/vsys/vif_up.in", O_WRONLY | O_NONBLOCK);
194 VLOG_ERR("Cannot open vif_up.in: %s", strerror(errno));
198 maxfd = (ifd < ofd) ? ofd : ifd;
200 msg = xasprintf("%s\n"IP_FMT"\n%d\n",
202 IP_ARGS(&dev->local_addr.sin_addr),
204 reply = (char*)xmalloc(bytes_to_read);
205 if (!msg || !reply) {
206 VLOG_ERR("Out of memory");
210 bytes_to_write = strlen(msg);
211 while (bytes_to_write || bytes_to_read) {
212 fd_set readset, writeset, errorset;
217 if (bytes_to_write) {
218 FD_SET(ifd, &writeset);
219 FD_SET(ifd, &errorset);
221 FD_SET(ofd, &readset);
222 FD_SET(ofd, &errorset);
223 if (select(maxfd + 1, &readset, &writeset, &errorset, NULL) < 0) {
226 VLOG_ERR("selec error: %s", strerror(errno));
230 if (FD_ISSET(ifd, &errorset) || FD_ISSET(ofd, &errorset)) {
231 VLOG_ERR("error condition on ifd or ofd");
234 if (FD_ISSET(ifd, &writeset)) {
235 ssize_t n = write(ifd, msg + bytes_written, bytes_to_write);
237 if (errno != EAGAIN && errno != EINTR) {
238 VLOG_ERR("write on vif_up.in: %s", strerror(errno));
245 if (bytes_to_write == 0)
249 if (FD_ISSET(ofd, &readset)) {
250 ssize_t n = read(ofd, reply + bytes_read, bytes_to_read);
252 if (errno != EAGAIN && errno != EINTR) {
253 VLOG_ERR("read on vif_up.out: %s", strerror(errno));
266 reply[bytes_read] = '\0';
267 VLOG_ERR("vif_up returned: %s", reply);
273 dev->finalized = true;
276 netdev_pltap_update_seq(dev);
287 netdev_pltap_get_config(struct netdev_dev *dev_, struct smap *args)
289 struct netdev_dev_pltap *netdev_dev = netdev_dev_pltap_cast(dev_);
291 if (netdev_dev->valid_local_ip)
292 smap_add_format(args, "local_ip", IP_FMT,
293 IP_ARGS(&netdev_dev->local_addr.sin_addr));
294 if (netdev_dev->valid_local_netmask)
295 smap_add_format(args, "local_netmask", "%"PRIu32,
296 ntohs(netdev_dev->local_netmask));
297 return netdev_pltap_create_finalize(netdev_dev);
301 netdev_pltap_set_config(struct netdev_dev *dev_, const struct smap *args)
303 struct netdev_dev_pltap *netdev_dev = netdev_dev_pltap_cast(dev_);
304 struct shash_node *node;
306 VLOG_DBG("pltap_set_config(%s)", netdev_dev_get_name(dev_));
307 SMAP_FOR_EACH(node, args) {
308 VLOG_DBG("arg: %s->%s", node->name, (char*)node->data);
309 if (!strcmp(node->name, "local_ip")) {
311 if (lookup_ip(node->data, &addr)) {
312 VLOG_WARN("%s: bad 'local_ip'", node->name);
314 netdev_dev->local_addr.sin_addr = addr;
315 netdev_dev->valid_local_ip = true;
317 } else if (!strcmp(node->name, "local_netmask")) {
318 netdev_dev->local_netmask = atoi(node->data);
319 // XXX check valididy
320 netdev_dev->valid_local_netmask = true;
322 VLOG_WARN("%s: unknown argument '%s'",
323 netdev_dev_get_name(dev_), node->name);
326 return netdev_pltap_create_finalize(netdev_dev);
330 netdev_pltap_listen(struct netdev *netdev_ OVS_UNUSED)
336 netdev_pltap_recv(struct netdev *netdev_, void *buffer, size_t size)
338 struct netdev_dev_pltap *dev =
339 netdev_dev_pltap_cast(netdev_get_dev(netdev_));
344 retval = read(dev->fd, buffer, size);
345 VLOG_DBG("%s: read(%"PRIxPTR", %"PRIu64") = %"PRId64,
346 netdev_get_name(netdev_), (uintptr_t)buffer, size, retval);
348 if (retval <= size) {
353 } else if (errno != EINTR) {
354 if (errno != EAGAIN) {
355 VLOG_WARN_RL(&rl, "error receiveing Ethernet packet on %s: %s",
356 netdev_get_name(netdev_), strerror(errno));
364 netdev_pltap_recv_wait(struct netdev *netdev_)
366 struct netdev_dev_pltap *dev =
367 netdev_dev_pltap_cast(netdev_get_dev(netdev_));
368 if (dev->finalized && dev->fd >= 0) {
369 poll_fd_wait(dev->fd, POLLIN);
374 netdev_pltap_send(struct netdev *netdev_, const void *buffer, size_t size)
376 struct netdev_dev_pltap *dev =
377 netdev_dev_pltap_cast(netdev_get_dev(netdev_));
378 if (dev->fd < 0 || !dev->finalized)
382 retval = write(dev->fd, buffer, size);
383 VLOG_DBG("%s: write(%"PRIxPTR", %"PRIu64") = %"PRId64,
384 netdev_get_name(netdev_), (uintptr_t)buffer, size, retval);
386 if (retval != size) {
387 VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%"PRId64" bytes of "
388 "%"PRIu64") on %s", retval, size, netdev_get_name(netdev_));
391 } else if (errno != EINTR) {
392 if (errno != EAGAIN) {
393 VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: %s",
394 netdev_get_name(netdev_), strerror(errno));
402 netdev_pltap_send_wait(struct netdev *netdev_)
404 struct netdev_dev_pltap *dev =
405 netdev_dev_pltap_cast(netdev_get_dev(netdev_));
406 if (dev->finalized && dev->fd >= 0) {
407 poll_fd_wait(dev->fd, POLLOUT);
412 netdev_pltap_drain(struct netdev *netdev_)
414 struct netdev_dev_pltap *dev =
415 netdev_dev_pltap_cast(netdev_get_dev(netdev_));
419 if (dev->fd < 0 || !dev->finalized)
422 error = recv(dev->fd, buffer, 128, MSG_TRUNC);
424 if (error == -EAGAIN)
426 else if (error != -EMSGSIZE)
434 netdev_pltap_set_etheraddr(struct netdev *netdev,
435 const uint8_t mac[ETH_ADDR_LEN])
437 struct netdev_dev_pltap *dev =
438 netdev_dev_pltap_cast(netdev_get_dev(netdev));
440 if (!eth_addr_equals(dev->hwaddr, mac)) {
441 memcpy(dev->hwaddr, mac, ETH_ADDR_LEN);
442 netdev_pltap_update_seq(dev);
448 // XXX we need the real mac
450 netdev_pltap_get_etheraddr(const struct netdev *netdev,
451 uint8_t mac[ETH_ADDR_LEN])
453 const struct netdev_dev_pltap *dev =
454 netdev_dev_pltap_cast(netdev_get_dev(netdev));
456 memcpy(mac, dev->hwaddr, ETH_ADDR_LEN);
461 // XXX can we read stats in planetlab?
463 netdev_pltap_get_stats(const struct netdev *netdev OVS_UNUSED, struct netdev_stats *stats OVS_UNUSED)
469 netdev_pltap_set_stats(struct netdev *netdev OVS_UNUSED, const struct netdev_stats *stats OVS_UNUSED)
475 netdev_pltap_update_flags(struct netdev *netdev,
476 enum netdev_flags off, enum netdev_flags on,
477 enum netdev_flags *old_flagsp)
479 struct netdev_dev_pltap *dev =
480 netdev_dev_pltap_cast(netdev_get_dev(netdev));
482 if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) {
486 // XXX should we actually do something with these flags?
487 *old_flagsp = dev->flags;
490 if (*old_flagsp != dev->flags) {
491 netdev_pltap_update_seq(dev);
497 netdev_pltap_change_seq(const struct netdev *netdev)
499 return netdev_dev_pltap_cast(netdev_get_dev(netdev))->change_seq;
502 /* Helper functions. */
505 netdev_pltap_update_seq(struct netdev_dev_pltap *dev)
508 if (!dev->change_seq) {
514 netdev_pltap_get_real_name(struct unixctl_conn *conn,
515 int argc OVS_UNUSED, const char *argv[], void *aux OVS_UNUSED)
517 struct netdev_dev_pltap *pltap_dev;
519 pltap_dev = shash_find_data(&pltap_netdev_devs, argv[1]);
521 unixctl_command_reply_error(conn, "no such pltap netdev");
524 if (pltap_dev->error) {
525 unixctl_command_reply_error(conn, pltap_dev->error);
529 unixctl_command_reply(conn, pltap_dev->real_name);
533 netdev_pltap_init(void)
535 unixctl_command_register("netdev-pltap/get-tapname", "port",
536 1, 1, netdev_pltap_get_real_name, NULL);
540 const struct netdev_class netdev_pltap_class = {
547 netdev_pltap_destroy,
548 netdev_pltap_get_config,
549 netdev_pltap_set_config,
556 netdev_pltap_recv_wait,
560 netdev_pltap_send_wait,
562 netdev_pltap_set_etheraddr,
563 netdev_pltap_get_etheraddr,
566 NULL, /* get_ifindex */
567 NULL, /* get_carrier */
568 NULL, /* get_carrier_resets */
569 NULL, /* get_miimon */
570 netdev_pltap_get_stats,
571 netdev_pltap_set_stats,
573 NULL, /* get_features */
574 NULL, /* set_advertisements */
576 NULL, /* set_policing */
577 NULL, /* get_qos_types */
578 NULL, /* get_qos_capabilities */
581 NULL, /* get_queue */
582 NULL, /* set_queue */
583 NULL, /* delete_queue */
584 NULL, /* get_queue_stats */
585 NULL, /* dump_queues */
586 NULL, /* dump_queue_stats */
591 NULL, /* add_router */
592 NULL, /* get_next_hop */
593 NULL, /* get_drv_info */
594 NULL, /* arp_lookup */
596 netdev_pltap_update_flags,
598 netdev_pltap_change_seq