From de5caa49061db0555813c9354029128d07960935 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Fri, 24 Oct 2008 14:25:10 -0700 Subject: [PATCH] Change the secchan "hook" mechanism to be easier to add new callbacks. --- secchan/fail-open.c | 18 ++++-- secchan/fail-open.h | 10 ++-- secchan/in-band.c | 17 ++++-- secchan/in-band.h | 8 +-- secchan/port-watcher.c | 20 ++++--- secchan/port-watcher.h | 7 ++- secchan/ratelimit.c | 18 ++++-- secchan/ratelimit.h | 8 +-- secchan/secchan.c | 123 +++++++++++++++++++++++++++-------------- secchan/secchan.h | 16 +++--- secchan/snat.c | 14 ++++- secchan/snat.h | 3 +- secchan/status.c | 15 ++++- secchan/status.h | 7 ++- secchan/stp-secchan.c | 18 ++++-- secchan/stp-secchan.h | 6 +- 16 files changed, 203 insertions(+), 105 deletions(-) diff --git a/secchan/fail-open.c b/secchan/fail-open.c index 8440efaaf..06e1c31ee 100644 --- a/secchan/fail-open.c +++ b/secchan/fail-open.c @@ -131,9 +131,18 @@ fail_open_status_cb(struct status_reply *sr, void *fail_open_) 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; @@ -146,6 +155,5 @@ fail_open_hook_create(const struct settings *s, struct switch_status *ss, } 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); } diff --git a/secchan/fail-open.h b/secchan/fail-open.h index ed69c8855..69a3b3102 100644 --- a/secchan/fail-open.h +++ b/secchan/fail-open.h @@ -34,13 +34,13 @@ #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 */ diff --git a/secchan/in-band.c b/secchan/in-band.c index 141f23516..e925fa562 100644 --- a/secchan/in-band.c +++ b/secchan/in-band.c @@ -284,9 +284,18 @@ in_band_local_port_cb(const struct ofp_phy_port *port, void *in_band_) } } -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; @@ -298,5 +307,5 @@ in_band_hook_create(const struct settings *s, struct switch_status *ss, 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); } diff --git a/secchan/in-band.h b/secchan/in-band.h index 573914e9c..b4d21ab9f 100644 --- a/secchan/in-band.h +++ b/secchan/in-band.h @@ -36,12 +36,12 @@ 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 */ diff --git a/secchan/port-watcher.c b/secchan/port-watcher.c index 33f420557..8ab8ded82 100644 --- a/secchan/port-watcher.c +++ b/secchan/port-watcher.c @@ -475,9 +475,18 @@ port_watcher_is_ready(const struct port_watcher *pw) 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; @@ -488,8 +497,5 @@ port_watcher_create(struct rconn *local_rconn, struct rconn *remote_rconn, 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); } diff --git a/secchan/port-watcher.h b/secchan/port-watcher.h index e5758bb60..904e545a8 100644 --- a/secchan/port-watcher.h +++ b/secchan/port-watcher.h @@ -40,10 +40,11 @@ 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); diff --git a/secchan/ratelimit.c b/secchan/ratelimit.c index ee25f16b5..5f0da2df6 100644 --- a/secchan/ratelimit.c +++ b/secchan/ratelimit.c @@ -227,9 +227,18 @@ rate_limit_wait_cb(void *rl_) } } -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; @@ -244,6 +253,5 @@ rate_limit_hook_create(const struct settings *s, struct switch_status *ss, 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); } diff --git a/secchan/ratelimit.h b/secchan/ratelimit.h index e3a3f8f5f..e29125451 100644 --- a/secchan/ratelimit.h +++ b/secchan/ratelimit.h @@ -35,12 +35,12 @@ #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 */ diff --git a/secchan/secchan.c b/secchan/secchan.c index e40183f28..1d28eaae6 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -70,6 +70,16 @@ #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 *); @@ -81,7 +91,7 @@ static struct vconn *accept_vconn(struct pvconn *pvconn); 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 *); @@ -92,8 +102,7 @@ main(int argc, char *argv[]) struct list relays = LIST_INITIALIZER(&relays); - struct hook hooks[8]; - size_t n_hooks = 0; + struct secchan secchan; struct pvconn *monitor; @@ -115,6 +124,10 @@ main(int argc, char *argv[]) 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++) { @@ -123,7 +136,7 @@ main(int argc, char *argv[]) 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); @@ -159,27 +172,25 @@ main(int argc, char *argv[]) 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; @@ -187,7 +198,7 @@ main(int argc, char *argv[]) /* 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 (;;) { @@ -204,9 +215,9 @@ main(int argc, char *argv[]) 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) { @@ -233,9 +244,9 @@ main(int argc, char *argv[]) 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) { @@ -273,20 +284,20 @@ accept_vconn(struct pvconn *pvconn) 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 * @@ -381,8 +392,34 @@ relay_create(struct rconn *local, struct rconn *remote, bool is_mgmt_conn) 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; @@ -401,14 +438,14 @@ relay_run(struct relay *r, const struct hook hooks[], size_t n_hooks) 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; } } } diff --git a/secchan/secchan.h b/secchan/secchan.h index 0345fa3fc..0a398adc5 100644 --- a/secchan/secchan.h +++ b/secchan/secchan.h @@ -40,6 +40,8 @@ #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. */ @@ -97,18 +99,16 @@ struct relay { 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 **); diff --git a/secchan/snat.c b/secchan/snat.c index 1869887ef..9d7306c4f 100644 --- a/secchan/snat.c +++ b/secchan/snat.c @@ -265,8 +265,16 @@ snat_port_changed_cb(uint16_t port_no, } } -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; @@ -281,5 +289,5 @@ snat_hook_create(struct port_watcher *pw) 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); } diff --git a/secchan/snat.h b/secchan/snat.h index 935b3223d..8f71b151c 100644 --- a/secchan/snat.h +++ b/secchan/snat.h @@ -37,7 +37,8 @@ #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 */ diff --git a/secchan/status.c b/secchan/status.c index 99c22aa0b..be4f86bf9 100644 --- a/secchan/status.c +++ b/secchan/status.c @@ -165,8 +165,17 @@ switch_status_cb(struct status_reply *sr, void *ss_) 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; @@ -175,7 +184,7 @@ switch_status_hook_create(const struct settings *s, struct switch_status **ssp) 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 diff --git a/secchan/status.h b/secchan/status.h index 14bffa675..68793effd 100644 --- a/secchan/status.h +++ b/secchan/status.h @@ -36,11 +36,12 @@ #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 *, diff --git a/secchan/stp-secchan.c b/secchan/stp-secchan.c index de3e1b782..306f05fba 100644 --- a/secchan/stp-secchan.c +++ b/secchan/stp-secchan.c @@ -286,9 +286,18 @@ stp_local_port_changed_cb(const struct ofp_phy_port *port, void *stp_) } } -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; @@ -304,6 +313,5 @@ stp_hook_create(const struct settings *s, struct port_watcher *pw, 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); } diff --git a/secchan/stp-secchan.h b/secchan/stp-secchan.h index 98a7a4ddd..ac4076f4a 100644 --- a/secchan/stp-secchan.h +++ b/secchan/stp-secchan.h @@ -40,9 +40,11 @@ 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 */ -- 2.45.2