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 bef7d10..1032461 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 6365f94..9dfd604 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 38c8475..faf2470 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 9a94d0b..094a2c8 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 17d86a8..5ec009a 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 6c53545..6ddff01 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 ee78dad..4bd8942 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 126d149..3551602 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 30ac56c..0abf115 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 1cc4ed4..7d31a69 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 7d368bb..700e7f8 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 ca140af..058404c 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 092274c..126cc6b 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 67ce413..67d1b3e 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 bcaf230..7c1ebd0 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 99d5a54..80ba471 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 ff77de8..e866c57 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 857618f..2118809 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 4537200..85f9f9f 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 3b5cf48..995e6b0 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 563690d..c831559 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 451ca1a..424dd7b 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 948df51..04b0a98 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 204e958..d9ee607 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 2d60525..04755b7 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) {