ofproto-dpif: Use execute_actions to execute controller actions
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index c52a3c5..a9d2ddd 100644 (file)
@@ -41,6 +41,7 @@
 #include "netlink.h"
 #include "nx-match.h"
 #include "odp-util.h"
+#include "odp-execute.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
 #include "ofp-actions.h"
@@ -563,8 +564,9 @@ struct vlan_splinter {
     int vid;
 };
 
-static uint32_t vsp_realdev_to_vlandev(const struct ofproto_dpif *,
-                                       uint32_t realdev, ovs_be16 vlan_tci);
+static uint16_t vsp_realdev_to_vlandev(const struct ofproto_dpif *,
+                                       uint16_t realdev_ofp_port,
+                                       ovs_be16 vlan_tci);
 static bool vsp_adjust_flow(const struct ofproto_dpif *, struct flow *);
 static void vsp_remove(struct ofport_dpif *);
 static void vsp_add(struct ofport_dpif *, uint16_t realdev_ofp_port, int vid);
@@ -649,6 +651,7 @@ struct dpif_backer {
     struct tag_set revalidate_set; /* Revalidate only matching facets. */
 
     struct hmap drop_keys; /* Set of dropped odp keys. */
+    bool recv_set_enable; /* Enables or disables receiving packets. */
 };
 
 /* All existing ofproto_backer instances, indexed by ofproto->up.type. */
@@ -658,8 +661,6 @@ static void drop_key_clear(struct dpif_backer *);
 static struct ofport_dpif *
 odp_port_to_ofport(const struct dpif_backer *, uint32_t odp_port);
 
