#define NETDEV_RULE_PRIORITY 0x8000
#define NR_THREADS 1
+/* Use per thread recirc_depth to prevent recirculation loop. */
+#define MAX_RECIRC_DEPTH 5
+DEFINE_STATIC_PER_THREAD_DATA(uint32_t, recirc_depth, 0)
/* Configuration parameters. */
enum { MAX_FLOWS = 65536 }; /* Maximum number of flows in flow table. */
return EINVAL;
}
- /* Force unwildcard the in_port. */
- mask->in_port.odp_port = u32_to_odp(UINT32_MAX);
} else {
enum mf_field_id id;
/* No mask key, unwildcard everything except fields whose
}
}
+ /* Force unwildcard the in_port.
+ *
+ * We need to do this even in the case where we unwildcard "everything"
+ * above because "everything" only includes the 16-bit OpenFlow port number
+ * mask->in_port.ofp_port, which only covers half of the 32-bit datapath
+ * port number mask->in_port.odp_port. */
+ mask->in_port.odp_port = u32_to_odp(UINT32_MAX);
+
return 0;
}
odp_flow_key_from_flow(&buf, &netdev_flow->flow,
netdev_flow->flow.in_port.odp_port);
- *key = buf.data;
- *key_len = buf.size;
+ *key = ofpbuf_data(&buf);
+ *key_len = ofpbuf_size(&buf);
}
if (key && mask) {
odp_to_u32(wc.masks.in_port.odp_port),
SIZE_MAX);
- *mask = buf.data;
- *mask_len = buf.size;
+ *mask = ofpbuf_data(&buf);
+ *mask_len = ofpbuf_size(&buf);
}
if (actions || stats) {
struct pkt_metadata *md = &execute->md;
struct flow key;
- if (execute->packet->size < ETH_HEADER_LEN ||
- execute->packet->size > UINT16_MAX) {
+ if (ofpbuf_size(execute->packet) < ETH_HEADER_LEN ||
+ ofpbuf_size(execute->packet) > UINT16_MAX) {
return EINVAL;
}
}
\f
-inline static void
+static void
dp_netdev_process_rxq_port(struct dp_netdev *dp,
struct dp_netdev_port *port,
struct netdev_rxq *rxq)
ovs_mutex_lock(&bucket->mutex);
bucket->used = MAX(now, bucket->used);
bucket->packet_count++;
- bucket->byte_count += packet->size;
+ bucket->byte_count += ofpbuf_size(packet);
bucket->tcp_flags |= tcp_flags;
ovs_mutex_unlock(&bucket->mutex);
}
}
static void
-dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
- struct pkt_metadata *md)
+dp_netdev_input(struct dp_netdev *dp, struct ofpbuf *packet,
+ struct pkt_metadata *md)
+ OVS_REQ_RDLOCK(dp->port_rwlock)
{
struct dp_netdev_flow *netdev_flow;
struct flow key;
- if (packet->size < ETH_HEADER_LEN) {
+ if (ofpbuf_size(packet) < ETH_HEADER_LEN) {
ofpbuf_delete(packet);
return;
}
}
}
+static void
+dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
+ struct pkt_metadata *md)
+ OVS_REQ_RDLOCK(dp->port_rwlock)
+{
+ uint32_t *recirc_depth = recirc_depth_get();
+
+ *recirc_depth = 0;
+ dp_netdev_input(dp, packet, md);
+}
+
static int
dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
int queue_no, int type, const struct flow *flow,
if (userdata) {
buf_size += NLA_ALIGN(userdata->nla_len);
}
- buf_size += packet->size;
+ buf_size += ofpbuf_size(packet);
ofpbuf_init(buf, buf_size);
/* Put ODP flow. */
odp_flow_key_from_flow(buf, flow, flow->in_port.odp_port);
- upcall->key = buf->data;
- upcall->key_len = buf->size;
+ upcall->key = ofpbuf_data(buf);
+ upcall->key_len = ofpbuf_size(buf);
/* Put userdata. */
if (userdata) {
NLA_ALIGN(userdata->nla_len));
}
- upcall->packet.data = ofpbuf_put(buf, packet->data, packet->size);
- upcall->packet.size = packet->size;
+ ofpbuf_set_data(&upcall->packet,
+ ofpbuf_put(buf, ofpbuf_data(packet), ofpbuf_size(packet)));
+ ofpbuf_set_size(&upcall->packet, ofpbuf_size(packet));
seq_change(q->seq);
struct dp_netdev_execute_aux *aux = aux_;
int type = nl_attr_type(a);
struct dp_netdev_port *p;
+ uint32_t *depth = recirc_depth_get();
switch ((enum ovs_action_attr)type) {
case OVS_ACTION_ATTR_OUTPUT:
break;
}
- case OVS_ACTION_ATTR_RECIRC: {
- const struct ovs_action_recirc *act;
- act = nl_attr_get(a);
- md->recirc_id =act->recirc_id;
- md->dp_hash = 0;
+ case OVS_ACTION_ATTR_RECIRC:
+ if (*depth < MAX_RECIRC_DEPTH) {
+ uint32_t old_recirc_id = md->recirc_id;
+ uint32_t old_dp_hash = md->dp_hash;
+ const struct ovs_action_recirc *act;
+ struct ofpbuf *recirc_packet;
- if (act->hash_alg == OVS_RECIRC_HASH_ALG_L4) {
- struct flow flow;
+ recirc_packet = may_steal ? packet : ofpbuf_clone(packet);
- flow_extract(packet, md, &flow);
- md->dp_hash = flow_hash_symmetric_l4(&flow, act->hash_bias);
- }
+ act = nl_attr_get(a);
+ md->recirc_id = act->recirc_id;
+ md->dp_hash = 0;
+
+ if (act->hash_alg == OVS_RECIRC_HASH_ALG_L4) {
+ struct flow flow;
+
+ flow_extract(recirc_packet, md, &flow);
+ md->dp_hash = flow_hash_symmetric_l4(&flow, act->hash_bias);
+ if (!md->dp_hash) {
+ md->dp_hash = 1; /* 0 is not valid */
+ }
+ }
+
+ (*depth)++;
+ dp_netdev_input(aux->dp, recirc_packet, md);
+ (*depth)--;
- dp_netdev_port_input(aux->dp, packet, md);
+ md->recirc_id = old_recirc_id;
+ md->recirc_id = old_dp_hash;
+ break;
+ } else {
+ VLOG_WARN("Packet dropped. Max recirculation depth exceeded.");
+ }
break;
- }
case OVS_ACTION_ATTR_PUSH_VLAN:
case OVS_ACTION_ATTR_POP_VLAN:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
}
-
}
static void