secchan: Make ofproto reconfigurable after it is created.
authorBen Pfaff <blp@nicira.com>
Wed, 4 Mar 2009 18:04:23 +0000 (10:04 -0800)
committerBen Pfaff <blp@nicira.com>
Thu, 5 Mar 2009 00:55:53 +0000 (16:55 -0800)
This will allow vswitchd to reconfigure the ofprotos that it instantiates
based on changes in the vswitchd configuration file.

17 files changed:
secchan/discovery.c
secchan/discovery.h
secchan/executer.c
secchan/executer.h
secchan/fail-open.c
secchan/fail-open.h
secchan/in-band.c
secchan/in-band.h
secchan/main.c
secchan/netflow.c
secchan/netflow.h
secchan/ofproto.c
secchan/ofproto.h
secchan/pinsched.c
secchan/pinsched.h
secchan/status.c
secchan/status.h

index 56beed258e29b23dff89603b32a763417de578e5..087fa2a184de7cba1b18f96630d88bf860a4b6d8 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <config.h>
 #include "discovery.h"
+#include <errno.h>
 #include <inttypes.h>
 #include <regex.h>
 #include <stdlib.h>
 #include "openflow/openflow.h"
 #include "packets.h"
 #include "status.h"
+#include "vconn-ssl.h"
 
 #define THIS_MODULE VLM_discovery
 #include "vlog.h"
 
 struct discovery {
-    const char *accept_controller_re;
+    char *re;
     bool update_resolv_conf;
-    regex_t accept_controller_regex;
+    regex_t *regex;
     struct dhclient *dhcp;
     int n_changes;
+    struct status_category *ss_cat;
 };
 
 static void modify_dhcp_request(struct dhcp_msg *, void *aux);
@@ -66,7 +69,7 @@ discovery_status_cb(struct status_reply *sr, void *d_)
 {
     struct discovery *d = d_;
 
-    status_reply_put(sr, "accept-remote=%s", d->accept_controller_re);
+    status_reply_put(sr, "accept-remote=%s", d->re);
     status_reply_put(sr, "n-changes=%d", d->n_changes);
     if (d->dhcp) {
         status_reply_put(sr, "state=%s", dhclient_get_state(d->dhcp));
@@ -106,9 +109,10 @@ discovery_status_cb(struct status_reply *sr, void *d_)
     }
 }
 
-struct discovery *
-discovery_create(const char *accept_controller_re, bool update_resolv_conf,
-                 struct dpif *dpif, struct switch_status *ss)
+int
+discovery_create(const char *re, bool update_resolv_conf,
+                 struct dpif *dpif, struct switch_status *ss,
+                 struct discovery **discoveryp)
 {
     struct discovery *d;
     struct odp_port port;
@@ -117,46 +121,94 @@ discovery_create(const char *accept_controller_re, bool update_resolv_conf,
     d = xcalloc(1, sizeof *d);
 
     /* Controller regular expression. */
-    d->accept_controller_re = accept_controller_re;
-    error = regcomp(&d->accept_controller_regex, accept_controller_re,
-                     REG_NOSUB | REG_EXTENDED);
+    error = discovery_set_accept_controller_re(d, re);
     if (error) {
-        size_t length = regerror(error, &d->accept_controller_regex, NULL, 0);
-        char *buffer = xmalloc(length);
-        regerror(error, &d->accept_controller_regex, buffer, length);
-        ofp_fatal(0, "%s: %s", accept_controller_re, buffer);
+        goto error_free;
     }
     d->update_resolv_conf = update_resolv_conf;
 
     /* Initialize DHCP client. */
     error = dpif_port_query_by_number(dpif, ODPP_LOCAL, &port);
     if (error) {
-        ofp_fatal(error, "failed to query datapath local port");
+        VLOG_ERR("failed to query datapath local port: %s", strerror(error));
+        goto error_regfree;
     }
     error = dhclient_create(port.devname, modify_dhcp_request,
                             validate_dhcp_offer, d, &d->dhcp);
     if (error) {
-        ofp_fatal(error, "failed to initialize DHCP client");
+        VLOG_ERR("failed to initialize DHCP client: %s", strerror(error));
+        goto error_regfree;
     }
     dhclient_set_max_timeout(d->dhcp, 3);
     dhclient_init(d->dhcp, 0);
 
-    switch_status_register_category(ss, "discovery", discovery_status_cb, d);
+    d->ss_cat = switch_status_register(ss, "discovery",
+                                       discovery_status_cb, d);
+
+    *discoveryp = d;
+    return 0;
 
-    return d;
+error_regfree:
+    regfree(d->regex);
+    free(d->regex);
+error_free:
+    free(d);
+    *discoveryp = 0;
+    return error;
 }
 
 void
 discovery_destroy(struct discovery *d)
 {
     if (d) {
-        /* We don't own d->accept_controller_re. */
-        regfree(&d->accept_controller_regex);
+        free(d->re);
+        regfree(d->regex);
+        free(d->regex);
         dhclient_destroy(d->dhcp);
+        switch_status_unregister(d->ss_cat);
         free(d);
     }
 }
 
+void
+discovery_set_update_resolv_conf(struct discovery *d,
+                                 bool update_resolv_conf)
+{
+    d->update_resolv_conf = update_resolv_conf;
+}
+
+int
+discovery_set_accept_controller_re(struct discovery *d, const char *re_)
+{
+    regex_t *regex;
+    int error;
+    char *re;
+
+    re = (!re_ ? xstrdup(vconn_ssl_is_configured() ? "^ssl:.*" : ".*")
+          : re_[0] == '^' ? xstrdup(re_) : xasprintf("^%s", re_));
+    regex = xmalloc(sizeof *regex);
+    error = regcomp(regex, re, REG_NOSUB | REG_EXTENDED);
+    if (error) {
+        size_t length = regerror(error, regex, NULL, 0);
+        char *buffer = xmalloc(length);
+        regerror(error, regex, buffer, length);
+        VLOG_WARN("%s: %s", re, buffer);
+        free(regex);
+        free(re);
+        return EINVAL;
+    } else {
+        if (d->regex) {
+            regfree(d->regex);
+            free(d->regex);
+        }
+        free(d->re);
+
+        d->regex = regex;
+        d->re = re;
+        return 0;
+    }
+}
+
 void
 discovery_question_connectivity(struct discovery *d)
 {
@@ -224,11 +276,10 @@ validate_dhcp_offer(const struct dhcp_msg *msg, void *d_)
         VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn");
         return false;
     }
-    accept = !regexec(&d->accept_controller_regex, vconn_name, 0, NULL,
-                      0);
+    accept = !regexec(d->regex, vconn_name, 0, NULL, 0);
     if (!accept) {
         VLOG_WARN_RL(&rl, "rejecting controller vconn that fails to match %s",
-                     d->accept_controller_re);
+                     d->re);
     }
     free(vconn_name);
     return accept;
index ba6d988e19f8a885eeea7f2d9753e07c172968c3..91f9af299428e0d2fe92518ca39ca95ccff2f613 100644 (file)
 #include <stdbool.h>
 
 struct dpif;
+struct discovery;
 struct settings;
 struct switch_status;
 
-struct discovery *discovery_create(const char *accept_controller_re,
-                                   bool update_resolv_conf,
-                                   struct dpif *, struct switch_status *);
+int discovery_create(const char *accept_controller_re, bool update_resolv_conf,
+                     struct dpif *, struct switch_status *,
+                     struct discovery **);
 void discovery_destroy(struct discovery *);
+void discovery_set_update_resolv_conf(struct discovery *,
+                                      bool update_resolv_conf);
+int discovery_set_accept_controller_re(struct discovery *, const char *re);
 void discovery_question_connectivity(struct discovery *);
 bool discovery_run(struct discovery *, char **controller_name);
 void discovery_wait(struct discovery *);
