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
--- /dev/null
+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 $@
+
# 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
fi
TAPNAME=$(pltap-ovs)
-cat < /vsys/vif_up.out&
-cat >/vsys/vif_up.in << EOF
+vsysc vif_up << EOF
$TAPNAME
$IP
$PREFIX
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"
# 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
--- /dev/null
+#!/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
--- /dev/null
+#!/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"
--- /dev/null
+#!/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"
--- /dev/null
+#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;
+}
+