#include "packets.h"
#include "poll-loop.h"
#include "rconn.h"
+#include "timeval.h"
#include "util.h"
#include "vconn-ssl.h"
#include "vconn.h"
struct half {
struct rconn *rconn;
struct buffer *rxbuf;
+ int n_txq; /* No. of packets queued for tx on 'rconn'. */
};
struct relay {
set_program_name(argv[0]);
register_fault_handlers();
+ time_init();
vlog_init();
parse_options(argc, argv, &s);
daemonize();
/* Connect to datapath. */
- local_rconn = rconn_create(1, 0, s.max_backoff);
+ local_rconn = rconn_create(0, s.max_backoff);
rconn_connect(local_rconn, s.nl_name);
/* Connect to controller. */
- remote_rconn = rconn_create(1, s.probe_interval, s.max_backoff);
+ remote_rconn = rconn_create(s.probe_interval, s.max_backoff);
if (s.controller_name) {
retval = rconn_connect(remote_rconn, s.controller_name);
if (retval == EAFNOSUPPORT) {
}
/* Create and return relay. */
- r1 = rconn_create(1, 0, 0);
+ r1 = rconn_create(0, 0);
rconn_connect_unreliably(r1, nl_name_without_subscription, new_local);
free(nl_name_without_subscription);
- r2 = rconn_create(1, 0, 0);
+ r2 = rconn_create(0, 0);
rconn_connect_unreliably(r2, "passive", new_remote);
return relay_create(r1, r2, true);
static struct relay *
relay_create(struct rconn *local, struct rconn *remote, bool is_mgmt_conn)
{
- struct relay *r;
- int i;
-
- r = xmalloc(sizeof *r);
+ struct relay *r = xcalloc(1, sizeof *r);
r->halves[HALF_LOCAL].rconn = local;
r->halves[HALF_REMOTE].rconn = remote;
- for (i = 0; i < 2; i++) {
- r->halves[i].rxbuf = NULL;
- }
r->is_mgmt_conn = is_mgmt_conn;
return r;
}
}
}
- if (this->rxbuf) {
- int retval = rconn_send(peer->rconn, this->rxbuf);
+ if (this->rxbuf && !this->n_txq) {
+ int retval = rconn_send(peer->rconn, this->rxbuf,
+ &this->n_txq);
if (retval != EAGAIN) {
if (!retval) {
progress = true;
struct mac_learning *ml;
struct netdev *of_device;
uint8_t mac[ETH_ADDR_LEN];
+ int n_queued;
};
static void
-queue_tx(struct rconn *rc, struct buffer *b)
+queue_tx(struct rconn *rc, struct in_band_data *in_band, struct buffer *b)
{
- if (rconn_force_send(rc, b)) {
- buffer_delete(b);
- }
+ rconn_send_with_limit(rc, b, &in_band->n_queued, 10);
}
-static bool
-is_controller_mac(const uint8_t dl_addr[ETH_ADDR_LEN], struct netdev *netdev,
- struct rconn *controller)
+static const uint8_t *
+get_controller_mac(struct netdev *netdev, struct rconn *controller)
{
static uint32_t ip, last_nonzero_ip;
static uint8_t mac[ETH_ADDR_LEN], last_nonzero_mac[ETH_ADDR_LEN];
uint32_t last_ip = ip;
- time_t now = time(0);
+ time_t now = time_now();
ip = rconn_get_ip(controller);
if (last_ip != ip || !next_refresh || now >= next_refresh) {
* Otherwise, we can afford to wait a little while. */
next_refresh = now + (!ip || have_mac ? 10 : 1);
}
- return !eth_addr_is_zero(mac) && eth_addr_equals(mac, dl_addr);
+ return !eth_addr_is_zero(mac) ? mac : NULL;
+}
+
+static bool
+is_controller_mac(const uint8_t mac[ETH_ADDR_LEN],
+ const uint8_t *controller_mac)
+{
+ return controller_mac && eth_addr_equals(mac, controller_mac);
}
static bool
struct buffer pkt;
struct flow flow;
uint16_t in_port, out_port;
+ const uint8_t *controller_mac;
if (half != HALF_LOCAL || r->is_mgmt_conn) {
return false;
flow_extract(&pkt, in_port, &flow);
/* Deal with local stuff. */
+ controller_mac = get_controller_mac(in_band->of_device,
+ r->halves[HALF_REMOTE].rconn);
if (in_port == OFPP_LOCAL) {
+ /* Sent by secure channel. */
out_port = mac_learning_lookup(in_band->ml, flow.dl_dst);
} else if (eth_addr_equals(flow.dl_dst, in_band->mac)) {
+ /* Sent to secure channel. */
out_port = OFPP_LOCAL;
if (mac_learning_learn(in_band->ml, flow.dl_src, in_port)) {
VLOG_DBG("learned that "ETH_ADDR_FMT" is on port %"PRIu16,
}
} else if (flow.dl_type == htons(ETH_TYPE_ARP)
&& eth_addr_is_broadcast(flow.dl_dst)
- && is_controller_mac(flow.dl_src, in_band->of_device,
- r->halves[HALF_REMOTE].rconn)) {
+ && is_controller_mac(flow.dl_src, controller_mac)) {
+ /* ARP sent by controller. */
out_port = OFPP_FLOOD;
+ } else if (is_controller_mac(flow.dl_dst, controller_mac)
+ && in_port == mac_learning_lookup(in_band->ml,
+ controller_mac)) {
+ /* Drop controller traffic that arrives on the controller port. */
+ queue_tx(rc, in_band, make_add_flow(&flow, ntohl(opi->buffer_id),
+ in_band->s->max_idle, 0));
+ return true;
} else {
return false;
}
if (out_port != OFPP_FLOOD) {
/* The output port is known, so add a new flow. */
- queue_tx(rc, make_add_simple_flow(&flow, ntohl(opi->buffer_id),
- out_port, in_band->s->max_idle));
+ queue_tx(rc, in_band,
+ make_add_simple_flow(&flow, ntohl(opi->buffer_id),
+ out_port, in_band->s->max_idle));
/* If the switch didn't buffer the packet, we need to send a copy. */
if (ntohl(opi->buffer_id) == UINT32_MAX) {
- queue_tx(rc, make_unbuffered_packet_out(&pkt, in_port, out_port));
+ queue_tx(rc, in_band,
+ make_unbuffered_packet_out(&pkt, in_port, out_port));
}
} else {
/* We don't know that MAC. Send along the packet without setting up a
b = make_buffered_packet_out(ntohl(opi->buffer_id),
in_port, out_port);
}
- queue_tx(rc, b);
+ queue_tx(rc, in_band, b);
}
return true;
}
struct in_band_data *in_band;
int retval;
- in_band = xmalloc(sizeof *in_band);
+ in_band = xcalloc(1, sizeof *in_band);
in_band->s = s;
in_band->ml = mac_learning_create();
retval = netdev_open(s->of_name, NETDEV_ETH_TYPE_NONE,