index ab7ae58ca0616d02e6b5be79bd33d23be5c6d1fe..b321f9812881fd6bef21f488d3653863a989f5b4 100644 (file)
@@ -78,8 +78,8 @@ struct child {
 
 struct executer {
     /* Settings. */
-    const char *command_acl;    /* Command white/blacklist, as shell globs. */
-    const char *command_dir;    /* Directory that contains commands. */
+    char *command_acl;          /* Command white/blacklist, as shell globs. */
+    char *command_dir;          /* Directory that contains commands. */
 
     /* Children. */
     struct child children[MAX_CHILDREN];
@@ -456,16 +456,19 @@ sigchld_handler(int signr UNUSED)
     write(signal_fds[1], "", 1);
 }
 
-struct executer *
-executer_create(const char *command_acl, const char *command_dir)
+int
+executer_create(const char *command_acl, const char *command_dir,
+                struct executer **executerp)
 {
     struct executer *e;
     struct sigaction sa;
 
+    *executerp = NULL;
     if (null_fd == -1) {
         /* Create pipe for notifying us that SIGCHLD was invoked. */
         if (pipe(signal_fds)) {
-            ofp_fatal(errno, "pipe failed");
+            VLOG_ERR("pipe failed: %s", strerror(errno));
+            return errno;
         }
         set_nonblocking(signal_fds[0]);
         set_nonblocking(signal_fds[1]);
@@ -473,7 +476,11 @@ executer_create(const char *command_acl, const char *command_dir)
         /* Open /dev/null. */
         null_fd = open("/dev/null", O_RDWR);
         if (null_fd < 0) {
-            ofp_fatal(errno, "could not open /dev/null");
+            int error = errno;
+            VLOG_ERR("could not open /dev/null: %s", strerror(error));
+            close(signal_fds[0]);
+            close(signal_fds[1]);
+            return error;
         }
     }
 
@@ -483,14 +490,16 @@ executer_create(const char *command_acl, const char *command_dir)
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
     if (sigaction(SIGCHLD, &sa, NULL)) {
-        ofp_fatal(errno, "sigaction(SIGCHLD) failed");
+        VLOG_ERR("sigaction(SIGCHLD) failed: %s", strerror(errno));
+        return errno;
     }
 
     e = xcalloc(1, sizeof *e);
-    e->command_acl = command_acl;
-    e->command_dir = command_dir;
+    e->command_acl = xstrdup(command_acl);
+    e->command_dir = xstrdup(command_dir);
     e->n_children = 0;
-    return e;
+    *executerp = e;
+    return 0;
 }
 
 void
@@ -499,7 +508,8 @@ executer_destroy(struct executer *e)
     if (e) {
         size_t i;
 
-        /* We don't own e->command_acl or e->command_dir. */
+        free(e->command_acl);
+        free(e->command_dir);
         for (i = 0; i < e->n_children; i++) {
             struct child *child = &e->children[i];
 
@@ -512,3 +522,12 @@ executer_destroy(struct executer *e)
         free(e);
     }
 }
+
+void
+executer_set_acl(struct executer *e, const char *acl, const char *dir)
+{
+    free(e->command_acl);
+    e->command_acl = xstrdup(acl);
+    free(e->command_dir);
+    e->command_dir = xstrdup(dir);
+}
index 30bb0a286d9de123ee5a50778a2b694c4cda581b..c9deca06f6748ecb6c560a854e78bdabca091ebc 100644 (file)
 #ifndef EXECUTER_H
 #define EXECUTER_H 1
 
+struct executer;
 struct nicira_header;
 struct rconn;
 
-struct executer *executer_create(const char *command_acl,
-                                 const char *command_dir);
+int executer_create(const char *acl, const char *dir, struct executer **);
+void executer_set_acl(struct executer *, const char *acl, const char *dir);
 void executer_destroy(struct executer *);
 void executer_run(struct executer *);
 void executer_wait(struct executer *);
index 203e0930cafacc33093a3441e926b7a060cd1c2e..90915a33bacfc033647294ad61f7b8a59b63cb73 100644 (file)
@@ -50,10 +50,10 @@ struct fail_open {
     int trigger_duration;
     int last_disconn_secs;
     struct mac_learning *mac_learning;
+    struct status_category *ss_cat;
 };
 
 /* Causes 'r' to enter or leave fail-open mode, if appropriate. */
-
 void
 fail_open_run(struct fail_open *fo)
 {
@@ -151,17 +151,24 @@ fail_open_create(int trigger_duration, struct switch_status *switch_status,
     fo->trigger_duration = trigger_duration;
     fo->last_disconn_secs = 0;
     fo->mac_learning = NULL;
-    switch_status_register_category(switch_status, "fail-open",
-                                    fail_open_status_cb, fo);
+    fo->ss_cat = switch_status_register(switch_status, "fail-open",
+                                        fail_open_status_cb, fo);
     return fo;
 }
 
+void
+fail_open_set_trigger_duration(struct fail_open *fo, int trigger_duration)
+{
+    fo->trigger_duration = trigger_duration;
+}
+
 void
 fail_open_destroy(struct fail_open *fo)
 {
     if (fo) {
         /* We don't own fo->controller. */
         mac_learning_destroy(fo->mac_learning);
+        switch_status_unregister(fo->ss_cat);
         free(fo);
     }
 }
index cb1ac761b23759b610966593a1676ab1acd07cab..207a7915338fadfe1dc363e315af906cc7cb877e 100644 (file)
@@ -46,6 +46,7 @@ struct switch_status;
 struct fail_open *fail_open_create(int trigger_duration,
                                    struct switch_status *,
                                    struct rconn *controller);
+void fail_open_set_trigger_duration(struct fail_open *, int trigger_duration);
 void fail_open_destroy(struct fail_open *);
 void fail_open_wait(struct fail_open *);
 void fail_open_run(struct fail_open *);
index 5c223e96a9b122a8758d0d0a4e9d6a11093c007c..fe1301f016bd9322759d1be33645730d91f7215a 100644 (file)
@@ -58,6 +58,7 @@ struct in_band {
     struct mac_learning *mac_learning;
     struct netdev *netdev;
     struct rconn *controller;
+    struct status_category *ss_cat;
 };
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
@@ -241,40 +242,46 @@ in_band_wait(struct in_band *in_band)
     mac_learning_wait(in_band->mac_learning);
 }
 
-struct in_band *
+int
 in_band_create(struct dpif *dpif, struct switch_status *ss,
-               struct rconn *controller)
+               struct rconn *controller, struct in_band **in_bandp)
 {
     struct in_band *in_band;
     struct netdev *netdev;
     struct odp_port port;
     int error;
 
+    *in_bandp = NULL;
     error = dpif_port_query_by_number(dpif, ODPP_LOCAL, &port);
     if (error) {
-        ofp_fatal(error, "failed to query datapath local port");
+        VLOG_ERR("failed to query datapath local port: %s", strerror(error));
+        return error;
     }
 
     error = netdev_open(port.devname, NETDEV_ETH_TYPE_NONE, &netdev);
     if (error) {
-        ofp_fatal(error, "failed to open %s network device", port.devname);
+        VLOG_ERR("failed to open %s network device: %s",
+                 port.devname, strerror(error));
+        return error;
     }
 
     in_band = xcalloc(1, sizeof *in_band);
     in_band->mac_learning = mac_learning_create();
     in_band->netdev = netdev;
     in_band->controller = controller;
-    switch_status_register_category(ss, "in-band", in_band_status_cb, in_band);
+    in_band->ss_cat = switch_status_register(ss, "in-band",
+                                             in_band_status_cb, in_band);
 
-    return in_band;
+    *in_bandp = in_band;
+    return 0;
 }
-
 void
 in_band_destroy(struct in_band *in_band)
 {
     if (in_band) {
         mac_learning_destroy(in_band->mac_learning);
         netdev_close(in_band->netdev);
+        switch_status_unregister(in_band->ss_cat);
         /* We don't own the rconn. */
     }
 }
index 5951692913815e1914becded8ecc3385479a79de..cc37af144c06c62f28282595fbc1754ca3323909 100644 (file)
 #include "flow.h"
 
 struct dpif;
+struct in_band;
 struct ofproto;
 struct rconn;
 struct secchan;
 struct settings;
 struct switch_status;
 
