dp-packet: Remove ofpbuf dependency.
[cascardo/ovs.git] / ofproto / ofproto-dpif-xlate.c
index 4a5b7fd..419e861 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
 #include "cfm.h"
 #include "connmgr.h"
 #include "coverage.h"
+#include "dp-packet.h"
 #include "dpif.h"
 #include "dynamic-string.h"
 #include "in-band.h"
@@ -52,7 +53,6 @@
 #include "ofproto/ofproto-dpif-sflow.h"
 #include "ofproto/ofproto-dpif.h"
 #include "ofproto/ofproto-provider.h"
-#include "packet-dpif.h"
 #include "ovs-router.h"
 #include "tnl-ports.h"
 #include "tunnel.h"
@@ -196,6 +196,7 @@ struct xlate_ctx {
     int recurse;                /* Current resubmit nesting depth. */
     int resubmits;              /* Total number of resubmits. */
     bool in_group;              /* Currently translating ofgroup, if true. */
+    bool in_action_set;         /* Currently translating action_set, if true. */
 
     uint32_t orig_skb_priority; /* Priority when packet arrived. */
     uint8_t table_id;           /* OpenFlow table ID where flow was found. */
@@ -1185,11 +1186,11 @@ stp_should_process_flow(const struct flow *flow, struct flow_wildcards *wc)
 }
 
 static void
-stp_process_packet(const struct xport *xport, const struct ofpbuf *packet)
+stp_process_packet(const struct xport *xport, const struct dp_packet *packet)
 {
     struct stp_port *sp = xport_get_stp_port(xport);
-    struct ofpbuf payload = *packet;
-    struct eth_header *eth = ofpbuf_data(&payload);
+    struct dp_packet payload = *packet;
+    struct eth_header *eth = dp_packet_data(&payload);
 
     /* Sink packets on ports that have STP disabled when the bridge has
      * STP enabled. */
@@ -1198,12 +1199,12 @@ stp_process_packet(const struct xport *xport, const struct ofpbuf *packet)
     }
 
     /* Trim off padding on payload. */
-    if (ofpbuf_size(&payload) > ntohs(eth->eth_type) + ETH_HEADER_LEN) {
-        ofpbuf_set_size(&payload, ntohs(eth->eth_type) + ETH_HEADER_LEN);
+    if (dp_packet_size(&payload) > ntohs(eth->eth_type) + ETH_HEADER_LEN) {
+        dp_packet_set_size(&payload, ntohs(eth->eth_type) + ETH_HEADER_LEN);
     }
 
-    if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) {
-        stp_received_bpdu(sp, ofpbuf_data(&payload), ofpbuf_size(&payload));
+    if (dp_packet_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) {
+        stp_received_bpdu(sp, dp_packet_data(&payload), dp_packet_size(&payload));
     }
 }
 
@@ -1238,10 +1239,10 @@ xport_rstp_should_manage_bpdu(const struct xport *xport)
 }
 
 static void
-rstp_process_packet(const struct xport *xport, const struct ofpbuf *packet)
+rstp_process_packet(const struct xport *xport, const struct dp_packet *packet)
 {
-    struct ofpbuf payload = *packet;
-    struct eth_header *eth = ofpbuf_data(&payload);
+    struct dp_packet payload = *packet;
+    struct eth_header *eth = dp_packet_data(&payload);
 
     /* Sink packets on ports that have no RSTP. */
     if (!xport->rstp_port) {
@@ -1249,13 +1250,13 @@ rstp_process_packet(const struct xport *xport, const struct ofpbuf *packet)
     }
 
     /* Trim off padding on payload. */
-    if (ofpbuf_size(&payload) > ntohs(eth->eth_type) + ETH_HEADER_LEN) {
-        ofpbuf_set_size(&payload, ntohs(eth->eth_type) + ETH_HEADER_LEN);
+    if (dp_packet_size(&payload) > ntohs(eth->eth_type) + ETH_HEADER_LEN) {
+        dp_packet_set_size(&payload, ntohs(eth->eth_type) + ETH_HEADER_LEN);
     }
 
-    if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) {
-        rstp_port_received_bpdu(xport->rstp_port, ofpbuf_data(&payload),
-                                ofpbuf_size(&payload));
+    if (dp_packet_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) {
+        rstp_port_received_bpdu(xport->rstp_port, dp_packet_data(&payload),
+                                dp_packet_size(&payload));
     }
 }
 
@@ -1801,9 +1802,10 @@ is_admissible(struct xlate_ctx *ctx, struct xport *in_port,
         case BV_DROP_IF_MOVED:
             ovs_rwlock_rdlock(&xbridge->ml->rwlock);
             mac = mac_learning_lookup(xbridge->ml, flow->dl_src, vlan);
-            if (mac && mac->port.p != in_xbundle->ofbundle &&
-                (!is_gratuitous_arp(flow, &ctx->xout->wc)
-                 || mac_entry_is_grat_arp_locked(mac))) {
+            if (mac
+                && mac_entry_get_port(xbridge->ml, mac) != in_xbundle->ofbundle
+                && (!is_gratuitous_arp(flow, &ctx->xout->wc)
+                    || mac_entry_is_grat_arp_locked(mac))) {
                 ovs_rwlock_unlock(&xbridge->ml->rwlock);
                 xlate_report(ctx, "SLB bond thinks this packet looped back, "
                              "dropping");
@@ -1855,7 +1857,7 @@ OVS_REQ_RDLOCK(ml->rwlock)
         }
     }
 
-    return mac->port.p != in_xbundle->ofbundle;
+    return mac_entry_get_port(ml, mac) != in_xbundle->ofbundle;
 }
 
 
@@ -1891,7 +1893,7 @@ OVS_REQ_WRLOCK(xbridge->ml->rwlock)
         }
     }
 