-static void dpif_stats_update_hit_count(struct ofproto_dpif *ofproto,
-                                        uint64_t delta);
 struct avg_subfacet_rates {
     double add_rate;     /* Moving average of new flows created per minute. */
     double del_rate;     /* Moving average of flows deleted per minute. */
@@ -676,6 +677,7 @@ struct ofproto_dpif {
     /* Special OpenFlow rules. */
     struct rule_dpif *miss_rule; /* Sends flow table misses to controller. */
     struct rule_dpif *no_packet_in_rule; /* Drops flow table misses. */
+    struct rule_dpif *drop_frags_rule; /* Used in OFPC_FRAG_DROP mode. */
 
     /* Bridging. */
     struct netflow *netflow;
@@ -759,8 +761,6 @@ static unsigned long long int avg_subfacet_life_span(
                                         const struct ofproto_dpif *);
 static double avg_subfacet_count(const struct ofproto_dpif *ofproto);
 static void update_moving_averages(struct ofproto_dpif *ofproto);
-static void dpif_stats_update_hit_count(struct ofproto_dpif *ofproto,
-                                        uint64_t delta);
 static void update_max_subfacet_count(struct ofproto_dpif *ofproto);
 
 /* Defer flow mod completion until "ovs-appctl ofproto/unclog"?  (Useful only
@@ -922,6 +922,21 @@ type_run(const char *type)
         push_all_stats();
     }
 
+    /* If vswitchd started with other_config:flow_restore_wait set as "true",
+     * and the configuration has now changed to "false", enable receiving
+     * packets from the datapath. */
+    if (!backer->recv_set_enable && !ofproto_get_flow_restore_wait()) {
+        backer->recv_set_enable = true;
+
+        error = dpif_recv_set(backer->dpif, backer->recv_set_enable);
+        if (error) {
+            VLOG_ERR("Failed to enable receiving packets in dpif.");
+            return error;
+        }
+        dpif_flow_flush(backer->dpif);
+        backer->need_revalidate = REV_RECONFIGURE;
+    }
+
     if (backer->need_revalidate
         || !tag_set_is_empty(&backer->revalidate_set)) {
         struct tag_set revalidate_set = backer->revalidate_set;
@@ -1015,7 +1030,10 @@ type_run(const char *type)
         }
     }
 
-    if (timer_expired(&backer->next_expiration)) {
+    if (!backer->recv_set_enable) {
+        /* Wake up before a max of 1000ms. */
+        timer_set_duration(&backer->next_expiration, 1000);
+    } else if (timer_expired(&backer->next_expiration)) {
         int delay = expire(backer);
         timer_set_duration(&backer->next_expiration, delay);
     }
@@ -1081,6 +1099,11 @@ dpif_backer_run_fast(struct dpif_backer *backer, int max_batch)
 {
     unsigned int work;
 
+    /* If recv_set_enable is false, we should not handle upcalls. */
+    if (!backer->recv_set_enable) {
+        return 0;
+    }
+
     /* Handle one or more batches of upcalls, until there's nothing left to do
      * or until we do a fixed total amount of work.
      *
@@ -1280,9 +1303,12 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
     backer->need_revalidate = 0;
     simap_init(&backer->tnl_backers);
     tag_set_init(&backer->revalidate_set);
+    backer->recv_set_enable = !ofproto_get_flow_restore_wait();
     *backerp = backer;
 
-    dpif_flow_flush(backer->dpif);
+    if (backer->recv_set_enable) {
+        dpif_flow_flush(backer->dpif);
+    }
 
     /* Loop through the ports already on the datapath and remove any
      * that we don't need anymore. */
@@ -1306,7 +1332,7 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
 
     shash_add(&all_dpif_backers, type, backer);
 
-    error = dpif_recv_set(backer->dpif, true);
+    error = dpif_recv_set(backer->dpif, backer->recv_set_enable);
     if (error) {
         VLOG_ERR("failed to listen on datapath of type %s: %s",
                  type, strerror(error));
@@ -1478,6 +1504,12 @@ add_internal_flows(struct ofproto_dpif *ofproto)
     ofpbuf_clear(&ofpacts);
     error = add_internal_flow(ofproto, id++, &ofpacts,
                               &ofproto->no_packet_in_rule);
+    if (error) {
+        return error;
+    }
+
+    error = add_internal_flow(ofproto, id++, &ofpacts,
+                              &ofproto->drop_frags_rule);
     return error;
 }
 
@@ -1542,6 +1574,12 @@ run_fast(struct ofproto *ofproto_)
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
     struct ofport_dpif *ofport;
 
+    /* Do not perform any periodic activity required by 'ofproto' while
+     * waiting for flow restore to complete. */
+    if (ofproto_get_flow_restore_wait()) {
+        return 0;
+    }
+
     HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
         port_run_fast(ofport);
     }
@@ -1561,6 +1599,12 @@ run(struct ofproto *ofproto_)
         complete_operations(ofproto);
     }
 
+    /* Do not perform any periodic activity below required by 'ofproto' while
+     * waiting for flow restore to complete. */
+    if (ofproto_get_flow_restore_wait()) {
+        return 0;
+    }
+
     error = run_fast(ofproto_);
     if (error) {
         return error;
@@ -1635,6 +1679,10 @@ wait(struct ofproto *ofproto_)
         poll_immediate_wake();
     }
 
+    if (ofproto_get_flow_restore_wait()) {
+        return;
+    }
+
     dpif_wait(ofproto->backer->dpif);
     dpif_recv_wait(ofproto->backer->dpif);
     if (ofproto->sflow) {
@@ -1724,7 +1772,7 @@ get_tables(struct ofproto *ofproto_, struct ofp12_table_stats *ots)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
     struct dpif_dp_stats s;
-    uint64_t n_miss, n_no_pkt_in, n_bytes;
+    uint64_t n_miss, n_no_pkt_in, n_bytes, n_dropped_frags;
     uint64_t n_lookup;
 
     strcpy(ots->name, "classifier");
@@ -1732,8 +1780,9 @@ get_tables(struct ofproto *ofproto_, struct ofp12_table_stats *ots)
     dpif_get_dp_stats(ofproto->backer->dpif, &s);
     rule_get_stats(&ofproto->miss_rule->up, &n_miss, &n_bytes);
     rule_get_stats(&ofproto->no_packet_in_rule->up, &n_no_pkt_in, &n_bytes);
+    rule_get_stats(&ofproto->drop_frags_rule->up, &n_dropped_frags, &n_bytes);
 
-    n_lookup = s.n_hit + s.n_missed;
+    n_lookup = s.n_hit + s.n_missed - n_dropped_frags;
     ots->lookup_count = htonll(n_lookup);
     ots->matched_count = htonll(n_lookup - n_miss - n_no_pkt_in);
 }
@@ -1864,6 +1913,10 @@ port_modified(struct ofport *port_)
     if (port->bundle && port->bundle->bond) {
         bond_slave_set_netdev(port->bundle->bond, port, port->up.netdev);
     }
+
+    if (port->cfm) {
+        cfm_set_netdev(port->cfm, port->up.netdev);
+    }
 }
 
 static void
