#include "poll-loop.h"
#include "port-array.h"
#include "process.h"
-#include "rconn.h"
#include "secchan/ofproto.h"
#include "socket-util.h"
#include "stp.h"
struct bridge {
struct list node; /* Node in global list of bridges. */
char *name; /* User-specified arbitrary name. */
- struct rconn_packet_counter *txqlen; /* # queued to send on 'rconn'. */
struct mac_learning *ml; /* MAC learning table, or null not to learn. */
int flow_idle_time; /* Idle time for flows we set up. */
bool sent_config_request; /* Successfully sent config request? */
/* OpenFlow switch processing. */
struct ofproto *ofproto; /* OpenFlow switch. */
- struct rconn *rconn; /* Connection to switch. */
/* Kernel datapath information. */
struct dpif dpif; /* Kernel datapath. */
static int bridge_run_one(struct bridge *);
static void bridge_reconfigure_one(struct bridge *);
static void bridge_get_all_ifaces(const struct bridge *, struct svec *ifaces);
-static bool bridge_is_backlogged(const struct bridge *);
static void bridge_fetch_dp_ifaces(struct bridge *);
static void bridge_flush(struct bridge *);
static void bridge_pick_local_hw_addr(struct bridge *,
struct iface *local_iface);
-static void bridge_process_msg(struct bridge *, struct ofpbuf *);
static void revalidate_flow(struct bridge *, struct ft_flow *);
static void flowstats_run(struct bridge *);
continue;
}
- rconn_run_wait(br->rconn);
- if (!bridge_is_backlogged(br)) {
- rconn_recv_wait(br->rconn);
- }
if (br->ml) {
mac_learning_wait(br->ml);
}
}
br->name = xstrdup(name);
- br->txqlen = rconn_packet_counter_create();
br->ml = mac_learning_create();
br->flow_idle_time = 5;
br->sent_config_request = false;
eth_addr_random(br->default_ea);
- br->rconn = rconn_create(30, 1);
-
port_array_init(&br->ifaces);
br->ft = ft_create();
return br;
}
-static void
-connect_ofproto(struct bridge *br)
-{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- int sockets[2];
- int i;
-
- if (ofproto_is_alive(br->ofproto)) {
- return;
- }
-
- VLOG_INFO_RL(&rl, "%s: connecting to internal OpenFlow switch", br->name);
- if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets)) {
- VLOG_ERR("%s: failed to create socket pair: %s",
- br->name, strerror(errno));
- /* XXX need to wait before trying again */
- return;
- }
-
- /* Connect the ofproto to one end of the socketpair, and ourselves to the
- * other end. */
- for (i = 0; i < 2; i++) {
- char *name = xasprintf("fd:%d", sockets[i]);
- set_nonblocking(sockets[i]);
- if (i) {
- ofproto_set_controller(br->ofproto, name);
- } else {
- rconn_connect(br->rconn, name);
- }
- free(name);
- }
-}
-
static void
bridge_destroy(struct bridge *br)
{
}
dpif_close(&br->dpif);
ofproto_destroy(br->ofproto);
- rconn_destroy(br->rconn);
- rconn_packet_counter_destroy(br->txqlen);
free(br->controller);
ft_destroy(br->ft);
mac_learning_destroy(br->ml);
return retval;
}
-static void
-send_set_config_request(struct bridge *br)
-{
- struct ofp_switch_config *osc;
- struct ofpbuf *msg;
-
- osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &msg);
- osc->flags = htons(OFPC_SEND_FLOW_EXP | OFPC_FRAG_NORMAL);
- osc->miss_send_len = htons(OFP_DEFAULT_MISS_SEND_LEN);
- if (!rconn_send_with_limit(br->rconn, msg, br->txqlen, INT_MAX)) {
- br->sent_config_request = true;
- }
-}
-
static int
bridge_run_one(struct bridge *br)
{
- int iteration;
int error;
if (br->controller) {
return ofproto_run(br->ofproto);
}
- rconn_run(br->rconn);
-
- if (rconn_is_connected(br->rconn)) {
- if (!br->sent_config_request) {
- send_set_config_request(br);
- }
- }
-
/* Now do the things that may want to revalidate flows. */
- for (iteration = 0; iteration < 50 && !bridge_is_backlogged(br);
- iteration++) {
- struct ofpbuf *msg = rconn_recv(br->rconn);
- if (!msg) {
- break;
- }
-
- bridge_process_msg(br, msg);
- ofpbuf_delete(msg);
- }
+ error = ofproto_run(br->ofproto);
hmap_shrink(&br->ft->flows);
if (br->ml) {
mac_learning_run(br->ml, &br->revalidate_set);
bond_run(br);
brstp_run(br);
- /* Start or restart switch if necessary. */
- connect_ofproto(br);
- error = ofproto_run(br->ofproto);
-
/* Now revalidate any flows that need it. */
if (br->flush || !tag_set_is_empty(&br->revalidate_set)) {
struct ft_flow *f, *next;
assert(svec_is_unique(ifaces));
}
-static bool
-bridge_is_backlogged(const struct bridge *br)
-{
- return br->txqlen->n >= 100;
-}
-
/* For robustness, in case the administrator moves around datapath ports behind
* our back, we re-check all the datapath port numbers here. */
static void
\f
/* Bridge packet processing functions. */
-typedef void packet_handler_func(struct bridge *, void *);
-static packet_handler_func process_echo_request;
-
-static void
-bridge_process_msg(struct bridge *br, struct ofpbuf *msg)
-{
- struct ofp_header *oh = msg->data;
- switch (oh->type) {
- case OFPT_ECHO_REQUEST:
- process_echo_request(br, msg->data);
- break;
- default:
- if (VLOG_IS_DBG_ENABLED()) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
- char *p = ofp_to_string(msg->data, msg->size, 2);
- VLOG_DBG_RL(&rl, "bridge %s: OpenFlow packet ignored: %s",
- br->name, p);
- free(p);
- }
- break;
- }
-}
-
-static void
-queue_tx(struct bridge *br, struct ofpbuf *msg)
-{
- int retval;
- update_openflow_length(msg);
- retval = rconn_send(br->rconn, msg, br->txqlen);
- if (retval) {
- ofpbuf_delete(msg);
- /* No point in logging: rconn_send() only fails due to disconnection,
- * and disconnecting from the switch will cause all kinds of log
- * messages anyhow. */
- }
-}
-
static struct bond_entry *
lookup_bond_entry(const struct port *port, const uint8_t mac[ETH_ADDR_LEN])
{
process_flow(br, &f->flow, NULL);
}
-static void
-process_echo_request(struct bridge *br, void *rq_)
-{
- struct ofp_header *rq = rq_;
- queue_tx(br, make_echo_reply(rq));
-}
-
/* Careful: 'opp' is in host byte order and opp->port_no is an OFP port
* number. */
static void
static void
flowstats_run(struct bridge *br)
{
- if (rconn_is_connected(br->rconn)
- && time_now() >= br->next_stats_request) {
+ if (time_now() >= br->next_stats_request) {
request_flow_stats(br);
br->next_stats_request = time_now() + 10;
}
static void
flowstats_wait(struct bridge *br)
{
- if (rconn_is_connected(br->rconn)) {
- poll_timer_wait((br->next_stats_request - time_now()) * 1000);
- }
+ poll_timer_wait((br->next_stats_request - time_now()) * 1000);
}
\f
/* Port functions. */