-struct in_band *in_band_create(struct dpif *, struct switch_status *,
-                               struct rconn *controller);
+int in_band_create(struct dpif *, struct switch_status *,
+                   struct rconn *controller, struct in_band **);
 void in_band_destroy(struct in_band *);
 void in_band_run(struct in_band *);
 void in_band_wait(struct in_band *);
index 197055af7c3c649576c66953da2959f8a434c2a0..d0bb73a468018e6976ad6c56d9e2eacbad23579d 100644 (file)
@@ -62,6 +62,7 @@
 #include "rconn.h"
 #include "signals.h"
 #include "status.h"
+#include "svec.h"
 #include "timeval.h"
 #include "util.h"
 #include "vconn-ssl.h"
 #include "vlog.h"
 #define THIS_MODULE VLM_secchan
 
-static void reconfigure(struct ofproto *);
+/* Behavior when the connection to the controller fails. */
+enum fail_mode {
+    FAIL_OPEN,                  /* Act as learning switch. */
+    FAIL_CLOSED                 /* Drop all packets. */
+};
+
+/* Settings that may be configured by the user. */
+struct ofsettings {
+    /* Configuration. */
+    const char *br_name;      /* Bridge name to use for configuration lookup */
+
+    /* Overall mode of operation. */
+    bool discovery;           /* Discover the controller automatically? */
+    bool in_band;             /* Connect to controller in-band? */
+
+    /* Datapath. */
+    uint64_t datapath_id;       /* Datapath ID. */
+    const char *dp_name;        /* Name of local datapath. */
+
+    /* Description strings. */
+    const char *mfr_desc;       /* Manufacturer. */
+    const char *hw_desc;        /* Hardware. */
+    const char *sw_desc;        /* Software version. */
+    const char *serial_desc;    /* Serial number. */
+
+    /* Related vconns and network devices. */
+    const char *controller_name; /* Controller (if not discovery mode). */
+    struct svec listeners;       /* Listen for management connections. */
+
+    /* Failure behavior. */
+    enum fail_mode fail_mode; /* Act as learning switch if no controller? */
+    int max_idle;             /* Idle time for flows in fail-open mode. */
+    int probe_interval;       /* # seconds idle before sending echo request. */
+    int max_backoff;          /* Max # seconds between connection attempts. */
+
+    /* Packet-in rate-limiting. */
+    int rate_limit;           /* Tokens added to bucket per second. */
+    int burst_limit;          /* Maximum number token bucket size. */
+
+    /* Discovery behavior. */
+    const char *accept_controller_re; /* Controller vconns to accept. */
+    bool update_resolv_conf;          /* Update /etc/resolv.conf? */
+
+    /* Spanning tree protocol. */
+    bool enable_stp;
+
+    /* Remote command execution. */
+    char *command_acl;          /* Command white/blacklist, as shell globs. */
+    char *command_dir;          /* Directory that contains commands. */
+};
+
+static void reconfigure(struct ofproto *, const char *br_name);
 static void parse_options(int argc, char *argv[], struct ofsettings *);
 static void usage(void) NO_RETURN;
 
@@ -81,7 +133,7 @@ main(int argc, char *argv[])
     struct signal *sighup;
     struct ofproto *ofproto;
     struct ofsettings s;
-    int retval;
+    int error;
 
     set_program_name(argv[0]);
     register_fault_handlers();
@@ -95,21 +147,60 @@ main(int argc, char *argv[])
     daemonize();
 
     /* Start listening for vlogconf requests. */
