tunneling: Add support for tunnel ID.
authorJesse Gross <jesse@nicira.com>
Mon, 12 Apr 2010 15:49:16 +0000 (11:49 -0400)
committerJesse Gross <jesse@nicira.com>
Mon, 19 Apr 2010 13:11:51 +0000 (09:11 -0400)
Add a tun_id field which contains the ID of the encapsulating tunnel
on which a packet was received (0 if not received on a tunnel).  Also
add an action which allows the tunnel ID to be set for outgoing
packets.  At this point there aren't any tunnel implementations so
these fields don't have any effect.

The matching is exposed to OpenFlow by overloading the high 32 bits
of the cookie as the tunnel ID.  ovs-ofctl is capable of turning
on this special behavior using a new "tun-cookie" command but this
command is intentially undocumented to avoid it being used without
a full understanding of the consequences.

25 files changed:
datapath/actions.c
datapath/datapath.c
datapath/datapath.h
datapath/flow.c
include/openflow/nicira-ext.h
include/openvswitch/datapath-protocol.h
lib/classifier.c
lib/classifier.h
lib/dhcp-client.c
lib/dpif-netdev.c
lib/flow.c
lib/flow.h
lib/learning-switch.c
lib/odp-util.c
lib/ofp-print.c
lib/vconn.c
ofproto/fail-open.c
ofproto/in-band.c
ofproto/ofproto-sflow.c
ofproto/ofproto.c
tests/test-classifier.c
tests/test-flows.c
utilities/ovs-ofctl.8.in
utilities/ovs-ofctl.c
vswitchd/bridge.c

index bef7d108c3e7b1ef61f53824bbd426bbea925a22..10324619d3d66566126644f96a15584e7d92765e 100644 (file)
@@ -58,6 +58,11 @@ make_writable(struct sk_buff *skb, unsigned min_headroom, gfp_t gfp)
        return NULL;
 }
 
+static void set_tunnel(struct sk_buff *skb, struct odp_flow_key *key,
+                      __be32 tun_id)
+{
+       OVS_CB(skb)->tun_id = key->tun_id = tun_id;
+}
 
 static struct sk_buff *
 vlan_pull_tag(struct sk_buff *skb)
@@ -477,6 +482,8 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
                }
        }
 
+       OVS_CB(skb)->tun_id = 0;
+
        for (; n_actions > 0; a++, n_actions--) {
                WARN_ON_ONCE(skb_shared(skb));
                if (prev_port != -1) {
@@ -502,6 +509,10 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
                        }
                        break;
 
+               case ODPAT_SET_TUNNEL:
+                       set_tunnel(skb, key, a->tunnel.tun_id);
+                       break;
+
                case ODPAT_SET_VLAN_VID:
                case ODPAT_SET_VLAN_PCP:
                        skb = modify_vlan_tci(dp, skb, key, a, n_actions, gfp);
index 6365f9474564dbac9c7be08d6c697a416bda155b..9dfd6042d25b53e3c01046600368422062904422 100644 (file)
@@ -537,6 +537,7 @@ void dp_process_received_packet(struct sk_buff *skb, struct net_bridge_port *p)
        WARN_ON_ONCE(skb_shared(skb));
 
        compute_ip_summed(skb, false);
+       OVS_CB(skb)->tun_id = 0;
 
        /* BHs are off so we don't have to use get_cpu()/put_cpu() here. */
        stats = percpu_ptr(dp->stats_percpu, smp_processor_id());
@@ -558,7 +559,7 @@ void dp_process_received_packet(struct sk_buff *skb, struct net_bridge_port *p)
                stats->n_hit++;
        } else {
                stats->n_missed++;
-               dp_output_control(dp, skb, _ODPL_MISS_NR, 0);
+               dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id);
        }
 }
 
@@ -1302,6 +1303,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *executep)
        skb = alloc_skb(execute.length, GFP_KERNEL);
        if (!skb)
                goto error_free_actions;
