#include "packets.h"
#include "poll-loop.h"
#include "rconn.h"
+#include "stp.h"
#include "switch-flow.h"
#include "table.h"
#include "timeval.h"
#define THIS_MODULE VLM_datapath
#include "vlog.h"
-enum br_port_flags {
- BRPF_NO_FLOOD = 1 << 0,
-};
-
-enum br_port_status {
- BRPS_PORT_DOWN = 1 << 0,
- BRPS_LINK_DOWN = 1 << 1,
-};
-
extern char mfr_desc;
extern char hw_desc;
extern char sw_desc;
| (1 << OFPAT_SET_TP_SRC) \
| (1 << OFPAT_SET_TP_DST) )
+#define PORT_STATUS_BITS (OFPPFL_PORT_DOWN | OFPPFL_LINK_DOWN)
+#define PORT_FLAG_BITS (~PORT_STATUS_BITS)
+
struct sw_port {
- uint32_t flags; /* BRPF_* flags */
- uint32_t status; /* BRPS_* flags */
+ uint32_t flags; /* Some subset of PORT_FLAG_BITS. */
+ uint32_t status; /* Some subset of PORT_STATUS_BITS. */
struct datapath *dp;
struct netdev *netdev;
struct list node; /* Element in datapath.ports. */
/* Remote connections. */
struct remote *controller; /* Connection to controller. */
struct list remotes; /* All connections (including controller). */
- struct vconn *listen_vconn;
+ struct pvconn *listen_pvconn;
time_t last_timeout;
static void remote_destroy(struct remote *);
void dp_output_port(struct datapath *, struct ofpbuf *,
- int in_port, int out_port);
+ int in_port, int out_port, bool ignore_no_fwd);
void dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm);
void dp_output_control(struct datapath *, struct ofpbuf *, int in_port,
size_t max_len, int reason);
static void del_switch_port(struct sw_port *p);
static void execute_actions(struct datapath *, struct ofpbuf *,
int in_port, const struct sw_flow_key *,
- const struct ofp_action *, int n_actions);
+ const struct ofp_action *, int n_actions,
+ bool ignore_no_fwd);
static void modify_vlan(struct ofpbuf *buffer, const struct sw_flow_key *key,
const struct ofp_action *a);
static void modify_nh(struct ofpbuf *buffer, uint16_t eth_proto,
#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS)
-int run_flow_through_tables(struct datapath *, struct ofpbuf *, int in_port);
-void fwd_port_input(struct datapath *, struct ofpbuf *, int in_port);
+int run_flow_through_tables(struct datapath *, struct ofpbuf *,
+ struct sw_port *);
+void fwd_port_input(struct datapath *, struct ofpbuf *, struct sw_port *);
int fwd_control_input(struct datapath *, const struct sender *,
const void *, size_t);
dp->last_timeout = time_now();
list_init(&dp->remotes);
dp->controller = remote_create(dp, rconn);
- dp->listen_vconn = NULL;
+ dp->listen_pvconn = NULL;
dp->id = dpid <= UINT64_C(0xffffffffffff) ? dpid : gen_datapath_id();
dp->chain = chain_create();
if (!dp->chain) {
}
void
-dp_add_listen_vconn(struct datapath *dp, struct vconn *listen_vconn)
+dp_add_listen_pvconn(struct datapath *dp, struct pvconn *listen_pvconn)
{
- assert(!dp->listen_vconn);
- dp->listen_vconn = listen_vconn;
+ assert(!dp->listen_pvconn);
+ dp->listen_pvconn = listen_pvconn;
}
void
if (!error) {
p->rx_packets++;
p->rx_bytes += buffer->size;
- fwd_port_input(dp, buffer, port_no(dp, p));
+ fwd_port_input(dp, buffer, p);
buffer = NULL;
} else if (error != EAGAIN) {
VLOG_ERR_RL(&rl, "error receiving data from %s: %s",
LIST_FOR_EACH_SAFE (r, rn, struct remote, node, &dp->remotes) {
remote_run(dp, r);
}
- if (dp->listen_vconn) {
+ if (dp->listen_pvconn) {
for (;;) {
struct vconn *new_vconn;
int retval;
- retval = vconn_accept(dp->listen_vconn, &new_vconn);
+ retval = pvconn_accept(dp->listen_pvconn, OFP_VERSION, &new_vconn);
if (retval) {
if (retval != EAGAIN) {
VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval));
LIST_FOR_EACH (r, struct remote, node, &dp->remotes) {
remote_wait(r);
}
- if (dp->listen_vconn) {
- vconn_accept_wait(dp->listen_vconn);
+ if (dp->listen_pvconn) {
+ pvconn_wait(dp->listen_pvconn);
}
}
if (port_no(dp, p) == in_port) {
continue;
}
- if (flood && p->flags & BRPF_NO_FLOOD) {
+ if (flood && p->flags & OFPPFL_NO_FLOOD) {
continue;
}
if (prev_port != -1) {
- dp_output_port(dp, ofpbuf_clone(buffer), in_port, prev_port);
+ dp_output_port(dp, ofpbuf_clone(buffer), in_port, prev_port,
+ false);
}
prev_port = port_no(dp, p);
}
if (prev_port != -1)
- dp_output_port(dp, buffer, in_port, prev_port);
+ dp_output_port(dp, buffer, in_port, prev_port, false);
else
ofpbuf_delete(buffer);
{
if (out_port >= 0 && out_port < OFPP_MAX) {
struct sw_port *p = &dp->ports[out_port];
- if (p->netdev != NULL && !(p->status & BRPS_PORT_DOWN)) {
+ if (p->netdev != NULL && !(p->status & OFPPFL_PORT_DOWN)) {
if (!netdev_send(p->netdev, buffer)) {
p->tx_packets++;
p->tx_bytes += buffer->size;
*/
void
dp_output_port(struct datapath *dp, struct ofpbuf *buffer,
- int in_port, int out_port)
+ int in_port, int out_port, bool ignore_no_fwd)
{
assert(buffer);
} else if (out_port == OFPP_IN_PORT) {
output_packet(dp, buffer, in_port);
} else if (out_port == OFPP_TABLE) {
- if (run_flow_through_tables(dp, buffer, in_port)) {
+ struct sw_port *p = in_port < OFPP_MAX ? &dp->ports[in_port] : 0;
+ if (run_flow_through_tables(dp, buffer, p)) {
ofpbuf_delete(buffer);
}
} else {
desc->flags = 0;
desc->features = htonl(netdev_get_features(p->netdev));
desc->speed = htonl(netdev_get_speed(p->netdev));
-
- if (p->flags & BRPF_NO_FLOOD) {
- desc->flags |= htonl(OFPPFL_NO_FLOOD);
- } else if (p->status & BRPS_PORT_DOWN) {
- desc->flags |= htonl(OFPPFL_PORT_DOWN);
- } else if (p->status & BRPS_LINK_DOWN) {
- desc->flags |= htonl(OFPPFL_LINK_DOWN);
- }
+ desc->flags = htonl(p->flags | p->status);
}
static void
ofr = make_openflow_reply(sizeof *ofr, OFPT_FEATURES_REPLY,
sender, &buffer);
- ofr->datapath_id = htonll(dp->id);
- ofr->n_exact = htonl(2 * TABLE_HASH_MAX_FLOWS);
- ofr->n_compression = 0; /* Not supported */
- ofr->n_general = htonl(TABLE_LINEAR_MAX_FLOWS);
- ofr->buffer_mb = htonl(UINT32_MAX);
- ofr->n_buffers = htonl(N_PKT_BUFFERS);
- ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES);
- ofr->actions = htonl(OFP_SUPPORTED_ACTIONS);
+ ofr->datapath_id = htonll(dp->id);
+ ofr->n_tables = dp->chain->n_tables;
+ ofr->n_buffers = htonl(N_PKT_BUFFERS);
+ ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES);
+ ofr->actions = htonl(OFP_SUPPORTED_ACTIONS);
LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) {
struct ofp_phy_port *opp = ofpbuf_put_uninit(buffer, sizeof *opp);
memset(opp, 0, sizeof *opp);
int port_no = ntohs(opp->port_no);
if (port_no < OFPP_MAX) {
struct sw_port *p = &dp->ports[port_no];
+ uint32_t flag_mask;
/* Make sure the port id hasn't changed since this was sent */
if (!p || memcmp(opp->hw_addr, netdev_get_etheraddr(p->netdev),
}
- if (opm->mask & htonl(OFPPFL_NO_FLOOD)) {
- if (opp->flags & htonl(OFPPFL_NO_FLOOD))
- p->flags |= BRPF_NO_FLOOD;
- else
- p->flags &= ~BRPF_NO_FLOOD;
+ flag_mask = ntohl(opm->mask) & PORT_FLAG_BITS;
+ if (flag_mask) {
+ p->flags &= ~flag_mask;
+ p->flags |= ntohl(opp->flags) & flag_mask;
}
if (opm->mask & htonl(OFPPFL_PORT_DOWN)) {
if ((opp->flags & htonl(OFPPFL_PORT_DOWN))
- && (p->status & BRPS_PORT_DOWN) == 0) {
- p->status |= BRPS_PORT_DOWN;
+ && (p->status & OFPPFL_PORT_DOWN) == 0) {
+ p->status |= OFPPFL_PORT_DOWN;
netdev_turn_flags_off(p->netdev, NETDEV_UP, true);
} else if ((opp->flags & htonl(OFPPFL_PORT_DOWN)) == 0
- && (p->status & BRPS_PORT_DOWN)) {
- p->status &= ~BRPS_PORT_DOWN;
+ && (p->status & OFPPFL_PORT_DOWN)) {
+ p->status &= ~OFPPFL_PORT_DOWN;
netdev_turn_flags_on(p->netdev, NETDEV_UP, true);
}
}
return 0;
} else {
if (flags & NETDEV_UP) {
- p->status &= ~BRPS_PORT_DOWN;
+ p->status &= ~OFPPFL_PORT_DOWN;
} else {
- p->status |= BRPS_PORT_DOWN;
+ p->status |= OFPPFL_PORT_DOWN;
}
}
* error. */
retval = netdev_get_link_status(p->netdev);
if (retval == 1) {
- p->status &= ~BRPS_LINK_DOWN;
+ p->status &= ~OFPPFL_LINK_DOWN;
} else if (retval == 0) {
- p->status |= BRPS_LINK_DOWN;
+ p->status |= OFPPFL_LINK_DOWN;
}
return (orig_status != p->status);
void
dp_send_error_msg(struct datapath *dp, const struct sender *sender,
- uint16_t type, uint16_t code, const uint8_t *data, size_t len)
+ uint16_t type, uint16_t code, const void *data, size_t len)
{
struct ofpbuf *buffer;
struct ofp_error_msg *oem;
- oem = make_openflow_reply(sizeof(*oem)+len, OFPT_ERROR_MSG,
- sender, &buffer);
+ oem = make_openflow_reply(sizeof(*oem)+len, OFPT_ERROR, sender, &buffer);
oem->type = htons(type);
oem->code = htons(code);
memcpy(oem->data, data, len);
}
\f
-/* 'buffer' was received on 'in_port', a physical switch port between 0 and
- * OFPP_MAX. Process it according to 'dp''s flow table. Returns 0 if
+/* 'buffer' was received on 'p', which may be a a physical switch port or a
+ * null pointer. Process it according to 'dp''s flow table. Returns 0 if
* successful, in which case 'buffer' is destroyed, or -ESRCH if there is no
* matching flow, in which case 'buffer' still belongs to the caller. */
int run_flow_through_tables(struct datapath *dp, struct ofpbuf *buffer,
- int in_port)
+ struct sw_port *p)
{
struct sw_flow_key key;
struct sw_flow *flow;
key.wildcards = 0;
- if (flow_extract(buffer, in_port, &key.flow)
+ if (flow_extract(buffer, p ? port_no(dp, p) : OFPP_NONE, &key.flow)
&& (dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) {
/* Drop fragment. */
ofpbuf_delete(buffer);
return 0;
}
+ if (p && p->flags & (OFPPFL_NO_RECV | OFPPFL_NO_RECV_STP)
+ && p->flags & (!eth_addr_equals(key.flow.dl_dst, stp_eth_addr)
+ ? OFPPFL_NO_RECV : OFPPFL_NO_RECV_STP)) {
+ ofpbuf_delete(buffer);
+ return 0;
+ }
flow = chain_lookup(dp->chain, &key);
if (flow != NULL) {
flow_used(flow, buffer);
- execute_actions(dp, buffer, in_port, &key,
- flow->actions, flow->n_actions);
+ execute_actions(dp, buffer, port_no(dp, p),
+ &key, flow->actions, flow->n_actions, false);
return 0;
} else {
return -ESRCH;
}
}
-/* 'buffer' was received on 'in_port', a physical switch port between 0 and
- * OFPP_MAX. Process it according to 'dp''s flow table, sending it up to the
- * controller if no flow matches. Takes ownership of 'buffer'. */
-void fwd_port_input(struct datapath *dp, struct ofpbuf *buffer, int in_port)
+/* 'buffer' was received on 'p', which may be a a physical switch port or a
+ * null pointer. Process it according to 'dp''s flow table, sending it up to
+ * the controller if no flow matches. Takes ownership of 'buffer'. */
+void fwd_port_input(struct datapath *dp, struct ofpbuf *buffer,
+ struct sw_port *p)
{
- if (run_flow_through_tables(dp, buffer, in_port)) {
- dp_output_control(dp, buffer, in_port, dp->miss_send_len,
- OFPR_NO_MATCH);
+ if (run_flow_through_tables(dp, buffer, p)) {
+ dp_output_control(dp, buffer, port_no(dp, p),
+ dp->miss_send_len, OFPR_NO_MATCH);
}
}
static void
do_output(struct datapath *dp, struct ofpbuf *buffer, int in_port,
- size_t max_len, int out_port)
+ size_t max_len, int out_port, bool ignore_no_fwd)
{
if (out_port != OFPP_CONTROLLER) {
- dp_output_port(dp, buffer, in_port, out_port);
+ dp_output_port(dp, buffer, in_port, out_port, ignore_no_fwd);
} else {
dp_output_control(dp, buffer, in_port, max_len, OFPR_ACTION);
}
static void
execute_actions(struct datapath *dp, struct ofpbuf *buffer,
int in_port, const struct sw_flow_key *key,
- const struct ofp_action *actions, int n_actions)
+ const struct ofp_action *actions, int n_actions,
+ bool ignore_no_fwd)
{
/* Every output action needs a separate clone of 'buffer', but the common
* case is just a single output action, so that doing a clone and then
struct eth_header *eh = buffer->l2;
if (prev_port != -1) {
- do_output(dp, ofpbuf_clone(buffer), in_port, max_len, prev_port);
+ do_output(dp, ofpbuf_clone(buffer), in_port, max_len, prev_port,
+ ignore_no_fwd);
prev_port = -1;
}
}
}
if (prev_port != -1)
- do_output(dp, buffer, in_port, max_len, prev_port);
+ do_output(dp, buffer, in_port, max_len, prev_port, ignore_no_fwd);
else
ofpbuf_delete(buffer);
}
flow_extract(buffer, ntohs(opo->in_port), &key.flow);
execute_actions(dp, buffer, ntohs(opo->in_port),
- &key, opo->actions, n_actions);
+ &key, opo->actions, n_actions, true);
return 0;
}
uint16_t in_port = ntohs(ofm->match.in_port);
flow_used(flow, buffer);
flow_extract(buffer, in_port, &key.flow);
- execute_actions(dp, buffer, in_port, &key, ofm->actions, n_actions);
+ execute_actions(dp, buffer, in_port, &key,
+ ofm->actions, n_actions, false);
} else {
error = -ESRCH;
}
dp->chain->tables[i]->stats(dp->chain->tables[i], &stats);
strncpy(ots->name, stats.name, sizeof ots->name);
ots->table_id = i;
+ ots->wildcards = htonl(stats.wildcards);
memset(ots->pad, 0, sizeof ots->pad);
ots->max_entries = htonl(stats.max_flows);
ots->active_count = htonl(stats.n_flows);
handler = recv_echo_reply;
break;
default:
- return -ENOSYS;
+ dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
+ msg, length);
+ return -EINVAL;
}
/* Handle it. */