ofproto/bond: Implement bond megaflow using recirculation
[sliver-openvswitch.git] / lib / dpif-netdev.c
index 15cf5c1..423daba 100644 (file)
@@ -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