status_reply_put(sr, "max-idle=%d", s->max_idle);
}
-struct hook
-fail_open_hook_create(const struct settings *s, struct switch_status *ss,
- struct rconn *local_rconn, struct rconn *remote_rconn)
+static struct hook_class fail_open_hook_class = {
+ fail_open_local_packet_cb, /* local_packet_cb */
+ NULL, /* remote_packet_cb */
+ fail_open_periodic_cb, /* periodic_cb */
+ fail_open_wait_cb, /* wait_cb */
+ NULL, /* closing_cb */
+};
+
+void
+fail_open_start(struct secchan *secchan, const struct settings *s,
+ struct switch_status *ss,
+ struct rconn *local_rconn, struct rconn *remote_rconn)
{
struct fail_open_data *fail_open = xmalloc(sizeof *fail_open);
fail_open->s = s;
}
switch_status_register_category(ss, "fail-open",
fail_open_status_cb, fail_open);
- return make_hook(fail_open_local_packet_cb, NULL,
- fail_open_periodic_cb, fail_open_wait_cb, fail_open);
+ add_hook(secchan, &fail_open_hook_class, fail_open);
}
#ifndef FAIL_OPEN_H
#define FAIL_OPEN_H 1
+struct rconn;
+struct secchan;
struct settings;
struct switch_status;
-struct rconn;
-struct hook fail_open_hook_create(const struct settings *,
- struct switch_status *,
- struct rconn *local,
- struct rconn *remote);
+void fail_open_start(struct secchan *, const struct settings *,
+ struct switch_status *,
+ struct rconn *local, struct rconn *remote);
#endif /* fail-open.h */
}
}
-struct hook
-in_band_hook_create(const struct settings *s, struct switch_status *ss,
- struct port_watcher *pw, struct rconn *remote)
+static struct hook_class in_band_hook_class = {
+ in_band_local_packet_cb, /* local_packet_cb */
+ NULL, /* remote_packet_cb */
+ NULL, /* periodic_cb */
+ NULL, /* wait_cb */
+ NULL, /* closing_cb */
+};
+
+void
+in_band_start(struct secchan *secchan,
+ const struct settings *s, struct switch_status *ss,
+ struct port_watcher *pw, struct rconn *remote)
{
struct in_band_data *in_band;
switch_status_register_category(ss, "in-band", in_band_status_cb, in_band);
port_watcher_register_local_port_callback(pw, in_band_local_port_cb,
in_band);
- return make_hook(in_band_local_packet_cb, NULL, NULL, NULL, in_band);
+ add_hook(secchan, &in_band_hook_class, in_band);
}
struct port_watcher;
struct rconn;
+struct secchan;
struct settings;
struct switch_status;
-struct hook in_band_hook_create(const struct settings *,
- struct switch_status *,
- struct port_watcher *,
- struct rconn *remote);
+void in_band_start(struct secchan *, const struct settings *,
+ struct switch_status *, struct port_watcher *,
+ struct rconn *remote);
#endif /* in-band.h */
return pw->got_feature_reply;
}
-struct hook
-port_watcher_create(struct rconn *local_rconn, struct rconn *remote_rconn,
- struct port_watcher **pwp)
+static struct hook_class port_watcher_hook_class = {
+ port_watcher_local_packet_cb, /* local_packet_cb */
+ port_watcher_remote_packet_cb, /* remote_packet_cb */
+ port_watcher_periodic_cb, /* periodic_cb */
+ port_watcher_wait_cb, /* wait_cb */
+ NULL, /* closing_cb */
+};
+
+void
+port_watcher_start(struct secchan *secchan,
+ struct rconn *local_rconn, struct rconn *remote_rconn,
+ struct port_watcher **pwp)
{
struct port_watcher *pw;
port_array_init(&pw->ports);
pw->local_port_name[0] = '\0';
port_watcher_register_callback(pw, log_port_status, NULL);
- return make_hook(port_watcher_local_packet_cb,
- port_watcher_remote_packet_cb,
- port_watcher_periodic_cb,
- port_watcher_wait_cb, pw);
+ add_hook(secchan, &port_watcher_hook_class, pw);
}
struct ofp_phy_port;
struct port_watcher;
+struct secchan;
-struct hook port_watcher_create(struct rconn *local,
- struct rconn *remote,
- struct port_watcher **);
+void port_watcher_start(struct secchan *,
+ struct rconn *local, struct rconn *remote,
+ struct port_watcher **);
bool port_watcher_is_ready(const struct port_watcher *);
uint32_t port_watcher_get_config(const struct port_watcher *,
uint16_t port_no);
}
}
-struct hook
-rate_limit_hook_create(const struct settings *s, struct switch_status *ss,
- struct rconn *local, struct rconn *remote)
+static struct hook_class rate_limit_hook_class = {
+ rate_limit_local_packet_cb, /* local_packet_cb */
+ NULL, /* remote_packet_cb */
+ rate_limit_periodic_cb, /* periodic_cb */
+ rate_limit_wait_cb, /* wait_cb */
+ NULL, /* closing_cb */
+};
+
+void
+rate_limit_start(struct secchan *secchan, const struct settings *s,
+ struct switch_status *ss,
+ struct rconn *local, struct rconn *remote)
{
struct rate_limiter *rl;
size_t i;
rl->tokens = s->rate_limit * 100;
switch_status_register_category(ss, "rate-limit",
rate_limit_status_cb, rl);
- return make_hook(rate_limit_local_packet_cb, NULL, rate_limit_periodic_cb,
- rate_limit_wait_cb, rl);
+ add_hook(secchan, &rate_limit_hook_class, rl);
}
#define RATELIMIT_H 1
struct rconn;
+struct secchan;
struct settings;
struct switch_status;
-struct hook rate_limit_hook_create(const struct settings *,
- struct switch_status *,
- struct rconn *local,
- struct rconn *remote);
+void rate_limit_start(struct secchan *, const struct settings *,
+ struct switch_status *,
+ struct rconn *local, struct rconn *remote);
#endif /* ratelimit.h */
#include "vlog.h"
#define THIS_MODULE VLM_secchan
+struct hook {
+ const struct hook_class *class;
+ void *aux;
+};
+
+struct secchan {
+ struct hook *hooks;
+ size_t n_hooks, allocated_hooks;
+};
+
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
static void parse_options(int argc, char *argv[], struct settings *);
static struct relay *relay_create(struct rconn *local, struct rconn *remote,
bool is_mgmt_conn);
static struct relay *relay_accept(const struct settings *, struct pvconn *);
-static void relay_run(struct relay *, const struct hook[], size_t n_hooks);
+static void relay_run(struct relay *, struct secchan *);
static void relay_wait(struct relay *);
static void relay_destroy(struct relay *);
struct list relays = LIST_INITIALIZER(&relays);
- struct hook hooks[8];
- size_t n_hooks = 0;
+ struct secchan secchan;
struct pvconn *monitor;
parse_options(argc, argv, &s);
signal(SIGPIPE, SIG_IGN);
+ secchan.hooks = NULL;
+ secchan.n_hooks = 0;
+ secchan.allocated_hooks = 0;
+
/* Start listening for management and monitoring connections. */
n_listeners = 0;
for (i = 0; i < s.n_listeners; i++) {
monitor = s.monitor_name ? open_passive_vconn(s.monitor_name) : NULL;
/* Initialize switch status hook. */
- hooks[n_hooks++] = switch_status_hook_create(&s, &switch_status);
+ switch_status_start(&secchan, &s, &switch_status);
/* Start listening for vlogconf requests. */
retval = vlog_server_listen(NULL, NULL);
list_push_back(&relays, &controller_relay->node);
/* Set up hooks. */
- hooks[n_hooks++] = port_watcher_create(local_rconn, remote_rconn, &pw);
+ port_watcher_start(&secchan, local_rconn, remote_rconn, &pw);
discovery = s.discovery ? discovery_init(&s, pw, switch_status) : NULL;
#ifdef SUPPORT_SNAT
- hooks[n_hooks++] = snat_hook_create(pw);
+ snat_start(&secchan, pw);
#endif
if (s.enable_stp) {
- hooks[n_hooks++] = stp_hook_create(&s, pw, local_rconn, remote_rconn);
+ stp_start(&secchan, &s, pw, local_rconn, remote_rconn);
}
if (s.in_band) {
- hooks[n_hooks++] = in_band_hook_create(&s, switch_status, pw,
- remote_rconn);
+ in_band_start(&secchan, &s, switch_status, pw, remote_rconn);
}
if (s.fail_mode == FAIL_OPEN) {
- hooks[n_hooks++] = fail_open_hook_create(&s, switch_status,
- local_rconn, remote_rconn);
+ fail_open_start(&secchan, &s, switch_status,
+ local_rconn, remote_rconn);
}
if (s.rate_limit) {
- hooks[n_hooks++] = rate_limit_hook_create(&s, switch_status,
- local_rconn, remote_rconn);
+ rate_limit_start(&secchan, &s, switch_status,
+ local_rconn, remote_rconn);
}
- assert(n_hooks <= ARRAY_SIZE(hooks));
for (;;) {
struct relay *r, *n;
/* Do work. */
LIST_FOR_EACH_SAFE (r, n, struct relay, node, &relays) {
- relay_run(r, hooks, n_hooks);
+ relay_run(r, &secchan);
}
for (i = 0; i < n_listeners; i++) {
for (;;) {
rconn_add_monitor(local_rconn, new);
}
}
- for (i = 0; i < n_hooks; i++) {
- if (hooks[i].periodic_cb) {
- hooks[i].periodic_cb(hooks[i].aux);
+ for (i = 0; i < secchan.n_hooks; i++) {
+ if (secchan.hooks[i].class->periodic_cb) {
+ secchan.hooks[i].class->periodic_cb(secchan.hooks[i].aux);
}
}
if (s.discovery) {
if (monitor) {
pvconn_wait(monitor);
}
- for (i = 0; i < n_hooks; i++) {
- if (hooks[i].wait_cb) {
- hooks[i].wait_cb(hooks[i].aux);
+ for (i = 0; i < secchan.n_hooks; i++) {
+ if (secchan.hooks[i].class->wait_cb) {
+ secchan.hooks[i].class->wait_cb(secchan.hooks[i].aux);
}
}
if (discovery) {
return new;
}
-struct hook
-make_hook(bool (*local_packet_cb)(struct relay *, void *aux),
- bool (*remote_packet_cb)(struct relay *, void *aux),
- void (*periodic_cb)(void *aux),
- void (*wait_cb)(void *aux),
- void *aux)
+void
+add_hook(struct secchan *secchan, const struct hook_class *class, void *aux)
{
- struct hook h;
- h.packet_cb[HALF_LOCAL] = local_packet_cb;
- h.packet_cb[HALF_REMOTE] = remote_packet_cb;
- h.periodic_cb = periodic_cb;
- h.wait_cb = wait_cb;
- h.aux = aux;
- return h;
+ struct hook *hook;
+
+ if (secchan->n_hooks >= secchan->allocated_hooks) {
+ secchan->allocated_hooks = secchan->allocated_hooks * 2 + 1;
+ secchan->hooks = xrealloc(secchan->hooks,
+ (sizeof *secchan->hooks
+ * secchan->allocated_hooks));
+ }
+ hook = &secchan->hooks[secchan->n_hooks++];
+ hook->class = class;
+ hook->aux = aux;
}
struct ofp_packet_in *
return r;
}
+static bool
+call_local_packet_cbs(struct secchan *secchan, struct relay *r)
+{
+ const struct hook *h;
+ for (h = secchan->hooks; h < &secchan->hooks[secchan->n_hooks]; h++) {
+ bool (*cb)(struct relay *, void *aux) = h->class->local_packet_cb;
+ if (cb && (cb)(r, h->aux)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool
+call_remote_packet_cbs(struct secchan *secchan, struct relay *r)
+{
+ const struct hook *h;
+ for (h = secchan->hooks; h < &secchan->hooks[secchan->n_hooks]; h++) {
+ bool (*cb)(struct relay *, void *aux) = h->class->remote_packet_cb;
+ if (cb && (cb)(r, h->aux)) {
+ return true;
+ }
+ }
+ return false;
+}
+
static void
-relay_run(struct relay *r, const struct hook hooks[], size_t n_hooks)
+relay_run(struct relay *r, struct secchan *secchan)
{
int iteration;
int i;
if (!this->rxbuf) {
this->rxbuf = rconn_recv(this->rconn);
if (this->rxbuf && (i == HALF_REMOTE || !r->is_mgmt_conn)) {
- const struct hook *h;
- for (h = hooks; h < &hooks[n_hooks]; h++) {
- if (h->packet_cb[i] && h->packet_cb[i](r, h->aux)) {
- ofpbuf_delete(this->rxbuf);
- this->rxbuf = NULL;
- progress = true;
- break;
- }
+ if (i == HALF_LOCAL
+ ? call_local_packet_cbs(secchan, r)
+ : call_remote_packet_cbs(secchan, r))
+ {
+ ofpbuf_delete(this->rxbuf);
+ this->rxbuf = NULL;
+ progress = true;
+ break;
}
}
}
#include "list.h"
#include "packets.h"
+struct secchan;
+
/* Behavior when the connection to the controller fails. */
enum fail_mode {
FAIL_OPEN, /* Act as learning switch. */
bool is_mgmt_conn;
};
-struct hook {
- bool (*packet_cb[2])(struct relay *, void *aux);
+struct hook_class {
+ bool (*local_packet_cb)(struct relay *, void *aux);
+ bool (*remote_packet_cb)(struct relay *, void *aux);
void (*periodic_cb)(void *aux);
void (*wait_cb)(void *aux);
- void *aux;
+ void (*closing_cb)(struct relay *, void *aux);
};
-struct hook make_hook(bool (*local_packet_cb)(struct relay *, void *),
- bool (*remote_packet_cb)(struct relay *, void *),
- void (*periodic_cb)(void *),
- void (*wait_cb)(void *),
- void *aux);
+void add_hook(struct secchan *, const struct hook_class *, void *);
+
struct ofp_packet_in *get_ofp_packet_in(struct relay *);
bool get_ofp_packet_eth_header(struct relay *, struct ofp_packet_in **,
struct eth_header **);
}
}
-struct hook
-snat_hook_create(struct port_watcher *pw)
+static struct hook_class snat_hook_class = {
+ NULL, /* local_packet_cb */
+ snat_remote_packet_cb, /* remote_packet_cb */
+ NULL, /* periodic_cb */
+ NULL, /* wait_cb */
+ NULL, /* closing_cb */
+};
+
+void
+snat_start(struct secchan *secchan, struct port_watcher *pw)
{
int ret;
struct snat_data *snat;
list_init(&snat->port_list);
port_watcher_register_callback(pw, snat_port_changed_cb, snat);
- return make_hook(NULL, snat_remote_packet_cb, NULL, NULL, snat);
+ add_hook(secchan, &snat_hook_class, snat);
}
#include "secchan.h"
struct port_watcher;
+struct secchan;
-struct hook snat_hook_create(struct port_watcher *pw);
+void snat_start(struct secchan *, struct port_watcher *);
#endif /* snat.h */
status_reply_put(sr, "pid=%ld", (long int) getpid());
}
-struct hook
-switch_status_hook_create(const struct settings *s, struct switch_status **ssp)
+static struct hook_class switch_status_hook_class = {
+ NULL, /* local_packet_cb */
+ switch_status_remote_packet_cb, /* remote_packet_cb */
+ NULL, /* periodic_cb */
+ NULL, /* wait_cb */
+ NULL, /* closing_cb */
+};
+
+void
+switch_status_start(struct secchan *secchan, const struct settings *s,
+ struct switch_status **ssp)
{
struct switch_status *ss = xcalloc(1, sizeof *ss);
ss->s = s;
config_status_cb, (void *) s);
switch_status_register_category(ss, "switch", switch_status_cb, ss);
*ssp = ss;
- return make_hook(NULL, switch_status_remote_packet_cb, NULL, NULL, ss);
+ add_hook(secchan, &switch_status_hook_class, ss);
}
void
#include "secchan.h"
-struct switch_status;
+struct secchan;
struct status_reply;
+struct switch_status;
-struct hook switch_status_hook_create(const struct settings *,
- struct switch_status **);
+void switch_status_start(struct secchan *, const struct settings *,
+ struct switch_status **);
void switch_status_register_category(struct switch_status *,
const char *category,
void (*cb)(struct status_reply *,
}
}
-struct hook
-stp_hook_create(const struct settings *s, struct port_watcher *pw,
- struct rconn *local, struct rconn *remote)
+static struct hook_class stp_hook_class = {
+ stp_local_packet_cb, /* local_packet_cb */
+ NULL, /* remote_packet_cb */
+ stp_periodic_cb, /* periodic_cb */
+ stp_wait_cb, /* wait_cb */
+ NULL, /* closing_cb */
+};
+
+void
+stp_start(struct secchan *secchan, const struct settings *s,
+ struct port_watcher *pw,
+ struct rconn *local, struct rconn *remote)
{
uint8_t dpid[ETH_ADDR_LEN];
struct stp_data *stp;
port_watcher_register_callback(pw, stp_port_changed_cb, stp);
port_watcher_register_local_port_callback(pw, stp_local_port_changed_cb,
stp);
- return make_hook(stp_local_packet_cb, NULL,
- stp_periodic_cb, stp_wait_cb, stp);
+ add_hook(secchan, &stp_hook_class, stp);
}
struct port_watcher;
struct rconn;
+struct secchan;
struct settings;
-struct hook stp_hook_create(const struct settings *s, struct port_watcher *pw,
- struct rconn *local, struct rconn *remote);
+void stp_start(struct secchan *, const struct settings *,
+ struct port_watcher *,
+ struct rconn *local, struct rconn *remote);
#endif /* stp-secchan.h */