ofproto-dpif: Use execute_actions to execute controller actions
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index c866206..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);
@@ -675,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;
@@ -1501,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;
 }
 
@@ -1763,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");
@@ -1771,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);
 }
@@ -1903,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
@@ -3814,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);
@@ -5425,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);
     }
@@ -5998,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;
@@ -6161,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;
@@ -6170,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);
-
-        if (ctx->xin->flow.vlan_tci & htons(VLAN_CFI)) {
-            eth_push_vlan(packet, ctx->xin->flow.vlan_tci);
-        }
-
-        mpls_depth = eth_mpls_depth(packet);
+    key.skb_priority = 0;
+    key.skb_mark = 0;
+    memset(&key.tunnel, 0, sizeof key.tunnel);
 
-        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);
-        }
+    commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
+                       &ctx->xout->odp_actions);
 
-        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);
-            }
-
-            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;
@@ -8112,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) {
@@ -8559,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 *