planetlab scripts and utilities
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Tue, 15 May 2012 13:31:22 +0000 (15:31 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Tue, 15 May 2012 13:31:22 +0000 (15:31 +0200)
planetlab/automake.mk
planetlab/scripts/Makefile [new file with mode: 0644]
planetlab/scripts/create_bridge
planetlab/scripts/create_port
planetlab/scripts/del_bridge
planetlab/scripts/del_port [new file with mode: 0755]
planetlab/scripts/start_ovsdb-server [new file with mode: 0644]
planetlab/scripts/start_vswitchd [new file with mode: 0644]
planetlab/vsysc/vsysc.c [new file with mode: 0644]

index a08dd8e..70c59d1 100644 (file)
@@ -1,12 +1,20 @@
 sbin_PROGRAMS += \
-       planetlab/pltap-ovs/pltap-ovs
+       planetlab/pltap-ovs/pltap-ovs \
+       planetlab/vsysc/vsysc
 
 dist_sbin_SCRIPTS += \
+       planetlab/scripts/start_ovsdb-server \
+       planetlab/scripts/start_vswitchd \
        planetlab/scripts/create_bridge \
        planetlab/scripts/create_port \
-       planetlab/scripts/del_bridge
+       planetlab/scripts/del_bridge \
+       planetlab/scripts/del_port \
+       planetlab/scripts/Makefile
 
 planetlab_pltap_ovs_pltap_ovs_SOURCES = \
        planetlab/pltap-ovs/pltap-ovs.c \
        planetlab/pltap-ovs/tunalloc.c \
        planetlab/pltap-ovs/tunalloc.h
+
+planetlab_vsysc_vsysc_SOURCES = \
+       planetlab/vsysc/vsysc.c
diff --git a/planetlab/scripts/Makefile b/planetlab/scripts/Makefile
new file mode 100644 (file)
index 0000000..ea71624
--- /dev/null
@@ -0,0 +1,107 @@
+include conf.mk
+
+# proj1(x@y) = x
+proj1=$(word 1,$(subst @, ,$(1)))
+
+# proj2(x@y) = y
+proj2=$(word 2,$(subst @, ,$(1)))
+
+# get(x-y@1) = x
+# get(x-y@2) = y
+get=$(word $(call proj2,$(1)),$(subst -, ,$(call proj1,$(1))))
+
+# flip(1) = 2
+# flip(2) = 1
+flip=$(if $(findstring 1,$(1)),2,1)
+
+# opp(x-y@1) = x-y@2
+# opp(x-y@2) = x-y@1
+opp=$(call proj1,$(1))@$(call flip,$(call proj2,$(1)))
+
+# rget(x-y@1) = y
+# rget(x-y@2) = x
+rget=$(call get,$(call opp,$(1)))
+
+
+.SECONDARY:
+
+all: $(addprefix L/,$(shell cat links))
+
+
+cache/host.%:
+       @echo "IP lookup for host $*"
+       @host $(HOST_$*) | sed -n 's/^.*has address *//p' > $@
+
+cache/db.%:
+       @echo "Starting db server on host $*"
+       @ssh -l $(SLICE) $(HOST_$*) \
+               sudo start_ovsdb-server > $@ \
+        || { rm $@; exit 1; }
+
+cache/switchd.%: cache/db.%
+       @echo "Starting vswitchd on host $*"
+       @ssh -l $(SLICE) $(HOST_$*) \
+               sudo start_vswitchd > $@ \
+        || { rm $@; exit 1; }
+
+cache/bridge.%: cache/switchd.%
+       @echo "Creating bridge on host $*"
+       @ssh -l $(SLICE) $(HOST_$*) \
+               sudo create_bridge $(IP_$*) > $@ \
+        || { rm $@; exit 1; }
+
+
+L/%: cache/link.%@1 cache/link.%@2
+       @touch $@
+       @echo "Created link $*"
+
+del.%: del-iface.%@1 del-iface.%@2
+       @rm -f L/$*
+       @echo "Deleted link $*"
+
+del-iface.%:
+       @echo "Removing interface for link $(call proj1,$*) from host $(call get,$*)"
+       @ssh -l $(SLICE) $(HOST_$(call get,$*)) \
+               sudo ovs-vsctl del-port L$(call proj1,$*)
+       @rm -f cache/iface.$* cache/link.$* cache/link.$(call opp,$*)
+
+del-bridge.%:
+       @echo "Deleting bridge on host $*"
+       @if [ -f cache/bridge.$* ]; then \
+               ssh -l $(SLICE) $(HOST_$*) \
+                       sudo del_bridge $$(cat cache/bridge.$*);\
+        fi
+       @rm -f cache/bridge.$* \
+             cache/iface.$*-*@1 cache/iface.*-$*@2 \
+             cache/link.$*-*@?  cache/link.*-$*@?  \
+             L/$*-*             L/*-$*
+
+graph.dot:
+       ( echo "digraph $(SLICE) {"; ls L | sed 's/-/->/;s/$$/;/'; echo "}" ) > $@
+
+graph.ps: graph.dot
+       dot -Tps < $^ > $@      
+
+.PHONY: clean del-links graph.dot
+
+
+clean: $(addprefix del-,$(notdir $(wildcard cache/bridge.*)))
+
+del-links: $(addprefix del.,$(notdir $(wildcard L/*)))
+
+.SECONDEXPANSION:
+
+cache/iface.%: cache/bridge.$$(call get,%)
+       @echo "Creating iterface for link $(call proj1,$*) on host $(call get,$*)"
+       @ssh -l $(SLICE) $(HOST_$(call get,$*)) \
+               sudo create_port $$(cat $^) L$(call proj1,$*) > $@ \
+        || { rm $@; exit 1; }
+
+cache/link.%: cache/host.$$(call rget,$$*) cache/iface.% cache/iface.$$(call opp,$$*)
+       @echo "Setting port number of link $(call proj1,$*) on host $(call get,$*)"
+       @ssh -l $(SLICE) $(HOST_$(call get,$*)) \
+               sudo ovs-vsctl set interface L$(call proj1,$*) \
+                       options:remote_ip=$$(cat cache/host.$(call rget,$*)) \
+                       options:remote_port=$$(cat cache/iface.$(call opp,$*)) \
+        && touch $@
+
index 72acfd7..ad88305 100755 (executable)
@@ -25,11 +25,9 @@ set -e
 
 # ensure ovs-vswitchd is running
 if ! is_switch_running; then
-       ovs-vswitchd --pidfile --detach --log-file >/dev/null 2>&1
+       echo "ovs-vswitchd not running" >&2
+       exit 1
 fi
-while ! is_switch_running; do 
-       sleep 1
-done
        
 
 # check whether the address is already assigned
@@ -44,8 +42,7 @@ if [ ! -z "$TAPNAME" ]; then
 fi
 
 TAPNAME=$(pltap-ovs)
-cat < /vsys/vif_up.out&
-cat >/vsys/vif_up.in << EOF
+vsysc vif_up << EOF
        $TAPNAME
        $IP
        $PREFIX
index 6fa8ea5..211a827 100755 (executable)
@@ -10,7 +10,8 @@ if [ -z "$2" ]; then
        error "Usage ${0##*/} <bridge> <port>"
 fi
 
