void *make_openflow_xid(size_t openflow_len, uint8_t type,
uint32_t xid, struct buffer **);
void update_openflow_length(struct buffer *);
+struct buffer *make_add_flow(const struct flow *, uint32_t buffer_id,
+ uint16_t max_idle, size_t n_actions);
struct buffer *make_add_simple_flow(const struct flow *,
uint32_t buffer_id, uint16_t out_port,
uint16_t max_idle);
}
struct buffer *
-make_add_simple_flow(const struct flow *flow,
- uint32_t buffer_id, uint16_t out_port, uint16_t max_idle)
+make_add_flow(const struct flow *flow, uint32_t buffer_id, uint16_t max_idle,
+ size_t n_actions)
{
struct ofp_flow_mod *ofm;
- size_t size = sizeof *ofm + sizeof ofm->actions[0];
+ size_t size = sizeof *ofm + n_actions * sizeof ofm->actions[0];
struct buffer *out = buffer_new(size);
ofm = buffer_put_uninit(out, size);
memset(ofm, 0, size);
ofm->command = htons(OFPFC_ADD);
ofm->max_idle = htons(max_idle);
ofm->buffer_id = htonl(buffer_id);
+ return out;
+}
+
+struct buffer *
+make_add_simple_flow(const struct flow *flow,
+ uint32_t buffer_id, uint16_t out_port, uint16_t max_idle)
+{
+ struct buffer *buffer = make_add_flow(flow, buffer_id, max_idle, 1);
+ struct ofp_flow_mod *ofm = buffer->data;
ofm->actions[0].type = htons(OFPAT_OUTPUT);
ofm->actions[0].arg.output.max_len = htons(0);
ofm->actions[0].arg.output.port = htons(out_port);
- return out;
+ return buffer;
}
struct buffer *
}
}
-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];
* 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, make_add_flow(&flow, ntohl(opi->buffer_id),
+ in_band->s->max_idle, 0));
+ return true;
} else {
return false;
}