The kernel datapath was claiming that it implements STP, which is untrue.
In fact, the secchan implements STP, so if the secchan was not running
the STP support did not work. Thus, "controller nl:0" would do the
wrong thing.
This makes the secchan edit the responses from the datapath to claim
STP support.
desc->features = 0;
desc->speed = 0;
desc->features = 0;
desc->speed = 0;
- if (p->port_no < 255) {
- /* FIXME: this is a layering violation and should really be
- * done in the secchan, as with OFPC_STP in
- * OFP_SUPPORTED_CAPABILITIES. */
- desc->features |= OFPPF_STP;
- }
-
spin_lock_irqsave(&p->lock, flags);
desc->flags = htonl(p->flags | p->status);
spin_unlock_irqrestore(&p->lock, flags);
spin_lock_irqsave(&p->lock, flags);
desc->flags = htonl(p->flags | p->status);
spin_unlock_irqrestore(&p->lock, flags);
#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \
| OFPC_TABLE_STATS \
| OFPC_PORT_STATS \
#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \
| OFPC_TABLE_STATS \
| OFPC_PORT_STATS \
| OFPC_MULTI_PHY_TX )
/* Actions supported by this implementation. */
| OFPC_MULTI_PHY_TX )
/* Actions supported by this implementation. */
\f
/* Port status watcher. */
\f
/* Port status watcher. */
-typedef void port_watcher_cb_func(uint16_t port_no,
+typedef void edit_port_cb_func(struct ofp_phy_port *port, void *aux);
+typedef void port_changed_cb_func(uint16_t port_no,
const struct ofp_phy_port *old,
const struct ofp_phy_port *new,
void *aux);
struct port_watcher_cb {
const struct ofp_phy_port *old,
const struct ofp_phy_port *new,
void *aux);
struct port_watcher_cb {
- port_watcher_cb_func *function;
+ edit_port_cb_func *edit_port;
+ port_changed_cb_func *port_changed;
-call_pw_callbacks(struct port_watcher *pw, int port_no,
- const struct ofp_phy_port *old,
- const struct ofp_phy_port *new)
+call_port_changed_callbacks(struct port_watcher *pw, int port_no,
+ const struct ofp_phy_port *old,
+ const struct ofp_phy_port *new)
{
if (opp_differs(old, new)) {
int i;
for (i = 0; i < pw->n_cbs; i++) {
{
if (opp_differs(old, new)) {
int i;
for (i = 0; i < pw->n_cbs; i++) {
- pw->cbs[i].function(port_no, old, new, pw->cbs[i].aux);
+ port_changed_cb_func *port_changed = pw->cbs[i].port_changed;
+ if (port_changed) {
+ (port_changed)(port_no, old, new, pw->cbs[i].aux);
+ }
+ }
+ }
+}
+
+static void
+call_edit_port_callbacks(struct port_watcher *pw, struct ofp_phy_port *p)
+{
+ int i;
+ for (i = 0; i < pw->n_cbs; i++) {
+ edit_port_cb_func *edit_port = pw->cbs[i].edit_port;
+ if (edit_port) {
+ (edit_port)(p, pw->cbs[i].aux);
*pw_opp = *opp;
sanitize_opp(pw_opp);
}
*pw_opp = *opp;
sanitize_opp(pw_opp);
}
- call_pw_callbacks(pw, port_no, &old, pw_opp);
+ call_port_changed_callbacks(pw, port_no, &old, pw_opp);
n_ports = ((msg->size - offsetof(struct ofp_switch_features, ports))
/ sizeof *osf->ports);
for (i = 0; i < n_ports; i++) {
n_ports = ((msg->size - offsetof(struct ofp_switch_features, ports))
/ sizeof *osf->ports);
for (i = 0; i < n_ports; i++) {
- update_phy_port(pw, &osf->ports[i], OFPPR_MOD, seen);
+ struct ofp_phy_port *opp = &osf->ports[i];
+ call_edit_port_callbacks(pw, opp);
+ update_phy_port(pw, opp, OFPPR_MOD, seen);
}
/* Delete all the ports not included in the message. */
}
/* Delete all the ports not included in the message. */
} else if (oh->type == OFPT_PORT_STATUS
&& msg->size >= sizeof(struct ofp_port_status)) {
struct ofp_port_status *ops = msg->data;
} else if (oh->type == OFPT_PORT_STATUS
&& msg->size >= sizeof(struct ofp_port_status)) {
struct ofp_port_status *ops = msg->data;
+ call_edit_port_callbacks(pw, &ops->desc);
update_phy_port(pw, &ops->desc, ops->reason, NULL);
}
return false;
update_phy_port(pw, &ops->desc, ops->reason, NULL);
}
return false;
struct ofp_phy_port old = *pw_opp;
pw_opp->flags = ((pw_opp->flags & ~opm->mask)
| (opm->desc.flags & opm->mask));
struct ofp_phy_port old = *pw_opp;
pw_opp->flags = ((pw_opp->flags & ~opm->mask)
| (opm->desc.flags & opm->mask));
- call_pw_callbacks(pw, port_no, &old, pw_opp);
+ call_port_changed_callbacks(pw, port_no, &old, pw_opp);
static void
port_watcher_register_callback(struct port_watcher *pw,
static void
port_watcher_register_callback(struct port_watcher *pw,
- port_watcher_cb_func *function,
+ edit_port_cb_func *edit_port,
+ port_changed_cb_func *port_changed,
void *aux)
{
assert(pw->n_cbs < ARRAY_SIZE(pw->cbs));
void *aux)
{
assert(pw->n_cbs < ARRAY_SIZE(pw->cbs));
- pw->cbs[pw->n_cbs].function = function;
+ pw->cbs[pw->n_cbs].edit_port = edit_port;
+ pw->cbs[pw->n_cbs].port_changed = port_changed;
pw->cbs[pw->n_cbs].aux = aux;
pw->n_cbs++;
}
pw->cbs[pw->n_cbs].aux = aux;
pw->n_cbs++;
}
/* Update our idea of the flags. */
p->flags = htonl((ntohl(p->flags) & ~mask) | (flags & mask));
/* Update our idea of the flags. */
p->flags = htonl((ntohl(p->flags) & ~mask) | (flags & mask));
- call_pw_callbacks(pw, port_no, &old, p);
+ call_port_changed_callbacks(pw, port_no, &old, p);
/* Change the flags in the datapath. */
opm = make_openflow(sizeof *opm, OFPT_PORT_MOD, &b);
/* Change the flags in the datapath. */
opm = make_openflow(sizeof *opm, OFPT_PORT_MOD, &b);
for (i = 0; i < OFPP_MAX; i++) {
pw->ports[i].port_no = htons(OFPP_NONE);
}
for (i = 0; i < OFPP_MAX; i++) {
pw->ports[i].port_no = htons(OFPP_NONE);
}
- port_watcher_register_callback(pw, log_port_status, NULL);
+ port_watcher_register_callback(pw, NULL, log_port_status, NULL);
return make_hook(port_watcher_local_packet_cb,
port_watcher_remote_packet_cb,
port_watcher_periodic_cb, NULL, pw);
return make_hook(port_watcher_local_packet_cb,
port_watcher_remote_packet_cb,
port_watcher_periodic_cb, NULL, pw);
static bool
stp_local_packet_cb(struct relay *r, void *stp_)
{
static bool
stp_local_packet_cb(struct relay *r, void *stp_)
{
+ struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf;
+ struct ofp_header *oh;
struct stp_data *stp = stp_;
struct ofp_packet_in *opi;
struct eth_header *eth;
struct stp_data *stp = stp_;
struct ofp_packet_in *opi;
struct eth_header *eth;
uint16_t port_no;
struct flow flow;
uint16_t port_no;
struct flow flow;
+ oh = msg->data;
+ if (oh->type == OFPT_FEATURES_REPLY
+ && msg->size >= offsetof(struct ofp_switch_features, ports)) {
+ struct ofp_switch_features *osf = msg->data;
+ osf->capabilities |= htonl(OFPC_STP);
+ return false;
+ }
+
if (!get_ofp_packet_eth_header(r, &opi, ð)
|| !eth_addr_equals(eth->eth_dst, stp_eth_addr)) {
return false;
if (!get_ofp_packet_eth_header(r, &opi, ð)
|| !eth_addr_equals(eth->eth_dst, stp_eth_addr)) {
return false;
rconn_send_with_limit(stp->local_rconn, opo, &stp->n_txq, OFPP_MAX);
}
rconn_send_with_limit(stp->local_rconn, opo, &stp->n_txq, OFPP_MAX);
}
+static bool
+stp_is_port_supported(uint16_t port_no)
+{
+ /* STP only supports a maximum of 255 ports, one less than OpenFlow. We
+ * don't support STP on OFPP_LOCAL, either. */
+ return port_no < STP_MAX_PORTS;
+}
+
+static void
+stp_edit_port_cb(struct ofp_phy_port *p, void *stp_ UNUSED)
+{
+ uint16_t port_no = ntohs(p->port_no);
+ if (stp_is_port_supported(port_no)) {
+ p->features |= htonl(OFPPF_STP);
+ }
+}
+
-stp_port_watcher_cb(uint16_t port_no,
+stp_port_changed_cb(uint16_t port_no,
const struct ofp_phy_port *old,
const struct ofp_phy_port *new,
void *stp_)
const struct ofp_phy_port *old,
const struct ofp_phy_port *new,
void *stp_)
struct stp_data *stp = stp_;
struct stp_port *p;
struct stp_data *stp = stp_;
struct stp_port *p;
- /* STP only supports a maximum of 255 ports, one less than OpenFlow. We
- * don't support STP on OFPP_LOCAL, either. */
- if (port_no >= STP_MAX_PORTS) {
+ if (!stp_is_port_supported(port_no)) {
stp->remote_rconn = remote;
stp->last_tick_256ths = time_256ths();
stp->remote_rconn = remote;
stp->last_tick_256ths = time_256ths();
- port_watcher_register_callback(pw, stp_port_watcher_cb, stp);
+ port_watcher_register_callback(pw, stp_edit_port_cb,
+ stp_port_changed_cb, stp);
return make_hook(stp_local_packet_cb, NULL,
stp_periodic_cb, stp_wait_cb, stp);
}
return make_hook(stp_local_packet_cb, NULL,
stp_periodic_cb, stp_wait_cb, stp);
}