-if ovs-vsctl list-ports "$1" | grep -q "^$2$"; then
-       exit 0
+set -e
+if ! ovs-vsctl list-ports "$1" | grep -q "^$2\$"; then
+       ovs-vsctl add-port "$1" "$2" -- set interface "$2" type=tunnel
 fi
-ovs-vsctl add-port "$1" "$2" -- set interface "$2" type=tunnel
+ovs-appctl netdev-tunnel/get-port "$2"
index 9f62afc..e25ff92 100755 (executable)
@@ -17,8 +17,10 @@ fi
 
 # ensure ovs-vswitchd is running
 if ! is_switch_running; then
-       exit 0;
+       echo "ovs-vswitchd not runnig" >&2
+       exit 1
 fi
 
-ovs-vsctl del-br $1 || true
-ovs-appctl exit 
+if ovs-vsctl bridge-exists "$1"; then
+       ovs-vsctl del-br $1
+fi
diff --git a/planetlab/scripts/del_port b/planetlab/scripts/del_port
new file mode 100755 (executable)
index 0000000..5b1ef8e
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+function error 
+{
+       echo $1 >&2
+       exit 1
+}
+
+if [ -z "$1" ]; then
+       error "Usage ${0##*/} <port>"
+fi
+
+set -e
+if ovs-vsctl port-to-br "$2" >/dev/null 2>&1; then
+       ovs-vsctl del-port "$2"
+fi
diff --git a/planetlab/scripts/start_ovsdb-server b/planetlab/scripts/start_ovsdb-server
new file mode 100644 (file)
index 0000000..49bd0a4
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+PIDF=/usr/local/var/run/openvswitch/ovsdb-server.pid
+
+if [ ! -f "$PIDF" ]; then
+       sudo ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \
+                            --remote=db:Open_vSwitch,manager_options \
+                            --private-key=db:SSL,private_key \
+                            --certificate=db:SSL,certificate \
+                            --bootstrap-ca-cert=db:SSL,ca_cert \
+                            --pidfile --detach
+fi
+while [ ! -f "$PIDF" ]; do
+       echo "Waiting for ovsdb-server to start..." >&2
+       sleep 1;
+done
+cat "$PIDF"
diff --git a/planetlab/scripts/start_vswitchd b/planetlab/scripts/start_vswitchd
new file mode 100644 (file)
index 0000000..248e8cb
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+PIDF=/usr/local/var/run/openvswitch/ovs-vswitchd.pid
+
+if [ ! -f "$PIDF" ]; then
+       sudo ovs-vswitchd --pidfile --detach --log-file >/dev/null
+fi
+while [ ! -f "$PIDF" ]; do
+       echo "Waiting for ovs-vswitchd to start..." >&2
+       sleep 1;
+done
+cat "$PIDF"
diff --git a/planetlab/vsysc/vsysc.c b/planetlab/vsysc/vsysc.c
new file mode 100644 (file)
index 0000000..98c90e7
--- /dev/null
@@ -0,0 +1,191 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define VSYS_PATH "/vsys"
+
+#define MAXPATH 1024
+#define BUFSIZE 4096
+
+#define IN 0
+#define OUT 1
+
+char ctrl[2][MAXPATH]; /* paths of vsys.in & vsys.out */
+
+static void mkpath(int dir, const char* vsys)
+{
+       static const char *suffix[] = { "in", "out" };
+       int n;
+
+       if ( (n = snprintf(ctrl[dir], MAXPATH, "%s/%s.%s", VSYS_PATH, vsys, suffix[dir])) < 0) {
+               perror(vsys);
+               exit(EXIT_FAILURE);
+       } else if (n >= MAXPATH) {
+               fprintf(stderr, "argument too long\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static int open_ctrl(int dir)
+{
+       int fd;
+       
+       if ( (fd = open(ctrl[dir], (dir == IN ? O_WRONLY : O_RDONLY) | O_NONBLOCK)) < 0) {
+               perror(ctrl[dir]);
+               exit(EXIT_FAILURE);
+       }
+       return fd;
+}
+
+
+static void set_nonblocking(int fd)
+{
+       int val;
+
+       if ( (val = fcntl(fd, F_GETFL, 0)) < 0) {
+               perror("fcntl F_GETFL");
+               exit(EXIT_FAILURE);
+       }
+       if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) {
+               perror("fcntl F_SETFL");
+               exit(EXIT_FAILURE);
+       }
+}
+
+#if 0
+static void print_set(const char* name, int max, const fd_set* set)
+{
+       int i, n = 0;
+       fprintf(stderr, "%s: {", name);
+       for (i = 0; i < max; i++) {
+               if (FD_ISSET(i, set)) {
+                       if (n++) fprintf(stderr, ", ");
+                       fprintf(stderr, "%d", i);
+               }
+       }
+       fprintf(stderr, "}\n");
+}
+#endif
+
+struct channel {
+       const char *name;
+       int active;
+       int writing;
+       char buf[BUFSIZE];
+       char *rp, *wp;
+       int rfd, wfd;
+};
+
+static int active_channels = 0;
+
+static void channel_init(struct channel *c, const char* name, int rfd, int wfd)
+{
+       c->name = name;
+       c->rp = c->buf;
+       c->wp = c->buf;
+       c->rfd = rfd;
+       c->wfd = wfd;
+       c->active = 1;
+       active_channels++;
+}
+
+static void channel_fdset(struct channel *c, fd_set* readset, fd_set* writeset)
+{
+       if (!c->active)
+               return;
+       if (c->writing) {
+               FD_SET(c->wfd, writeset);
+       } else {
+               FD_SET(c->rfd, readset);
+       } 
+}
+
+static void channel_run(struct channel *c, const fd_set* readset, const fd_set* writeset)
+{
+       int n;
+
+       if (!c->active)
+               return;
+       if (c->writing) {
+               if (FD_ISSET(c->wfd, writeset)) {
+                       if ( (n = write(c->wfd, c->wp, c->rp - c->wp)) < 0) {
+                               perror(c->name);
+                               exit(EXIT_FAILURE);
+                       }
+                       c->wp += n;
+                       if (c->wp == c->rp) {
+                               c->wp = c->rp = c->buf;
+                               c->writing = 0;
+                       } 
+               }
+       } else {
+               if (FD_ISSET(c->rfd, readset)) {
+                       if ( (n = read(c->rfd, c->rp, BUFSIZE)) < 0) {
+                               perror(c->name);
+                               exit(EXIT_FAILURE);
+                       }
+                       if (n) {
+                               c->wp = c->rp;
+                               c->rp += n;
+                               c->writing = 1;
+                       } else {
+                               close(c->wfd);
+                               c->active = 0;
+                               active_channels--;
+                       }
+               }
+       }
+}
+
+static struct channel channels[2];
+
+
+int main(int argc, char *argv[])
+{
+       int fd[2]; /* fds of vsys.in & vsys.out */
+       int maxfd;
+
+       fd_set readset, writeset;
+
+       if (argc != 2) {
+               fprintf(stderr, "Usage: %s <vsys>\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       mkpath(IN,  argv[1]);
+       mkpath(OUT, argv[1]);
+
+       maxfd = (STDOUT_FILENO > STDIN_FILENO ? STDOUT_FILENO : STDIN_FILENO);
+
+       fd[OUT] = open_ctrl(OUT);
+       if (fd[OUT] > maxfd)
+               maxfd = fd[OUT];
+       fd[IN]  = open_ctrl(IN);
+       if (fd[IN] > maxfd)
+               maxfd = fd[IN];
+
+       set_nonblocking(STDIN_FILENO);
+       set_nonblocking(STDOUT_FILENO);
+
+       channel_init(&channels[IN], "IN", STDIN_FILENO, fd[IN]);
+       channel_init(&channels[OUT], "OUT", fd[OUT], STDOUT_FILENO);
+
+       while (active_channels) {
+               FD_ZERO(&readset);
+               FD_ZERO(&writeset);
+               channel_fdset(&channels[IN], &readset, &writeset);
+               channel_fdset(&channels[OUT], &readset, &writeset);
+               if (select(maxfd + 1, &readset, &writeset, NULL, NULL) < 0) {
+                       perror("select");
+                       exit(EXIT_FAILURE);
+               }
+               channel_run(&channels[IN], &readset, &writeset);
+               channel_run(&channels[OUT], &readset, &writeset);
+       }
+       return EXIT_SUCCESS;
+}
+