-    retval = vlog_server_listen(NULL, NULL);
-    if (retval) {
-        ofp_fatal(retval, "Could not listen for vlog connections");
+    error = vlog_server_listen(NULL, NULL);
+    if (error) {
+        ofp_fatal(error, "Could not listen for vlog connections");
     }
 
     VLOG_INFO("OpenFlow reference implementation version %s", VERSION BUILDNR);
     VLOG_INFO("OpenFlow protocol version 0x%02x", OFP_VERSION);
 
     /* Start OpenFlow processing. */
-    ofproto = ofproto_create(&s);
+    error = ofproto_create(s.dp_name, &ofproto);
+    if (error) {
+        ofp_fatal(error, "could not initialize openflow switch");
+    }
+    error = ofproto_set_in_band(ofproto, s.in_band);
+    if (error) {
+        ofp_fatal(error, "failed to configure in-band control");
+    }
+    error = ofproto_set_discovery(ofproto, s.discovery, s.accept_controller_re,
+                                  s.update_resolv_conf);
+    if (error) {
+        ofp_fatal(error, "failed to configure controller discovery");
+    }
+    if (s.datapath_id) {
+        ofproto_set_datapath_id(ofproto, s.datapath_id);
+    }
+    ofproto_set_desc(ofproto, s.mfr_desc, s.hw_desc, s.sw_desc, s.serial_desc);
+    error = ofproto_set_listeners(ofproto, &s.listeners);
+    if (error) {
+        ofp_fatal(error, "failed to configure management connections");
+    }
+    ofproto_set_failure(ofproto, s.fail_mode == FAIL_OPEN);
+    ofproto_set_probe_interval(ofproto, s.probe_interval);
+    ofproto_set_max_backoff(ofproto, s.max_backoff);
+    ofproto_set_rate_limit(ofproto, s.rate_limit, s.burst_limit);
+    error = ofproto_set_stp(ofproto, s.enable_stp);
+    if (error) {
+        ofp_fatal(error, "failed to configure STP");
+    }
+    error = ofproto_set_remote_execution(ofproto, s.command_acl,
+                                         s.command_dir);
+    if (error) {
+        ofp_fatal(error, "failed to configure remote command execution");
+    }
+    if (!s.discovery) {
+        error = ofproto_set_controller(ofproto, s.controller_name);
+        if (error) {
+            ofp_fatal(error, "failed to configure controller");
+        }
+    }
 
-    reconfigure(ofproto);
+    reconfigure(ofproto, s.br_name);
     while (ofproto_is_alive(ofproto)) {
         if (signal_poll(sighup)) {
-            reconfigure(ofproto);
+            reconfigure(ofproto, s.br_name);
         }
 
         /* Do work. */
@@ -125,10 +216,17 @@ main(int argc, char *argv[])
 }
 
 static void
-reconfigure(struct ofproto *ofproto)
+reconfigure(struct ofproto *ofproto, const char *br_name)
 {
     cfg_read();
-    ofproto_reconfigure(ofproto);
+    if (br_name) {
+        struct svec collectors;
+
+        svec_init(&collectors);
+        cfg_get_all_keys(&collectors, "netflow.%s.host", br_name);
+        ofproto_set_netflow(ofproto, &collectors);
+        svec_destroy(&collectors);
+    }
 }
 \f
 /* User interface. */
@@ -201,15 +299,15 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
     /* Set defaults that we can figure out before parsing options. */
     s->br_name = NULL;
     s->datapath_id = 0;
-    s->mfr_desc = "Nicira Networks, Inc.";
-    s->hw_desc = "Reference Implementation";
-    s->sw_desc = VERSION BUILDNR;
-    s->serial_desc = "None";
-    s->n_listeners = 0;
+    s->mfr_desc = NULL;
+    s->hw_desc = NULL;
+    s->sw_desc = NULL;
+    s->serial_desc = NULL;
+    svec_init(&s->listeners);
     s->fail_mode = FAIL_OPEN;
-    s->max_idle = 15;
-    s->probe_interval = 15;
-    s->max_backoff = 15;
+    s->max_idle = 0;
+    s->probe_interval = 0;
+    s->max_backoff = 0;
     s->update_resolv_conf = true;
     s->rate_limit = 0;
     s->burst_limit = 0;
@@ -257,8 +355,7 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
             break;
 
         case OPT_ACCEPT_VCONN:
-            s->accept_controller_re = (optarg[0] == '^' ? optarg
-                                       : xasprintf("^%s", optarg));
+            s->accept_controller_re = optarg;
             break;
 
         case OPT_BR_NAME:
@@ -361,12 +458,7 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
             break;
 
         case 'l':
-            if (s->n_listeners >= MAX_MGMT) {
-                ofp_fatal(0,
-                          "-l or --listen may be specified at most %d times",
-                          MAX_MGMT);
-            }
-            s->listener_names[s->n_listeners++] = optarg;
+            svec_add(&s->listeners, optarg);
             break;
 
         case 'h':
index 7f2d320f44ef746410aae4b415cc4f9723d50f6e..4996bcd01abc45f56018c7a246ca6afcb7c7447b 100644 (file)
@@ -104,19 +104,17 @@ struct netflow_v5_record {
 };
 BUILD_ASSERT_DECL(sizeof(struct netflow_v5_record) == 48);
 
-#define MAX_COLLECTORS 8
-
 struct netflow {
-    const char *br_name;          /* Bridge name, for reading config file. */
     long long int boot_time;      /* Time when netflow_create() was called. */
-    int netflow_fds[MAX_COLLECTORS]; /* Sockets for NetFlow collectors. */
+    int *fds;                     /* Sockets for NetFlow collectors. */
+    size_t n_fds;                 /* Number of Netflow collectors. */
     uint32_t netflow_cnt;         /* Flow sequence number for NetFlow. */
 };
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
 static int
-udp_open(char *dst)
+open_collector(char *dst)
 {
     char *save_ptr;
     const char *host_name;
@@ -228,14 +226,10 @@ netflow_expire(struct netflow *nf, const flow_t *flow,
     nf_rec.src_mask = 0;
     nf_rec.dst_mask = 0;
 
-    for (i=0; i<MAX_COLLECTORS; i++) {
+    for (i = 0; i < nf->n_fds; i++) {
         struct msghdr msghdr;
         struct iovec iov[2];
 
-        if (nf->netflow_fds[i] == -1) {
-            break;
-        }
-
         iov[0].iov_base = &nf_hdr;
         iov[0].iov_len = sizeof nf_hdr;
         iov[1].iov_base = &nf_rec;
@@ -247,7 +241,7 @@ netflow_expire(struct netflow *nf, const flow_t *flow,
         msghdr.msg_control = NULL;
         msghdr.msg_controllen = 0;
         msghdr.msg_flags = 0;
-        if (sendmsg(nf->netflow_fds[i], &msghdr, 0) < 0) {
+        if (sendmsg(nf->fds[i], &msghdr, 0) < 0) {
             VLOG_WARN_RL(&rl, "netflow message send failed: %s",
                          strerror(errno));
         }
@@ -255,58 +249,59 @@ netflow_expire(struct netflow *nf, const flow_t *flow,
     nf->netflow_cnt++;
 }
 
-void
-netflow_reconfigure(struct netflow *nf)
+static void
+clear_collectors(struct netflow *nf)
 {
-    struct svec collectors;
-    int i, nf_idx=0;
+    size_t i;
 
-    /* Configure NetFlow collectors. */
-    for (i=0; i<MAX_COLLECTORS; i++) {
-        if (nf->netflow_fds[i] >= 0) {
-            close(nf->netflow_fds[i]);
-            nf->netflow_fds[i] = -1;
-        }
+    for (i = 0; i < nf->n_fds; i++) {
+        close(nf->fds[i]);
     }
+    free(nf->fds);
+    nf->fds = NULL;
+    nf->n_fds = 0;
+}
 
-    svec_init(&collectors);
-    cfg_get_all_keys(&collectors, "netflow.%s.host", nf->br_name);
-    svec_sort(&collectors);
-    if (!svec_is_unique(&collectors)) {
-        VLOG_WARN("%s specified twice as netflow collector",
-                  svec_get_duplicate(&collectors));
-        svec_unique(&collectors);
-    }
-
-    for (i=0; i<collectors.n; i++) {
-        if (nf_idx >= MAX_COLLECTORS) {
-            VLOG_WARN("too many netflow collectors specified, ignoring %s\n", 
-                      collectors.names[i]);
-            continue;
-        }
-
-        nf->netflow_fds[nf_idx] = udp_open(collectors.names[i]);
-        if (nf->netflow_fds[nf_idx] < 0) {
-            VLOG_WARN("couldn't open connection to collector, ignoring %s\n", 
-                      collectors.names[i]);
+int
+netflow_set_collectors(struct netflow *nf, const struct svec *collectors_)
+{
+    struct svec collectors;
+    int error = 0;
+    size_t i;
+
+    clear_collectors(nf);
+
+    svec_clone(&collectors, collectors_);
+    svec_sort_unique(&collectors);
+
+    nf->fds = xmalloc(sizeof *nf->fds * collectors.n);
+    for (i = 0; i < collectors.n; i++) {
+        const char *name = collectors.names[i];
+        char *tmpname = xstrdup(name);
+        int fd = open_collector(tmpname);
+        free(tmpname);
+        if (fd >= 0) {
+            nf->fds[nf->n_fds++] = fd;
         } else {
-            nf_idx++;
+            VLOG_WARN("couldn't open connection to collector (%s), "
+                      "ignoring %s\n", strerror(-fd), name);
+            if (!error) {
+                error = -fd;
+            }
         }
     }
+
+    svec_destroy(&collectors);
+    return error;
 }
 
 struct netflow *
-netflow_create(const char *br_name)
+netflow_create(void)
 {
-    struct netflow *nf;
-    int i;
-
-    nf = xmalloc(sizeof *nf);
-    nf->br_name = br_name;
+    struct netflow *nf = xmalloc(sizeof *nf);
     nf->boot_time = time_msec();
-    for (i = 0; i < MAX_COLLECTORS; i++) {
-        nf->netflow_fds[i] = -1;
-    }
+    nf->fds = NULL;
+    nf->n_fds = 0;
     nf->netflow_cnt = 0;
     return nf;
 }
@@ -315,15 +310,7 @@ void
 netflow_destroy(struct netflow *nf)
 {
     if (nf) {
-        int i;
-
-        /* We don't own nf->br_name. */
-        for (i = 0; i < MAX_COLLECTORS; i++) {
-            int fd = nf->netflow_fds[i];
-            if (fd >= 0) {
-                close(fd);
-            }
-        }
+        clear_collectors(nf);
         free(nf);
     }
 }
index 9c4987776fd12ae81a5e9ae732d1a34fe2b9760b..6ccca66614975512187eb4408400d3ec0f730a33 100644 (file)
 #include "flow.h"
 
 struct odp_flow_stats;
+struct svec;
 
-struct netflow *netflow_create(const char *br_name);
+struct netflow *netflow_create(void);
 void netflow_destroy(struct netflow *);
-void netflow_reconfigure(struct netflow *);
+int netflow_set_collectors(struct netflow *, const struct svec *collectors);
 void netflow_expire(struct netflow *, const flow_t *,
                     const struct odp_flow_stats *,
                     long long int created);
index 38ced4cf1bfbf15662af26ebac44c6e83adf95f4..b14556c36dfa7719c8cd2a90b86ed288bcd80498 100644 (file)
@@ -62,6 +62,7 @@
 #include "svec.h"
 #include "timeval.h"
 #include "vconn.h"
+#include "vconn-ssl.h"
 #include "xtoxll.h"
 
 #define THIS_MODULE VLM_ofproto
@@ -140,10 +141,11 @@ static void queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn);
 struct ofproto {
     /* Settings. */
     uint64_t datapath_id;       /* Datapath ID. */
-    const char *mfr_desc;       /* Manufacturer. */
-    const char *hw_desc;        /* Hardware. */
-    const char *sw_desc;        /* Software version. */
-    const char *serial_desc;    /* Serial number. */
+    uint64_t fallback_dpid;     /* Datapath ID if no better choice found. */
+    char *manufacturer;         /* Manufacturer. */
+    char *hardware;             /* Hardware. */
+    char *software;             /* Software version. */
+    char *serial;               /* Serial number. */
 
     /* Datapath. */
     struct dpif dpif;
@@ -153,6 +155,7 @@ struct ofproto {
 
     /* Configuration. */
     struct switch_status *switch_status;
+    struct status_category *ss_cat;
     struct in_band *in_band;
     struct discovery *discovery;
     struct fail_open *fail_open;
@@ -168,13 +171,14 @@ struct ofproto {
     /* OpenFlow connections. */
     struct list all_conns;
     struct ofconn *controller;
-    struct pvconn *listeners[MAX_MGMT];
+    struct pvconn **listeners;
     size_t n_listeners;
 };
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
-static uint64_t pick_datapath_id(struct dpif *);
+static uint64_t pick_datapath_id(struct dpif *, uint64_t fallback_dpid);
+static uint64_t pick_fallback_dpid(void);
 static void send_packet_in_miss(struct ofpbuf *, void *ofproto);
 static void send_packet_in_action(struct ofpbuf *, void *ofproto);
 static void update_used(struct ofproto *);
@@ -189,95 +193,69 @@ static void handle_openflow(struct ofconn *, struct ofproto *,
 
 static void refresh_port_group(struct ofproto *, unsigned int group);
 static void update_port(struct ofproto *, const char *devname);
-static void init_ports(struct ofproto *);
+static int init_ports(struct ofproto *);
 static void reinit_ports(struct ofproto *);
 
 static uint16_t odp_port_to_ofp_port(uint16_t odp_port);
 static uint16_t ofp_port_to_odp_port(uint16_t ofp_port);
 
-struct ofproto *
-ofproto_create(const struct ofsettings *settings)
+int
+ofproto_create(const char *datapath, struct ofproto **ofprotop)
 {
     struct dpifmon *dpifmon;
-    struct rconn *controller;
     struct ofproto *p;
     struct dpif dpif;
     int error;
-    size_t i;
+
+    *ofprotop = NULL;
 
     /* Connect to datapath and start listening for messages. */
-    error = dpif_open(settings->dp_name, &dpif);
+    error = dpif_open(datapath, &dpif);
     if (error) {
-        ofp_fatal(error, "Failed to open datapath %s", settings->dp_name);
+        VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error));
+        return error;
     }
     error = dpif_set_listen_mask(&dpif, ODPL_MISS | ODPL_ACTION);
     if (error) {
-        ofp_fatal(error, "failed to listen on dpif %d", dpif.minor);
+        VLOG_ERR("failed to listen on datapath %s: %s",
+                 datapath, strerror(error));
+        dpif_close(&dpif);
+        return error;
     }
 
     /* Start monitoring datapath ports for status changes. */
     error = dpifmon_create(&dpif, &dpifmon);
     if (error) {
-        ofp_fatal(error, "failed to starting monitoring dpif %d", dpif.minor);
-    }
-
-    /* Create controller connection. */
-    controller = rconn_create(settings->probe_interval, settings->max_backoff);
-    if (settings->controller_name) {
-        error = rconn_connect(controller, settings->controller_name);
-        if (error == EAFNOSUPPORT) {
-            ofp_fatal(0, "No support for %s vconn", settings->controller_name);
-        }
+        VLOG_ERR("failed to starting monitoring datapath %s: %s",
+                 datapath, strerror(error));
+        dpif_close(&dpif);
+        return error;
     }
 
     /* Initialize settings. */
     p = xcalloc(1, sizeof *p);
-    p->datapath_id = settings->datapath_id;
-    if (!p->datapath_id) {
-        p->datapath_id = pick_datapath_id(&dpif);
-    }
+    p->fallback_dpid = pick_fallback_dpid();
+    p->datapath_id = pick_datapath_id(&dpif, p->fallback_dpid);
     VLOG_INFO("using datapath ID %012"PRIx64, p->datapath_id);
-    p->mfr_desc = settings->mfr_desc;
-    p->hw_desc = settings->hw_desc;
-    p->sw_desc = settings->sw_desc;
-    p->serial_desc = settings->serial_desc;
+    p->manufacturer = xstrdup("Nicira Networks, Inc.");
+    p->hardware = xstrdup("Reference Implementation");
+    p->software = xstrdup(VERSION BUILDNR);
+    p->serial = xstrdup("None");
 
-    /* Initialize datapath information. */
+    /* Initialize datapath. */
     p->dpif = dpif;
     p->dpifmon = dpifmon;
     port_array_init(&p->ports);
     shash_init(&p->port_by_name);
 
     /* Initialize submodules. */
-    p->switch_status = switch_status_create(settings);
-    switch_status_register_category(p->switch_status, "remote",
-                                    rconn_status_cb, controller);
-    if (settings->in_band) {
-        p->in_band = in_band_create(&dpif, p->switch_status, controller);
-    }
-    if (settings->discovery) {
-        p->discovery = discovery_create(settings->accept_controller_re,
-                                        settings->update_resolv_conf, &p->dpif,
-                                        p->switch_status);
-    }
-    if (settings->fail_mode == FAIL_OPEN) {
-        p->fail_open = fail_open_create(settings->probe_interval * 3,
-                                        p->switch_status, controller);
-    }
-    if (settings->rate_limit) {
-        p->miss_sched = pinsched_create(settings->rate_limit,
-                                        settings->burst_limit,
-                                        p->switch_status);
-        p->action_sched = pinsched_create(settings->rate_limit,
-                                          settings->burst_limit, NULL);
-    }
-    if (settings->command_acl[0]) {
-        p->executer = executer_create(settings->command_acl,
-                                      settings->command_dir);
-    }
-    if (settings->br_name) {
-        p->netflow = netflow_create(settings->br_name);
-    }
+    p->switch_status = switch_status_create(p);
+    p->in_band = NULL;
+    p->discovery = NULL;
+    p->fail_open = NULL;
+    p->miss_sched = p->action_sched = NULL;
+    p->executer = NULL;
+    p->netflow = NULL;
 
     /* Initialize flow table. */
     classifier_init(&p->cls);
@@ -286,25 +264,300 @@ ofproto_create(const struct ofsettings *settings)
 
     /* Initialize OpenFlow connections. */
     list_init(&p->all_conns);
-    p->controller = ofconn_create(p, controller);
+    p->controller = ofconn_create(p, rconn_create(15, 15));
     p->controller->pktbuf = pktbuf_create();
     p->controller->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN;
+    p->listeners = NULL;
     p->n_listeners = 0;
-    for (i = 0; i < settings->n_listeners; i++) {
-        const char *name = settings->listener_names[i];
+
+    /* Register switch status category. */
+    p->ss_cat = switch_status_register(p->switch_status, "remote",
+                                       rconn_status_cb, p->controller->rconn);
+
+    /* Almost done... */
+    error = init_ports(p);
+    if (error) {
+        ofproto_destroy(p);
+        return error;
+    }
+
+    *ofprotop = p;
+    return 0;
+}
+
+void
+ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id)
+{
+    uint64_t old_dpid = p->datapath_id;
+    p->datapath_id = (datapath_id
+                      ? datapath_id
+                      : pick_datapath_id(&p->dpif, p->fallback_dpid));
+    if (p->datapath_id != old_dpid) {
+        VLOG_INFO("datapath ID changed to %012"PRIx64, p->datapath_id);
+        rconn_reconnect(p->controller->rconn);
+    }
+}
+
+void
+ofproto_set_probe_interval(struct ofproto *p, int probe_interval)
+{
+    if (probe_interval) {
+        rconn_set_probe_interval(p->controller->rconn, probe_interval);
+        if (p->fail_open) {
+            fail_open_set_trigger_duration(p->fail_open, probe_interval * 3);
+        }
+    }
+}
+
+void
+ofproto_set_max_backoff(struct ofproto *p, int max_backoff)
+{
+    if (max_backoff) {
+        rconn_set_max_backoff(p->controller->rconn, max_backoff);
+    }
+}
+
+void
+ofproto_set_desc(struct ofproto *p,
+                 const char *manufacturer, const char *hardware,
+                 const char *software, const char *serial)
+{
+    if (manufacturer) {
+        free(p->manufacturer);
+        p->manufacturer = xstrdup(manufacturer);
+    }
+    if (hardware) {
+        free(p->hardware);
+        p->hardware = xstrdup(hardware);
+    }
+    if (software) {
+        free(p->software);
+        p->software = xstrdup(software);
+    }
+    if (serial) {
+        free(p->serial);
+        p->serial = xstrdup(serial);
+    }
+}
+
+int
+ofproto_set_in_band(struct ofproto *p, bool in_band)
+{
+    if (in_band != (p->in_band != NULL)) {
+        if (in_band) {
+            return in_band_create(&p->dpif, p->switch_status,
+                                  p->controller->rconn, &p->in_band);
+        } else {
+            ofproto_set_discovery(p, false, NULL, true);
+            in_band_destroy(p->in_band);
+            p->in_band = NULL;
+        }
+        rconn_reconnect(p->controller->rconn);
+    }
+    return 0;
+}
+
+int
+ofproto_set_discovery(struct ofproto *p, bool discovery,
+                      const char *re, bool update_resolv_conf)
+{
+    if (discovery != (p->discovery != NULL)) {
+        if (discovery) {
+            int error = ofproto_set_in_band(p, true);
+            if (error) {
+                return error;
+            }
+            error = discovery_create(re, update_resolv_conf,
+                                     &p->dpif, p->switch_status,
+                                     &p->discovery);
+            if (error) {
+                return error;
+            }
+        } else {
+            discovery_destroy(p->discovery);
+            p->discovery = NULL;
+        }
+        rconn_disconnect(p->controller->rconn);
+    } else if (discovery) {
+        discovery_set_update_resolv_conf(p->discovery, update_resolv_conf);
+        return discovery_set_accept_controller_re(p->discovery, re);
+    }
+    return 0;
+}
+
+int
+ofproto_set_controller(struct ofproto *ofproto, const char *controller)
+{
+    if (ofproto->discovery) {
+        return EINVAL;
+    }
+    rconn_connect(ofproto->controller->rconn, controller);
+    return 0;
+}
+
+int
+ofproto_set_listeners(struct ofproto *ofproto, const struct svec *listeners)
+{
+    int retval = 0;
+    size_t i;
+
+    for (i = 0; i < ofproto->n_listeners; i++) {
+        pvconn_close(ofproto->listeners[i]);
+    }
+    free(ofproto->listeners);
+    ofproto->n_listeners = 0;
+
+    ofproto->listeners = xmalloc(listeners->n * sizeof *ofproto->listeners);
+    for (i = 0; i < listeners->n; i++) {
+        const char *name = listeners->names[i];
         struct pvconn *pvconn;
+        int error;
 
         error = pvconn_open(name, &pvconn);
-        if (error && error != EAGAIN) {
-            ofp_fatal(error, "opening %s", name);
+        if (!error) {
+            ofproto->listeners[ofproto->n_listeners++] = pvconn;
+        } else {
+            VLOG_ERR("failed to listen on %s: %s", name, strerror(error));
+            if (!retval) {
+                retval = error;
+            }
         }
-        p->listeners[p->n_listeners++] = pvconn;
     }
+    return retval;
+}
 
-    /* Retrieve initial port status. */
-    init_ports(p);
+int
+ofproto_set_netflow(struct ofproto *ofproto, const struct svec *collectors)
+{
+    if (collectors && collectors->n) {
+        if (!ofproto->netflow) {
+            ofproto->netflow = netflow_create();
+        }
+        return netflow_set_collectors(ofproto->netflow, collectors);
+    } else {
+        netflow_destroy(ofproto->netflow);
+        ofproto->netflow = NULL;
+        return 0;
+    }
+}
 
-    return p;
+void
+ofproto_set_failure(struct ofproto *ofproto, bool fail_open)
+{
+    if (fail_open) {
+        struct rconn *rconn = ofproto->controller->rconn;
+        int trigger_duration = rconn_get_probe_interval(rconn) * 3;
+        if (!ofproto->fail_open) {
+            ofproto->fail_open = fail_open_create(trigger_duration,
+                                                  ofproto->switch_status,
+                                                  rconn);
+        } else {
+            fail_open_set_trigger_duration(ofproto->fail_open,
+                                           trigger_duration);
+        }
+    } else {
+        fail_open_destroy(ofproto->fail_open);
+        ofproto->fail_open = NULL;
+    }
+}
+
+void
+ofproto_set_rate_limit(struct ofproto *ofproto,
+                       int rate_limit, int burst_limit)
+{
+    if (rate_limit) {
+        if (!ofproto->miss_sched) {
+            ofproto->miss_sched = pinsched_create(rate_limit, burst_limit,
+                                                  ofproto->switch_status);
+            ofproto->action_sched = pinsched_create(rate_limit, burst_limit,
+                                                    NULL);
+        } else {
+            pinsched_set_limits(ofproto->miss_sched, rate_limit, burst_limit);
+            pinsched_set_limits(ofproto->action_sched,
+                                rate_limit, burst_limit);
+        }
+    } else {
+        pinsched_destroy(ofproto->miss_sched);
+        ofproto->miss_sched = NULL;
+        pinsched_destroy(ofproto->action_sched);
+        ofproto->action_sched = NULL;
+    }
+}
+
+int
+ofproto_set_stp(struct ofproto *ofproto UNUSED, bool enable_stp)
+{
+    /* XXX */
+    if (enable_stp) {
+        VLOG_WARN("STP is not yet implemented");
+        return EINVAL;
+    } else {
+        return 0;
+    }
+}
+
+int
+ofproto_set_remote_execution(struct ofproto *ofproto, const char *command_acl,
+                             const char *command_dir)
+{
+    if (command_acl) {
+        if (!ofproto->executer) {
+            return executer_create(command_acl, command_dir,
+                                   &ofproto->executer);
+        } else {
+            executer_set_acl(ofproto->executer, command_acl, command_dir);
+        }
+    } else {
+        executer_destroy(ofproto->executer);
+        ofproto->executer = NULL;
+    }
+    return 0;
+}
+
+uint64_t
+ofproto_get_datapath_id(const struct ofproto *ofproto)
+{
+    return ofproto->datapath_id;
+}
+
+int
+ofproto_get_probe_interval(const struct ofproto *ofproto)
+{
+    return rconn_get_probe_interval(ofproto->controller->rconn);
+}
+
+int
+ofproto_get_max_backoff(const struct ofproto *ofproto)
+{
+    return rconn_get_max_backoff(ofproto->controller->rconn);
+}
+
+bool
+ofproto_get_in_band(const struct ofproto *ofproto)
+{
+    return ofproto->in_band != NULL;
+}
+
+bool
+ofproto_get_discovery(const struct ofproto *ofproto)
+{
+    return ofproto->discovery != NULL;
+}
+
+const char *
+ofproto_get_controller(const struct ofproto *ofproto)
+{
+    return rconn_get_name(ofproto->controller->rconn);
+}
+
+void
+ofproto_get_listeners(const struct ofproto *ofproto, struct svec *listeners)
+{
+    size_t i;
+
+    for (i = 0; i < ofproto->n_listeners; i++) {
+        svec_add(listeners, pvconn_get_name(ofproto->listeners[i]));
+    }
 }
 
 void
@@ -340,21 +593,16 @@ ofproto_destroy(struct ofproto *p)
     executer_destroy(p->executer);
     netflow_destroy(p->netflow);
 
+    switch_status_unregister(p->ss_cat);
+
     for (i = 0; i < p->n_listeners; i++) {
         pvconn_close(p->listeners[i]);
     }
+    free(p->listeners);
 
     free(p);
 }
 
-void
-ofproto_reconfigure(struct ofproto *p)
-{
-    if (p->netflow) {
-        netflow_reconfigure(p->netflow);
-    }
-}
-
 void
 ofproto_run(struct ofproto *p)
 {
@@ -767,7 +1015,7 @@ update_port(struct ofproto *p, const char *devname)
     refresh_port_groups(p);
 }
 
-static void
+static int
 init_ports(struct ofproto *p)
 {
     struct odp_port *ports;
@@ -777,7 +1025,7 @@ init_ports(struct ofproto *p)
 
     error = dpif_port_list(&p->dpif, &ports, &n_ports);
     if (error) {
-        ofp_fatal(error, "failed to list datapath ports");
+        return error;
     }
 
     for (i = 0; i < n_ports; i++) {
@@ -791,6 +1039,7 @@ init_ports(struct ofproto *p)
     }
     free(ports);
     refresh_port_groups(p);
+    return 0;
 }
 \f
 static struct ofconn *
@@ -1468,10 +1717,10 @@ handle_desc_stats_request(struct ofproto *p, struct ofconn *ofconn,
 
     msg = start_stats_reply(request, sizeof *ods);
     ods = append_stats_reply(sizeof *ods, ofconn, &msg);
-    strncpy(ods->mfr_desc, p->mfr_desc, sizeof ods->mfr_desc);
-    strncpy(ods->hw_desc, p->hw_desc, sizeof ods->hw_desc);
-    strncpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc);
-    strncpy(ods->serial_num, p->serial_desc, sizeof ods->serial_num);
+    strncpy(ods->mfr_desc, p->manufacturer, sizeof ods->mfr_desc);
+    strncpy(ods->hw_desc, p->hardware, sizeof ods->hw_desc);
+    strncpy(ods->sw_desc, p->software, sizeof ods->sw_desc);
+    strncpy(ods->serial_num, p->serial, sizeof ods->serial_num);
     queue_tx(msg, ofconn);
 
     return 0;
@@ -2541,7 +2790,7 @@ send_packet_in_miss(struct ofpbuf *packet, void *p_)
 }
 
 static uint64_t
-pick_datapath_id(struct dpif *dpif)
+pick_datapath_id(struct dpif *dpif, uint64_t fallback_dpid)
 {
     struct odp_port port;
     uint8_t ea[ETH_ADDR_LEN];
@@ -2559,10 +2808,16 @@ pick_datapath_id(struct dpif *dpif)
         VLOG_WARN("datapath local port query failed (%s)", strerror(error));
     }
 
+    return fallback_dpid;
+}
+
+static uint64_t
+pick_fallback_dpid(void)
+{
+    uint8_t ea[ETH_ADDR_LEN];
     eth_addr_random(ea);
     ea[0] = 0x00;               /* Set Nicira OUI. */
     ea[1] = 0x23;
     ea[2] = 0x20;
     return eth_addr_to_uint64(ea);
 }
-
index a50be0de202e8e5a535dd24f7578ccc59e3bcf0b..7a92e1c87ee4eeb101ef861b0609e5440bc56c16 100644 (file)
 
 #include <stdbool.h>
 #include <stddef.h>
+#include <stdint.h>
 #include "flow.h"
 
-/* Behavior when the connection to the controller fails. */
-enum fail_mode {
-    FAIL_OPEN,                  /* Act as learning switch. */
-    FAIL_CLOSED                 /* Drop all packets. */
-};
+struct ofproto;
+struct svec;
 
-/* Maximum number of management connection listeners. */
-#define MAX_MGMT 8
-
-/* Settings that may be configured by the user. */
-struct ofsettings {
-    /* Configuration. */
-    const char *br_name;      /* Bridge name to use for configuration lookup */
-
-    /* Overall mode of operation. */
-    bool discovery;           /* Discover the controller automatically? */
-    bool in_band;             /* Connect to controller in-band? */
-
-    /* Datapath. */
-    uint64_t datapath_id;       /* Datapath ID. */
-    const char *dp_name;        /* Name of local datapath. */
-
-    /* Description strings. */
-    const char *mfr_desc;       /* Manufacturer. */
-    const char *hw_desc;        /* Hardware. */
-    const char *sw_desc;        /* Software version. */
-    const char *serial_desc;    /* Serial number. */
-
-    /* Related vconns and network devices. */
-    const char *controller_name; /* Controller (if not discovery mode). */
-    const char *listener_names[MAX_MGMT]; /* Listen for mgmt connections. */
-    size_t n_listeners;          /* Number of mgmt connection listeners. */
-
-    /* Failure behavior. */
-    enum fail_mode fail_mode; /* Act as learning switch if no controller? */
-    int max_idle;             /* Idle time for flows in fail-open mode. */
-    int probe_interval;       /* # seconds idle before sending echo request. */
-    int max_backoff;          /* Max # seconds between connection attempts. */
-
-    /* Packet-in rate-limiting. */
-    int rate_limit;           /* Tokens added to bucket per second. */
-    int burst_limit;          /* Maximum number token bucket size. */
-
-    /* Discovery behavior. */
-    const char *accept_controller_re; /* Controller vconns to accept. */
-    bool update_resolv_conf;          /* Update /etc/resolv.conf? */
-
-    /* Spanning tree protocol. */
-    bool enable_stp;
-
-    /* Remote command execution. */
-    char *command_acl;          /* Command white/blacklist, as shell globs. */
-    char *command_dir;          /* Directory that contains commands. */
-};
-
-struct ofproto *ofproto_create(const struct ofsettings *);
+int ofproto_create(const char *datapath, struct ofproto **ofprotop);
 void ofproto_destroy(struct ofproto *);
-void ofproto_reconfigure(struct ofproto *);
 void ofproto_run(struct ofproto *);
 void ofproto_wait(struct ofproto *);
-bool ofproto_is_alive(const struct ofproto *p);
-
-int ofproto_send_packet(struct ofproto *p, const flow_t *,
+bool ofproto_is_alive(const struct ofproto *);
+
+/* Configuration. */
+void ofproto_set_datapath_id(struct ofproto *, uint64_t datapath_id);
+void ofproto_set_probe_interval(struct ofproto *, int probe_interval);
+void ofproto_set_max_backoff(struct ofproto *, int max_backoff);
+void ofproto_set_desc(struct ofproto *,
+                      const char *manufacturer, const char *hardware,
+                      const char *software, const char *serial);
+int ofproto_set_in_band(struct ofproto *, bool in_band);
+int ofproto_set_discovery(struct ofproto *, bool discovery,
+                          const char *accept_controller_re,
+                          bool update_resolv_conf);
+int ofproto_set_controller(struct ofproto *, const char *controller);
+int ofproto_set_listeners(struct ofproto *, const struct svec *listeners);
+int ofproto_set_netflow(struct ofproto *, const struct svec *collectors);
+void ofproto_set_failure(struct ofproto *, bool fail_open);
+void ofproto_set_rate_limit(struct ofproto *, int rate_limit, int burst_limit);
+int ofproto_set_stp(struct ofproto *, bool enable_stp);
+int ofproto_set_remote_execution(struct ofproto *, const char *command_acl,
+                                 const char *command_dir);
+
+/* Configuration querying. */
+uint64_t ofproto_get_datapath_id(const struct ofproto *);
+int ofproto_get_probe_interval(const struct ofproto *);
+int ofproto_get_max_backoff(const struct ofproto *);
+bool ofproto_get_in_band(const struct ofproto *);
+bool ofproto_get_discovery(const struct ofproto *);
+const char *ofproto_get_controller(const struct ofproto *);
+void ofproto_get_listeners(const struct ofproto *, struct svec *);
+
+/* Functions for use by ofproto implementation modules, not by clients. */
+int ofproto_send_packet(struct ofproto *, const flow_t *,
                         const union ofp_action *, size_t n_actions,
                         const struct ofpbuf *);
 void ofproto_setup_exact_flow(struct ofproto *, const flow_t *,
index 09843937c28c0aee6d4df7560942e30d7507ed79..ca4d5ed95930235705d09114cdb5dd88f4a3473d 100644 (file)
@@ -73,6 +73,9 @@ struct pinsched {
     unsigned long long n_limited;       /* # queued for rate limiting. */
     unsigned long long n_queue_dropped; /* # dropped due to queue overflow. */
     unsigned long long n_tx_dropped;    /* # dropped due to tx overflow. */
+
+    /* Switch status. */
+    struct status_category *ss_cat;
 };
 
 static struct ofpbuf *
@@ -250,8 +253,8 @@ pinsched_create(int rate_limit, int burst_limit, struct switch_status *ss)
     ps->n_tx_dropped = 0;
 
     if (ss) {
-        switch_status_register_category(ss, "rate-limit",
-                                        pinsched_status_cb, ps);
+        ps->ss_cat = switch_status_register(ss, "rate-limit",
+                                            pinsched_status_cb, ps);
     }
 
     return ps;
@@ -269,6 +272,17 @@ pinsched_destroy(struct pinsched *ps)
             free(queue);
         }
         port_array_destroy(&ps->queues);
+        switch_status_unregister(ps->ss_cat);
         free(ps);
     }
 }
+
+void
+pinsched_set_limits(struct pinsched *ps, int rate_limit, int burst_limit)
+{
+    ps->rate_limit = rate_limit;
+    ps->burst_limit = burst_limit;
+    while (ps->n_queued > burst_limit) {
+        drop_packet(ps);
+    }
+}
index 237d4a2d117b38ff1fe2f1743e62fe84ea245872..f67df2eb63a89771d5e735bebc415e71550b6111 100644 (file)
@@ -42,6 +42,7 @@ struct switch_status;
 typedef void pinsched_tx_cb(struct ofpbuf *, void *aux);
 struct pinsched *pinsched_create(int rate_limit, int burst_limit,
                                  struct switch_status *);
+void pinsched_set_limits(struct pinsched *, int rate_limit, int burst_limit);
 void pinsched_destroy(struct pinsched *);
 void pinsched_send(struct pinsched *, uint16_t port_no, struct ofpbuf *,
                    pinsched_tx_cb *, void *aux);
index bfe20ba27d9e2d30e52f3391f7d5ab8cb33eefac..738c6dc6a6993da055682892423938801b75044c 100644 (file)
 #include <stdlib.h>
 #include <unistd.h>
 #include "dynamic-string.h"
+#include "list.h"
 #include "ofpbuf.h"
 #include "ofproto.h"
 #include "openflow/nicira-ext.h"
 #include "rconn.h"
+#include "svec.h"
 #include "timeval.h"
 #include "vconn.h"
 
 #define THIS_MODULE VLM_status
 #include "vlog.h"
 
-struct switch_status_category {
+struct status_category {
+    struct list node;
     char *name;
     void (*cb)(struct status_reply *, void *aux);
     void *aux;
@@ -57,12 +60,13 @@ struct switch_status_category {
 
 struct switch_status {
     time_t booted;
-    struct switch_status_category *categories;
-    size_t n_categories, allocated_categories;
+    struct status_category *config_cat;
+    struct status_category *switch_cat;
+    struct list categories;
 };
 
 struct status_reply {
-    struct switch_status_category *category;
+    struct status_category *category;
     struct ds request;
     struct ds output;
 };
@@ -71,7 +75,7 @@ int
 switch_status_handle_request(struct switch_status *ss, struct rconn *rconn,
                              struct nicira_header *request)
 {
-    struct switch_status_category *c;
+    struct status_category *c;
     struct nicira_header *reply;
     struct status_reply sr;
     struct ofpbuf *b;
@@ -80,7 +84,7 @@ switch_status_handle_request(struct switch_status *ss, struct rconn *rconn,
     sr.request.string = (void *) (request + 1);
     sr.request.length = ntohs(request->header.length) - sizeof *request;
     ds_init(&sr.output);
-    for (c = ss->categories; c < &ss->categories[ss->n_categories]; c++) {
+    LIST_FOR_EACH (c, struct status_category, node, &ss->categories) {
         if (!memcmp(c->name, sr.request.string,
                     MIN(strlen(c->name), sr.request.length))) {
             sr.category = c;
@@ -125,19 +129,28 @@ rconn_status_cb(struct status_reply *sr, void *rconn_)
 }
 
 static void
-config_status_cb(struct status_reply *sr, void *s_)
+config_status_cb(struct status_reply *sr, void *ofproto_)
 {
-    const struct ofsettings *s = s_;
+    const struct ofproto *ofproto = ofproto_;
+    struct svec listeners;
+    int probe_interval, max_backoff;
     size_t i;
 
-    for (i = 0; i < s->n_listeners; i++) {
-        status_reply_put(sr, "management%zu=%s", i, s->listener_names[i]);
+    svec_init(&listeners);
+    ofproto_get_listeners(ofproto, &listeners);
+    for (i = 0; i < listeners.n; i++) {
+        status_reply_put(sr, "management%zu=%s", i, listeners.names[i]);
     }
-    if (s->probe_interval) {
-        status_reply_put(sr, "probe-interval=%d", s->probe_interval);
+    svec_destroy(&listeners);
+
+    probe_interval = ofproto_get_probe_interval(ofproto);
+    if (probe_interval) {
+        status_reply_put(sr, "probe-interval=%d", probe_interval);
     }
-    if (s->max_backoff) {
-        status_reply_put(sr, "max-backoff=%d", s->max_backoff);
+
+    max_backoff = ofproto_get_max_backoff(ofproto);
+    if (max_backoff) {
+        status_reply_put(sr, "max-backoff=%d", max_backoff);
     }
 }
 
@@ -153,13 +166,15 @@ switch_status_cb(struct status_reply *sr, void *ss_)
 }
 
 struct switch_status *
-switch_status_create(const struct ofsettings *settings)
+switch_status_create(const struct ofproto *ofproto)
 {
     struct switch_status *ss = xcalloc(1, sizeof *ss);
     ss->booted = time_now();
-    switch_status_register_category(ss, "config",
-                                    config_status_cb, (void *) settings);
-    switch_status_register_category(ss, "switch", switch_status_cb, ss);
+    list_init(&ss->categories);
+    ss->config_cat = switch_status_register(ss, "config", config_status_cb,
+                                            (void *) ofproto);
+    ss->switch_cat = switch_status_register(ss, "switch", switch_status_cb,
+                                            ss);
     return ss;
 }
 
@@ -167,26 +182,41 @@ void
 switch_status_destroy(struct switch_status *ss)
 {
     if (ss) {
-        free(ss->categories);
+        /* Orphan any remaining categories, so that unregistering them later
+         * won't write to bad memory. */
+        struct status_category *c;
+        LIST_FOR_EACH (c, struct status_category, node, &ss->categories) {
+            list_init(&c->node);
+        }
+        switch_status_unregister(ss->config_cat);
+        switch_status_unregister(ss->switch_cat);
         free(ss);
     }
 }
 
-void
-switch_status_register_category(struct switch_status *ss,
-                                const char *category,
-                                void (*cb)(struct status_reply *, void *aux),
-                                void *aux)
+struct status_category *
+switch_status_register(struct switch_status *ss,
+                       const char *category,
+                       status_cb_func *cb, void *aux)
 {
-    struct switch_status_category *c;
-    if (ss->n_categories >= ss->allocated_categories) {
-        ss->categories = x2nrealloc(ss->categories, &ss->allocated_categories,
-                                    sizeof *ss->categories);
-    }
-    c = &ss->categories[ss->n_categories++];
+    struct status_category *c = xmalloc(sizeof *c);
     c->cb = cb;
     c->aux = aux;
     c->name = xstrdup(category);
+    list_push_back(&ss->categories, &c->node);
+    return c;
+}
+
+void
+switch_status_unregister(struct status_category *c)
+{
+    if (c) {
+        if (!list_is_empty(&c->node)) {
+            list_remove(&c->node);
+        }
+        free(c->name);
+        free(c);
+    }
 }
 
 void
index da879be7fa9aba6c52f470dad17ec2b7c5f58a74..918a881e365fd13ac0ef463dd565b31e40460eae 100644 (file)
 struct nicira_header;
 struct rconn;
 struct secchan;
-struct ofsettings;
+struct ofproto;
 struct status_reply;
 
-struct switch_status *switch_status_create(const struct ofsettings *);
+struct switch_status *switch_status_create(const struct ofproto *);
 void switch_status_destroy(struct switch_status *);
 
 int switch_status_handle_request(struct switch_status *, struct rconn *,
                                  struct nicira_header *);
 
-void switch_status_register_category(struct switch_status *,
-                                     const char *category,
-                                     void (*cb)(struct status_reply *,
-                                                void *aux),
-                                     void *aux);
+typedef void status_cb_func(struct status_reply *, void *aux);
+struct status_category *switch_status_register(struct switch_status *,
+                                               const char *category,
+                                               status_cb_func *, void *aux);
+void switch_status_unregister(struct status_category *);
 
 void status_reply_put(struct status_reply *, const char *, ...)
     PRINTF_FORMAT(2, 3);