+
        if (execute.in_port < DP_MAX_PORTS) {
                struct net_bridge_port *p = dp->ports[execute.in_port];
                if (p)
index 38c84756f04a64b8bcc95b167428f9afb629ad6c..faf247042fd105a0e20a5c96e4eb192b3fa03dd9 100644 (file)
@@ -195,7 +195,8 @@ enum csum_type {
  * kernel versions.
  */
 struct ovs_skb_cb {
-       enum csum_type  ip_summed;
+       enum csum_type          ip_summed;
+       __be32                  tun_id;
 };
 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
 
index 9a94d0ba8d28971e5430e9bdc3dbc1c0657a03b9..094a2c8d96c99a24cbf2796f4d8bab40789f523b 100644 (file)
@@ -202,8 +202,9 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
        int nh_ofs;
 
        memset(key, 0, sizeof *key);
-       key->dl_vlan = htons(ODP_VLAN_NONE);
+       key->tun_id = OVS_CB(skb)->tun_id;
        key->in_port = in_port;
+       key->dl_vlan = htons(ODP_VLAN_NONE);
 
        if (skb->len < sizeof *eth)
                return 0;
index 17d86a86575c5bdce66c7764f214d705ef6bdd93..5ec009a767df6f2653f6b65222cfcc75b30c27ba 100644 (file)
@@ -45,6 +45,10 @@ enum nicira_type {
     NXT_FLOW_END_CONFIG__OBSOLETE,
     NXT_FLOW_END__OBSOLETE,
     NXT_MGMT__OBSOLETE,
+
+    /* Use the high 32 bits of the cookie field as the tunnel ID in the flow
+     * match. */
+    NXT_TUN_ID_FROM_COOKIE,
 };
 
 struct nicira_header {
@@ -54,6 +58,14 @@ struct nicira_header {
 };
 OFP_ASSERT(sizeof(struct nicira_header) == 16);
 
+struct nxt_tun_id_cookie {
+    struct ofp_header header;
+    uint32_t vendor;            /* NX_VENDOR_ID. */
+    uint32_t subtype;           /* NXT_TUN_ID_FROM_COOKIE */
+    uint8_t set;                /* Nonzero to enable, zero to disable. */
+    uint8_t pad[7];
+};
+OFP_ASSERT(sizeof(struct nxt_tun_id_cookie) == 24);
 
 enum nx_action_subtype {
     NXAST_SNAT__OBSOLETE,           /* No longer used. */
@@ -80,13 +92,15 @@ enum nx_action_subtype {
      *
      * NXAST_RESUBMIT may be used any number of times within a set of actions.
      */
-    NXAST_RESUBMIT
+    NXAST_RESUBMIT,
+
+    NXAST_SET_TUNNEL                /* Set encapsulating tunnel ID. */
 };
 
 /* Action structure for NXAST_RESUBMIT. */
 struct nx_action_resubmit {
     uint16_t type;                  /* OFPAT_VENDOR. */
-    uint16_t len;                   /* Length is 8. */
+    uint16_t len;                   /* Length is 16. */
     uint32_t vendor;                /* NX_VENDOR_ID. */
     uint16_t subtype;               /* NXAST_RESUBMIT. */
     uint16_t in_port;               /* New in_port for checking flow table. */
@@ -94,14 +108,31 @@ struct nx_action_resubmit {
 };
 OFP_ASSERT(sizeof(struct nx_action_resubmit) == 16);
 
+/* Action structure for NXAST_SET_TUNNEL. */
+struct nx_action_set_tunnel {
+    uint16_t type;                  /* OFPAT_VENDOR. */
+    uint16_t len;                   /* Length is 16. */
+    uint32_t vendor;                /* NX_VENDOR_ID. */
+    uint16_t subtype;               /* NXAST_SET_TUNNEL. */
+    uint8_t pad[2];
+    uint32_t tun_id;                /* Tunnel ID. */
+};
+OFP_ASSERT(sizeof(struct nx_action_set_tunnel) == 16);
+
 /* Header for Nicira-defined actions. */
 struct nx_action_header {
     uint16_t type;                  /* OFPAT_VENDOR. */
-    uint16_t len;                   /* Length is 8. */
+    uint16_t len;                   /* Length is 16. */
     uint32_t vendor;                /* NX_VENDOR_ID. */
     uint16_t subtype;               /* NXAST_*. */
     uint8_t pad[6];
 };
 OFP_ASSERT(sizeof(struct nx_action_header) == 16);
 
+/* Wildcard for tunnel ID. */
+#define NXFW_TUN_ID  (1 << 25)
+
+#define NXFW_ALL NXFW_TUN_ID
+#define OVSFW_ALL (OFPFW_ALL | NXFW_ALL)
+
 #endif /* openflow/nicira-ext.h */
index 6c5354548ea4ae38e373f5f94728973d326708a3..6ddff014111ad2bdfc2cce0a3a74e6bc236f1427 100644 (file)
@@ -127,7 +127,8 @@ struct odp_stats {
  * @arg: Argument value whose meaning depends on @type.
  *
  * For @type == %_ODPL_MISS_NR, the header is followed by packet data.  The
- * @arg member is unused and set to 0.
+ * @arg member is the ID (in network byte order) of the tunnel that
+ * encapsulated this packet. It is 0 if the packet was not received on a tunnel.
  *
  * For @type == %_ODPL_ACTION_NR, the header is followed by packet data.  The
  * @arg member is copied from the &struct odp_action_controller that caused
@@ -191,6 +192,7 @@ struct odp_flow_stats {
 };
 
 struct odp_flow_key {
+    __be32 tun_id;               /* Encapsulating tunnel ID. */
     __be32 nw_src;               /* IP source address. */
     __be32 nw_dst;               /* IP destination address. */
     __u16  in_port;              /* Input switch port. */
@@ -253,7 +255,8 @@ struct odp_flowvec {
 #define ODPAT_SET_NW_TOS        10   /* IP ToS/DSCP field (6 bits). */
 #define ODPAT_SET_TP_SRC        11   /* TCP/UDP source port. */
 #define ODPAT_SET_TP_DST        12   /* TCP/UDP destination port. */
-#define ODPAT_N_ACTIONS         13
+#define ODPAT_SET_TUNNEL        13   /* Set the encapsulating tunnel ID. */
+#define ODPAT_N_ACTIONS         14
 
 struct odp_action_output {
     __u16 type;                  /* ODPAT_OUTPUT. */
@@ -275,6 +278,12 @@ struct odp_action_controller {
     __u32 arg;                  /* Copied to struct odp_msg 'arg' member. */
 };
 
+struct odp_action_tunnel {
+    __u16 type;                 /* ODPAT_SET_TUNNEL. */
+    __u16 reserved;
+    __be32 tun_id;              /* Tunnel ID. */
+};
+
 /* Action structure for ODPAT_SET_VLAN_VID. */
 struct odp_action_vlan_vid {
     __u16 type;                  /* ODPAT_SET_VLAN_VID. */
@@ -326,6 +335,7 @@ union odp_action {
     struct odp_action_output output;
     struct odp_action_output_group output_group;
     struct odp_action_controller controller;
+    struct odp_action_tunnel tunnel;
     struct odp_action_vlan_vid vlan_vid;
     struct odp_action_vlan_pcp vlan_pcp;
     struct odp_action_dl_addr dl_addr;
index ee78dadd95d80cba9bab0656359420de7d6622be..4bd894216593f920d5fc26b186ee7c33464c89a1 100644 (file)
@@ -55,8 +55,8 @@ static bool rules_match_2wild(const struct cls_rule *wild1,
 /* Converts the flow in 'flow' into a cls_rule in 'rule', with the given
  * 'wildcards' and 'priority'.*/
 void
-cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
-                   uint32_t wildcards, unsigned int priority)
+cls_rule_from_flow(const flow_t *flow, uint32_t wildcards,
+                   unsigned int priority, struct cls_rule *rule)
 {
     assert(!flow->reserved[0] && !flow->reserved[1] && !flow->reserved[2]);
     rule->flow = *flow;
@@ -66,13 +66,15 @@ cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
 }
 
 /* Converts the ofp_match in 'match' into a cls_rule in 'rule', with the given
- * 'priority'. */
+ * 'priority'.  If 'tun_id_from_cookie' is set then the upper 32 bits of
+ * 'cookie' are stored in the rule as the tunnel ID. */
 void
-cls_rule_from_match(struct cls_rule *rule, const struct ofp_match *match,
-                    unsigned int priority)
+cls_rule_from_match(const struct ofp_match *match, unsigned int priority,
+                    bool tun_id_from_cookie, uint64_t cookie,
+                    struct cls_rule *rule)
 {
     uint32_t wildcards;
-    flow_from_match(&rule->flow, &wildcards, match);
+    flow_from_match(match, tun_id_from_cookie, cookie, &rule->flow, &wildcards);
     flow_wildcards_init(&rule->wc, wildcards);
     rule->priority = rule->wc.wildcards ? priority : UINT16_MAX;
     rule->table_idx = table_idx_from_wildcards(rule->wc.wildcards);
@@ -305,7 +307,7 @@ classifier_lookup_wild(const struct classifier *cls, const flow_t *flow)
         struct cls_rule target;
         int i;
 
-        cls_rule_from_flow(&target, flow, 0, 0);
+        cls_rule_from_flow(flow, 0, 0, &target);
         for (i = 0; i < CLS_N_FIELDS; i++) {
             struct cls_rule *rule = search_table(&cls->tables[i], i, &target);
             if (rule && (!best || rule->priority > best->priority)) {
@@ -330,7 +332,7 @@ classifier_find_rule_exactly(const struct classifier *cls,
         return search_exact_table(cls, flow_hash(target, 0), target);
     }
 
-    assert(wildcards == (wildcards & OFPFW_ALL));
+    assert(wildcards == (wildcards & OVSFW_ALL));
     table_idx = table_idx_from_wildcards(wildcards);
     hash = hash_fields(target, table_idx);
     HMAP_FOR_EACH_WITH_HASH (bucket, struct cls_bucket, hmap_node, hash,
@@ -367,7 +369,7 @@ classifier_rule_overlaps(const struct classifier *cls,
             true : false;
     }
 
-    cls_rule_from_flow(&target_rule, target, wildcards, priority);
+    cls_rule_from_flow(target, wildcards, priority, &target_rule);
 
     for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) {
         struct cls_bucket *bucket;
index 126d1498acd918622185bc39d7f48ed413cd4a26..35516022b3a90ba8d55578293b1a066566dda9f8 100644 (file)
 #include "flow.h"
 #include "hmap.h"
 #include "list.h"
+#include "openflow/nicira-ext.h"
 #include "openflow/openflow.h"
 
 /* Number of bytes of fields in a rule. */
-#define CLS_N_BYTES 31
+#define CLS_N_BYTES 37
 
 /* Fields in a rule.
  *
@@ -59,6 +60,7 @@
     /*        wildcard bit(s)    member name  name     */   \
     /*        -----------------  -----------  -------- */   \
     CLS_FIELD(OFPFW_IN_PORT,     in_port,     IN_PORT)      \
+    CLS_FIELD(NXFW_TUN_ID,       tun_id,      TUN_ID)       \
     CLS_FIELD(OFPFW_DL_VLAN,     dl_vlan,     DL_VLAN)      \
     CLS_FIELD(OFPFW_DL_VLAN_PCP, dl_vlan_pcp, DL_VLAN_PCP)  \
     CLS_FIELD(OFPFW_DL_SRC,      dl_src,      DL_SRC)       \
@@ -121,10 +123,11 @@ struct cls_rule {
     unsigned int table_idx;     /* Index into struct classifier 'tables'. */
 };
 
-void cls_rule_from_flow(struct cls_rule *, const flow_t *, uint32_t wildcards,
-                        unsigned int priority);
-void cls_rule_from_match(struct cls_rule *, const struct ofp_match *,
-                         unsigned int priority);
+void cls_rule_from_flow(const flow_t *, uint32_t wildcards,
+                        unsigned int priority, struct cls_rule *);
+void cls_rule_from_match(const struct ofp_match *, unsigned int priority,
+                         bool tun_id_from_cookie, uint64_t cookie,
+                         struct cls_rule *);
 char *cls_rule_to_string(const struct cls_rule *);
 void cls_rule_print(const struct cls_rule *);
 void cls_rule_moved(struct classifier *,
index 30ac56c930dae95dd9abe1b4b217ce4e80a5f73b..0abf115b025937b3d897582968fe1b6e397469f1 100644 (file)
@@ -931,7 +931,7 @@ do_receive_msg(struct dhclient *cli, struct dhcp_msg *msg)
             goto drained;
         }
 
-        flow_extract(&b, 0, &flow);
+        flow_extract(&b, 0, 0, &flow);
         if (flow.dl_type != htons(ETH_TYPE_IP)
             || flow.nw_proto != IP_TYPE_UDP
             || flow.tp_dst != htons(DHCP_CLIENT_PORT)
index 1cc4ed46d3b510e9b2930dff7fb5d30155c8f109..7d31a69bb71a3e9d0e23799b643ed459f9f1548c 100644 (file)
@@ -932,7 +932,7 @@ dpif_netdev_execute(struct dpif *dpif, uint16_t in_port,
          * if we don't. */
         copy = *packet;
     }
-    flow_extract(&copy, in_port, &flow);
+    flow_extract(&copy, 0, in_port, &flow);
     error = dp_netdev_execute_actions(dp, &copy, &flow, actions, n_actions);
     if (mutates) {
         ofpbuf_uninit(&copy);
@@ -1026,7 +1026,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
     struct dp_netdev_flow *flow;
     flow_t key;
 
-    if (flow_extract(packet, port->port_no, &key) && dp->drop_frags) {
+    if (flow_extract(packet, 0, port->port_no, &key) && dp->drop_frags) {
         dp->n_frags++;
         return;
     }
index 7d368bb6d4917aa2aaab1acc86cf777103b0c2f6..700e7f8133c5c501be61031744810e1e0dd84f1c 100644 (file)
@@ -27,6 +27,7 @@
 #include "openflow/openflow.h"
 #include "openvswitch/datapath-protocol.h"
 #include "packets.h"
+#include "xtoxll.h"
 
 #include "vlog.h"
 #define THIS_MODULE VLM_flow
@@ -87,9 +88,12 @@ pull_vlan(struct ofpbuf *packet)
     return ofpbuf_try_pull(packet, VLAN_HEADER_LEN);
 }
 
-/* Returns 1 if 'packet' is an IP fragment, 0 otherwise. */
+/* Returns 1 if 'packet' is an IP fragment, 0 otherwise.
+ * 'tun_id' is in network byte order, while 'in_port' is in host byte order.
+ * These byte orders are the same as they are in struct odp_flow_key. */
 int
-flow_extract(struct ofpbuf *packet, uint16_t in_port, flow_t *flow)
+flow_extract(struct ofpbuf *packet, uint32_t tun_id, uint16_t in_port,
+             flow_t *flow)
 {
     struct ofpbuf b = *packet;
     struct eth_header *eth;
@@ -98,8 +102,9 @@ flow_extract(struct ofpbuf *packet, uint16_t in_port, flow_t *flow)
     COVERAGE_INC(flow_extract);
 
     memset(flow, 0, sizeof *flow);
-    flow->dl_vlan = htons(OFP_VLAN_NONE);
+    flow->tun_id = tun_id;
     flow->in_port = in_port;
+    flow->dl_vlan = htons(OFP_VLAN_NONE);
 
     packet->l2 = b.data;
     packet->l3 = NULL;
@@ -240,9 +245,14 @@ flow_extract_stats(const flow_t *flow, struct ofpbuf *packet,
 /* Extract 'flow' with 'wildcards' into the OpenFlow match structure
  * 'match'. */
 void
-flow_to_match(const flow_t *flow, uint32_t wildcards, struct ofp_match *match)
+flow_to_match(const flow_t *flow, uint32_t wildcards, bool tun_id_from_cookie,
+              struct ofp_match *match)
 {
+    if (!tun_id_from_cookie) {
+        wildcards &= OFPFW_ALL;
+    }
     match->wildcards = htonl(wildcards);
+
     match->in_port = htons(flow->in_port == ODPP_LOCAL ? OFPP_LOCAL
                            : flow->in_port);
     match->dl_vlan = flow->dl_vlan;
@@ -261,14 +271,21 @@ flow_to_match(const flow_t *flow, uint32_t wildcards, struct ofp_match *match)
 }
 
 void
-flow_from_match(flow_t *flow, uint32_t *wildcards,
-                const struct ofp_match *match)
+flow_from_match(const struct ofp_match *match, bool tun_id_from_cookie,
+                uint64_t cookie, flow_t *flow, uint32_t *wildcards)
 {
     if (wildcards) {
         *wildcards = ntohl(match->wildcards);
+
+        if (!tun_id_from_cookie) {
+            *wildcards |= NXFW_TUN_ID;
+        }
     }
     flow->nw_src = match->nw_src;
     flow->nw_dst = match->nw_dst;
+    if (tun_id_from_cookie) {
+        flow->tun_id = htonl(ntohll(cookie) >> 32);
+    }
     flow->in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL
                      : ntohs(match->in_port));
     flow->dl_vlan = match->dl_vlan;
@@ -294,14 +311,27 @@ flow_to_string(const flow_t *flow)
 void
 flow_format(struct ds *ds, const flow_t *flow)
 {
-    ds_put_format(ds, "in_port%04x:vlan%d:pcp%d mac"ETH_ADDR_FMT
-                  "->"ETH_ADDR_FMT" type%04x proto%"PRId8" tos%"PRIu8
-                  " ip"IP_FMT"->"IP_FMT" port%d->%d",
-                  flow->in_port, ntohs(flow->dl_vlan), flow->dl_vlan_pcp,
-                  ETH_ADDR_ARGS(flow->dl_src), ETH_ADDR_ARGS(flow->dl_dst),
-                  ntohs(flow->dl_type), flow->nw_proto, flow->nw_tos,
-                  IP_ARGS(&flow->nw_src), IP_ARGS(&flow->nw_dst),
-                  ntohs(flow->tp_src), ntohs(flow->tp_dst));
+    ds_put_format(ds, "tunnel%08"PRIx32":in_port%04"PRIx16
+                      ":vlan%"PRIu16":pcp%"PRIu8
+                      " mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT
+                      " type%04"PRIx16
+                      " proto%"PRIu8
+                      " tos%"PRIu8
+                      " ip"IP_FMT"->"IP_FMT
+                      " port%"PRIu16"->%"PRIu16,
+                  ntohl(flow->tun_id),
+                  flow->in_port,
+                  ntohs(flow->dl_vlan),
+                  flow->dl_vlan_pcp,
+                  ETH_ADDR_ARGS(flow->dl_src),
+                  ETH_ADDR_ARGS(flow->dl_dst),
+                  ntohs(flow->dl_type),
+                  flow->nw_proto,
+                  flow->nw_tos,
+                  IP_ARGS(&flow->nw_src),
+                  IP_ARGS(&flow->nw_dst),
+                  ntohs(flow->tp_src),
+                  ntohs(flow->tp_dst));
 }
 
 void
index ca140afaaaddff4debb28fc2131a629ab46c247d..058404c87c0844dfcb97062909edd6935e8fbc7d 100644 (file)
@@ -21,9 +21,9 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include <string.h>
+#include "openflow/nicira-ext.h"
 #include "openflow/openflow.h"
 #include "hash.h"
-#include "openflow/openflow.h"
 #include "openvswitch/datapath-protocol.h"
 #include "util.h"
 
@@ -33,11 +33,13 @@ struct ofpbuf;
 
 typedef struct odp_flow_key flow_t;
 
-int flow_extract(struct ofpbuf *, uint16_t in_port, flow_t *);
+int flow_extract(struct ofpbuf *, uint32_t tun_id, uint16_t in_port, flow_t *);
 void flow_extract_stats(const flow_t *flow, struct ofpbuf *packet, 
         struct odp_flow_stats *stats);
-void flow_to_match(const flow_t *, uint32_t wildcards, struct ofp_match *);
-void flow_from_match(flow_t *, uint32_t *wildcards, const struct ofp_match *);
+void flow_to_match(const flow_t *, uint32_t wildcards, bool tun_id_cookie,
+                   struct ofp_match *);
+void flow_from_match(const struct ofp_match *, bool tun_id_from_cookie,
+                     uint64_t cookie, flow_t *, uint32_t *wildcards);
 char *flow_to_string(const flow_t *);
 void flow_format(struct ds *, const flow_t *);
 void flow_print(FILE *, const flow_t *);
@@ -94,7 +96,7 @@ flow_nw_bits_to_mask(uint32_t wildcards, int shift)
 static inline void
 flow_wildcards_init(struct flow_wildcards *wc, uint32_t wildcards)
 {
-    wc->wildcards = wildcards & OFPFW_ALL;
+    wc->wildcards = wildcards & OVSFW_ALL;
     wc->nw_src_mask = flow_nw_bits_to_mask(wc->wildcards, OFPFW_NW_SRC_SHIFT);
     wc->nw_dst_mask = flow_nw_bits_to_mask(wc->wildcards, OFPFW_NW_DST_SHIFT);
 }
index 092274cb57dcc365eed6b47e517858576d21abc7..126cc6b898fe30b5b26754f29b0951844ae42b03 100644 (file)
@@ -404,7 +404,7 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn, void *opi_)
     pkt_len = ntohs(opi->header.length) - pkt_ofs;
     pkt.data = opi->data;
     pkt.size = pkt_len;
-    flow_extract(&pkt, in_port, &flow);
+    flow_extract(&pkt, 0, in_port, &flow);
 
     if (may_learn(sw, in_port) && sw->ml) {
         if (mac_learning_learn(sw->ml, flow.dl_src, 0, in_port)) {
index 67ce413244503d6b3ecf987a3e258d8bf7e3d5af..67d1b3ee7951eaeb9d7710fbb050606f13c87893 100644 (file)
@@ -55,6 +55,9 @@ format_odp_action(struct ds *ds, const union odp_action *a)
     case ODPAT_CONTROLLER:
         ds_put_format(ds, "ctl(%"PRIu32")", a->controller.arg);
         break;
+    case ODPAT_SET_TUNNEL:
+        ds_put_format(ds, "set_tunnel(0x%08"PRIx32")", ntohl(a->tunnel.tun_id));
+        break;
     case ODPAT_SET_VLAN_VID:
         ds_put_format(ds, "set_vlan(%"PRIu16")", ntohs(a->vlan_vid.vlan_vid));
         break;
index bcaf2307907c41a895ede7cd8bfe4e05d57e347b..7c1ebd006719c20d242aae8824f86ddfb80addbb 100644 (file)
@@ -134,8 +134,8 @@ ofp_packet_in(struct ds *string, const void *oh, size_t len, int verbosity)
         struct ofp_match match;
         packet.data = (void *) op->data;
         packet.size = data_len;
-        flow_extract(&packet, ntohs(op->in_port), &flow);
-        flow_to_match(&flow, 0, &match);
+        flow_extract(&packet, 0, ntohs(op->in_port), &flow);
+        flow_to_match(&flow, 0, false, &match);
         ofp_print_match(string, &match, verbosity);
         ds_put_char(string, '\n');
     }
@@ -193,6 +193,13 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
         break;
     }
 
+    case NXAST_SET_TUNNEL: {
+        const struct nx_action_set_tunnel *nast =
+                                            (struct nx_action_set_tunnel *)nah;
+        ds_put_format(string, "set_tunnel:0x%08"PRIx32, ntohl(nast->tun_id));
+        break;
+    }
+
     default:
         ds_put_format(string, "***unknown Nicira action:%d***\n",
                       ntohs(nah->subtype));
@@ -672,6 +679,9 @@ ofp_match_to_string(const struct ofp_match *om, int verbosity)
             skip_type = false;
         }
     }
+    if (w & NXFW_TUN_ID) {
+        ds_put_cstr(&f, "tun_id_wild,");
+    }
     print_wild(&f, "in_port=", w & OFPFW_IN_PORT, verbosity,
                "%d", ntohs(om->in_port));
     print_wild(&f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
index 99d5a54d4e8f572293d3f88a70e25365d49f87fa..80ba471b9a49a8db9787cc19e440e5746a8e6fd5 100644 (file)
@@ -1358,6 +1358,7 @@ check_nicira_action(const union ofp_action *a, unsigned int len)
 
     switch (ntohs(nah->subtype)) {
     case NXAST_RESUBMIT:
+    case NXAST_SET_TUNNEL:
         return check_action_exact_len(a, len, 16);
     default:
         return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE);
@@ -1466,7 +1467,7 @@ normalize_match(struct ofp_match *m)
     enum { OFPFW_TP = OFPFW_TP_SRC | OFPFW_TP_DST };
     uint32_t wc;
 
-    wc = ntohl(m->wildcards) & OFPFW_ALL;
+    wc = ntohl(m->wildcards) & OVSFW_ALL;
     if (wc & OFPFW_DL_TYPE) {
         m->dl_type = 0;
 
index ff77de87ec7ce8d7a4d859f7947e018955f5ed49..e866c571cf71a067b2b6c4a5120e18b20fcc833f 100644 (file)
@@ -173,7 +173,7 @@ fail_open_recover(struct fail_open *fo)
         fo->next_bogus_packet_in = LLONG_MAX;
 
         memset(&flow, 0, sizeof flow);
-        ofproto_delete_flow(fo->ofproto, &flow, OFPFW_ALL, FAIL_OPEN_PRIORITY);
+        ofproto_delete_flow(fo->ofproto, &flow, OVSFW_ALL, FAIL_OPEN_PRIORITY);
     }
 }
 
@@ -201,7 +201,7 @@ fail_open_flushed(struct fail_open *fo)
         action.output.len = htons(sizeof action);
         action.output.port = htons(OFPP_NORMAL);
         memset(&flow, 0, sizeof flow);
-        ofproto_add_flow(fo->ofproto, &flow, OFPFW_ALL, FAIL_OPEN_PRIORITY,
+        ofproto_add_flow(fo->ofproto, &flow, OVSFW_ALL, FAIL_OPEN_PRIORITY,
                          &action, 1, 0);
     }
 }
index 857618fd0832b24bae0112711e2b77fdf11ff5cf..2118809ea9c3316b0f0ef3bb5ef1b5e09f33f557 100644 (file)
@@ -370,7 +370,7 @@ set_up_flow(struct in_band *in_band, int rule_idx, const flow_t *flow,
 
         rule->installed = true;
         rule->flow = *flow;
-        rule->wildcards = OFPFW_ALL & ~fixed_fields;
+        rule->wildcards = OVSFW_ALL & ~fixed_fields;
         rule->priority = IB_BASE_PRIORITY + (N_IB_RULES - rule_idx);
 
         action.type = htons(OFPAT_OUTPUT);
index 45372003dd16b5dc4c6c941f09e57e78616050e7..85f9f9ff47b6d936c4e1b930896e90f890d5a675 100644 (file)
@@ -496,7 +496,7 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg)
     /* Get packet payload and extract flow. */
     payload.data = (union odp_action *) (actions + n_actions);
     payload.size = msg->length - min_size;
-    flow_extract(&payload, msg->port, &flow);
+    flow_extract(&payload, 0, msg->port, &flow);
 
     /* Build a flow sample */
     memset(&fs, 0, sizeof fs);
index 3b5cf486ef7b4abc1a0944409c0dd2788548b50a..995e6b0fe9e256936b4f7ffa05beef5aeb308172 100644 (file)
@@ -219,6 +219,7 @@ struct ofproto {
     bool need_revalidate;
     long long int next_expiration;
     struct tag_set revalidate_set;
+    bool tun_id_from_cookie;
 
     /* OpenFlow connections. */
     struct list all_conns;
@@ -1029,7 +1030,7 @@ ofproto_add_flow(struct ofproto *p,
     rule = rule_create(p, NULL, actions, n_actions,
                        idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, 
                        0, 0, false);
-    cls_rule_from_flow(&rule->cr, flow, wildcards, priority);
+    cls_rule_from_flow(flow, wildcards, priority, &rule->cr);
     rule_insert(p, rule, NULL, 0);
 }
 
@@ -1583,7 +1584,7 @@ rule_insert(struct ofproto *p, struct rule *rule, struct ofpbuf *packet,
     /* Send the packet and credit it to the rule. */
     if (packet) {
         flow_t flow;
-        flow_extract(packet, in_port, &flow);
+        flow_extract(packet, 0, in_port, &flow);
         rule_execute(p, rule, packet, &flow);
     }
 
@@ -1610,9 +1611,8 @@ rule_create_subrule(struct ofproto *ofproto, struct rule *rule,
                                        rule->idle_timeout, rule->hard_timeout,
                                        0, false);
     COVERAGE_INC(ofproto_subrule_create);
-    cls_rule_from_flow(&subrule->cr, flow, 0,
-                       (rule->cr.priority <= UINT16_MAX ? UINT16_MAX
-                        : rule->cr.priority));
+    cls_rule_from_flow(flow, 0, (rule->cr.priority <= UINT16_MAX ? UINT16_MAX
+                        : rule->cr.priority), &subrule->cr);
     classifier_insert_exact(&ofproto->cls, &subrule->cr);
 
     return subrule;
@@ -2146,6 +2146,8 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
                     const struct nx_action_header *nah)
 {
     const struct nx_action_resubmit *nar;
+    const struct nx_action_set_tunnel *nast;
+    union odp_action *oa;
     int subtype = ntohs(nah->subtype);
 
     assert(nah->vendor == htonl(NX_VENDOR_ID));
@@ -2155,6 +2157,12 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
         xlate_table_action(ctx, ofp_port_to_odp_port(ntohs(nar->in_port)));
         break;
 
+    case NXAST_SET_TUNNEL:
+        nast = (const struct nx_action_set_tunnel *) nah;
+        oa = odp_actions_add(ctx->out, ODPAT_SET_TUNNEL);
+        ctx->flow.tun_id = oa->tunnel.tun_id = nast->tun_id;
+        break;
+
     /* If you add a new action here that modifies flow data, don't forget to
      * update the flow key in ctx->flow in the same key. */
 
@@ -2327,7 +2335,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn,
         buffer = NULL;
     }
 
-    flow_extract(&payload, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow);
+    flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow);
     error = xlate_actions((const union ofp_action *) opo->actions, n_actions,
                           &flow, p, &payload, &actions, NULL, NULL, NULL);
     if (error) {
@@ -2496,7 +2504,8 @@ handle_table_stats_request(struct ofproto *p, struct ofconn *ofconn,
     memset(ots, 0, sizeof *ots);
     ots->table_id = TABLEID_CLASSIFIER;
     strcpy(ots->name, "classifier");
-    ots->wildcards = htonl(OFPFW_ALL);
+    ots->wildcards = p->tun_id_from_cookie ? htonl(OVSFW_ALL)
+                                           : htonl(OFPFW_ALL);
     ots->max_entries = htonl(65536);
     ots->active_count = htonl(n_wild);
     ots->lookup_count = htonll(0);              /* XXX */
@@ -2654,7 +2663,8 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_)
     ofs->length = htons(len);
     ofs->table_id = rule->cr.wc.wildcards ? TABLEID_CLASSIFIER : TABLEID_HASH;
     ofs->pad = 0;
-    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofs->match);
+    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards,
+                  cbdata->ofproto->tun_id_from_cookie, &ofs->match);
     ofs->duration_sec = htonl(sec);
     ofs->duration_nsec = htonl(msec * 1000000);
     ofs->cookie = rule->flow_cookie;
@@ -2695,7 +2705,7 @@ handle_flow_stats_request(struct ofproto *p, struct ofconn *ofconn,
     cbdata.ofconn = ofconn;
     cbdata.out_port = fsr->out_port;
     cbdata.msg = start_stats_reply(osr, 1024);
-    cls_rule_from_match(&target, &fsr->match, 0);
+    cls_rule_from_match(&fsr->match, 0, false, 0, &target);
     classifier_for_each_match(&p->cls, &target,
                               table_id_to_include(fsr->table_id),
                               flow_stats_cb, &cbdata);
@@ -2724,7 +2734,8 @@ flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_)
     }
 
     query_stats(cbdata->ofproto, rule, &packet_count, &byte_count);
-    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &match);
+    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards,
+                  cbdata->ofproto->tun_id_from_cookie, &match);
 
     ds_put_format(results, "duration=%llds, ",
                   (time_msec() - rule->created) / 1000);
@@ -2746,12 +2757,12 @@ ofproto_get_all_flows(struct ofproto *p, struct ds *results)
     struct flow_stats_ds_cbdata cbdata;
 
     memset(&match, 0, sizeof match);
-    match.wildcards = htonl(OFPFW_ALL);
+    match.wildcards = htonl(OVSFW_ALL);
 
     cbdata.ofproto = p;
     cbdata.results = results;
 
-    cls_rule_from_match(&target, &match, 0);
+    cls_rule_from_match(&match, 0, false, 0, &target);
     classifier_for_each_match(&p->cls, &target, CLS_INC_ALL,
                               flow_stats_ds_cb, &cbdata);
 }
@@ -2804,7 +2815,7 @@ handle_aggregate_stats_request(struct ofproto *p, struct ofconn *ofconn,
     cbdata.packet_count = 0;
     cbdata.byte_count = 0;
     cbdata.n_flows = 0;
-    cls_rule_from_match(&target, &asr->match, 0);
+    cls_rule_from_match(&asr->match, 0, false, 0, &target);
     classifier_for_each_match(&p->cls, &target,
                               table_id_to_include(asr->table_id),
                               aggregate_stats_cb, &cbdata);
@@ -2912,7 +2923,8 @@ add_flow(struct ofproto *p, struct ofconn *ofconn,
         flow_t flow;
         uint32_t wildcards;
 
-        flow_from_match(&flow, &wildcards, &ofm->match);
+        flow_from_match(&ofm->match, p->tun_id_from_cookie, ofm->cookie,
+                        &flow, &wildcards);
         if (classifier_rule_overlaps(&p->cls, &flow, wildcards,
                                      ntohs(ofm->priority))) {
             return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP);
@@ -2923,7 +2935,8 @@ add_flow(struct ofproto *p, struct ofconn *ofconn,
                        n_actions, ntohs(ofm->idle_timeout),
                        ntohs(ofm->hard_timeout),  ofm->cookie,
                        ofm->flags & htons(OFPFF_SEND_FLOW_REM));
-    cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority));
+    cls_rule_from_match(&ofm->match, ntohs(ofm->priority),
+                        p->tun_id_from_cookie, ofm->cookie, &rule->cr);
 
     error = 0;
     if (ofm->buffer_id != htonl(UINT32_MAX)) {
@@ -2945,7 +2958,8 @@ find_flow_strict(struct ofproto *p, const struct ofp_flow_mod *ofm)
     uint32_t wildcards;
     flow_t flow;
 
-    flow_from_match(&flow, &wildcards, &ofm->match);
+    flow_from_match(&ofm->match, p->tun_id_from_cookie, ofm->cookie,
+                    &flow, &wildcards);
     return rule_from_cls_rule(classifier_find_rule_exactly(
                                   &p->cls, &flow, wildcards,
                                   ntohs(ofm->priority)));
@@ -2970,7 +2984,7 @@ send_buffered_packet(struct ofproto *ofproto, struct ofconn *ofconn,
         return error;
     }
 
-    flow_extract(packet, in_port, &flow);
+    flow_extract(packet, 0, in_port, &flow);
     rule_execute(ofproto, rule, packet, &flow);
     ofpbuf_delete(packet);
 
@@ -3007,7 +3021,8 @@ modify_flows_loose(struct ofproto *p, struct ofconn *ofconn,
     cbdata.n_actions = n_actions;
     cbdata.match = NULL;
 
-    cls_rule_from_match(&target, &ofm->match, 0);
+    cls_rule_from_match(&ofm->match, 0, p->tun_id_from_cookie, ofm->cookie,
+                        &target);
 
     classifier_for_each_match(&p->cls, &target, CLS_INC_ALL,
                               modify_flows_cb, &cbdata);
@@ -3108,7 +3123,8 @@ delete_flows_loose(struct ofproto *p, const struct ofp_flow_mod *ofm)
     cbdata.ofproto = p;
     cbdata.out_port = ofm->out_port;
 
-    cls_rule_from_match(&target, &ofm->match, 0);
+    cls_rule_from_match(&ofm->match, 0, p->tun_id_from_cookie, ofm->cookie,
+                        &target);
 
     classifier_for_each_match(&p->cls, &target, CLS_INC_ALL,
                               delete_flows_cb, &cbdata);
@@ -3212,6 +3228,20 @@ handle_flow_mod(struct ofproto *p, struct ofconn *ofconn,
     }
 }
 
+static int
+handle_tun_id_from_cookie(struct ofproto *p, struct nxt_tun_id_cookie *msg)
+{
+    int error;
+
+    error = check_ofp_message(&msg->header, OFPT_VENDOR, sizeof *msg);
+    if (error) {
+        return error;
+    }
+
+    p->tun_id_from_cookie = !!msg->set;
+    return 0;
+}
+
 static int
 handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg)
 {
@@ -3219,12 +3249,18 @@ handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg)
     struct nicira_header *nh;
 
     if (ntohs(ovh->header.length) < sizeof(struct ofp_vendor_header)) {
+        VLOG_WARN_RL(&rl, "received vendor message of length %zu "
+                          "(expected at least %zu)",
+                   ntohs(ovh->header.length), sizeof(struct ofp_vendor_header));
         return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
     }
     if (ovh->vendor != htonl(NX_VENDOR_ID)) {
         return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
     }
     if (ntohs(ovh->header.length) < sizeof(struct nicira_header)) {
+        VLOG_WARN_RL(&rl, "received Nicira vendor message of length %zu "
+                          "(expected at least %zu)",
+                     ntohs(ovh->header.length), sizeof(struct nicira_header));
         return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
     }
 
@@ -3233,6 +3269,9 @@ handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg)
     case NXT_STATUS_REQUEST:
         return switch_status_handle_request(p->switch_status, ofconn->rconn,
                                             msg);
+
+    case NXT_TUN_ID_FROM_COOKIE:
+        return handle_tun_id_from_cookie(p, msg);
     }
 
     return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
@@ -3330,7 +3369,7 @@ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet)
 
     payload.data = msg + 1;
     payload.size = msg->length - sizeof *msg;
-    flow_extract(&payload, msg->port, &flow);
+    flow_extract(&payload, msg->arg, msg->port, &flow);
 
     /* Check with in-band control to see if this packet should be sent
      * to the local port regardless of the flow table. */
@@ -3470,7 +3509,8 @@ revalidate_rule(struct ofproto *p, struct rule *rule)
 }
 
 static struct ofpbuf *
-compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason)
+compose_flow_removed(struct ofproto *p, const struct rule *rule,
+                     long long int now, uint8_t reason)
 {
     struct ofp_flow_removed *ofr;
     struct ofpbuf *buf;
@@ -3479,7 +3519,8 @@ compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason)
     uint32_t msec = tdiff - (sec * 1000);
 
     ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
-    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofr->match);
+    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, p->tun_id_from_cookie,
+                  &ofr->match);
     ofr->cookie = rule->flow_cookie;
     ofr->priority = htons(rule->cr.priority);
     ofr->reason = reason;
@@ -3524,7 +3565,7 @@ send_flow_removed(struct ofproto *p, struct rule *rule,
             if (prev) {
                 queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter);
             } else {
-                buf = compose_flow_removed(rule, now, reason);
+                buf = compose_flow_removed(p, rule, now, reason);
             }
             prev = ofconn;
         }
index 563690dd00725998ee034e55a0c752b3e7e4517b..c831559ba674b3cae08845b079c787609d34b472 100644 (file)
@@ -238,6 +238,7 @@ static uint32_t nw_src_values[] = { T_HTONL(0xc0a80001),
                                     T_HTONL(0xc0a04455) };
 static uint32_t nw_dst_values[] = { T_HTONL(0xc0a80002),
                                     T_HTONL(0xc0a04455) };
+static uint32_t tun_id_values[] = { 0, 0xffff0000 };
 static uint16_t in_port_values[] = { T_HTONS(1), T_HTONS(OFPP_LOCAL) };
 static uint16_t dl_vlan_values[] = { T_HTONS(101), T_HTONS(0) };
 static uint8_t dl_vlan_pcp_values[] = { 7, 0 };
@@ -257,6 +258,9 @@ static void *values[CLS_N_FIELDS][2];
 static void
 init_values(void)
 {
+    values[CLS_F_IDX_TUN_ID][0] = &tun_id_values[0];
+    values[CLS_F_IDX_TUN_ID][1] = &tun_id_values[1];
+
     values[CLS_F_IDX_IN_PORT][0] = &in_port_values[0];
     values[CLS_F_IDX_IN_PORT][1] = &in_port_values[1];
 
@@ -296,6 +300,7 @@ init_values(void)
 
 #define N_NW_SRC_VALUES ARRAY_SIZE(nw_src_values)
 #define N_NW_DST_VALUES ARRAY_SIZE(nw_dst_values)
+#define N_TUN_ID_VALUES ARRAY_SIZE(tun_id_values)
 #define N_IN_PORT_VALUES ARRAY_SIZE(in_port_values)
 #define N_DL_VLAN_VALUES ARRAY_SIZE(dl_vlan_values)
 #define N_DL_VLAN_PCP_VALUES ARRAY_SIZE(dl_vlan_pcp_values)
@@ -309,6 +314,7 @@ init_values(void)
 
 #define N_FLOW_VALUES (N_NW_SRC_VALUES *        \
                        N_NW_DST_VALUES *        \
+                       N_TUN_ID_VALUES *        \
                        N_IN_PORT_VALUES *       \
                        N_DL_VLAN_VALUES *       \
                        N_DL_VLAN_PCP_VALUES *   \
@@ -360,6 +366,7 @@ compare_classifiers(struct classifier *cls, struct tcls *tcls)
         x = i;
         flow.nw_src = nw_src_values[get_value(&x, N_NW_SRC_VALUES)];
         flow.nw_dst = nw_dst_values[get_value(&x, N_NW_DST_VALUES)];
+        flow.tun_id = tun_id_values[get_value(&x, N_TUN_ID_VALUES)];
         flow.in_port = in_port_values[get_value(&x, N_IN_PORT_VALUES)];
         flow.dl_vlan = dl_vlan_values[get_value(&x, N_DL_VLAN_VALUES)];
         flow.dl_vlan_pcp = dl_vlan_pcp_values[get_value(&x,
@@ -462,8 +469,8 @@ make_rule(int wc_fields, unsigned int priority, int value_pat)
     }
 
     rule = xzalloc(sizeof *rule);
-    cls_rule_from_flow(&rule->cls_rule, &flow, wildcards,
-                       !wildcards ? UINT_MAX : priority);
+    cls_rule_from_flow(&flow, wildcards, !wildcards ? UINT_MAX : priority,
+                       &rule->cls_rule);
     return rule;
 }
 
index 451ca1ad0ea5f8e1c72d9a2ac8d118a32632845f..424dd7b01cd425ac9dc9b14dee1fb4f1011bd848 100644 (file)
@@ -67,8 +67,8 @@ main(int argc OVS_UNUSED, char *argv[])
             ovs_fatal(retval, "error reading pcap file");
         }
 
-        flow_extract(packet, 1, &flow);
-        flow_to_match(&flow, 0, &extracted_match);
+        flow_extract(packet, 0, 1, &flow);
+        flow_to_match(&flow, 0, false, &extracted_match);
 
         if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) {
             char *exp_s = ofp_match_to_string(&expected_match, 2);
index 948df51d719dc6d4aec02f95f385d5b92a1de93e..04b0a989ab42afb584921a7f8c0761218d3d634f 100644 (file)
@@ -391,14 +391,22 @@ Sets the IP ToS/DSCP field to \fItos\fR.  Valid values are between 0 and
 255, inclusive.  Note that the two lower reserved bits are never
 modified.
 .
+.RE
+.IP
+The following actions are Nicira vendor extensions that, as of this writing, are
+only known to be implemented by Open vSwitch:
+.
+.RS
+.
 .IP \fBresubmit\fB:\fIport\fR
 Re-searches the OpenFlow flow table with the \fBin_port\fR field
 replaced by \fIport\fR and executes the actions found, if any, in
 addition to any other actions in this flow entry.  Recursive
 \fBresubmit\fR actions are ignored.
-.IP
-This action is a Nicira vendor extension that, as of this writing, is
-only known to be implemented by Open vSwitch.
+.
+.IP \fBset_tunnel\fB:\fIid\fR
+If outputting to a port that encapsulates the packet in a tunnel and supports
+an identifier (such as GRE), sets the identifier to \fBid\fR.
 .
 .RE
 .
index 204e9582f22975dd5877eced8a78f9b3b432c9fa..d9ee607b349435b7e9ffdac3c3ae6b13cb637060 100644 (file)
@@ -647,6 +647,12 @@ str_to_action(char *str, struct ofpbuf *b)
             nar->vendor = htonl(NX_VENDOR_ID);
             nar->subtype = htons(NXAST_RESUBMIT);
             nar->in_port = htons(str_to_u32(arg));
+        } else if (!strcasecmp(act, "set_tunnel")) {
+            struct nx_action_set_tunnel *nast;
+            nast = put_action(b, sizeof *nast, OFPAT_VENDOR);
+            nast->vendor = htonl(NX_VENDOR_ID);
+            nast->subtype = htons(NXAST_SET_TUNNEL);
+            nast->tun_id = htonl(str_to_u32(arg));
         } else if (!strcasecmp(act, "output")) {
             put_output_action(b, str_to_u32(arg));
         } else if (!strcasecmp(act, "drop")) {
@@ -717,7 +723,7 @@ static bool
 parse_field(const char *name, const struct field **f_out) 
 {
 #define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER)
-    static const struct field fields[] = { 
+    static const struct field fields[] = {
         { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port), 0 },
         { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 0 },
         { "dl_vlan_pcp", OFPFW_DL_VLAN_PCP, F_U8, F_OFS(dl_vlan_pcp), 0 },
@@ -825,6 +831,8 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
                 *hard_timeout = atoi(value);
             } else if (cookie && !strcmp(name, "cookie")) {
                 *cookie = str_to_u64(value);
+            } else if (!strcmp(name, "tun_id_wild")) {
+                wildcards |= NXFW_TUN_ID;
             } else if (parse_field(name, &f)) {
                 void *data = (char *) match + f->offset;
                 if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
@@ -1033,6 +1041,24 @@ static void do_del_flows(int argc, char *argv[])
     vconn_close(vconn);
 }
 
+static void
+do_tun_cookie(int argc OVS_UNUSED, char *argv[])
+{
+    struct nxt_tun_id_cookie *tun_id_cookie;
+    struct ofpbuf *buffer;
+    struct vconn *vconn;
+
+    tun_id_cookie = make_openflow(sizeof *tun_id_cookie, OFPT_VENDOR, &buffer);
+
+    tun_id_cookie->vendor = htonl(NX_VENDOR_ID);
+    tun_id_cookie->subtype = htonl(NXT_TUN_ID_FROM_COOKIE);
+    tun_id_cookie->set = !strcmp(argv[2], "true");
+
+    open_vconn(argv[1], &vconn);
+    send_openflow_buffer(vconn, buffer);
+    vconn_close(vconn);
+}
+
 static void
 do_monitor(int argc OVS_UNUSED, char *argv[])
 {
@@ -1274,6 +1300,7 @@ static const struct command all_commands[] = {
     { "add-flows", 2, 2, do_add_flows },
     { "mod-flows", 2, 2, do_mod_flows },
     { "del-flows", 1, 2, do_del_flows },
+    { "tun-cookie", 2, 2, do_tun_cookie },
     { "dump-ports", 1, 2, do_dump_ports },
     { "mod-port", 3, 3, do_mod_port },
     { "probe", 1, 1, do_probe },
index 2d6052569951606f8de5ffc347848baab8e970ff..04755b7bcdb9c384c6c5a259342ba909c9222ca1 100644 (file)
@@ -1590,8 +1590,7 @@ bridge_reconfigure_controller(const struct ovsrec_open_vswitch *ovs_cfg,
         action.output.len = htons(sizeof action);
         action.output.port = htons(OFPP_NORMAL);
         memset(&flow, 0, sizeof flow);
-        ofproto_add_flow(br->ofproto, &flow, OFPFW_ALL, 0,
-                         &action, 1, 0);
+        ofproto_add_flow(br->ofproto, &flow, OVSFW_ALL, 0, &action, 1, 0);
 
         ofproto_set_in_band(br->ofproto, false);
         ofproto_set_max_backoff(br->ofproto, 1);
@@ -2779,7 +2778,7 @@ bond_send_learning_packets(struct port *port)
         n_packets++;
         compose_benign_packet(&packet, "Open vSwitch Bond Failover", 0xf177,
                               e->mac);
-        flow_extract(&packet, ODPP_NONE, &flow);
+        flow_extract(&packet, 0, ODPP_NONE, &flow);
         retval = ofproto_send_packet(br->ofproto, &flow, actions, a - actions,
                                      &packet);
         if (retval) {