X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fdpif-netdev.c;h=423daba613616f2d17848727ea51afc8c03df8d9;hb=adcf00ba35a0ce9cf2f1a84bce44559eab1f83a1;hp=15cf5c134b7d24cbe06e4047725e86c4040452f7;hpb=ebed9f7859a2a051d7bb59d7d73775f0c5c0edd7;p=sliver-openvswitch.git diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 15cf5c134..423daba61 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -68,6 +68,9 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev); #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. */ @@ -1997,8 +2000,9 @@ dp_netdev_count_packet(struct dp_netdev *dp, enum dp_stat_type type) } 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; @@ -2027,6 +2031,17 @@ dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet, } } +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, @@ -2096,6 +2111,7 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, 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: @@ -2122,23 +2138,40 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, break; } - case OVS_ACTION_ATTR_RECIRC: { - const struct ovs_action_recirc *act; + 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; - act = nl_attr_get(a); - md->recirc_id = act->recirc_id; - md->dp_hash = 0; + recirc_packet = may_steal ? packet : ofpbuf_clone(packet); - if (act->hash_alg == OVS_RECIRC_HASH_ALG_L4) { - struct flow flow; + act = nl_attr_get(a); + md->recirc_id = act->recirc_id; + md->dp_hash = 0; - flow_extract(packet, md, &flow); - md->dp_hash = flow_hash_symmetric_l4(&flow, act->hash_bias); - } + 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 */ + } + } - dp_netdev_port_input(aux->dp, packet, md); + (*depth)++; + dp_netdev_input(aux->dp, recirc_packet, md); + (*depth)--; + + 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: @@ -2150,7 +2183,6 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); } - } static void