Implement Debian-based packaging and deployment infrastructure.
authorBen Pfaff <blp@nicira.com>
Fri, 13 Jun 2008 20:36:00 +0000 (13:36 -0700)
committerBen Pfaff <blp@nicira.com>
Fri, 13 Jun 2008 20:36:00 +0000 (13:36 -0700)
47 files changed:
configure.ac
debian/.gitignore [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/control.modules.in [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/dirs [new file with mode: 0644]
debian/ofp-switch-setup [new file with mode: 0755]
debian/ofp-switch-setup.8 [new file with mode: 0644]
debian/openflow-common.install [new file with mode: 0644]
debian/openflow-common.manpages [new file with mode: 0644]
debian/openflow-controller.README.Debian [new file with mode: 0644]
debian/openflow-controller.default [new file with mode: 0644]
debian/openflow-controller.dirs [new file with mode: 0644]
debian/openflow-controller.init [new file with mode: 0755]
debian/openflow-controller.install [new file with mode: 0644]
debian/openflow-controller.manpages [new file with mode: 0644]
debian/openflow-controller.postinst [new file with mode: 0755]
debian/openflow-datapath-module-_KVERS_.postinst.modules.in [new file with mode: 0755]
debian/openflow-datapath-source.README.Debian [new file with mode: 0644]
debian/openflow-datapath-source.copyright [new file with mode: 0644]
debian/openflow-datapath-source.dirs [new file with mode: 0644]
debian/openflow-pki.apache2 [new file with mode: 0644]
debian/openflow-pki.dirs [new file with mode: 0644]
debian/openflow-pki.install [new file with mode: 0644]
debian/openflow-pki.postinst [new file with mode: 0755]
debian/openflow-switch.README.Debian [new file with mode: 0644]
debian/openflow-switch.config [new file with mode: 0755]
debian/openflow-switch.default [new file with mode: 0644]
debian/openflow-switch.dirs [new file with mode: 0644]
debian/openflow-switch.init [new file with mode: 0755]
debian/openflow-switch.install [new file with mode: 0644]
debian/openflow-switch.links [new file with mode: 0644]
debian/openflow-switch.manpages [new file with mode: 0644]
debian/openflow-switch.overrides [new file with mode: 0644]
debian/openflow-switch.postinst [new file with mode: 0755]
debian/openflow-switch.templates [new file with mode: 0644]
debian/po/POTFILES.in [new file with mode: 0644]
debian/po/templates.pot [new file with mode: 0644]
debian/rules [new file with mode: 0755]
utilities/.gitignore
utilities/Makefile.am
utilities/ofp-pki [deleted file]
utilities/ofp-pki-cgi.in [new file with mode: 0755]
utilities/ofp-pki.8 [deleted file]
utilities/ofp-pki.in [new file with mode: 0755]

index 0cdc593a6386db8e73c33ea15800f40174c9f9b6..2be62d5900f987bee6f18c4e5afc6a6a49696c2c 100644 (file)
@@ -6,6 +6,12 @@ AC_PROG_CC
 AC_PROG_CPP
 AC_PROG_LD
 
+AC_ARG_VAR([PERL], [path to Perl interpreter])
+AC_PATH_PROG([PERL], perl, no)
+if test "$PERL" = no; then
+   AC_MSG_ERROR([Perl interpreter not found in $PATH or $PERL.])
+fi
+
 AC_USE_SYSTEM_EXTENSIONS
 
 AC_PROG_LIBTOOL
diff --git a/debian/.gitignore b/debian/.gitignore
new file mode 100644 (file)
index 0000000..b3189e7
--- /dev/null
@@ -0,0 +1,9 @@
+*.debhelper
+/files
+/openflow
+/openflow-common
+/openflow-controller
+/openflow-pki
+/openflow-switch
+/openflow-datapath-source
+*.substvars
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..ad26b6c
--- /dev/null
@@ -0,0 +1,5 @@
+openflow (0.8.1) unstable; urgency=low
+
+  * Development version.
+
+ -- OpenFlow team <openflow-dev@lists.stanford.edu>  Mon, 19 Nov 2007 14:57:52 -0800
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7ed6ff8
--- /dev/null
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..ce55e8e
--- /dev/null
@@ -0,0 +1,57 @@
+Source: openflow
+Section: net
+Priority: extra
+Maintainer: OpenFlow Team <openflow-dev@lists.stanford.edu>
+Build-Depends: debhelper (>= 5), autoconf (>= 2.60), automake1.10, libssl-dev, pkg-config (>= 0.21), po-debconf, bzip2
+Standards-Version: 3.7.3
+
+Package: openflow-datapath-source
+Architecture: all
+Depends: module-assistant, bzip2, debhelper (>= 5.0.37)
+Suggests: openflow-switch
+Description: Source code for OpenFlow datapath Linux module
+ This package provides the OpenFlow datapath module source code that
+ is needed by the kernel-based OpenFlow switch.  The kernel module can
+ be built from it using module-assistant or make-kpkg.  README.Debian
+ in this package provides further instructions.
+ .
+ OpenFlow is a protocol for flow-based control over network switching.
+
+Package: openflow-common
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: OpenFlow common components
+ openflow-common provides components required by both openflow-switch
+ and openflow-controller.
+ .
+ OpenFlow is a protocol for flow-based control over network switching.
+
+Package: openflow-switch
+Architecture: any
+Suggests: openflow-datapath-module
+Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-common, libwww-perl, libdigest-sha1-perl, dhcp3-client
+Description: OpenFlow switch implementations
+ openflow-switch provides the userspace components and utilities for
+ the OpenFlow kernel-based switch.  It also includes a userspace-only
+ implementation of an OpenFlow switch.
+ .
+ OpenFlow is a protocol for flow-based control over network switching.
+
+Package: openflow-pki
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, apache2
+Description: OpenFlow public key infrastructure
+ openflow-pki provides PKI (public key infrastructure) support for
+ OpenFlow switches and controllers, reducing the risk of
+ man-in-the-middle attacks on the OpenFlow network infrastructure.
+ .
+ OpenFlow is a protocol for flow-based control over network switching.
+
+Package: openflow-controller
+Architecture: any
+Depends: ${shlibs:Depends}, openflow-common, openflow-pki
+Description: OpenFlow controller implementation
+ The OpenFlow controller enables OpenFlow switches that connect to it
+ to act as MAC-learning Ethernet switches.
+ .
+ OpenFlow is a protocol for flow-based control over network switching.
diff --git a/debian/control.modules.in b/debian/control.modules.in
new file mode 100644 (file)
index 0000000..cc149ca
--- /dev/null
@@ -0,0 +1,19 @@
+Source: openflow
+Section: net
+Priority: extra
+Maintainer: OpenFlow Team <openflow-dev@lists.stanford.edu>
+Build-Depends: debhelper (>= 5.0.37)
+Standards-Version: 3.7.3
+
+Package: openflow-datapath-module-_KVERS_
+Architecture: any
+Recommends: kernel-image-_KVERS_, openflow-switch
+Provides: openflow-datapath-module
+Description: OpenFlow Linux datapath kernel module
+ This package contains the OpenFlow loadable datapath kernel modules for
+ the kernel-image-_KVERS_ package.
+ .
+ If you compiled a custom kernel, you will most likely need to compile
+ a custom version of this module as well.  The openflow-datapath-source
+ package has been provided for this purpose.  Refer to README.Debian
+ provided in that package for further instructions.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..b369ec3
--- /dev/null
@@ -0,0 +1,38 @@
+Upstream Authors: 
+
+    The Board of Trustees of The Leland Stanford Junior University
+
+Copyright: 
+
+    Copyright (C) 2008 The Board of Trustees of The Leland Stanford
+    Junior University
+
+License:
+
+    We are making the OpenFlow specification and associated documentation
+    (Software) available for public use and benefit with the expectation
+    that others will use, modify and enhance the Software and contribute
+    those enhancements back to the community. However, since we would like
+    to make the Software available for broadest use, with as few
+    restrictions as possible permission is hereby granted, free of charge,
+    to any person obtaining a copy of this Software to deal in the Software
+    under the copyrights without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included
+    in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    The name and trademarks of copyright holder(s) may NOT be used in
+    advertising or publicity pertaining to the Software or any derivatives
+    without specific, written prior permission.
+
diff --git a/debian/dirs b/debian/dirs
new file mode 100644 (file)
index 0000000..ca882bb
--- /dev/null
@@ -0,0 +1,2 @@
+usr/bin
+usr/sbin
diff --git a/debian/ofp-switch-setup b/debian/ofp-switch-setup
new file mode 100755 (executable)
index 0000000..0c03c33
--- /dev/null
@@ -0,0 +1,487 @@
+#! /usr/bin/perl
+
+use POSIX;
+use Debconf::Client::ConfModule ':all';
+use HTTP::Request;
+use LWP::UserAgent;
+use Digest::SHA1 'sha1_hex';
+use strict;
+use warnings;
+
+my $debconf_owner = 'openflow-switch';
+
+my $default = '/etc/default/openflow-switch';
+my $etc = '/etc/openflow-switch';
+my $privkey_file = "$etc/of0-privkey.pem";
+my $req_file = "$etc/of0-req.pem";
+my $cert_file = "$etc/of0-cert.pem";
+my $cacert_file = "$etc/cacert.pem";
+
+my $ua = LWP::UserAgent->new;
+$ua->timeout(10);
+$ua->env_proxy;
+
+version('2.0');
+capb('backup');
+title('OpenFlow Switch Setup');
+
+my (%netdevs) = find_netdevs();
+db_subst('netdevs', 'choices',
+         join(', ', map($netdevs{$_}, sort(keys(%netdevs)))));
+db_set('netdevs', join(', ', grep(!/IP/, values(%netdevs))));
+
+if (-e $default) {
+    my (%config) = load_config($default);
+
+    my (%map) =
+      (NETDEVS => sub {
+           db_set('netdevs', join(', ', map($netdevs{$_},
+                                            grep(exists $netdevs{$_}, split))))
+       },
+       IN_BAND => sub {
+           db_set('band', $_ eq 'no' ? 'in-band' : 'out-of-band')
+       },
+       SWITCH_IP => sub { db_set('switch-ip', $_) },
+       CONTROLLER => sub { db_set('controller-vconn', $_) },
+       PRIVKEY => sub { $privkey_file = $_ },
+       CERT => sub { $cert_file = $_ },
+       CACERT => sub { $cacert_file = $_ },
+      );
+
+    for my $key (keys(%map)) {
+        local $_ = $config{$key};
+        &{$map{$key}}() if defined && !/^\s*$/;
+    }
+}
+
+my $cacert_preverified = -e $cacert_file;
+
+if (! -e $privkey_file) {
+    my $old_umask = umask(077);
+    run_cmd("ofp-pki req $etc/of0 >&2 2>/dev/null");
+    chmod(0644, $req_file) or die "$req_file: chmod: $!\n";
+    umask($old_umask);
+}
+
+my ($req, $req_fingerprint);
+if (! -e $cert_file) {
+    open(REQ, '<', $req_file) or die "$req_file: open: $!\n";
+    $req = join('', <REQ>);
+    close(REQ);
+    $req_fingerprint = sha1_hex($req);
+}
+
+my (@states) =
+  (sub {
+       # User backed up from first dialog box.
+       exit(10);
+   },
+   sub {
+       # Prompt for ports to include in switch.
+       db_input('netdevs');
+       return;
+   },
+   sub {
+       # Validate the chosen ports.
+       my (@netdevs) = split(', ', db_get('netdevs'));
+       if (!@netdevs) {
+           # No ports chosen.  Disable switch.
+           db_input('no-netdevs');
+           return 'prev' if db_go();
+           return 'done';
+       } elsif (my (@conf_netdevs) = grep(/IP/, @netdevs)) {
+           # Point out that some ports have configured IP addresses.
+           db_subst('configured-netdevs', 'configured-netdevs',
+                    join(', ', @conf_netdevs));
+           db_input('configured-netdevs');
+           return;
+       } else {
+           # Otherwise proceed.
+           return 'skip';
+       }
+   },
+   sub {
+       # In-band or out-of-band controller?
+       db_input('band');
+       return;
+   },
+   sub {
+       return 'skip' if db_get('band') eq 'out-of-band';
+       for (;;) {
+           db_input('switch-ip');
+           return 'prev' if db_go();
+
+           my $ip = db_get('switch-ip');
+           return 'next' if $ip =~ /^dhcp|\d+\.\d+.\d+.\d+$/i;
+
+           db_input('switch-ip-error');
+           db_go();
+       }
+   },
+   sub {
+       for (;;) {
+           my $old_vconn = db_get('controller-vconn');
+           db_input('controller-vconn');
+           return 'prev' if db_go();
+
+           my $vconn = db_get('controller-vconn');
+           if ($vconn =~ /^(tcp|ssl):([^:]+)(:.*)?/) {
+               if ($old_vconn ne $vconn
+                   || db_get('pki-host') eq '') {
+                   db_set('pki-host', $2);
+               }
+               return 'next';
+           }
+
+           db_input('controller-vconn-error');
+           db_go();
+       }
+   },
+   sub {
+       return 'skip' if !ssl_enabled();
+       return 'skip' if -e $cacert_file && -e $cert_file;
+
+       db_input('pki-host');
+       return 'prev' if db_go();
+       return;
+   },
+   sub {
+       return 'skip' if !ssl_enabled();
+       return 'skip' if -e $cacert_file;
+
+       my $pki_host = db_get('pki-host');
+       my $url = "http://$pki_host/openflow/pki/controllerca/cacert.pem";
+       my $response = $ua->get($url, ':content_file' => $cacert_file);
+       if ($response->is_success) {
+           return 'next';
+       }
+
+       db_subst('fetch-cacert-failed', 'url', $url);
+       db_subst('fetch-cacert-failed', 'error', $response->status_line);
+       db_subst('fetch-cacert-failed', 'pki-host', $pki_host);
+       db_input('fetch-cacert-failed');
+       db_go();
+       return 'prev';
+   },
+   sub {
+       return 'skip' if !ssl_enabled();
+       return 'skip' if -e $cert_file;
+
+       for (;;) {
+           db_set('send-cert-req', 'yes');
+           db_input('send-cert-req');
+           return 'prev' if db_go();
+           return 'next' if db_get('send-cert-req') eq 'no';
+
+           my $pki_host = db_get('pki-host');
+           my $url = "http://$pki_host/cgi-bin/ofp-pki-cgi";
+           my $response = $ua->post($url, {'type' => 'switch',
+                                           'req' => $req});
+           return 'next' if $response->is_success;
+
+           db_subst('send-cert-req-failed', 'url', $url);
+           db_subst('send-cert-req-failed', 'error',
+                    $response->status_line);
+           db_subst('send-cert-req-failed', 'pki-host',
+                    $pki_host);
+           db_input('send-cert-req-failed');
+           db_go();
+       }
+   },
+   sub {
+       return 'skip' if !ssl_enabled();
+       return 'skip' if $cacert_preverified;
+
+       my ($cacert_fingerprint) = x509_fingerprint($cacert_file);
+       db_subst('verify-controller-ca', 'fingerprint', $cacert_fingerprint);
+       db_input('verify-controller-ca');
+       return 'prev' if db_go();
+       return 'next' if db_get('verify-controller-ca') eq 'yes';
+       unlink($cacert_file);
+       return 'prev';
+   },
+   sub {
+       return 'skip' if !ssl_enabled();
+       return 'skip' if -e $cert_file;
+
+       for (;;) {
+           db_set('fetch-switch-cert', 'yes');
+           db_input('fetch-switch-cert');
+           return 'prev' if db_go();
+           exit(1) if db_get('fetch-switch-cert') eq 'no';
+
+           my $pki_host = db_get('pki-host');
+           my $url = "http://$pki_host/openflow/pki/switchca/certs/$req_fingerprint-cert.pem";
+           my $response = $ua->get($url, ':content_file' => $cert_file);
+           if ($response->is_success) {
+               return 'next';
+           }
+
+           db_subst('fetch-switch-cert-failed', 'url', $url);
+           db_subst('fetch-switch-cert-failed', 'error',
+                    $response->status_line);
+           db_subst('fetch-switch-cert-failed', 'pki-host',
+                    $pki_host);
+           db_input('fetch-switch-cert-failed');
+           db_go();
+       }
+   },
+   sub {
+       db_input('complete');
+       db_go();
+       return;
+   },
+   sub {
+       return 'done';
+   },
+);
+
+my $state = 1;
+my $direction = 1;
+for (;;) {
+    my $ret = &{$states[$state]}();
+    $ret = db_go() ? 'prev' : 'next' if !defined $ret;
+    if ($ret eq 'next') {
+        $direction = 1;
+    } elsif ($ret eq 'prev') {
+        $direction = -1;
+    } elsif ($ret eq 'skip') {
+        # Nothing to do.
+    } elsif ($ret eq 'done') {
+        last;
+    } else {
+        die "unknown ret $ret";
+    }
+    $state += $direction;
+}
+
+my %config;
+$config{NETDEVS} = join(' ', map(/^(\S+)/, split(', ', db_get('netdevs'))));
+if (db_get('band') eq 'in-band') {
+    $config{IN_BAND} = 'yes';
+    $config{SWITCH_IP} = db_get('switch-ip');
+} else {
+    $config{IN_BAND} = 'no';
+}
+$config{CONTROLLER} = db_get('controller-vconn');
+$config{PRIVKEY} = $privkey_file;
+$config{CERT} = $cert_file;
+$config{CACERT} = $cacert_file;
+save_config($default, %config);
+
+dup2(2, 1);                     # Get stdout back.
+system("/etc/init.d/openflow-switch restart");
+
+sub ssl_enabled {
+    return db_get('controller-vconn') =~ /^ssl:/;
+}
+
+sub db_subst {
+    my ($question, $key, $value) = @_;
+    $question = "$debconf_owner/$question";
+    my ($ret, $seen) = subst($question, $key, $value);
+    if ($ret && $ret != 30) {
+        die "Error substituting $value for $key in debconf question "
+          . "$question: $seen";
+    }
+}
+
+sub db_set {
+    my ($question, $value) = @_;
+    $question = "$debconf_owner/$question";
+    my ($ret, $seen) = set($question, $value);
+    if ($ret && $ret != 30) {
+        die "Error setting debconf question $question to $value: $seen";
+    }
+}
+
+sub db_get {
+    my ($question) = @_;
+    $question = "$debconf_owner/$question";
+    my ($ret, $seen) = get($question);
+    if ($ret) {
+        die "Error getting debconf question $question answer: $seen";
+    }
+    return $seen;
+}
+
+sub db_fset {
+    my ($question, $flag, $value) = @_;
+    $question = "$debconf_owner/$question";
+    my ($ret, $seen) = fset($question, $flag, $value);
+    if ($ret && $ret != 30) {
+        die "Error setting debconf question $question flag $flag to $value: "
+          . "$seen";
+    }
+}
+
+sub db_fget {
+    my ($question, $flag) = @_;
+    $question = "$debconf_owner/$question";
+    my ($ret, $seen) = fget($question, $flag);
+    if ($ret) {
+        die "Error getting debconf question $question flag $flag: $seen";
+    }
+    return $seen;
+}
+
+sub db_input {
+    my ($question) = @_;
+    db_fset($question, "seen", "false");
+
+    $question = "$debconf_owner/$question";
+    my ($ret, $seen) = input('high', $question);
+    if ($ret && $ret != 30) {
+        die "Error requesting debconf question $question: $seen";
+    }
+    return $ret;
+}
+
+sub db_go {
+    my ($ret, $seen) = go();
+    if (!defined($ret)) {
+        exit(1);                # Cancel button was pushed.
+    }
+    if ($ret && $ret != 30) {
+        die "Error asking debconf questions: $seen";
+    }
+    return $ret;
+}
+
+sub run_cmd {
+    my ($cmd) = @_;
+    return if system($cmd) == 0;
+
+    if ($? == -1) {
+        die "$cmd: failed to execute: $!\n";
+    } elsif ($? & 127) {
+        die sprintf("$cmd: child died with signal %d, %s coredump\n",
+                    ($? & 127),  ($? & 128) ? 'with' : 'without');
+    } else {
+        die sprintf("$cmd: child exited with value %d\n", $? >> 8);
+    }
+}
+
+sub x509_fingerprint {
+    my ($file) = @_;
+    my $cmd = "openssl x509 -noout -in $file -fingerprint";
+    open(OPENSSL, '-|', $cmd) or die "$cmd: failed to execute: $!\n";
+    my $line = <OPENSSL>;
+    close(OPENSSL);
+    my ($fingerprint) = $line =~ /SHA1 Fingerprint=(.*)/;
+    return $line if !defined $fingerprint;
+    $fingerprint =~ s/://g;
+    return $fingerprint;
+}
+
+sub find_netdevs {
+    my ($netdev, %netdevs);
+    open(IFCONFIG, "/sbin/ifconfig -a|") or die "ifconfig failed: $!";
+    while (<IFCONFIG>) {
+        if (my ($nd) = /^([^\s]+)/) {
+            $netdev = $nd;
+            $netdevs{$netdev} = "$netdev";
+            if (my ($hwaddr) = /HWaddr (\S+)/) {
+                $netdevs{$netdev} .= " (MAC: $hwaddr)";
+            }
+        } elsif (my ($ip4) = /^\s*inet addr:(\S+)/) {
+            $netdevs{$netdev} .= " (IP: $ip4)";
+        } elsif (my ($ip6) = /^\s*inet6 addr:(\S+)/) {
+            $netdevs{$netdev} .= " (IPv6: $ip6)";
+        }
+    }
+    foreach my $nd (keys(%netdevs)) {
+        delete $netdevs{$nd} if $nd eq 'lo' || $nd =~ /^wmaster/;
+    }
+    close(IFCONFIG);
+    return %netdevs;
+}
+
+sub load_config {
+    my ($file) = @_;
+    my ($cmd) = "set -a && . $file && env";
+    if (!open(VARS, '-|', $cmd)) {
+        print STDERR "$cmd: failed to execute: $!\n";
+        return;
+    }
+    my (%config);
+    while (<VARS>) {
+        my ($var, $value) = /^([^=]+)=(.*)$/ or next;
+        $config{$var} = $value;
+    }
+    close(VARS);
+    return %config;
+}
+
+sub shell_escape {
+    local $_ = $_[0];
+    if (m&^[-a-zA-Z0-9:./%^_+,]*$&) {
+        return $_;
+    } else {
+        s/'/'\\''/;
+        return "'$_'";
+    }
+}
+
+sub shell_assign {
+    my ($var, $value) = @_;
+    return $var . '=' . shell_escape($value);
+}
+
+sub save_config {
+    my ($file, %config) = @_;
+    my (@lines);
+    if (open(FILE, '<', $file)) {
+        @lines = <FILE>;
+        chomp @lines;
+        close(FILE);
+    }
+
+    # Replace all existing variable assignments.
+    for (my ($i) = 0; $i <= $#lines; $i++) {
+        local $_ = $lines[$i];
+        my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next;
+        if (exists($config{$var})) {
+            $lines[$i] = shell_assign($var, $config{$var});
+            delete $config{$var};
+        } else {
+            $lines[$i] = "#$lines[$i]";
+        }
+    }
+
+    # Find a place to put any remaining variable assignments.
+  VAR:
+    for my $var (keys(%config)) {
+        my $assign = shell_assign($var, $config{$var});
+
+        # Replace the last commented-out variable assignment to $var, if any.
+        for (my ($i) = $#lines; $i >= 0; $i--) {
+            local $_ = $lines[$i];
+            if (/^\s*#\s*$var=/) {
+                $lines[$i] = $assign;
+                next VAR;
+            }
+        }
+
+        # Find a place to add the var: after the final commented line
+        # just after a line that contains "$var:".
+        for (my ($i) = 0; $i <= $#lines; $i++) {
+            if ($lines[$i] =~ /^\s*#\s*$var:/) {
+                for (my ($j) = $i + 1; $j <= $#lines; $j++) {
+                    if ($lines[$j] !~ /^\s*#/) {
+                        splice(@lines, $j, 0, $assign);
+                        next VAR;
+                    }
+                }
+            }
+        }
+
+        # Just append it.
+        push(@lines, $assign);
+    }
+
+    open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n";
+    print NEWFILE join('', map("$_\n", @lines));
+    close(NEWFILE);
+    rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n";
+}
diff --git a/debian/ofp-switch-setup.8 b/debian/ofp-switch-setup.8
new file mode 100644 (file)
index 0000000..50904cf
--- /dev/null
@@ -0,0 +1,41 @@
+.TH ofp-switch-setup 8 "June 2008" "OpenFlow" "OpenFlow Manual"
+
+.SH NAME
+ofp\-switch\-setup \- interactive setup for OpenFlow switch
+
+.SH SYNOPSIS
+.B ofp\-switch\-setup
+
+.SH DESCRIPTION
+The \fBofp\-switch\-setup\fR program is an interactive program that
+assists the system administrator in configuring an OpenFlow switch,
+including the underlying public key infrastructure (PKI).
+
+.SH OPTIONS
+ofp\-switch\-setup does not accept any command-line options.
+
+.SH FILES
+.IP /etc/default/openflow-switch
+Main configuration file for OpenFlow switch.
+
+.IP /etc/openflow-switch/cacert.pem
+Default location of CA certificate for OpenFlow controllers.
+
+.IP /etc/openflow-switch/of0-cert.pem
+Default location of certificate for the OpenFlow switch's private key.
+
+.IP /etc/openflow-switch/of0-privkey.pem
+Default location of the OpenFlow switch's private key.  This file
+should be readable only by \fBroot\fR.
+
+.IP /etc/openflow-switch/of0-req.pem
+Default location of certificate request for the OpenFlow switch's
+certificate.  This file is not used after the signed certificate
+(typically \fB/etc/openflow-switch/of0-cert.pem\fR, above) has been
+obtained from the OpenFlow PKI server.
+
+.SH "SEE ALSO"
+
+.BR ofp-pki (8),
+.BR dpctl (8),
+.BR secchan (8)
diff --git a/debian/openflow-common.install b/debian/openflow-common.install
new file mode 100644 (file)
index 0000000..4175c30
--- /dev/null
@@ -0,0 +1,2 @@
+utilities/ofp-pki usr/sbin
+utilities/vlogconf usr/sbin
diff --git a/debian/openflow-common.manpages b/debian/openflow-common.manpages
new file mode 100644 (file)
index 0000000..282ec32
--- /dev/null
@@ -0,0 +1,2 @@
+utilities/vlogconf.8
+utilities/ofp-pki.8
diff --git a/debian/openflow-controller.README.Debian b/debian/openflow-controller.README.Debian
new file mode 100644 (file)
index 0000000..c54e569
--- /dev/null
@@ -0,0 +1,5 @@
+README.Debian for openflow-controller
+-------------------------------------
+
+* To reconfigure the controller, edit /etc/default/openflow-controller
+  and run "/etc/init.d/openflow-controller restart".
diff --git a/debian/openflow-controller.default b/debian/openflow-controller.default
new file mode 100644 (file)
index 0000000..a827546
--- /dev/null
@@ -0,0 +1,33 @@
+# This is a POSIX shell fragment                -*- sh -*-
+
+# LISTEN: What OpenFlow connection methods should the controller listen on?
+#
+# This is a space-delimited list of connection methods:
+#
+# * "pssl:[PORT]": Listen for SSL connections on the specified PORT
+#   (default: 976).  The private key, certificate, and CA certificate
+#   must be specified below.
+#
+# * "pctp:[PORT]": Listen for TCP connections on the specified PORT
+#   (default: 975).  Not recommended for security reasons.
+#
+# * "nl:DP_IDX": Listen on local datapath DP_IDX.  Used only if this
+#   machine is also an OpenFlow switch and not running the secure
+#   channel, and only if you know what you're doing.
+#
+LISTEN="pssl:"
+
+# PRIVKEY: Name of file containing controller's private key.
+# Required if SSL enabled.
+PRIVKEY=/etc/openflow-controller/privkey.pem
+
+# CERT: Name of file containing certificate for private key.
+# Required if SSL enabled.
+CERT=/etc/openflow-controller/cert.pem
+
+# CACERT: Name of file containing switch CA certificate.
+# Required if SSL enabled.
+CACERT=/etc/openflow-controller/cacert.pem
+
+# Additional options to pass to controller, e.g. "--hub"
+DAEMON_OPTS=""
diff --git a/debian/openflow-controller.dirs b/debian/openflow-controller.dirs
new file mode 100644 (file)
index 0000000..0a19a9f
--- /dev/null
@@ -0,0 +1 @@
+etc/openflow-controller
diff --git a/debian/openflow-controller.init b/debian/openflow-controller.init
new file mode 100755 (executable)
index 0000000..121fd76
--- /dev/null
@@ -0,0 +1,269 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Javier Fernandez-Sanguino <jfs@debian.org>
+#
+# This is free software; you may redistribute it and/or modify
+# it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2,
+# or (at your option) any later version.
+#
+# This is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License with
+# the Debian operating system, in /usr/share/common-licenses/GPL;  if
+# not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+#
+### BEGIN INIT INFO
+# Provides:          openflow-controller
+# Required-Start:    $network $local_fs
+# Required-Stop:     
+# Should-Start:      $named
+# Should-Stop:       
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: OpenFlow controller
+### END INIT INFO
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+
+DAEMON=/usr/sbin/controller # Introduce the server's location here
+NAME=controller             # Introduce the short server's name here
+DESC=controller             # Introduce a short description here
+LOGDIR=/var/log/openflow    # Log directory to use
+
+PIDFILE=/var/run/$NAME.pid 
+
+test -x $DAEMON || exit 0
+
+. /lib/lsb/init-functions
+
+# Default options, these can be overriden by the information
+# at /etc/default/$NAME
+DAEMON_OPTS=""          # Additional options given to the server 
+
+DODTIME=10              # Time to wait for the server to die, in seconds
+                        # If this value is set too low you might not
+                        # let some servers to die gracefully and
+                        # 'restart' will not work
+                        
+LOGFILE=$LOGDIR/$NAME.log  # Server logfile
+#DAEMONUSER=            # User to run the daemons as. If this value
+                        # is set start-stop-daemon will chuid the server
+
+# Include defaults if available
+default=/etc/default/openflow-controller
+if [ -f $default ] ; then
+       . $default
+fi
+
+# Check that the user exists (if we set a user)
+# Does the user exist?
+if [ -n "$DAEMONUSER" ] ; then
+    if getent passwd | grep -q "^$DAEMONUSER:"; then
+        # Obtain the uid and gid
+        DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'`
+        DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'`
+    else
+        log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist."
+        exit 1
+    fi
+fi
+
+
+set -e
+
+running_pid() {
+# Check if a given process pid's cmdline matches a given name
+    pid=$1
+    name=$2
+    [ -z "$pid" ] && return 1 
+    [ ! -d /proc/$pid ] &&  return 1
+    cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1`
+    # Is this the expected server
+    [ "$cmd" != "$name" ] &&  return 1
+    return 0
+}
+
+running() {
+# Check if the process is running looking at /proc
+# (works for all users)
+
+    # No pidfile, probably no daemon present
+    [ ! -f "$PIDFILE" ] && return 1
+    pid=`cat $PIDFILE`
+    running_pid $pid $DAEMON || return 1
+    return 0
+}
+
+start_server() {
+    if [ -z "$LISTEN" ]; then
+        echo "$default: No connection methods configured, controller disabled" >&2
+        exit 0
+    fi
+
+    SSL_OPTS=
+    case $LISTEN in
+        *ssl*)
+            : ${PRIVKEY:=/etc/openflow-controller/privkey.pem}
+            : ${CERT:=/etc/openflow-controller/cert.pem}
+            : ${CACERT:=/etc/openflow-controller/cacert.pem}
+            if test ! -e "$PRIVKEY" || test ! -e "$CERT" ||
+                test ! -e "$CACERT"; then
+                if test ! -e "$PRIVKEY"; then
+                    echo "$PRIVKEY: private key missing" >&2
+                fi
+                if test ! -e "$CERT"; then
+                    echo "$CERT: certificate for private key missing" >&2
+                fi
+                if test ! -e "$CACERT"; then
+                    echo "$CACERT: CA certificate missing" >&2
+                fi
+                exit 1
+            fi
+            SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT --ca-cert=$CACERT"
+            ;;
+    esac
+
+# Start the process using the wrapper
+        if [ -z "$DAEMONUSER" ] ; then
+            start-stop-daemon --start --pidfile $PIDFILE \
+                        --exec $DAEMON -- --detach --pidfile=$PIDFILE \
+                        $LISTEN $DAEMON_OPTS $SSL_OPTS
+            errcode=$?
+        else
+# if we are using a daemonuser then change the user id
+            start-stop-daemon --start --quiet --pidfile $PIDFILE \
+                        --chuid $DAEMONUSER --exec $DAEMON -- \
+                        --detach --pidfile=$PIDFILE $LISTEN $DAEMON_OPTS \
+                        $SSL_OPTS
+            errcode=$?
+        fi
+       return $errcode
+}
+
+stop_server() {
+# Stop the process using the wrapper
+        if [ -z "$DAEMONUSER" ] ; then
+            start-stop-daemon --stop --quiet --pidfile $PIDFILE \
+                        --exec $DAEMON
+            errcode=$?
+        else
+# if we are using a daemonuser then look for process that match
+            start-stop-daemon --stop --quiet --pidfile $PIDFILE \
+                        --user $DAEMONUSER --exec $DAEMON
+            errcode=$?
+        fi
+
+       return $errcode
+}
+
+reload_server() {
+    [ ! -f "$PIDFILE" ] && return 1
+    pid=`cat $PIDFILE` # This is the daemon's pid
+    # Send a SIGHUP
+    kill -1 $pid
+    return $?
+}
+
+force_stop() {
+# Force the process to die killing it manually
+       [ ! -e "$PIDFILE" ] && return
+       if running ; then
+               kill -15 $pid
+       # Is it really dead?
+               sleep "$DIETIME"s
+               if running ; then
+                       kill -9 $pid
+                       sleep "$DIETIME"s
+                       if running ; then
+                               echo "Cannot kill $NAME (pid=$pid)!"
+                               exit 1
+                       fi
+               fi
+       fi
+       rm -f $PIDFILE
+}
+
+
+case "$1" in
+  start)
+       log_daemon_msg "Starting $DESC " "$NAME"
+        # Check if it's running first
+        if running ;  then
+            log_progress_msg "apparently already running"
+            log_end_msg 0
+            exit 0
+        fi
+        if start_server && running ;  then
+            # It's ok, the server started and is running
+            log_end_msg 0
+        else
+            # Either we could not start it or it is not running
+            # after we did
+            # NOTE: Some servers might die some time after they start,
+            # this code does not try to detect this and might give
+            # a false positive (use 'status' for that)
+            log_end_msg 1
+        fi
+       ;;
+  stop)
+        log_daemon_msg "Stopping $DESC" "$NAME"
+        if running ; then
+            # Only stop the server if we see it running
+            stop_server
+            log_end_msg $?
+        else
+            # If it's not running don't do anything
+            log_progress_msg "apparently not running"
+            log_end_msg 0
+            exit 0
+        fi
+        ;;
+  force-stop)
+        # First try to stop gracefully the program
+        $0 stop
+        if running; then
+            # If it's still running try to kill it more forcefully
+            log_daemon_msg "Stopping (force) $DESC" "$NAME"
+            force_stop
+            log_end_msg $?
+        fi
+       ;;
+  restart|force-reload)
+        log_daemon_msg "Restarting $DESC" "$NAME"
+        stop_server
+        # Wait some sensible amount, some server need this
+        [ -n "$DIETIME" ] && sleep $DIETIME
+        start_server
+        running
+        log_end_msg $?
+       ;;
+  status)
+
+        log_daemon_msg "Checking status of $DESC" "$NAME"
+        if running ;  then
+            log_progress_msg "running"
+            log_end_msg 0
+        else
+            log_progress_msg "apparently not running"
+            log_end_msg 1
+            exit 1
+        fi
+        ;;
+  # Use this if the daemon cannot reload
+  reload)
+        log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon"
+        log_warning_msg "cannot re-read the config file (use restart)."
+        ;;
+  *)
+       N=/etc/init.d/$NAME
+       echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2
+       exit 1
+       ;;
+esac
+
+exit 0
diff --git a/debian/openflow-controller.install b/debian/openflow-controller.install
new file mode 100644 (file)
index 0000000..75ab435
--- /dev/null
@@ -0,0 +1 @@
+controller/controller usr/sbin
diff --git a/debian/openflow-controller.manpages b/debian/openflow-controller.manpages
new file mode 100644 (file)
index 0000000..c30c912
--- /dev/null
@@ -0,0 +1 @@
+controller/controller.8
diff --git a/debian/openflow-controller.postinst b/debian/openflow-controller.postinst
new file mode 100755 (executable)
index 0000000..93e3911
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh
+# postinst script for openflow-controller
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <postinst> `abort-remove'
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    configure)
+        cd /etc/openflow-controller
+        if ! test -e cacert.pem; then
+            ln -s /usr/share/openflow/pki/switchca/cacert.pem cacert.pem
+        fi
+        if ! test -e privkey.pem || ! test -e cert.pem; then
+            oldumask=$(umask)
+            umask 077
+            ofp-pki req+sign tmp controller >/dev/null
+            mv tmp-privkey.pem privkey.pem
+            mv tmp-cert.pem cert.pem
+            mv tmp-req.pem req.pem
+            chmod go+r cert.pem req.pem
+            umask $oldumask
+        fi
+        ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+        ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+        ;;
+esac
+
+#DEBHELPER#
+
+exit 0
+
+
diff --git a/debian/openflow-datapath-module-_KVERS_.postinst.modules.in b/debian/openflow-datapath-module-_KVERS_.postinst.modules.in
new file mode 100755 (executable)
index 0000000..49e52d6
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# postinst script for #PACKAGE#
+#
+# see: dh_installdeb(1)
+
+set -e
+
+depmod -a
+
+#DEBHELPER#
+
+exit 0
+
+
diff --git a/debian/openflow-datapath-source.README.Debian b/debian/openflow-datapath-source.README.Debian
new file mode 100644 (file)
index 0000000..59965df
--- /dev/null
@@ -0,0 +1,31 @@
+OpenFlow for Debian
+-------------------
+
+* How do I build this module the Debian way?
+
+    - Building with module-assistant:
+
+        $ module-assistant auto-install openflow
+      or
+        $ m-a a-i openflow
+
+      If kernel source or headers are in a non-standard directory, add
+      the option -k /path/to/kernel/source with the correct path.
+
+    - Building with make-kpkg
+
+        $ cd /usr/src/
+        $ tar jxvf openflow.tar.bz2
+        $ cd /usr/src/kernel-source-2.6.9
+        $ make-kpkg --added-modules=openflow modules
+
+    - Building without make-kpkg
+
+        $ cd /usr/src/
+        $ tar jxvf openflow.tar.bz2
+        $ cd modules/openflow
+        $ fakeroot debian/rules kdist_image
+
+      If you run this as root, fakeroot is not needed.
+
+ -- OpenFlow Team <openflow-dev@lists.stanford.edu>, Thu, 12 Jun 2008 16:42:38 -0700
diff --git a/debian/openflow-datapath-source.copyright b/debian/openflow-datapath-source.copyright
new file mode 100644 (file)
index 0000000..f7bcdda
--- /dev/null
@@ -0,0 +1,16 @@
+Upstream Authors: 
+
+    The Board of Trustees of The Leland Stanford Junior University
+
+Copyright: 
+
+    Copyright (C) 2008 The Board of Trustees of The Leland Stanford
+    Junior University
+
+License:
+
+    Files in the datapath/ and its sub-directories are covered under the GNU
+    General Public License Version 2.
+
+    On Debian systems, the complete text of the GNU General
+    Public License can be found in `/usr/share/common-licenses/GPL'.
diff --git a/debian/openflow-datapath-source.dirs b/debian/openflow-datapath-source.dirs
new file mode 100644 (file)
index 0000000..4ddf234
--- /dev/null
@@ -0,0 +1 @@
+usr/src/modules/openflow-datapath/debian
diff --git a/debian/openflow-pki.apache2 b/debian/openflow-pki.apache2
new file mode 100644 (file)
index 0000000..a341c50
--- /dev/null
@@ -0,0 +1 @@
+Alias /openflow/pki/ /usr/share/openflow/pki/
diff --git a/debian/openflow-pki.dirs b/debian/openflow-pki.dirs
new file mode 100644 (file)
index 0000000..7307777
--- /dev/null
@@ -0,0 +1 @@
+etc/apache2/sites-available
diff --git a/debian/openflow-pki.install b/debian/openflow-pki.install
new file mode 100644 (file)
index 0000000..58cfb4e
--- /dev/null
@@ -0,0 +1 @@
+utilities/ofp-pki-cgi usr/lib/cgi-bin
diff --git a/debian/openflow-pki.postinst b/debian/openflow-pki.postinst
new file mode 100755 (executable)
index 0000000..8a68717
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+# postinst script for openflow
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <postinst> `abort-remove'
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+case "$1" in
+    configure)
+        # Create certificate authorities.
+        if test ! -d /usr/share/openflow/pki; then
+            ofp-pki init
+        fi
+
+        # Enable site under Apache.
+        a2ensite openflow-pki >/dev/null
+        if command -v invoke-rc.d >/dev/null 2>&1; then
+                invoke-rc.d apache2 force-reload || :
+        else
+                [ -x /etc/init.d/apache2 ] && /etc/init.d/apache2 force-reload || :
+        fi
+        ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+        ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+        ;;
+esac
+
+#DEBHELPER#
+
+exit 0
+
+
diff --git a/debian/openflow-switch.README.Debian b/debian/openflow-switch.README.Debian
new file mode 100644 (file)
index 0000000..73be13a
--- /dev/null
@@ -0,0 +1,15 @@
+README.Debian for openflow-switch
+---------------------------------
+
+* The switch must be configured before it can be used.  To configure
+  it interactively, run the ofp-switch-setup program.  Alternatively,
+  edit /etc/default/openflow-switch by hand, then start the switch
+  manually with "/etc/init.d/openflow-switch start".
+
+* To use the Linux kernel-based switch implementation, you will need
+  to build and install the OpenFlow kernel module.  To do so, install
+  the openflow-datapath-source package, then follow the instructions
+  given in /usr/share/doc/openflow-datapath-source/README.Debian
+
+* This package does not yet support the userspace switch
+  implementation.
diff --git a/debian/openflow-switch.config b/debian/openflow-switch.config
new file mode 100755 (executable)
index 0000000..7546e02
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+set -e
+. /usr/share/debconf/confmodule
+# Nothing more to do -- the user is responsible for running ofp-switch-setup.
diff --git a/debian/openflow-switch.default b/debian/openflow-switch.default
new file mode 100644 (file)
index 0000000..f2ce5a6
--- /dev/null
@@ -0,0 +1,77 @@
+# This is a POSIX shell fragment                -*- sh -*-
+
+# To configure the secure channel, fill in the following properly and
+# uncomment them.  Afterward, the secure channel will come up
+# automatically at boot time.  It can be started immediately with
+#       /etc/init.d/openflow-switch start
+# Alternatively, use the ofp-switch-setup program to do everything
+# automatically.
+
+# NETDEVS: Which network devices should the OpenFlow switch include?
+#
+# List the network devices that should become part of the OpenFlow
+# switch, separated by spaces.  At least two devices must be selected
+# for this machine to be a useful switch.  Unselecting all network
+# devices will disable the OpenFlow switch entirely.
+# 
+# The network devices that you select should not be configured with IP
+# or IPv6 addresses, even if the switch contacts the controller over
+# one of the selected network devices.  This is because a running
+# OpenFlow switch takes over network devices at a low level: they
+# become part of the switch and cannot be used for other purposes.
+#NETDEVS=""
+
+# IN_BAND: The OpenFlow switch must be able to contact the OpenFlow
+# controller over the network.  It can do so in one of two ways:
+# 
+# * in-band: A single network is used for OpenFlow traffic and other
+#   data traffic; that is, the switch contacts the controller over one
+#   of the network devices selected as OpenFlow switch ports in the
+#   previous question.  This is the most common case.
+# 
+# * out-of-band: OpenFlow traffic uses a network separate from the
+#   data traffic that it controls.  If this is the case, the control
+#   network must already be configured on a network device other than
+#   one of those selected as an OpenFlow switch port in the previous
+#   question.
+#
+# Set IN_BAND to yes for in-band control, or to no for out-of-band
+# control.
+IN_BAND=yes
+
+# SWITCH_IP: For in-band communication with the controller, the
+# OpenFlow switch must be able to determine its own IP address.  Its
+# IP address may be configured statically or dynamically:
+# 
+# * For static configuration, specify the switch's IP address as a
+#   string.
+# 
+# * For dynamic configuration with DHCP (the most common case),
+#   specify "dhcp".  Configuration with DHCP will only work reliably
+#   if the network topology allows the switch to contact the DHCP
+#   server before it connects to the OpenFlow controller.
+#
+# If IN_BAND is set to "no" above, this setting has no effect.
+SWITCH_IP=dhcp
+
+# CONTROLLER: Location of controller.
+# One of the following formats:
+#  tcp:HOST[:PORT]         via TCP to PORT (default: 975) on HOST
+#  ssl:HOST[:PORT]         via SSL to PORT (default: 976) on HOST
+# The default below assumes that the controller is running locally.
+#CONTROLLER="tcp:127.0.0.1"
+
+# PRIVKEY: Name of file containing switch's private key.
+# Required if SSL enabled.
+#PRIVKEY=/etc/openflow-switch/of0-privkey.pem
+
+# CERT: Name of file containing certificate for private key.
+# Required if SSL enabled.
+#CERT=/etc/openflow-switch/of0-cert.pem
+
+# CACERT: Name of file containing controller CA certificate.
+# Required if SSL enabled.
+#CACERT=/etc/openflow-switch/cacert.pem
+
+# Additional options to pass to secchan, e.g. "--fail=open"
+DAEMON_OPTS=""
diff --git a/debian/openflow-switch.dirs b/debian/openflow-switch.dirs
new file mode 100644 (file)
index 0000000..836e4e5
--- /dev/null
@@ -0,0 +1,2 @@
+/etc/openflow-switch
+/usr/share/lintian/overrides
diff --git a/debian/openflow-switch.init b/debian/openflow-switch.init
new file mode 100755 (executable)
index 0000000..1f03df1
--- /dev/null
@@ -0,0 +1,263 @@
+#! /bin/sh
+#
+# /etc/init.d/openflow-switch
+#
+# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
+# Modified for Debian by Ian Murdock <imurdock@gnu.ai.mit.edu>.
+# Further changes by Javier Fernandez-Sanguino <jfs@debian.org>
+# Modified for openflow-switch.
+#
+# Version:     @(#)skeleton  1.9  26-Feb-2001  miquels@cistron.nl
+#
+### BEGIN INIT INFO
+# Provides:          openflow-switch
+# Required-Start:    $network $named $remote_fs $syslog
+# Required-Stop:
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: OpenFlow switch
+### END INIT INFO
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/secchan
+NAME=secchan
+DESC=secchan
+
+test -x $DAEMON || exit 0
+
+LOGDIR=/var/log/openflow
+PIDFILE=/var/run/$NAME.pid
+DHCLIENT_PIDFILE=/var/run/dhclient.of0.pid
+DODTIME=1                   # Time to wait for the server to die, in seconds
+                            # If this value is set too low you might not
+                            # let some servers to die gracefully and
+                            # 'restart' will not work
+
+# Include secchan defaults if available
+default=/etc/default/openflow-switch
+if [ -f $default ] ; then
+       . $default
+fi
+
+set -e
+
+running_pid()
+{
+    # Check if a given process pid's cmdline matches a given name
+    pid=$1
+    name=$2
+    [ -z "$pid" ] && return 1 
+    [ ! -d /proc/$pid ] &&  return 1
+    cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1`
+    # Is this the expected child?
+    [ "$cmd" != "$name" ] &&  return 1
+    return 0
+}
+
+running()
+{
+# Check if the process is running looking at /proc
+# (works for all users)
+
+    # No pidfile, probably no daemon present
+    [ ! -f "$PIDFILE" ] && return 1
+    # Obtain the pid and check it against the binary name
+    pid=`cat $PIDFILE`
+    running_pid $pid $NAME || return 1
+    return 0
+}
+
+force_stop() {
+# Forcefully kill the process
+    [ ! -f "$PIDFILE" ] && return
+    if running ; then
+        kill -15 $pid
+        # Is it really dead?
+        [ -n "$DODTIME" ] && sleep "$DODTIME"s
+        if running ; then
+            kill -9 $pid
+            [ -n "$DODTIME" ] && sleep "$DODTIME"s
+            if running ; then
+                echo "Cannot kill $LABEL (pid=$pid)!"
+                exit 1
+            fi
+        fi
+    fi
+    rm -f $PIDFILE
+    return 0
+}
+
+must_succeed() {
+    echo -n "$1: "
+    shift
+    if "$@"; then
+        echo "success."
+    else
+        echo " ERROR."
+        exit 1
+    fi
+}
+
+check_op() {
+    echo -n "$1: "
+    shift
+    if "$@"; then
+        echo "success."
+    else
+        echo " ERROR."
+    fi
+}
+
+case "$1" in
+    start)
+        if test -z "$NETDEVS"; then
+            echo "$default: No network devices configured, switch disabled" >&2
+            echo "Run ofp-switch-setup or edit /etc/default/openflow-switch to configure" >&2
+            exit 0
+        fi
+        if test -z "$CONTROLLER"; then
+            echo "$default: No controller configured, switch disabled" >&2
+            echo "Run ofp-switch-setup or edit /etc/default/openflow-switch to configure" >&2
+            exit 0
+        fi
+        if test "$IN_BAND" != yes && test "$IN_BAND" != no; then
+            echo "$default: IN_BAND must set to 'yes' or 'no'" >&2
+            echo "Run ofp-switch-setup or edit /etc/default/openflow-switch to configure" >&2
+            exit 1
+        fi
+        case $CONTROLLER in
+            tcp:*)
+                ;;
+            ssl:*)
+                : ${PRIVKEY:=/etc/openflow-switch/of0-privkey.pem}
+                : ${CERT:=/etc/openflow-switch/of0-cert.pem}
+                : ${CACERT:=/etc/openflow-switch/cacert.pem}
+                if test ! -e "$PRIVKEY" || test ! -e "$CERT" ||
+                    test ! -e "$CACERT"; then
+                    if test ! -e "$PRIVKEY"; then
+                        echo "$PRIVKEY: private key missing" >&2
+                    fi
+                    if test ! -e "$CERT"; then
+                        echo "$CERT: certificate for private key missing" >&2
+                    fi
+                    if test ! -e "$CACERT"; then
+                        echo "$CACERT: CA certificate missing" >&2
+                    fi
+                    echo "Run ofp-switch-setup or edit /etc/default/openflow-switch to configure" >&2
+                    exit 1
+                fi
+                ;;
+            *)
+                echo "$default: CONTROLLER must be in the form 'ssl:HOST[:PORT]' or 'tcp:HOST[:PORT]'" >&2
+                echo "Run ofp-switch-setup or edit /etc/default/openflow-switch to configure" >&2
+                exit 1
+        esac
+
+        echo -n "Loading openflow_mod: "
+        if modprobe openflow_mod; then
+            echo "success."
+        else
+            echo " ERROR."
+            echo "openflow_mod has probably not been built for this kernel."
+            if ! test -d /usr/share/doc/openflow-datapath-source; then
+                echo "Install the openflow-datapath-source package, then read"
+                echo "/usr/share/doc/openflow-datapath-source/README.Debian"
+            else
+                echo "For instructions, read"
+                echo "/usr/share/doc/openflow-datapath-source/README.Debian"
+            fi
+            exit 1
+        fi
+
+        must_succeed "Adding datapath" dpctl adddp nl:0
+        for netdev in $NETDEVS; do
+            must_succeed "Adding $netdev to datapath" dpctl addif nl:0 $netdev
+        done
+
+        if test "$IN_BAND" = yes; then
+            if test "$SWITCH_IP" = dhcp; then
+                must_succeed "Temporarily disabling of0" ifconfig of0 down
+            else
+                must_succeed "Configuring of0 as $SWITCH_IP" ifconfig of0 $SWITCH_IP
+            fi
+        else
+            must_succeed "Disabling of0" ifconfig of0 down
+        fi
+
+       echo -n "Starting $DESC: "
+       start-stop-daemon --start --quiet --pidfile $PIDFILE \
+           --exec $DAEMON -- nl:0 $CONTROLLER --detach --pidfile=$PIDFILE \
+            $DAEMON_OPTS $SSL_OPTS
+        if running; then
+            echo "$NAME."
+        else
+            echo " ERROR."
+        fi
+
+        if test "$IN_BAND" = yes && test "$SWITCH_IP" = dhcp; then
+            echo -n "Starting dhclient on of0: "
+           start-stop-daemon --start --quiet --pidfile $DHCLIENT_PIDFILE \
+               --exec /sbin/dhclient -- -q -pf $DHCLIENT_PIDFILE of0
+            if running; then
+                echo "dhclient."
+            else
+                echo " ERROR."
+            fi
+        fi
+       ;;
+    stop)
+        if test -e /var/run/dhclient.of0.pid; then
+           echo -n "Stopping dhclient on of0: "
+           start-stop-daemon --stop --quiet --oknodo \
+                --pidfile $DHCLIENT_PIDFILE --exec /sbin/dhclient
+           echo "dhclient."
+        fi            
+
+       echo -n "Stopping $DESC: "
+       start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE \
+           --exec $DAEMON
+       echo "$NAME."
+
+        for netdev in $NETDEVS; do
+            check_op "Removing $netdev from datapath" dpctl delif nl:0 $netdev
+        done
+        check_op "Deleting datapath" dpctl deldp nl:0
+       ;;
+    force-stop)
+       echo -n "Forcefully stopping $DESC: "
+        force_stop
+        if ! running; then
+            echo "$NAME."
+        else
+            echo " ERROR."
+        fi
+       ;;
+    reload)
+        ;;
+    force-reload)
+       start-stop-daemon --stop --test --quiet --pidfile \
+           $PIDFILE --exec $DAEMON \
+           && $0 restart \
+           || exit 0
+       ;;
+    restart)
+        $0 stop || true
+        $0 start
+       ;;
+    status)
+        echo -n "$LABEL is "
+        if running ;  then
+            echo "running"
+        else
+            echo " not running."
+            exit 1
+        fi
+        ;;
+    *)
+       N=/etc/init.d/$NAME
+       echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2
+       exit 1
+       ;;
+esac
+
+exit 0
diff --git a/debian/openflow-switch.install b/debian/openflow-switch.install
new file mode 100644 (file)
index 0000000..96db727
--- /dev/null
@@ -0,0 +1,4 @@
+switch/switch usr/sbin
+secchan/secchan usr/sbin
+utilities/dpctl usr/sbin
+debian/ofp-switch-setup usr/sbin
diff --git a/debian/openflow-switch.links b/debian/openflow-switch.links
new file mode 100644 (file)
index 0000000..629db1d
--- /dev/null
@@ -0,0 +1 @@
+/usr/share/modass/packages/default.sh /usr/share/modass/packages/openflow-datapath-source
diff --git a/debian/openflow-switch.manpages b/debian/openflow-switch.manpages
new file mode 100644 (file)
index 0000000..905d060
--- /dev/null
@@ -0,0 +1,4 @@
+debian/ofp-switch-setup.8
+secchan/secchan.8
+switch/switch.8
+utilities/dpctl.8
diff --git a/debian/openflow-switch.overrides b/debian/openflow-switch.overrides
new file mode 100644 (file)
index 0000000..4ac77ab
--- /dev/null
@@ -0,0 +1 @@
+debconf-is-not-a-registry
diff --git a/debian/openflow-switch.postinst b/debian/openflow-switch.postinst
new file mode 100755 (executable)
index 0000000..c8dc9a4
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# postinst script for openflow-switch
+#
+# see: dh_installdeb(1)
+
+set -e
+
+. /usr/share/debconf/confmodule
+
+#DEBHELPER#
+
+exit 0
+
+
diff --git a/debian/openflow-switch.templates b/debian/openflow-switch.templates
new file mode 100644 (file)
index 0000000..c6d4b5e
--- /dev/null
@@ -0,0 +1,189 @@
+Template: openflow-switch/netdevs
+Type: multiselect
+_Choices: ${choices}
+_Description: OpenFlow switch network devices:
+ Choose the network devices that should become part of the OpenFlow
+ switch.  At least two devices must be selected for this machine to be
+ a useful switch.  Unselecting all network devices will disable the
+ OpenFlow switch entirely.
+ .
+ The network devices that you select should not be configured with IP
+ or IPv6 addresses, even if the switch contacts the controller over
+ one of the selected network devices.  This is because a running
+ OpenFlow switch takes over network devices at a low level: they
+ become part of the switch and cannot be used for other purposes.
+
+Template: openflow-switch/no-netdevs
+Type: error
+_Description: No network devices were selected.
+ No network devices were selected for inclusion in the OpenFlow switch.
+ The switch will be disabled.
+
+Template: openflow-switch/configured-netdevs
+Type: note
+_Description: Some Network Devices Have IP or IPv6 Addresses
+ The following network devices selected to be part of the OpenFlow switch
+ have IP or IPv6 addresses configured:
+ .
+ ${configured-netdevs}
+ .
+ This is usually a mistake, even if the switch contacts the controller over
+ one of the selected network devices.  This is because a running
+ OpenFlow switch takes over network devices at a low level: they
+ become part of the switch and cannot be used for other purposes.
+ .
+ If this is an unintentional mistake, move back and fix the selection,
+ or de-configure the IP or IPv6 from these network devices.
+
+Template: openflow-switch/band
+Type: select
+_Choices: in-band, out-of-band
+Default: in-band
+_Description: Switch-to-controller access method:
+ The OpenFlow switch must be able to contact the OpenFlow controller over
+ the network.  It can do so in one of two ways:
+ .
+ in-band: A single network is used for OpenFlow traffic and other data
+ traffic; that is, the switch contacts the controller over one of the
+ network devices selected as OpenFlow switch netdevs in the previous
+ question.  This is the most common case.
+ .
+ out-of-band: OpenFlow traffic uses a network separate from the data traffic
+ that it controls.  If this is the case, the control network must already
+ be configured on a network device other than one of those selected as
+ an OpenFlow switch netdev in the previous question.
+
+Template: openflow-switch/switch-ip
+Type: string
+Default: dhcp
+_Description: Switch IP address:
+ For in-band communication with the controller, the OpenFlow switch must
+ be able to determine its own IP address.  Its IP address may be configured
+ statically or dynamically.
+ .
+ For static configuration, specify the switch's IP address as a string.
+ .
+ For dynamic configuration with DHCP (the most common case), specify "dhcp".
+ Configuration with DHCP will only work reliably if the network topology
+ allows the switch to contact the DHCP server before it connects to the
+ OpenFlow controller.
+
+Template: openflow-switch/switch-ip-error
+Type: error
+_Description: The switch IP address is invalid.
+ The switch IP address must specified as "dhcp" or a valid IP address in
+ dotted-octet form (e.g. "1.2.3.4").
+
+Template: openflow-switch/controller-vconn
+Type: string
+_Description: Controller location:
+ Specify how the OpenFlow switch should connect to the OpenFlow controller.
+ The value should be in form "ssl:HOST[:PORT]" to connect to the controller
+ over SSL (recommended for security) or "tcp:HOST[:PORT]" to connect over
+ cleartext TCP.
+
+Template: openflow-switch/controller-vconn-error
+Type: error
+_Description: The controller location is invalid.
+ The controller location must be specifed as "ssl:HOST[:PORT]" to
+ connect to the controller over SSL (recommended for security) or
+ "tcp:HOST[:PORT]" to connect over cleartext TCP.
+
+Template: openflow-switch/pki-host
+Type: string
+_Description: OpenFlow PKI server host name:
+ Specify the host name or IP address of the server that hosts the OpenFlow
+ public key infrastructure (PKI).  This is usually the same host as the
+ OpenFlow controller.
+ .
+ The setup process will connect to the OpenFlow PKI server over
+ HTTP, using the system's configured default HTTP proxy (if any).
+
+Template: openflow-switch/fetch-cacert-failed
+Type: error
+_Description: The switch CA certificate could not be retrieved.
+ Retrieval of ${url} failed, with the following status: "${error}".
+ .
+ Ensure that the OpenFlow PKI server is correctly configured and
+ available on ${pki-host}.  If the system is configured to use an HTTP
+ proxy, also make sure that the HTTP proxy is available and that the
+ PKI server can be reached through it.
+
+Template: openflow-switch/verify-controller-ca
+Type: select
+_Choices: yes, no
+Default: yes
+_Description: Is ${fingerprint} the controller CA's fingerprint?
+ If a man-in-the-middle attack is possible in your network
+ environment, check that the controller CA's fingerprint is really
+ ${fingerprint}.  Answer "yes" if it matches, "no" if
+ there is a discrepancy.
+ .
+ If a man-in-the-middle attack is not a concern, there is no need to
+ verify the fingerprint.  Simply answer "yes".
+
+Template: openflow-switch/send-cert-req
+Type: select
+_Choices: yes, no
+Default: yes
+_Description: Send certificate request to switch CA?
+ Before it can connect to the controller over SSL, the OpenFlow
+ switch's key must be signed by the switch certificate authority (CA)
+ located on the OpenFlow PKI server, which is usually collocated with
+ the OpenFlow controller.  A signing request can be sent to the PKI
+ server now.
+ .
+ Answer "yes" to send a signing request to the switch CA now.  This is
+ ordinarily the correct choice.  There is no harm in sending a given
+ signing request more than once.
+ .
+ Answer "no" to skip sending a signing request to the switch CA.
+ Unless the request has already been sent to the switch CA, manual
+ sending of the request and signing will be necessary.
+
+Template: openflow-switch/send-cert-req-failed
+Type: error
+_Description: The certificate request could not be sent.
+ Posting to ${url} failed, with the following status: "${error}".
+ .
+ Ensure that the OpenFlow PKI server is correctly configured and
+ available on ${pki-host}.
+
+Template: openflow-switch/fetch-switch-cert
+Type: select
+_Choices: yes, no
+_Description: Fetch signed switch certificate from PKI server?
+ Before it can connect to the controller over SSL, the OpenFlow
+ switch's key must be signed by the switch certificate authority (CA)
+ located on the OpenFlow PKI server, which is usually collocated with
+ the OpenFlow controller.
+ .
+ At this point, a signing request has been sent to the switch CA (or
+ sending a request has been manually skipped), but the signed
+ certificate has not yet been retrieved.  Manual action may need to be
+ taken at the PKI server to approve the signing request.
+ .
+ Answer "yes" to attempt to retrieve the signed switch certificate
+ from the switch CA.  If the switch certificate request has been
+ signed at the PKI server, this is the correct choice.
+ .
+ Answer "no" to postpone switch configuration.  The configuration
+ process must be restarted later, when the switch certificate request
+ has been signed.
+
+Template: openflow-switch/fetch-switch-cert-failed
+Type: error
+_Description: Signed switch certificate could not be retrieved.
+ The signed switch certificate could not be retrieved from the switch
+ CA: retrieval of ${url} failed, with the following status: "${error}".
+ .
+ This probably indicates that the switch's certificate request has not
+ yet been signed.  If this is the problem, it may be fixed by signing
+ the certificate request at ${pki-host}, then trying to fetch the
+ signed switch certificate again.
+
+Template: openflow-switch/complete
+Type: note
+_Description: OpenFlow Switch Setup Finished
+ Setup of this OpenFlow switch is finished.  Complete the setup procedure
+ to enable the switch.
diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in
new file mode 100644 (file)
index 0000000..be39266
--- /dev/null
@@ -0,0 +1 @@
+[type: gettext/rfc822deb] openflow-switch.templates
diff --git a/debian/po/templates.pot b/debian/po/templates.pot
new file mode 100644 (file)
index 0000000..927eb09
--- /dev/null
@@ -0,0 +1,432 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: openflow-dev@lists.stanford.edu\n"
+"POT-Creation-Date: 2008-06-12 14:45-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: multiselect
+#. Choices
+#: ../openflow-switch.templates:1001
+msgid "${choices}"
+msgstr ""
+
+#. Type: multiselect
+#. Description
+#: ../openflow-switch.templates:1002
+msgid "OpenFlow switch network devices:"
+msgstr ""
+
+#. Type: multiselect
+#. Description
+#: ../openflow-switch.templates:1002
+msgid ""
+"Choose the network devices that should become part of the OpenFlow switch.  "
+"At least two devices must be selected for this machine to be a useful "
+"switch.  Unselecting all network devices will disable the OpenFlow switch "
+"entirely."
+msgstr ""
+
+#. Type: multiselect
+#. Description
+#: ../openflow-switch.templates:1002
+msgid ""
+"The network devices that you select should not be configured with IP or IPv6 "
+"addresses, even if the switch contacts the controller over one of the "
+"selected network devices.  This is because a running OpenFlow switch takes "
+"over network devices at a low level: they become part of the switch and "
+"cannot be used for other purposes."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:2001
+msgid "No network devices were selected."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:2001
+msgid ""
+"No network devices were selected for inclusion in the OpenFlow switch. The "
+"switch will be disabled."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../openflow-switch.templates:3001
+msgid "Some Network Devices Have IP or IPv6 Addresses"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../openflow-switch.templates:3001
+msgid ""
+"The following network devices selected to be part of the OpenFlow switch "
+"have IP or IPv6 addresses configured:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../openflow-switch.templates:3001
+msgid "${configured-netdevs}"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../openflow-switch.templates:3001
+msgid ""
+"This is usually a mistake, even if the switch contacts the controller over "
+"one of the selected network devices.  This is because a running OpenFlow "
+"switch takes over network devices at a low level: they become part of the "
+"switch and cannot be used for other purposes."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../openflow-switch.templates:3001
+msgid ""
+"If this is an unintentional mistake, move back and fix the selection, or de-"
+"configure the IP or IPv6 from these network devices."
+msgstr ""
+
+#. Type: select
+#. Choices
+#: ../openflow-switch.templates:4001
+msgid "in-band, out-of-band"
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:4002
+msgid "Switch-to-controller access method:"
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:4002
+msgid ""
+"The OpenFlow switch must be able to contact the OpenFlow controller over the "
+"network.  It can do so in one of two ways:"
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:4002
+msgid ""
+"in-band: A single network is used for OpenFlow traffic and other data "
+"traffic; that is, the switch contacts the controller over one of the network "
+"devices selected as OpenFlow switch netdevs in the previous question.  This "
+"is the most common case."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:4002
+msgid ""
+"out-of-band: OpenFlow traffic uses a network separate from the data traffic "
+"that it controls.  If this is the case, the control network must already be "
+"configured on a network device other than one of those selected as an "
+"OpenFlow switch netdev in the previous question."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../openflow-switch.templates:5001
+msgid "Switch IP address:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../openflow-switch.templates:5001
+msgid ""
+"For in-band communication with the controller, the OpenFlow switch must be "
+"able to determine its own IP address.  Its IP address may be configured "
+"statically or dynamically."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../openflow-switch.templates:5001
+msgid "For static configuration, specify the switch's IP address as a string."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../openflow-switch.templates:5001
+msgid ""
+"For dynamic configuration with DHCP (the most common case), specify \"dhcp"
+"\". Configuration with DHCP will only work reliably if the network topology "
+"allows the switch to contact the DHCP server before it connects to the "
+"OpenFlow controller."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:6001
+msgid "The switch IP address is invalid."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:6001
+msgid ""
+"The switch IP address must specified as \"dhcp\" or a valid IP address in "
+"dotted-octet form (e.g. \"1.2.3.4\")."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../openflow-switch.templates:7001
+msgid "Controller location:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../openflow-switch.templates:7001
+msgid ""
+"Specify how the OpenFlow switch should connect to the OpenFlow controller. "
+"The value should be in form \"ssl:HOST[:PORT]\" to connect to the controller "
+"over SSL (recommended for security) or \"tcp:HOST[:PORT]\" to connect over "
+"cleartext TCP."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:8001
+msgid "The controller location is invalid."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:8001
+msgid ""
+"The controller location must be specifed as \"ssl:HOST[:PORT]\" to connect "
+"to the controller over SSL (recommended for security) or \"tcp:HOST[:PORT]\" "
+"to connect over cleartext TCP."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../openflow-switch.templates:9001
+msgid "OpenFlow PKI server host name:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../openflow-switch.templates:9001
+msgid ""
+"Specify the host name or IP address of the server that hosts the OpenFlow "
+"public key infrastructure (PKI).  This is usually the same host as the "
+"OpenFlow controller."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../openflow-switch.templates:9001
+msgid ""
+"The setup process will connect to the OpenFlow PKI server over HTTP, using "
+"the system's configured default HTTP proxy (if any)."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:10001
+msgid "The switch CA certificate could not be retrieved."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:10001
+msgid "Retrieval of ${url} failed, with the following status: \"${error}\"."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:10001
+msgid ""
+"Ensure that the OpenFlow PKI server is correctly configured and available on "
+"${pki-host}.  If the system is configured to use an HTTP proxy, also make "
+"sure that the HTTP proxy is available and that the PKI server can be reached "
+"through it."
+msgstr ""
+
+#. Type: select
+#. Choices
+#. Type: select
+#. Choices
+#. Type: select
+#. Choices
+#: ../openflow-switch.templates:11001 ../openflow-switch.templates:12001
+#: ../openflow-switch.templates:14001
+msgid "yes, no"
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:11002
+msgid "Is ${fingerprint} the controller CA's fingerprint?"
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:11002
+msgid ""
+"If a man-in-the-middle attack is possible in your network environment, check "
+"that the controller CA's fingerprint is really ${fingerprint}.  Answer \"yes"
+"\" if it matches, \"no\" if there is a discrepancy."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:11002
+msgid ""
+"If a man-in-the-middle attack is not a concern, there is no need to verify "
+"the fingerprint.  Simply answer \"yes\"."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:12002
+msgid "Send certificate request to switch CA?"
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:12002
+msgid ""
+"Before it can connect to the controller over SSL, the OpenFlow switch's key "
+"must be signed by the switch certificate authority (CA) located on the "
+"OpenFlow PKI server, which is usually collocated with the OpenFlow "
+"controller.  A signing request can be sent to the PKI server now."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:12002
+msgid ""
+"Answer \"yes\" to send a signing request to the switch CA now.  This is "
+"ordinarily the correct choice.  There is no harm in sending a given signing "
+"request more than once."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:12002
+msgid ""
+"Answer \"no\" to skip sending a signing request to the switch CA. Unless the "
+"request has already been sent to the switch CA, manual sending of the "
+"request and signing will be necessary."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:13001
+msgid "The certificate request could not be sent."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:13001
+msgid "Posting to ${url} failed, with the following status: \"${error}\"."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:13001
+msgid ""
+"Ensure that the OpenFlow PKI server is correctly configured and available on "
+"${pki-host}."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:14002
+msgid "Fetch signed switch certificate from PKI server?"
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:14002
+msgid ""
+"Before it can connect to the controller over SSL, the OpenFlow switch's key "
+"must be signed by the switch certificate authority (CA) located on the "
+"OpenFlow PKI server, which is usually collocated with the OpenFlow "
+"controller."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:14002
+msgid ""
+"At this point, a signing request has been sent to the switch CA (or sending "
+"a request has been manually skipped), but the signed certificate has not yet "
+"been retrieved.  Manual action may need to be taken at the PKI server to "
+"approve the signing request."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:14002
+msgid ""
+"Answer \"yes\" to attempt to retrieve the signed switch certificate from the "
+"switch CA.  If the switch certificate request has been signed at the PKI "
+"server, this is the correct choice."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../openflow-switch.templates:14002
+msgid ""
+"Answer \"no\" to postpone switch configuration.  The configuration process "
+"must be restarted later, when the switch certificate request has been signed."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:15001
+msgid "Signed switch certificate could not be retrieved."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:15001
+msgid ""
+"The signed switch certificate could not be retrieved from the switch CA: "
+"retrieval of ${url} failed, with the following status: \"${error}\"."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../openflow-switch.templates:15001
+msgid ""
+"This probably indicates that the switch's certificate request has not yet "
+"been signed.  If this is the problem, it may be fixed by signing the "
+"certificate request at ${pki-host}, then trying to fetch the signed switch "
+"certificate again."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../openflow-switch.templates:16001
+msgid "OpenFlow Switch Setup Finished"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../openflow-switch.templates:16001
+msgid ""
+"Setup of this OpenFlow switch is finished.  Complete the setup procedure to "
+"enable the switch."
+msgstr ""
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..ab44b77
--- /dev/null
@@ -0,0 +1,145 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+#
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+#
+# Modified to make a template file for a multi-binary package with separated
+# build-arch and build-indep targets  by Bill Allombert 2001
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This has to be exported to make some magic below work.
+export DH_OPTIONS
+
+# prefix of the target package name
+PACKAGE=openflow-datapath-module
+# modifieable for experiments or debugging m-a
+MA_DIR ?= /usr/share/modass
+# load generic variable handling
+-include $(MA_DIR)/include/generic.make
+# load default rules
+-include $(MA_DIR)/include/common-rules.make
+
+configure: configure-stamp
+configure-stamp:
+       dh_testdir
+       test -e configure || ./boot.sh
+       test -e Makefile || \
+               ./configure --prefix=/usr --localstatedir=/var --enable-ssl
+       touch configure-stamp
+
+#Architecture 
+build: build-arch build-indep
+
+build-arch: build-arch-stamp
+build-arch-stamp: configure-stamp 
+       $(MAKE)
+       touch $@
+
+build-indep: build-indep-stamp
+build-indep-stamp: configure-stamp 
+       $(MAKE) dist distdir=openflow
+       touch $@
+
+clean:
+       dh_testdir
+       dh_testroot
+       rm -f build-arch-stamp build-indep-stamp configure-stamp
+       [ ! -f Makefile ] || $(MAKE) distclean
+       dh_clean 
+       debconf-updatepo
+
+MAJOR=$(shell echo $(KVERS) | sed -e 's/\(...\).*/\1/')
+ifeq ($(MAJOR),2.6)
+KO=k
+l2x=l26
+dpdir=datapath/linux-2.6
+else
+KO=
+l2x=l24
+dpdir=datapath/linux-2.4
+endif
+
+kdist_clean:
+       dh_clean
+       make KERNELDIR=$(KSRC) KVERREL=$(KVERS) clean
+
+kdist_config: prep-deb-files
+
+binary-modules: DSTDIR = $(CURDIR)/debian/$(PKGNAME)/lib/modules/$(KVERS)
+binary-modules: prep-deb-files
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       tar xzf openflow.tar.gz
+       cd openflow && ./configure --with-$(l2x)=$(KSRC)
+       cd openflow && $(MAKE) -C $(dpdir)
+       install -d -m755 $(DSTDIR)
+       install -m644 openflow/$(dpdir)/*_mod.$(KO)o $(DSTDIR)/
+       dh_installdocs
+       dh_installchangelogs
+       dh_compress
+       dh_fixperms
+       dh_installdeb
+       dh_gencontrol -- -v$(VERSION)
+       dh_md5sums
+       dh_builddeb --destdir=$(DEB_DESTDIR)
+
+install: install-indep install-arch
+install-indep: MODDIR = $(CURDIR)/debian/openflow-datapath-source/usr/src/modules/openflow-datapath
+install-indep: build-indep
+       dh_testdir
+       dh_testroot
+       dh_clean -k -i 
+       dh_installdirs -i
+       cp openflow.tar.gz $(MODDIR)
+       cd debian; cp changelog control compat *.modules.in rules $(MODDIR)/debian
+       cd debian/openflow-datapath-source/usr/src && tar -c modules | bzip2 -9 > openflow-datapath.tar.bz2 && rm -rf modules
+       install -m644 debian/openflow-pki.apache2 debian/openflow-pki/etc/apache2/sites-available/openflow-pki
+       dh_install -i
+
+install-arch: build-arch
+       dh_testdir
+       dh_testroot
+       dh_clean -k -s 
+       dh_installdirs -s
+       $(MAKE) DESTDIR=$(CURDIR)/debian/openflow install
+       cp debian/openflow-switch.overrides debian/openflow-switch/usr/share/lintian/overrides/openflow-switch
+       dh_install -s
+
+# Must not depend on anything. This is to be called by
+# binary-arch/binary-indep
+# in another 'make' thread.
+binary-common:
+       dh_testdir
+       dh_testroot
+       dh_installchangelogs 
+       dh_installdocs
+       dh_installexamples
+       dh_installdebconf
+#      dh_installlogrotate
+       dh_installinit
+       dh_installman
+       dh_link
+       dh_strip
+       dh_compress 
+       dh_fixperms
+       dh_perl
+       dh_makeshlibs
+       dh_installdeb
+       dh_shlibdeps
+       dh_gencontrol
+       dh_md5sums
+       dh_builddeb
+binary-indep: install-indep
+       $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common
+binary-arch: install-arch
+       $(MAKE) -f debian/rules DH_OPTIONS=-s binary-common
+
+binary: binary-arch binary-indep
+.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch configure
index b2c322f2c5acdfec338c1efdf688675ad627cbb9..fbc6f086e169500bad34be344992c4c5e732916a 100644 (file)
@@ -1,4 +1,7 @@
 /Makefile
 /Makefile.in
 /dpctl
+/ofp-pki
+/ofp-pki-cgi
+/ofp-pki.8
 /vlogconf
index 9b3e4df2870e01bddc2411c4a5338ce7ec68ed59..566e2addb6c9c9ec489bb288c77f17a2c11977da 100644 (file)
@@ -1,10 +1,28 @@
 include ../Make.vars
 
 bin_PROGRAMS = vlogconf dpctl
-dist_man_MANS = vlogconf.8 dpctl.8 ofp-pki.8
+bin_SCRIPTS = ofp-pki
+noinst_SCRIPTS = ofp-pki-cgi
+
+EXTRA_DIST = ofp-pki.in ofp-pki-cgi.in ofp-pki.8.in
+DISTCLEANFILES = ofp-pki ofp-pki-cgi ofp-pki.8
+
+dist_man_MANS = vlogconf.8 dpctl.8
+man_MANS = ofp-pki.8
 
 dpctl_SOURCES = dpctl.c
 dpctl_LDADD = ../lib/libopenflow.la
 
 vlogconf_SOURCES = vlogconf.c
 vlogconf_LDADD = ../lib/libopenflow.la
+
+pkidir = $(pkgdatadir)/pki
+
+ofp-pki: ofp-pki.in Makefile
+       $(do_subst) < $(srcdir)/ofp-pki.in | $(ro_script) > ofp-pki
+       chmod +x ofp-pki
+ofp-pki-cgi: ofp-pki-cgi.in Makefile
+       $(do_subst) < $(srcdir)/ofp-pki-cgi.in | $(ro_script) > ofp-pki-cgi
+       chmod +x ofp-pki-cgi
+ofp-pki.8: ofp-pki.8.in Makefile
+       ($(do_subst) && $(ro_man)) < $(srcdir)/ofp-pki.8.in > ofp-pki.8
diff --git a/utilities/ofp-pki b/utilities/ofp-pki
deleted file mode 100755 (executable)
index f9a0735..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-#! /bin/sh -e
-
-DIR=pki
-command=
-arg1=
-arg2=
-prev=
-force=no
-batch=no
-log=ofp-pki.log
-for option; do
-    # This option-parsing mechanism borrowed from a Autoconf-generated
-    # configure script under the following license:
-
-    # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-    # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
-    # This configure script is free software; the Free Software Foundation
-    # gives unlimited permission to copy, distribute and modify it.
-
-    # If the previous option needs an argument, assign it.
-    if test -n "$prev"; then
-        eval $prev=\$option
-        prev=
-        continue
-    fi
-    case $option in
-        *=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;;
-        *) optarg=yes ;;
-    esac
-
-    case $dashdash$option in
-        --)
-            dashdash=yes ;;
-        -h|--help)
-            cat <<EOF
-ofp-pki, for managing a simple OpenFlow public key infrastructure 
-usage: $0 [OPTION...] COMMAND [ARG...]
-where the valid commands and their arguments are:
-  new-pki              Create a new PKI
-  req NAME             Create new private key and certificate request
-                       named NAME-privkey.pem and NAME-req.pem, resp.
-                       TYPE is a certificate type: 'switch' or 'controller'
-  sign NAME TYPE       Sign switch certificate request NAME-req.pem,
-                       producing certificate NAME-cert.pem
-                       TYPE is a certificate type: 'switch' or 'controller'
-  req+sign NAME TYPE   Combine the above two steps, producing all three files.
-  verify NAME TYPE     Checks that NAME-cert.pem is a valid TYPE certificate
-                       TYPE is a certificate type: 'switch' or 'controller'
-The valid OPTIONS are:
-  -d, --dir=DIR        Directory where the PKI is located (default: pki)
-  -f, --force          Continue even if file or directory already exists
-  -b, --batch          Skip fingerprint verification
-  -l, --log=FILE       Log openssl output to FILE (default: ofp-log.log)
-  -h, --help           Print this usage message.
-EOF
-            exit 0
-            ;;
-        --d*=*)
-            DIR=$optarg
-            ;;
-        --d*|-d)
-            prev=DIR
-            ;;
-        --force|-f)
-            force=yes
-            ;;
-        --batch|-b)
-            batch=yes
-            ;;
-        -*)
-            echo "unrecognized option $option"
-            exit 1
-            ;;
-        *)
-            if test -z "$command"; then
-                command=$option
-            elif test -z "$arg1"; then
-                arg1=$option
-            elif test -z "$arg2"; then
-                arg2=$option
-            else
-                echo "only two arguments may be specified"
-                exit 1
-            fi
-            ;;
-    esac
-    shift
-done
-if test -n "$prev"; then
-    option=--`echo $prev | sed 's/_/-/g'`
-    { echo "$as_me: error: missing argument to $option" >&2
-        { (exit 1); exit 1; }; }
-fi
-if test -z "$command"; then
-    echo "$0: missing command name; use --help for help"
-    exit 1
-fi
-exec 3>>$log
-
-if test "$command" = "new-pki"; then
-    if test -e "$DIR" && test "$force" != "yes"; then
-        echo "$0: $DIR already exists"
-        exit 1
-    fi
-
-    if test ! -d "$DIR"; then
-        mkdir "$DIR"
-    fi
-    cd "$DIR"
-
-    if test ! -e dsaparam.pem; then
-        echo "Generating DSA parameters, please wait..."
-        openssl dsaparam -out dsaparam.pem 2048 1>&3 2>&3
-    fi
-
-    # Create the request configuration.
-    if test ! -e req.cnf; then
-        cat > req.cnf <<EOF
-[ req ]
-prompt = no
-distinguished_name = req_distinguished_name
-
-[ req_distinguished_name ]
-C = US
-ST = CA
-L = Palo Alto
-O = OpenFlow
-OU = OpenFlow certifier
-CN = OpenFlow certificate
-EOF
-    fi
-
-    # Create the CAs.
-    for ca in controllerca switchca; do
-        echo "Creating $ca..."
-        oldpwd=$PWD
-        mkdir -p $ca
-        cd $ca
-
-        mkdir -p certs crl newcerts private
-        touch index.txt
-        test -e crlnumber || echo 01 > crlnumber
-        test -e serial || echo 01 > serial
-
-        # Put DSA parameters in directory.
-        if test ! -e dsaparam.pem; then
-            cp ../dsaparam.pem .
-        fi
-
-    # Write CA configuration file.
-        if test ! -e ca.cnf; then
-            cat > ca.cnf <<'EOF'
-[ req ]
-prompt = no
-distinguished_name = req_distinguished_name
-
-[ req_distinguished_name ]
-C = US
-ST = CA
-L = Palo Alto
-O = OpenFlow
-OU = OpenFlow
-CN = OpenFlow
-
-[ ca ]
-default_ca = the_ca
-
-[ the_ca ]
-dir            = .                     # top dir
-database       = $dir/index.txt        # index file.
-new_certs_dir  = $dir/newcerts         # new certs dir
-certificate    = $dir/cacert.pem       # The CA cert
-serial         = $dir/serial           # serial no file
-private_key    = $dir/private/cakey.pem# CA private key
-RANDFILE       = $dir/private/.rand    # random number file
-default_days   = 365                   # how long to certify for
-default_crl_days= 30                   # how long before next CRL
-default_md     = md5                   # md to use
-policy         = policy                # default policy
-email_in_dn    = no                    # Don't add the email into cert DN
-name_opt       = ca_default            # Subject name display option
-cert_opt       = ca_default            # Certificate display option
-copy_extensions = none                 # Don't copy extensions from request
-
-# For the CA policy
-[ policy ]
-countryName             = optional
-stateOrProvinceName     = optional
-organizationName        = match
-organizationalUnitName  = optional
-commonName              = supplied
-emailAddress            = optional
-EOF
-        fi
-
-        # Create certificate authority.
-        openssl req -config ca.cnf -nodes \
-            -newkey dsa:dsaparam.pem -keyout private/cakey.pem -out careq.pem \
-            1>&3 2>&3
-        openssl ca -config ca.cnf -create_serial -out cacert.pem \
-            -days 1095 -batch -keyfile private/cakey.pem -selfsign \
-            -infiles careq.pem 1>&3 2>&3
-
-        cd "$oldpwd"
-    done
-    exit 0
-fi
-
-one_arg() {
-    if test -z "$arg1" || test -n "$arg2"; then
-        echo "$0: $command must have exactly one argument; use --help for help"
-        exit 1
-    fi
-}
-
-two_args() {
-    if test -z "$arg1" || test -z "$arg2"; then
-        echo "$0: $command must have exactly two arguments; use --help for help"
-        exit 1
-    fi
-}
-
-must_not_exist() {
-    if test -e "$1" && test "$force" != "yes"; then
-        echo "$0: $1 already exists and --force not supplied"
-        exit 1
-    fi
-}
-
-fingerprint() {
-    printf "$1-req.pem fingerprint is "
-    sha1sum "$1-req.pem" | awk '{print $1}'
-}
-
-check_type() {
-    if test "$1" != switch && test "$1" != controller; then
-        echo "$0: type argument must be 'switch' or 'controller'"
-        exit 1
-    fi
-}
-
-must_exist() {
-    if test ! -e "$1"; then
-        echo "$0: $1 does not exist"
-        exit 1
-    fi
-}
-
-DIR_must_exist() {
-    if test ! -e "$DIR"; then
-        echo "$0: $DIR does not exist (need to use --dir or new-pki?)"
-        exit 1
-    elif test ! -d "$DIR"; then
-        echo "$0: $DIR is not a directory"
-        exit 1
-    fi
-}
-
-make_request() {
-    must_not_exist "$arg1-privkey.pem"
-    must_not_exist "$arg1-req.pem"
-    DIR_must_exist
-    openssl req -config "$DIR/req.cnf" -text -nodes \
-        -newkey "dsa:$DIR/dsaparam.pem" -keyout "$1-privkey.pem" \
-        -out "$1-req.pem" 1>&3 2>&3
-}
-
-sign_request() {
-    must_exist "$1-req.pem"
-    must_not_exist "$1-cert.pem"
-    check_type "$2"
-    DIR_must_exist
-    (cd "$DIR/$2ca" && openssl ca -config ca.cnf -batch -in /dev/stdin) \
-        < "$1-req.pem" > "$1-cert.pem.tmp" 2>&3
-    mv "$1-cert.pem.tmp" "$1-cert.pem"
-}
-
-if test "$command" = req; then
-    one_arg
-    make_request "$arg1"
-    fingerprint "$arg1"
-elif test "$command" = sign; then
-    two_args
-    fingerprint "$arg1"
-    if test $batch != yes; then
-        echo "Does fingerprint match? (yes/no)"
-        read answer
-        if test "$answer" != yes; then 
-            echo "Match failure, aborting"
-            exit 1
-        fi
-    fi
-    sign_request "$arg1" "$arg2"
-elif test "$command" = req+sign; then
-    two_args
-    make_request "$arg1"
-    sign_request "$arg1" "$arg2"
-    fingerprint "$arg1"
-elif test "$command" = verify; then
-    two_args
-    must_exist "$arg1-cert.pem"
-    check_type "$arg2"
-    DIR_must_exist
-    openssl verify -CAfile "$DIR/${arg2}ca/cacert.pem" "$arg1-cert.pem"
-else
-    echo "$0: $command command unknown; use --help for help"
-    exit 1
-fi
diff --git a/utilities/ofp-pki-cgi.in b/utilities/ofp-pki-cgi.in
new file mode 100755 (executable)
index 0000000..291352e
--- /dev/null
@@ -0,0 +1,41 @@
+#! @PERL@
+
+use CGI;
+use Digest::SHA1;
+use Fcntl;
+
+$CGI::POST_MAX = 65536;    # Limit POSTs to 64 kB.
+
+use strict;
+use warnings;
+
+my $pkidir = '@pkidir@';
+my $q = new CGI;
+
+die unless $q->request_method() eq 'POST';
+
+my $type = $q->param('type');
+die unless defined $type;
+die unless $type eq 'switch' or $type eq 'controller';
+
+my $req = $q->param('req');
+die unless defined $req;
+die unless $req =~ /^-----BEGIN CERTIFICATE REQUEST-----$/m;
+die unless $req =~ /^-----END CERTIFICATE REQUEST-----$/m;
+
+my $digest = Digest::SHA1::sha1_hex($req);
+my $incoming = "$pkidir/${type}ca/incoming";
+my $dst = "$incoming/$digest-req.pem";
+
+sysopen(REQUEST, "$dst.tmp", O_RDWR | O_CREAT | O_EXCL, 0600)
+  or die "sysopen $dst.tmp: $!";
+print REQUEST $req;
+close(REQUEST) or die "close $dst.tmp: $!";
+
+rename("$dst.tmp", $dst) or die "rename $dst.tmp to $dst: $!";
+
+print $q->header('text/html', '204 No response');
+
+# Local Variables:
+# mode: perl
+# End:
diff --git a/utilities/ofp-pki.8 b/utilities/ofp-pki.8
deleted file mode 100644 (file)
index 113b325..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-.TH ofp-pki 8 "May 2008" "OpenFlow" "OpenFlow Manual"
-
-.SH NAME
-ofp\-pki \- OpenFlow public key infrastructure management utility
-
-.SH SYNOPSIS
-\fBofp\-pki\fR [\fIOPTIONS\fR] \fICOMMAND\fR [\fIARGS\fR]
-.sp
-Commands with their arguments:
-.br
-\fBofp\-pki\fR \fBnew-pki\fR
-.br
-\fBofp\-pki\fR \fBreq\fR \fINAME\fR
-.br
-\fBofp\-pki\fR \fBsign\fR \fINAME\fR \fITYPE\fR
-.br
-\fBofp\-pki\fR \fBreq+sign\fR \fINAME\fR \fITYPE\fR
-.br
-\fBofp\-pki\fR \fBverify\fR \fINAME\fR \fITYPE\fR
-.sp
-The available options are:
-.br
-[\fB-d\fR \fIDIR\fR | \fB--dir=\fR\fIDIR\fR] [\fB-f\fR | \fB--force\fR] [\fB-b\fR | \fB--batch\fR] [\fB-l\fR \fIFILE\fR | \fB--log=\fIFILE\fR] [\fB-h\fR | \fB--help\fR]
-
-.SH DESCRIPTION
-The \fBofp-pki\fR program sets up and manages a public key
-infrastructure for use with OpenFlow.  It is intended to be a simple
-interface for organizations that do not have an established public key
-infrastructure.  Other PKI tools can substitute for or supplement the
-use of \fBofp-pki\fR.
-
-\fBofp-pki\fR uses \fBopenssl\fR(1) for certificate management and key
-generation.
-
-The commands supported by \fBofp-pki\fR are:
-
-.TP
-\fBnew-pki\fR
-Creates a new PKI directory (by default named \fBpki\fR) and populates
-it with a pair of certificate authorities for controllers and
-switches.
-
-This command should ideally be run on a high-security machine separate
-from any OpenFlow controller or switch, called the CA machine.  The
-files \fBpki/controllerca/cacert.pem\fR and
-\fBpki/switchca/cacert.pem\fR that it produces will need to be copied
-over to the OpenFlow switches and controllers, respectively.  Their
-contents may safely be made public.
-
-Other files generated by \fBnew-pki\fR may remain on the CA machine.
-The files \fBpki/controllerca/private/cakey.pem\fR and
-\fBpki/switchca/private/cakey.pem\fR have particularly sensitive
-contents that should not be exposed.
-
-.TP
-\fBreq\fR \fINAME\fR
-Generates a new private key named \fINAME\fR\fB-privkey.pem\fR and
-corresponding certificate request named \fINAME\fR\fB-req.pem\fR.
-The private key can be intended for use by a switch or a controller.
-
-This command should ideally be run on the switch or controller that
-will use the private key to identify itself.  The file
-\fINAME\fR\fB-req.pem\fR must be copied to the CA machine for signing
-with the \fBsign\fR command (below).  
-
-This command will output a fingerprint to stdout as its final step.
-Write down the fingerprint and take it to the CA machine before
-continuing with the \fBsign\fR step.
-
-\fINAME\fR\fB-privkey.pem\fR has sensitive contents that should not be
-exposed.  \fINAME\fR\fB-req.pem\fR may be safely made public.
-
-.TP
-\fBsign\fR \fINAME\fR \fITYPE\fR
-Signs the certificate request named \fINAME\fR\fB-req.pem\fR that was
-produced in the previous step, producing a certificate named
-\fINAME\fR\fB-cert.pem\fR.  \fITYPE\fR, which must be \fBswitch\fR or
-\fBcontroller\fR, indicates the use for which the key is being
-certified.
-
-This command must be run on the CA machine.
-
-The command will output a fingerprint to stdout and request that you
-verify that it is the same fingerprint output by the \fBreq\fR
-command.  This ensures that the request being signed is the same one
-produced by \fBreq\fR.
-
-The file \fINAME\fR\fB-cert.pem\fR will need to be copied back to the
-switch or controller for which it is intended.  Its contents may
-safely be made public.
-
-.TP
-\fBreq+sign\fR \fINAME\fR \fITYPE\fR
-Combines the \fBreq\fR and \fBsign\fR commands into a single step,
-outputting all the files produced by each.  The
-\fINAME\fR\fB-privkey.pem\fR and \fINAME\fR\fB-cert.pem\fR files must
-be copied securely to the switch or controller.
-\fINAME\fR\fB-privkey.pem\fR has sensitive contents and must not be
-exposed in transit.  Afterward, it should be deleted from the CA
-machine.
-
-This combined method is, theoretically, less secure than the
-individual steps performed separately on two different machines,
-because there is additional potential for exposure of the private
-key.  However, it is also more convenient.
-
-.TP
-\fBverify\fR \fINAME\fR \fITYPE\fR
-Verifies that \fINAME\fR\fB-cert.pem\fR is a valid certificate for the
-given \fITYPE\fR of use (either \fBswitch\fR or \fBcontroller\fR).  If
-the certificate is valid for this use, it prints the message
-``\fINAME\fR\fB-cert.pem\fR: OK''; otherwise, it prints an error
-message.
-
-.SH OPTIONS
-.TP
-[\fB-d\fR \fIDIR\fR | \fB--dir=\fR\fIDIR\fR]
-Specifies the location of the PKI hierarchy to be used or created by
-the command (default: \fBpki\fR under the current directory).  The
-\fBreq\fR command does not need access to a PKI hierarchy.
-
-.TP
-[\fB-f\fR | \fB--force\fR]
-By default, \fBofp-pki\fR will not overwrite existing files or
-directories.  This option overrides this behavior.
-
-.TP
-[\fB-b\fR | \fB--batch\fR]
-Suppresses the interactive verification of fingerprints that the
-\fBsign\fR command by default requires.
-
-.TP
-[\fB-l\fR \fIFILE\fR | \fB--log=\fIFILE\fR]
-Sets the log file to \fIFILE\fR (default: ofp-pki.log).
-
-.TP
-[\fB-h\fR | \fB--help\fR]
-Prints a help usage message and exits.
-
-.SH "SEE ALSO"
-
-.BR dpctl (8),
-.BR switch (8),
-.BR secchan (8),
-.BR controller (8)
diff --git a/utilities/ofp-pki.in b/utilities/ofp-pki.in
new file mode 100755 (executable)
index 0000000..74a53c6
--- /dev/null
@@ -0,0 +1,530 @@
+#! /bin/sh -e
+
+pkidir='@pkidir@'
+command=
+prev=
+force=no
+batch=no
+log=ofp-pki.log
+for option; do
+    # This option-parsing mechanism borrowed from a Autoconf-generated
+    # configure script under the following license:
+
+    # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+    # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+    # This configure script is free software; the Free Software Foundation
+    # gives unlimited permission to copy, distribute and modify it.
+
+    # If the previous option needs an argument, assign it.
+    if test -n "$prev"; then
+        eval $prev=\$option
+        prev=
+        continue
+    fi
+    case $option in
+        *=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;;
+        *) optarg=yes ;;
+    esac
+
+    case $dashdash$option in
+        --)
+            dashdash=yes ;;
+        -h|--help)
+            cat <<EOF
+ofp-pki, for managing a simple OpenFlow public key infrastructure 
+usage: $0 [OPTION...] COMMAND [ARG...]
+
+The valid stand-alone commands and their arguments are:
+  init                 Initialize the PKI
+  req NAME             Create new private key and certificate request
+                       named NAME-privkey.pem and NAME-req.pem, resp.
+  sign NAME [TYPE]     Sign switch certificate request NAME-req.pem,
+                       producing certificate NAME-cert.pem
+  req+sign NAME [TYPE] Combine the above two steps, producing all three files.
+  verify NAME [TYPE]   Checks that NAME-cert.pem is a valid TYPE certificate
+  fingerprint FILE     Prints the fingerprint for FILE
+
+The following additional commands manage an online PKI:
+  ls [PREFIX] [TYPE]   Lists incoming requests of the given TYPE, optionally 
+                       limited to those whose fingerprint begins with PREFIX
+  flush [TYPE]         Rejects all incoming requests of the given TYPE
+  reject PREFIX [TYPE] Rejects the incoming request(s) whose fingerprint begins
+                       with PREFIX and has the given TYPE
+  approve PREFIX [TYPE] Approves the incoming request whose fingerprint begins
+                       with PREFIX and has the given TYPE
+  expire [AGE]         Rejects all incoming requests older than AGE, in
+                       one of the forms Ns, Nmin, Nh, Nday (default: 1day)
+  prompt [TYPE]        Interactively prompts to accept or reject each incoming
+                       request of the given TYPE
+
+Each TYPE above is a certificate type: 'switch' (default) or 'controller'.
+
+The valid OPTIONS are:
+  -d, --dir=DIR        Directory where the PKI is located
+                         (default: $pkidir)
+  -f, --force          Continue even if file or directory already exists
+  -b, --batch          Skip fingerprint verification
+  -l, --log=FILE       Log openssl output to FILE (default: ofp-log.log)
+  -h, --help           Print this usage message.
+EOF
+            exit 0
+            ;;
+        --d*=*)
+            pkidir=$optarg
+            ;;
+        --d*|-d)
+            prev=pkidir
+            ;;
+        --l*=*)
+            log=$optarg
+            ;;
+        --l*|-l)
+            prev=log
+            ;;
+        --force|-f)
+            force=yes
+            ;;
+        --batch|-b)
+            batch=yes
+            ;;
+        -*)
+            echo "unrecognized option $option" >&2
+            exit 1
+            ;;
+        *)
+            if test -z "$command"; then
+                command=$option
+            elif test -z "${arg1+set}"; then
+                arg1=$option
+            elif test -z "${arg2+set}"; then
+                arg2=$option
+            else
+                echo "$option: only two arguments may be specified" >&2
+                exit 1
+            fi
+            ;;
+    esac
+    shift
+done
+if test -n "$prev"; then
+    option=--`echo $prev | sed 's/_/-/g'`
+    { echo "$as_me: error: missing argument to $option" >&2
+        { (exit 1); exit 1; }; }
+fi
+if test -z "$command"; then
+    echo "$0: missing command name; use --help for help" >&2
+    exit 1
+fi
+
+if test "$command" = "init"; then
+    if test -e "$pkidir" && test "$force" != "yes"; then
+        echo "$0: $pkidir already exists" >&2
+        exit 1
+    fi
+
+    if test ! -d "$pkidir"; then
+        mkdir -p "$pkidir"
+    fi
+    cd "$pkidir"
+    exec 3>>$log
+
+    if test ! -e dsaparam.pem; then
+        echo "Generating DSA parameters, please wait..." >&2
+        openssl dsaparam -out dsaparam.pem 2048 1>&3 2>&3
+    fi
+
+    # Create the request configuration.
+    if test ! -e req.cnf; then
+        cat > req.cnf <<EOF
+[ req ]
+prompt = no
+distinguished_name = req_distinguished_name
+
+[ req_distinguished_name ]
+C = US
+ST = CA
+L = Palo Alto
+O = OpenFlow
+OU = OpenFlow certifier
+CN = OpenFlow certificate
+EOF
+    fi
+
+    # Create the CAs.
+    for ca in controllerca switchca; do
+        echo "Creating $ca..." >&2
+        oldpwd=$PWD
+        mkdir -p $ca
+        cd $ca
+
+        mkdir -p certs crl newcerts
+        mkdir -p -m 0700 private
+        mkdir -p -m 0733 incoming
+        touch index.txt
+        test -e crlnumber || echo 01 > crlnumber
+        test -e serial || echo 01 > serial
+
+        # Put DSA parameters in directory.
+        if test ! -e dsaparam.pem; then
+            cp ../dsaparam.pem .
+        fi
+
+    # Write CA configuration file.
+        if test ! -e ca.cnf; then
+            cat > ca.cnf <<'EOF'
+[ req ]
+prompt = no
+distinguished_name = req_distinguished_name
+
+[ req_distinguished_name ]
+C = US
+ST = CA
+L = Palo Alto
+O = OpenFlow
+OU = OpenFlow
+CN = OpenFlow
+
+[ ca ]
+default_ca = the_ca
+
+[ the_ca ]
+dir            = .                     # top dir
+database       = $dir/index.txt        # index file.
+new_certs_dir  = $dir/newcerts         # new certs dir
+certificate    = $dir/cacert.pem       # The CA cert
+serial         = $dir/serial           # serial no file
+private_key    = $dir/private/cakey.pem# CA private key
+RANDFILE       = $dir/private/.rand    # random number file
+default_days   = 365                   # how long to certify for
+default_crl_days= 30                   # how long before next CRL
+default_md     = md5                   # md to use
+policy         = policy                # default policy
+email_in_dn    = no                    # Don't add the email into cert DN
+name_opt       = ca_default            # Subject name display option
+cert_opt       = ca_default            # Certificate display option
+copy_extensions = none                 # Don't copy extensions from request
+
+# For the CA policy
+[ policy ]
+countryName             = optional
+stateOrProvinceName     = optional
+organizationName        = match
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+EOF
+        fi
+
+        # Create certificate authority.
+        openssl req -config ca.cnf -nodes \
+            -newkey dsa:dsaparam.pem -keyout private/cakey.pem -out careq.pem \
+            1>&3 2>&3
+        openssl ca -config ca.cnf -create_serial -out cacert.pem \
+            -days 1095 -batch -keyfile private/cakey.pem -selfsign \
+            -infiles careq.pem 1>&3 2>&3
+        chmod 0700 private/cakey.pem
+
+        cd "$oldpwd"
+    done
+    exit 0
+fi
+
+one_arg() {
+    if test -z "$arg1" || test -n "$arg2"; then
+        echo "$0: $command must have exactly one argument; use --help for help" >&2
+        exit 1
+    fi
+}
+
+zero_or_one_args() {
+    if test -n "$arg2"; then
+        echo "$0: $command must have zero or one arguments; use --help for help" >&2
+        exit 1
+    fi
+}
+
+one_or_two_args() {
+    if test -z "$arg1"; then
+        echo "$0: $command must have one or two arguments; use --help for help" >&2
+        exit 1
+    fi
+}
+
+must_not_exist() {
+    if test -e "$1" && test "$force" != "yes"; then
+        echo "$0: $1 already exists and --force not supplied" >&2
+        exit 1
+    fi
+}
+
+resolve_prefix() {
+    test -n "$type" || exit 123 # Forgot to call check_type?
+
+    case $1 in
+        ????*)
+            ;;
+        *)
+            echo "Prefix $arg1 is too short (less than 4 hex digits)"
+            exit 0
+            ;;
+    esac
+    
+    fingerprint=$(cd "$pkidir/${type}ca/incoming" && echo "$1"*-req.pem
+                  | sed 's/-req\.pem$//')
+    case $fingerprint in
+        "${1}*")
+            echo "No certificate requests matching $1"
+            exit 1
+            ;;
+        *" "*)
+            echo "$1 matches more than one certificate request:"
+            echo $fingerprint | sed 's/ /\
+/g'
+            exit 1
+            ;;
+        *)
+            # Nothing to do.
+            ;;
+    esac
+    req="$pkidir/${type}ca/incoming/$fingerprint-req.pem"
+    cert="$pkidir/${type}ca/certs/$fingerprint-cert.pem"
+}
+
+make_tmpdir() {
+    TMP=/tmp/ofp-pki.tmp$$
+    rm -rf $TMP
+    trap "rm -rf $TMP" 0
+    mkdir -m 0700 $TMP
+}
+
+fingerprint() {
+    local file=$1
+    local name=${1-$2}
+    local date=$(date -r $file)
+    local fingerprint
+    if grep -q -e '-BEGIN CERTIFICATE-' "$file"; then
+        fingerprint=$(openssl x509 -noout -in "$file" -fingerprint |
+                      sed 's/SHA1 Fingerprint=//' | tr -d ':')
+    else
+        fingerprint=$(sha1sum "$file" | awk '{print $1}')
+    fi
+    printf "$name\\t$date\\n"
+    case $file in
+        $fingerprint*)
+            printf "\\t(correct fingerprint in filename)\\n"
+            ;;
+        *)
+            printf "\\tfingerprint $fingerprint\\n"
+            ;;
+    esac
+}
+
+verify_fingerprint() {
+    fingerprint "$@"
+    if test $batch != yes; then
+        echo "Does fingerprint match? (yes/no)"
+        read answer
+        if test "$answer" != yes; then 
+            echo "Match failure, aborting" >&2
+            exit 1
+        fi
+    fi
+}
+
+check_type() {
+    if test x = x"$1"; then
+        type=switch
+    elif test "$1" = switch || test "$1" = controller; then 
+        type=$1
+    else
+        echo "$0: type argument must be 'switch' or 'controller'" >&2
+        exit 1
+    fi
+}
+
+parse_age() {
+    number=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\1/')
+    unit=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\2/')
+    case $unit in
+        s)
+            factor=1
+            ;;
+        min)
+            factor=60
+            ;;
+        h)
+            factor=3600
+            ;;
+        day)
+            factor=86400
+            ;;
+        *)
+            echo "$1: age not in the form Ns, Nmin, Nh, Nday (e.g. 1day)" >&2
+            exit 1
+            ;;
+    esac
+    echo $(($number * $factor))
+}
+
+must_exist() {
+    if test ! -e "$1"; then
+        echo "$0: $1 does not exist" >&2
+        exit 1
+    fi
+}
+
+pkidir_must_exist() {
+    if test ! -e "$pkidir"; then
+        echo "$0: $pkidir does not exist (need to run 'init' or use '--dir'?)" >&2
+        exit 1
+    elif test ! -d "$pkidir"; then
+        echo "$0: $pkidir is not a directory" >&2
+        exit 1
+    fi
+}
+
+make_request() {
+    must_not_exist "$arg1-privkey.pem"
+    must_not_exist "$arg1-req.pem"
+    pkidir_must_exist
+    openssl req -config "$pkidir/req.cnf" -text -nodes \
+        -newkey "dsa:$pkidir/dsaparam.pem" -keyout "$1-privkey.pem" \
+        -out "$1-req.pem" 1>&3 2>&3
+}
+
+sign_request() {
+    must_exist "$1"
+    must_not_exist "$2"
+    pkidir_must_exist
+
+    (cd "$pkidir/${type}ca" && 
+     openssl ca -config ca.cnf -batch -in /dev/stdin) \
+        < "$1" > "$2.tmp$$" 2>&3
+    mv "$2.tmp$$" "$2"
+}
+
+glob() {
+    local files=$(echo $1)
+    if test "$files" != "$1"; then
+        echo "$files"
+    fi
+}
+
+case $log in
+    /*)
+        exec 3>>$log || true
+        ;;
+    *)
+        exec 3>>$pkidir/$log || true
+        ;;
+esac
+
+if test "$command" = req; then
+    one_arg
+
+    make_request "$arg1"
+    fingerprint "$arg1-req.pem"
+elif test "$command" = sign; then
+    one_or_two_args
+    check_type "$arg2"
+    verify_fingerprint "$arg1-req.pem"
+
+    sign_request "$arg1-req.pem" "$arg2-cert.pem"
+elif test "$command" = req+sign; then
+    one_or_two_args
+    check_type "$arg2"
+
+    make_request "$arg1"
+    sign_request "$arg1-req.pem" "$arg1-cert.pem"
+    fingerprint "$arg1-req.pem"
+elif test "$command" = verify; then
+    one_or_two_args
+    must_exist "$arg1-cert.pem"
+    check_type "$arg2"
+
+    pkidir_must_exist
+    openssl verify -CAfile "$pkidir/${type}ca/cacert.pem" "$arg1-cert.pem"
+elif test "$command" = fingerprint; then
+    one_arg
+
+    fingerprint "$arg1"
+elif test "$command" = ls; then
+    check_type "$arg2"
+
+    cd "$pkidir/${type}ca/incoming"
+    for file in $(glob "$arg1*-req.pem"); do
+        fingerprint $file
+    done
+elif test "$command" = flush; then
+    check_type "$arg1"
+
+    rm -f "$pkidir/${type}ca/incoming/"*
+elif test "$command" = reject; then
+    one_or_two_args
+    check_type "$arg2"
+    resolve_prefix "$arg1"
+
+    rm -f "$req"
+elif test "$command" = approve; then
+    one_or_two_args
+    check_type "$arg2"
+    resolve_prefix "$arg1"
+
+    make_tmpdir
+    cp "$req" "$TMP/$req"
+    verify_fingerprint "$TMP/$req"
+    sign_request "$TMP/$req"
+    rm -f "$req" "$TMP/$req"
+elif test "$command" = prompt; then
+    zero_or_one_args
+    check_type "$arg1"
+
+    make_tmpdir
+    cd "$pkidir/${type}ca/incoming"
+    for req in $(glob "*-req.pem"); do
+        cp "$req" "$TMP/$req"
+
+        cert=$(echo "$pkidir/${type}ca/certs/$req" |
+               sed 's/-req.pem/-cert.pem/')
+        if test -f $cert; then
+            echo "Request $req already approved--dropping duplicate request"
+            rm -f "$req" "$TMP/$req"
+            continue
+        fi
+
+        echo
+        echo
+        fingerprint "$TMP/$req" "$req"
+        printf "Disposition for this request (skip/approve/reject)? "
+        read answer
+        case $answer in
+            approve)
+                echo "Approving $req"
+                sign_request "$TMP/$req" "$cert"
+                rm -f "$req" "$TMP/$req"
+                ;;
+            r*)
+                echo "Rejecting $req"
+                rm -f "$req" "$TMP/$req"
+                ;;
+            *)
+                echo "Skipping $req"
+                ;;
+        esac
+    done
+elif test "$command" = expire; then
+    zero_or_one_args
+    cutoff=$(($(date +%s) - $(parse_age ${arg1-1day})))
+    for type in switch controller; do
+        cd "$pkidir/${type}ca/incoming" || exit 1
+        for file in $(glob "*"); do
+            time=$(date -r "$file" +%s)
+            if test "$time" -lt "$cutoff"; then
+                rm -f "$file"
+            fi
+        done
+    done
+else
+    echo "$0: $command command unknown; use --help for help" >&2
+    exit 1
+fi