From 6a71549c1dd2c59a140c38c1336d801f3762de87 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 7 May 2012 16:26:40 +0200 Subject: [PATCH] tap_pl: allocation of a tap using vsys Planetlab tap interfaces are allocated by a vsys script (fd_tuntap). The script chooses the name of the interface and sends the corresponding fd to user context through a Unix domain socket. The allocated tap interface is not persistent. Moreover, the tap interface is not visibile in user context until an IP address is assigned to it (by using vsys/vif_up). The create_bridge script first creates a Planetlab tap with an IP address, then creates a bridge with the same name of the tap. --- Makefile.am | 1 + planetlab/automake.mk | 12 +++ planetlab/pltap-ovs/pltap-ovs.c | 136 ++++++++++++++++++++++++++++++++ planetlab/pltap-ovs/tunalloc.c | 95 ++++++++++++++++++++++ planetlab/pltap-ovs/tunalloc.h | 6 ++ planetlab/scripts/create_bridge | 58 ++++++++++++++ planetlab/scripts/create_port | 16 ++++ planetlab/scripts/del_bridge | 24 ++++++ 8 files changed, 348 insertions(+) create mode 100644 planetlab/automake.mk create mode 100644 planetlab/pltap-ovs/pltap-ovs.c create mode 100644 planetlab/pltap-ovs/tunalloc.c create mode 100644 planetlab/pltap-ovs/tunalloc.h create mode 100755 planetlab/scripts/create_bridge create mode 100755 planetlab/scripts/create_port create mode 100755 planetlab/scripts/del_bridge diff --git a/Makefile.am b/Makefile.am index e138ba404..5ab0f55e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -204,3 +204,4 @@ include rhel/automake.mk include xenserver/automake.mk include python/automake.mk include python/compat/automake.mk +include planetlab/automake.mk diff --git a/planetlab/automake.mk b/planetlab/automake.mk new file mode 100644 index 000000000..a08dd8eb5 --- /dev/null +++ b/planetlab/automake.mk @@ -0,0 +1,12 @@ +sbin_PROGRAMS += \ + planetlab/pltap-ovs/pltap-ovs + +dist_sbin_SCRIPTS += \ + planetlab/scripts/create_bridge \ + planetlab/scripts/create_port \ + planetlab/scripts/del_bridge + +planetlab_pltap_ovs_pltap_ovs_SOURCES = \ + planetlab/pltap-ovs/pltap-ovs.c \ + planetlab/pltap-ovs/tunalloc.c \ + planetlab/pltap-ovs/tunalloc.h diff --git a/planetlab/pltap-ovs/pltap-ovs.c b/planetlab/pltap-ovs/pltap-ovs.c new file mode 100644 index 000000000..2e9833e3e --- /dev/null +++ b/planetlab/pltap-ovs/pltap-ovs.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tunalloc.h" + +#define OVS_SOCK "/var/tun/pl-ovs.control" + +char *appname; + +#define ERROR(msg) \ + do { \ + fprintf(stderr, "%s: %s: %s", appname, msg, strerror(errno)); \ + exit(1); \ + } while (0) + + +int send_vif_fd(int sock_fd, int vif_fd, char *vif_name) +{ + int retval; + struct msghdr msg; + struct cmsghdr *p_cmsg; + struct iovec vec; + size_t cmsgbuf[CMSG_SPACE(sizeof(vif_fd)) / sizeof(size_t)]; + int *p_fds; + + + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + p_cmsg = CMSG_FIRSTHDR(&msg); + p_cmsg->cmsg_level = SOL_SOCKET; + p_cmsg->cmsg_type = SCM_RIGHTS; + p_cmsg->cmsg_len = CMSG_LEN(sizeof(vif_fd)); + p_fds = (int *) CMSG_DATA(p_cmsg); + *p_fds = vif_fd; + msg.msg_controllen = p_cmsg->cmsg_len; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + + /* Send the interface name as the iov */ + vec.iov_base = vif_name; + vec.iov_len = strlen(vif_name)+1; + + while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR); + if (retval == -1) { + ERROR("sending file descriptor"); + } + return 0; +} + +void send_fd(int p, int fd, char* vif_name) +{ + int control_fd; + int accept_fd; + struct sockaddr_un addr, accept_addr; + socklen_t addr_len = sizeof(accept_addr); + int i; + + control_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (control_fd == -1 && errno != ENOENT) { + ERROR("Could not create UNIX socket"); + } + + memset(&addr, 0, sizeof(struct sockaddr_un)); + /* Clear structure */ + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, OVS_SOCK, + sizeof(addr.sun_path) - 1); + + if (unlink(OVS_SOCK) == -1 && errno != ENOENT) { + ERROR("Could not unlink " OVS_SOCK " control socket"); + } + + if (bind(control_fd, (struct sockaddr *) &addr, + sizeof(struct sockaddr_un)) == -1) { + ERROR("Could not bind to " OVS_SOCK " control socket"); + } + + if (listen(control_fd, 5) == -1) { + ERROR("listen on " OVS_SOCK " failed"); + } + if (write(p, "1", 1) != 1) { + ERROR("writing on the synch pipe"); + } + if ((accept_fd = accept(control_fd, (struct sockaddr*) &accept_addr, + &addr_len)) == -1) { + ERROR("accept on " OVS_SOCK " failed"); + } + send_vif_fd(accept_fd, fd, vif_name); +} + +int main(int argc, char* argv[]) +{ + char if_name[IFNAMSIZ]; + int p[2]; // synchronization pipe + char dummy; + + if (pipe(p) < 0) { + ERROR("pipe"); + } + + int tun_fd = tun_alloc(IFF_TAP, if_name); + + appname = argv[0]; + + switch(fork()) { + case -1: + ERROR("fork"); + exit(1); + case 0: + close(1); + open("/dev/null", O_WRONLY); + close(p[0]); + send_fd(p[1], tun_fd, if_name); + exit(0); + default: + close(p[1]); + if (read(p[0], &dummy, 1) != 1) { + ERROR("reading from the synch pipe"); + } + printf("%s\n", if_name); + } + return 0; +} diff --git a/planetlab/pltap-ovs/tunalloc.c b/planetlab/pltap-ovs/tunalloc.c new file mode 100644 index 000000000..6adcf24a5 --- /dev/null +++ b/planetlab/pltap-ovs/tunalloc.c @@ -0,0 +1,95 @@ +/* Slice-side code to allocate tuntap interface in root slice + * Based on bmsocket.c + * Thom Haddow - 08/10/09 + * + * Call tun_alloc() with IFFTUN or IFFTAP as an argument to get back fd to + * new tuntap interface. Interface name can be acquired via TUNGETIFF ioctl. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VSYS_TUNTAP "/vsys/fd_tuntap.control" + +/* Reads vif FD from "fd", writes interface name to vif_name, and returns vif FD. + * vif_name should be IFNAMSIZ chars long. */ +int receive_vif_fd(int fd, char *vif_name) +{ + struct msghdr msg; + struct iovec iov; + int rv; + size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; + struct cmsghdr *cmsg; + + /* Use IOV to read interface name */ + iov.iov_base = vif_name; + iov.iov_len = IFNAMSIZ; + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + /* old BSD implementations should use msg_accrights instead of + * msg_control; the interface is different. */ + msg.msg_control = ccmsg; + msg.msg_controllen = sizeof(ccmsg); + + while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); + if (rv == -1) { + perror("recvmsg"); + return -1; + } + if(!rv) { + /* EOF */ + return -1; + } + + cmsg = CMSG_FIRSTHDR(&msg); + if (!cmsg->cmsg_type == SCM_RIGHTS) { + fprintf(stderr, "got control message of unknown type %d\n", + cmsg->cmsg_type); + return -1; + } + return *(int*)CMSG_DATA(cmsg); +} + + +int tun_alloc(int iftype, char *if_name) +{ + int control_fd; + struct sockaddr_un addr; + int remotefd; + + control_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (control_fd == -1) { + perror("Could not create UNIX socket\n"); + exit(-1); + } + + memset(&addr, 0, sizeof(struct sockaddr_un)); + /* Clear structure */ + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, VSYS_TUNTAP, + sizeof(addr.sun_path) - 1); + + if (connect(control_fd, (struct sockaddr *) &addr, + sizeof(struct sockaddr_un)) == -1) { + perror("Could not connect to Vsys control socket"); + exit(-1); + } + + /* passing type param */ + if (send(control_fd, &iftype, sizeof(iftype), 0) != sizeof(iftype)) { + perror("Could not send paramater to Vsys control socket"); + exit(-1); + } + + remotefd = receive_vif_fd(control_fd, if_name); + return remotefd; +} diff --git a/planetlab/pltap-ovs/tunalloc.h b/planetlab/pltap-ovs/tunalloc.h new file mode 100644 index 000000000..3e5caae1d --- /dev/null +++ b/planetlab/pltap-ovs/tunalloc.h @@ -0,0 +1,6 @@ +#ifndef _TUNALLOC_H +#define _TUNALLOC_H + +int tun_alloc(int iftype, char *if_name); + +#endif diff --git a/planetlab/scripts/create_bridge b/planetlab/scripts/create_bridge new file mode 100755 index 000000000..72acfd7f4 --- /dev/null +++ b/planetlab/scripts/create_bridge @@ -0,0 +1,58 @@ +#!/bin/bash + +function error +{ + echo $1 >&2 + killall pltap-ovs 2>/dev/null || true + exit 1 +} + +function is_switch_running +{ + ovs-appctl version >/dev/null 2>&1 +} + +if [ -z "$1" ]; then + error "Usage: ${0##*/} " +fi + +# TODO: check paramether validity + +IP=${1%/*} +PREFIX=${1#*/} + +set -e + +# ensure ovs-vswitchd is running +if ! is_switch_running; then + ovs-vswitchd --pidfile --detach --log-file >/dev/null 2>&1 +fi +while ! is_switch_running; do + sleep 1 +done + + +# check whether the address is already assigned +set -e +TAPNAME=$(ip addr show to "$IP/32" | perl -ne '/^\s*\d+:\s*([\w-]+):/ && print $1') +if [ ! -z "$TAPNAME" ]; then + if ovs-vsctl br-exists "$TAPNAME"; then + echo $TAPNAME + exit 0 + fi + error "$IP already assigned to $TAPNAME" +fi + +TAPNAME=$(pltap-ovs) +cat < /vsys/vif_up.out& +cat >/vsys/vif_up.in << EOF + $TAPNAME + $IP + $PREFIX +EOF +while ! ip link show up | egrep -q "^[0-9]+: +$TAPNAME:"; do + echo "Waiting for $TAPNAME to come UP..." >&2 + sleep 1 +done +ovs-vsctl add-br $TAPNAME -- set bridge $TAPNAME datapath_type=planetlab +echo $TAPNAME diff --git a/planetlab/scripts/create_port b/planetlab/scripts/create_port new file mode 100755 index 000000000..6fa8ea5f5 --- /dev/null +++ b/planetlab/scripts/create_port @@ -0,0 +1,16 @@ +#!/bin/bash + +function error +{ + echo $1 >&2 + exit 1 +} + +if [ -z "$2" ]; then + error "Usage ${0##*/} " +fi + +if ovs-vsctl list-ports "$1" | grep -q "^$2$"; then + exit 0 +fi +ovs-vsctl add-port "$1" "$2" -- set interface "$2" type=tunnel diff --git a/planetlab/scripts/del_bridge b/planetlab/scripts/del_bridge new file mode 100755 index 000000000..9f62afcec --- /dev/null +++ b/planetlab/scripts/del_bridge @@ -0,0 +1,24 @@ +#!/bin/bash + +function error +{ + echo $1 >&2 + exit 1 +} + +function is_switch_running +{ + ovs-appctl version >/dev/null 2>&1 +} + +if [ -z "$1" ]; then + error "Usage: ${0##*/} " +fi + +# ensure ovs-vswitchd is running +if ! is_switch_running; then + exit 0; +fi + +ovs-vsctl del-br $1 || true +ovs-appctl exit -- 2.47.0