@@ -3775,7 +3828,7 @@ handle_flow_miss(struct flow_miss *miss, struct flow_miss_op *ops,
          * flow keys with fitness ODP_FIT_TO_LITTLE.  This breaks a fundamental
          * assumption used throughout the facet and subfacet handling code.
          * Since we have to handle these misses in userspace anyway, we simply
-         * skip facet creation, avoiding the problem alltogether. */
+         * skip facet creation, avoiding the problem altogether. */
         if (miss->key_fitness == ODP_FIT_TOO_LITTLE
             || !flow_miss_should_make_facet(ofproto, miss, hash)) {
             handle_flow_miss_without_facet(miss, ops, n_ops);
@@ -4299,6 +4352,7 @@ update_subfacet_stats(struct subfacet *subfacet,
                       const struct dpif_flow_stats *stats)
 {
     struct facet *facet = subfacet->facet;
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
     struct dpif_flow_stats diff;
 
     diff.tcp_flags = stats->tcp_flags;
@@ -4318,6 +4372,7 @@ update_subfacet_stats(struct subfacet *subfacet,
         diff.n_bytes = 0;
     }
 
+    ofproto->n_hit += diff.n_packets;
     subfacet->dp_packet_count = stats->n_packets;
     subfacet->dp_byte_count = stats->n_bytes;
     subfacet_update_stats(subfacet, &diff);
@@ -4391,12 +4446,6 @@ update_stats(struct dpif_backer *backer)
         subfacet = subfacet_find(ofproto, key, key_len, key_hash);
         switch (subfacet ? subfacet->path : SF_NOT_INSTALLED) {
         case SF_FAST_PATH:
-            /* Update ofproto_dpif's hit count. */
-            if (stats->n_packets > subfacet->dp_packet_count) {
-                uint64_t delta = stats->n_packets - subfacet->dp_packet_count;
-                dpif_stats_update_hit_count(ofproto, delta);
-            }
-
             update_subfacet_stats(subfacet, stats);
             break;
 
@@ -5390,20 +5439,22 @@ rule_dpif_lookup__(struct ofproto_dpif *ofproto, const struct flow *flow,
 {
     struct cls_rule *cls_rule;
     struct classifier *cls;
+    bool frag;
 
     if (table_id >= N_TABLES) {
         return NULL;
     }
 
     cls = &ofproto->up.tables[table_id].cls;
-    if (flow->nw_frag & FLOW_NW_FRAG_ANY
-        && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) {
-        /* For OFPC_NORMAL frag_handling, we must pretend that transport ports
-         * are unavailable. */
+    frag = (flow->nw_frag & FLOW_NW_FRAG_ANY) != 0;
+    if (frag && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) {
+        /* We must pretend that transport ports are unavailable. */
         struct flow ofpc_normal_flow = *flow;
         ofpc_normal_flow.tp_src = htons(0);
         ofpc_normal_flow.tp_dst = htons(0);
         cls_rule = classifier_lookup(cls, &ofpc_normal_flow);
+    } else if (frag && ofproto->up.frag_handling == OFPC_FRAG_DROP) {
+        cls_rule = &ofproto->drop_frags_rule->up.cr;
     } else {
         cls_rule = classifier_lookup(cls, flow);
     }
@@ -5963,10 +6014,14 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port,
                                  &ctx->xout->odp_actions);
         ctx->xin->flow.tunnel = flow_tnl; /* Restore tunnel metadata */
     } else {
+        uint16_t vlandev_port;
         odp_port = ofport->odp_port;
-        out_port = vsp_realdev_to_vlandev(ctx->ofproto, odp_port,
-                                          ctx->xin->flow.vlan_tci);
-        if (out_port != odp_port) {
+        vlandev_port = vsp_realdev_to_vlandev(ctx->ofproto, ofp_port,
+                                              ctx->xin->flow.vlan_tci);
+        if (vlandev_port == ofp_port) {
+            out_port = odp_port;
+        } else {
+            out_port = ofp_port_to_odp_port(ctx->ofproto, vlandev_port);
             ctx->xin->flow.vlan_tci = htons(0);
         }
         ctx->xin->flow.skb_mark &= ~IPSEC_MARK;
@@ -6126,6 +6181,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
 {
     struct ofputil_packet_in pin;
     struct ofpbuf *packet;
+    struct flow key;
 
     ovs_assert(!ctx->xout->slow || ctx->xout->slow == SLOW_CONTROLLER);
     ctx->xout->slow = SLOW_CONTROLLER;
@@ -6135,48 +6191,15 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
 
     packet = ofpbuf_clone(ctx->xin->packet);
 
-    if (packet->l2 && packet->l3) {
-        struct eth_header *eh;
-        uint16_t mpls_depth;
-
-        eth_pop_vlan(packet);
-        eh = packet->l2;
-
-        memcpy(eh->eth_src, ctx->xin->flow.dl_src, sizeof eh->eth_src);
-        memcpy(eh->eth_dst, ctx->xin->flow.dl_dst, sizeof eh->eth_dst);
+    key.skb_priority = 0;
+    key.skb_mark = 0;
+    memset(&key.tunnel, 0, sizeof key.tunnel);
 
-        if (ctx->xin->flow.vlan_tci & htons(VLAN_CFI)) {
-            eth_push_vlan(packet, ctx->xin->flow.vlan_tci);
-        }
-
-        mpls_depth = eth_mpls_depth(packet);
-
-        if (mpls_depth < ctx->xin->flow.mpls_depth) {
-            push_mpls(packet, ctx->xin->flow.dl_type, ctx->xin->flow.mpls_lse);
-        } else if (mpls_depth > ctx->xin->flow.mpls_depth) {
-            pop_mpls(packet, ctx->xin->flow.dl_type);
-        } else if (mpls_depth) {
-            set_mpls_lse(packet, ctx->xin->flow.mpls_lse);
-        }
-
-        if (packet->l4) {
-            if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IP)) {
-                packet_set_ipv4(packet, ctx->xin->flow.nw_src,
-                                ctx->xin->flow.nw_dst, ctx->xin->flow.nw_tos,
-                                ctx->xin->flow.nw_ttl);
-            }
+    commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
+                       &ctx->xout->odp_actions);
 
-            if (packet->l7) {
-                if (ctx->xin->flow.nw_proto == IPPROTO_TCP) {
-                    packet_set_tcp_port(packet, ctx->xin->flow.tp_src,
-                                        ctx->xin->flow.tp_dst);
-                } else if (ctx->xin->flow.nw_proto == IPPROTO_UDP) {
-                    packet_set_udp_port(packet, ctx->xin->flow.tp_src,
-                                        ctx->xin->flow.tp_dst);
-                }
-            }
-        }
-    }
+    odp_execute_actions(NULL, packet, &key, ctx->xout->odp_actions.data,
+                        ctx->xout->odp_actions.size, NULL, NULL);
 
     pin.packet = packet->data;
     pin.packet_len = packet->size;
@@ -8077,6 +8100,9 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
     } else if (rule == ofproto->no_packet_in_rule) {
         ds_put_cstr(ds, "\nNo match, packets dropped because "
                     "OFPPC_NO_PACKET_IN is set on in_port.\n");
+    } else if (rule == ofproto->drop_frags_rule) {
+        ds_put_cstr(ds, "\nPackets dropped because they are IP fragments "
+                    "and the fragment handling mode is \"drop\".\n");
     }
 
     if (rule) {
@@ -8524,33 +8550,31 @@ hash_realdev_vid(uint16_t realdev_ofp_port, int vid)
     return hash_2words(realdev_ofp_port, vid);
 }
 
-/* Returns the ODP port number of the Linux VLAN device that corresponds to
- * 'vlan_tci' on the network device with port number 'realdev_odp_port' in
- * 'ofproto'.  For example, given 'realdev_odp_port' of eth0 and 'vlan_tci' 9,
- * it would return the port number of eth0.9.
+/* Returns the OFP port number of the Linux VLAN device that corresponds to
+ * 'vlan_tci' on the network device with port number 'realdev_ofp_port' in
+ * 'struct ofport_dpif'.  For example, given 'realdev_ofp_port' of eth0 and
+ * 'vlan_tci' 9, it would return the port number of eth0.9.
  *
- * Unless VLAN splinters are enabled for port 'realdev_odp_port', this
- * function just returns its 'realdev_odp_port' argument. */
-static uint32_t
+ * Unless VLAN splinters are enabled for port 'realdev_ofp_port', this
+ * function just returns its 'realdev_ofp_port' argument. */
+static uint16_t
 vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto,
-                       uint32_t realdev_odp_port, ovs_be16 vlan_tci)
+                       uint16_t realdev_ofp_port, ovs_be16 vlan_tci)
 {
     if (!hmap_is_empty(&ofproto->realdev_vid_map)) {
-        uint16_t realdev_ofp_port;
         int vid = vlan_tci_to_vid(vlan_tci);
         const struct vlan_splinter *vsp;
 
-        realdev_ofp_port = odp_port_to_ofp_port(ofproto, realdev_odp_port);
         HMAP_FOR_EACH_WITH_HASH (vsp, realdev_vid_node,
                                  hash_realdev_vid(realdev_ofp_port, vid),
                                  &ofproto->realdev_vid_map) {
             if (vsp->realdev_ofp_port == realdev_ofp_port
                 && vsp->vid == vid) {
-                return ofp_port_to_odp_port(ofproto, vsp->vlandev_ofp_port);
+                return vsp->vlandev_ofp_port;
             }
         }
     }
-    return realdev_odp_port;
+    return realdev_ofp_port;
 }
 
 static struct vlan_splinter *
@@ -8771,12 +8795,6 @@ update_moving_averages(struct ofproto_dpif *ofproto)
     }
 }
 
-static void
-dpif_stats_update_hit_count(struct ofproto_dpif *ofproto, uint64_t delta)
-{
-    ofproto->n_hit += delta;
-}
-
 const struct ofproto_class ofproto_dpif_class = {
     init,
     enumerate_types,