-    if (mac->port.p != in_xbundle->ofbundle) {
+    if (mac_entry_get_port(xbridge->ml, mac) != in_xbundle->ofbundle) {
         /* The log messages here could actually be useful in debugging,
          * so keep the rate limit relatively high. */
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
@@ -1901,8 +1903,7 @@ OVS_REQ_WRLOCK(xbridge->ml->rwlock)
                     xbridge->name, ETH_ADDR_ARGS(flow->dl_src),
                     in_xbundle->name, vlan);
 
-        mac->port.p = in_xbundle->ofbundle;
-        mac_learning_changed(xbridge->ml);
+        mac_entry_set_port(xbridge->ml, mac, in_xbundle->ofbundle);
     }
 }
 
@@ -1982,7 +1983,7 @@ update_mcast_snooping_table(const struct xbridge *xbridge,
     struct mcast_snooping *ms = xbridge->ms;
     struct xlate_cfg *xcfg;
     struct xbundle *mcast_xbundle;
-    struct mcast_fport_bundle *fport;
+    struct mcast_port_bundle *fport;
 
     /* Don't learn the OFPP_NONE port. */
     if (in_xbundle == &ofpp_none_bundle) {
@@ -1993,7 +1994,7 @@ update_mcast_snooping_table(const struct xbridge *xbridge,
     mcast_xbundle = NULL;
     ovs_rwlock_wrlock(&ms->rwlock);
     xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
-    LIST_FOR_EACH(fport, fport_node, &ms->fport_list) {
+    LIST_FOR_EACH(fport, node, &ms->fport_list) {
         mcast_xbundle = xbundle_lookup(xcfg, fport->port);
         if (mcast_xbundle == in_xbundle) {
             break;
@@ -2066,11 +2067,11 @@ xlate_normal_mcast_send_fports(struct xlate_ctx *ctx,
     OVS_REQ_RDLOCK(ms->rwlock)
 {
     struct xlate_cfg *xcfg;
-    struct mcast_fport_bundle *fport;
+    struct mcast_port_bundle *fport;
     struct xbundle *mcast_xbundle;
 
     xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
-    LIST_FOR_EACH(fport, fport_node, &ms->fport_list) {
+    LIST_FOR_EACH(fport, node, &ms->fport_list) {
         mcast_xbundle = xbundle_lookup(xcfg, fport->port);
         if (mcast_xbundle && mcast_xbundle != in_xbundle) {
             xlate_report(ctx, "forwarding to mcast flood port");
@@ -2083,6 +2084,31 @@ xlate_normal_mcast_send_fports(struct xlate_ctx *ctx,
     }
 }
 
+/* forward the Reports to configured ports */
+static void
+xlate_normal_mcast_send_rports(struct xlate_ctx *ctx,
+                               struct mcast_snooping *ms,
+                               struct xbundle *in_xbundle, uint16_t vlan)
+    OVS_REQ_RDLOCK(ms->rwlock)
+{
+    struct xlate_cfg *xcfg;
+    struct mcast_port_bundle *rport;
+    struct xbundle *mcast_xbundle;
+
+    xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
+    LIST_FOR_EACH(rport, node, &ms->rport_list) {
+        mcast_xbundle = xbundle_lookup(xcfg, rport->port);
+        if (mcast_xbundle && mcast_xbundle != in_xbundle) {
+            xlate_report(ctx, "forwarding Report to mcast flagged port");
+            output_normal(ctx, mcast_xbundle, vlan);
+        } else if (!mcast_xbundle) {
+            xlate_report(ctx, "mcast port is unknown, dropping the Report");
+        } else {
+            xlate_report(ctx, "mcast port is input port, dropping the Report");
+        }
+    }
+}
+
 static void
 xlate_normal_flood(struct xlate_ctx *ctx, struct xbundle *in_xbundle,
                    uint16_t vlan)
@@ -2197,6 +2223,15 @@ xlate_normal(struct xlate_ctx *ctx)
             if (mcast_snooping_is_membership(flow->tp_src)) {
                 ovs_rwlock_rdlock(&ms->rwlock);
                 xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, vlan);
+                /* RFC4541: section 2.1.1, item 1: A snooping switch should
+                 * forward IGMP Membership Reports only to those ports where
+                 * multicast routers are attached.  Alternatively stated: a
+                 * snooping switch should not forward IGMP Membership Reports
+                 * to ports on which only hosts are attached.
+                 * An administrative control may be provided to override this
+                 * restriction, allowing the report messages to be flooded to
+                 * other ports. */
+                xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, vlan);
                 ovs_rwlock_unlock(&ms->rwlock);
             } else {
                 xlate_report(ctx, "multicast traffic, flooding");
@@ -2234,7 +2269,7 @@ xlate_normal(struct xlate_ctx *ctx)
     } else {
         ovs_rwlock_rdlock(&ctx->xbridge->ml->rwlock);
         mac = mac_learning_lookup(ctx->xbridge->ml, flow->dl_dst, vlan);
-        mac_port = mac ? mac->port.p : NULL;
+        mac_port = mac ? mac_entry_get_port(ctx->xbridge->ml, mac) : NULL;
         ovs_rwlock_unlock(&ctx->xbridge->ml->rwlock);
 
         if (mac_port) {
@@ -2459,7 +2494,7 @@ fix_sflow_action(struct xlate_ctx *ctx)
 
 static enum slow_path_reason
 process_special(struct xlate_ctx *ctx, const struct flow *flow,
-                const struct xport *xport, const struct ofpbuf *packet)
+                const struct xport *xport, const struct dp_packet *packet)
 {
     struct flow_wildcards *wc = &ctx->xout->wc;
     const struct xbridge *xbridge = ctx->xbridge;
@@ -2537,14 +2572,14 @@ tnl_route_lookup_flow(const struct flow *oflow,
 }
 
 static int
-xlate_flood_packet(struct xbridge *xbridge, struct ofpbuf *packet)
+xlate_flood_packet(struct xbridge *xbridge, struct dp_packet *packet)
 {
     struct ofpact_output output;
     struct flow flow;
 
     ofpact_init(&output.ofpact, OFPACT_OUTPUT, sizeof output);
     /* Use OFPP_NONE as the in_port to avoid special packet processing. */
-    flow_extract(packet, NULL, &flow);
+    flow_extract(packet, &flow);
     flow.in_port.ofp_port = OFPP_NONE;
     output.port = OFPP_FLOOD;
     output.max_len = 0;
@@ -2559,13 +2594,13 @@ tnl_send_arp_request(const struct xport *out_dev, const uint8_t eth_src[ETH_ADDR
                      ovs_be32 ip_src, ovs_be32 ip_dst)
 {
     struct xbridge *xbridge = out_dev->xbridge;
-    struct ofpbuf packet;
+    struct dp_packet packet;
 
-    ofpbuf_init(&packet, 0);
+    dp_packet_init(&packet, 0);
     compose_arp(&packet, eth_src, ip_src, ip_dst);
 
     xlate_flood_packet(xbridge, &packet);
-    ofpbuf_uninit(&packet);
+    dp_packet_uninit(&packet);
 }
 
 static int
@@ -2604,7 +2639,8 @@ build_tunnel_send(const struct xlate_ctx *ctx, const struct xport *xport,
         struct xc_entry *entry;
 
         entry = xlate_cache_add_entry(ctx->xin->xcache, XC_TNL_ARP);
-        strncpy(entry->u.tnl_arp_cache.br_name, out_dev->xbridge->name, IFNAMSIZ);
+        ovs_strlcpy(entry->u.tnl_arp_cache.br_name, out_dev->xbridge->name,
+                    sizeof entry->u.tnl_arp_cache.br_name);
         entry->u.tnl_arp_cache.d_ip = d_ip;
     }
     err = tnl_port_build_header(xport->ofport, flow,
@@ -2635,7 +2671,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
 
     /* If 'struct flow' gets additional metadata, we'll need to zero it out
      * before traversing a patch port. */
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
     memset(&flow_tnl, 0, sizeof flow_tnl);
 
     if (!xport) {
@@ -3160,14 +3196,14 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
                           uint16_t controller_id)
 {
     struct ofproto_packet_in *pin;
-    struct dpif_packet *packet;
+    struct dp_packet *packet;
 
     ctx->xout->slow |= SLOW_CONTROLLER;
     if (!ctx->xin->packet) {
         return;
     }
 
-    packet = dpif_packet_clone_from_ofpbuf(ctx->xin->packet);
+    packet = dp_packet_clone(ctx->xin->packet);
 
     ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
                                           ctx->xout->odp_actions,
@@ -3179,8 +3215,8 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
                         ofpbuf_size(ctx->xout->odp_actions), NULL);
 
     pin = xmalloc(sizeof *pin);
-    pin->up.packet_len = ofpbuf_size(&packet->ofpbuf);
-    pin->up.packet = ofpbuf_steal_data(&packet->ofpbuf);
+    pin->up.packet_len = dp_packet_size(packet);
+    pin->up.packet = dp_packet_steal_data(packet);
     pin->up.reason = reason;
     pin->up.table_id = ctx->table_id;
     pin->up.cookie = (ctx->rule
@@ -3208,7 +3244,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
         }
     }
     ofproto_dpif_send_packet_in(ctx->xbridge->ofproto, pin);
-    dpif_packet_delete(packet);
+    dp_packet_delete(packet);
 }
 
 static void
@@ -3430,7 +3466,10 @@ xlate_output_action(struct xlate_ctx *ctx,
         break;
     case OFPP_CONTROLLER:
         execute_controller_action(ctx, max_len,
-                                  ctx->in_group ? OFPR_GROUP : OFPR_ACTION, 0);
+                                  (ctx->in_group ? OFPR_GROUP
+                                   : ctx->in_action_set ? OFPR_ACTION_SET
+                                   : OFPR_ACTION),
+                                  0);
         break;
     case OFPP_NONE:
         break;
@@ -3712,9 +3751,11 @@ xlate_action_set(struct xlate_ctx *ctx)
     uint64_t action_list_stub[1024 / 64];
     struct ofpbuf action_list;
 
+    ctx->in_action_set = true;
     ofpbuf_use_stub(&action_list, action_list_stub, sizeof action_list_stub);
     ofpacts_execute_action_set(&action_list, &ctx->action_set);
     do_xlate_actions(ofpbuf_data(&action_list), ofpbuf_size(&action_list), ctx);
+    ctx->in_action_set = false;
     ofpbuf_uninit(&action_list);
 }
 
@@ -3742,6 +3783,7 @@ ofpact_needs_recirculation_after_mpls(const struct ofpact *a, struct xlate_ctx *
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
+    case OFPACT_CONJUNCTION:
     case OFPACT_NOTE:
     case OFPACT_OUTPUT_REG:
     case OFPACT_EXIT:
@@ -4055,6 +4097,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             xlate_learn_action(ctx, ofpact_get_LEARN(a));
             break;
 
+        case OFPACT_CONJUNCTION: {
+            /* A flow with a "conjunction" action represents part of a special
+             * kind of "set membership match".  Such a flow should not actually
+             * get executed, but it could via, say, a "packet-out", even though
+             * that wouldn't be useful.  Log it to help debugging. */
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+            VLOG_INFO_RL(&rl, "executing no-op conjunction action");
+            break;
+        }
+
         case OFPACT_EXIT:
             ctx->exit = true;
             break;
@@ -4110,7 +4162,7 @@ void
 xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto,
               const struct flow *flow, ofp_port_t in_port,
               struct rule_dpif *rule, uint16_t tcp_flags,
-              const struct ofpbuf *packet)
+              const struct dp_packet *packet)
 {
     xin->ofproto = ofproto;
     xin->flow = *flow;
@@ -4387,6 +4439,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     ctx.recurse = 0;
     ctx.resubmits = 0;
     ctx.in_group = false;
+    ctx.in_action_set = false;
     ctx.orig_skb_priority = flow->skb_priority;
     ctx.table_id = 0;
     ctx.exit = false;
@@ -4579,7 +4632,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
  * May modify 'packet'.
  * Returns 0 if successful, otherwise a positive errno value. */
 int
-xlate_send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
+xlate_send_packet(const struct ofport_dpif *ofport, struct dp_packet *packet)
 {
     struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
     struct xport *xport;
@@ -4588,7 +4641,7 @@ xlate_send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
 
     ofpact_init(&output.ofpact, OFPACT_OUTPUT, sizeof output);
     /* Use OFPP_NONE as the in_port to avoid special packet processing. */
-    flow_extract(packet, NULL, &flow);
+    flow_extract(packet, &flow);
     flow.in_port.ofp_port = OFPP_NONE;
 
     xport = xport_lookup(xcfg, ofport);