OpenFlow-level flow-based tunneling support.
authorJarno Rajahalme <jarno.rajahalme@nsn.com>
Thu, 9 May 2013 12:24:16 +0000 (15:24 +0300)
committerBen Pfaff <blp@nicira.com>
Fri, 10 May 2013 17:50:06 +0000 (10:50 -0700)
Adds tun_src and tun_dst match and set capabilities via new NXM fields
NXM_NX_TUN_IPV4_SRC and NXM_NX_TUN_IPV4_DST.  This allows management of
large number of tunnels via the flow tables, without requiring the tunnels
to be pre-configured.

Flow-based tunnels can be configured with options remote_ip=flow and
local_ip=flow.  local_ip=flow requires remote_ip=flow.  When set, the
tunnel remote IP address and/or local IP address is set from the flow,
instead of the tunnel configuration.

Example:

$ ovs-vsctl add-port br0 gre -- set Interface gre ofport_request=1 type=gre options:remote_ip=flow options:key=flow
$ ovs-ofctl add-flow br0 "in_port=LOCAL actions=set_tunnel:1,set_field:192.168.0.1->tun_dst,output:1"
$ ovs-ofctl add-flow br0 "in_port=1 tun_src=192.168.0.1 tun_id=1 actions=LOCAL"

Signed-off-by: Jarno Rajahalme <jarno.rajahalme@nsn.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
17 files changed:
NEWS
include/openflow/nicira-ext.h
lib/flow.c
lib/flow.h
lib/match.c
lib/meta-flow.c
lib/netdev-vport.c
lib/netdev.h
lib/nx-match.c
lib/ofp-print.c
lib/ofp-util.c
ofproto/ofproto-dpif.c
ofproto/tunnel.c
tests/ofproto.at
tests/tunnel.at
utilities/ovs-ofctl.8.in
vswitchd/vswitch.xml

diff --git a/NEWS b/NEWS
index 8536a14..4cb4499 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,9 @@
 post-v1.11.0
 ---------------------
+    - OpenFlow:
+      * New support for matching outer source and destination IP address
+        of tunneled packets, for tunnel ports configured with the newly
+       added "remote_ip=flow" and "local_ip=flow" options.
 
 
 v1.11.0 - xx xxx xxxx
index 8c9fab1..5ca343e 100644 (file)
@@ -478,6 +478,8 @@ OFP_ASSERT(sizeof(struct nx_action_pop_queue) == 16);
  *   - NXM_NX_ND_SLL
  *   - NXM_NX_ND_TLL
  *   - NXM_NX_REG(idx) for idx in the switch's accepted range.
+ *   - NXM_NX_TUN_IPV4_SRC
+ *   - NXM_NX_TUN_IPV4_DST
  *
  * The following nxm_header values are potentially acceptable as 'dst':
  *
@@ -503,8 +505,10 @@ OFP_ASSERT(sizeof(struct nx_action_pop_queue) == 16);
  *     adds or modifies the 802.1Q header appropriately, setting the TCI field
  *     to the field's new value (with the CFI bit masked out).
  *
- *   - NXM_NX_TUN_ID.  Modifying this value modifies the tunnel ID used for the
- *     packet's next tunnel encapsulation.
+ *   - NXM_NX_TUN_ID, NXM_NX_TUN_IPV4_SRC, NXM_NX_TUN_IPV4_DST.  Modifying
+ *     any of these values modifies the corresponding tunnel header field used
+ *     for the packet's next tunnel encapsulation, if allowed by the
+ *     configuration of the output tunnel port.
  *
  * A given nxm_header value may be used as 'src' or 'dst' only on a flow whose
  * nx_match satisfies its prerequisites.  For example, NXM_OF_IP_TOS may be
@@ -1748,6 +1752,21 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
 #define NXM_NX_COOKIE     NXM_HEADER  (0x0001, 30, 8)
 #define NXM_NX_COOKIE_W   NXM_HEADER_W(0x0001, 30, 8)
 
+/* The source or destination address in the outer IP header of a tunneled
+ * packet.
+ *
+ * For non-tunneled packets, the value is 0.
+ *
+ * Prereqs: None.
+ *
+ * Format: 32-bit integer in network byte order.
+ *
+ * Masking: Fully maskable. */
+#define NXM_NX_TUN_IPV4_SRC   NXM_HEADER  (0x0001, 31, 4)
+#define NXM_NX_TUN_IPV4_SRC_W NXM_HEADER_W(0x0001, 31, 4)
+#define NXM_NX_TUN_IPV4_DST   NXM_HEADER  (0x0001, 32, 4)
+#define NXM_NX_TUN_IPV4_DST_W NXM_HEADER_W(0x0001, 32, 4)
+
 /* ## --------------------- ## */
 /* ## Requests and replies. ## */
 /* ## --------------------- ## */
index e4154a7..3c12984 100644 (file)
@@ -494,6 +494,8 @@ flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
     BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     fmd->tun_id = flow->tunnel.tun_id;
+    fmd->tun_src = flow->tunnel.ip_src;
+    fmd->tun_dst = flow->tunnel.ip_dst;
     fmd->metadata = flow->metadata;
     memcpy(fmd->regs, flow->regs, sizeof fmd->regs);
     fmd->in_port = flow->in_port;
index 6e169d6..0fdf4ef 100644 (file)
@@ -118,6 +118,8 @@ BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 160 &&
 /* Represents the metadata fields of struct flow. */
 struct flow_metadata {
     ovs_be64 tun_id;                 /* Encapsulating tunnel ID. */
+    ovs_be32 tun_src;                /* Tunnel outer IPv4 src addr */
+    ovs_be32 tun_dst;                /* Tunnel outer IPv4 dst addr */
     ovs_be64 metadata;               /* OpenFlow 1.1+ metadata field. */
     uint32_t regs[FLOW_N_REGS];      /* Registers. */
     uint16_t in_port;                /* OpenFlow port or zero. */
index fc3c540..512253e 100644 (file)
@@ -135,13 +135,9 @@ match_wc_init(struct match *match, const struct flow *flow)
 void
 match_init_exact(struct match *match, const struct flow *flow)
 {
-    ovs_be64 tun_id = flow->tunnel.tun_id;
-
     match->flow = *flow;
     match->flow.skb_priority = 0;
     match->flow.skb_mark = 0;
-    memset(&match->flow.tunnel, 0, sizeof match->flow.tunnel);
-    match->flow.tunnel.tun_id = tun_id;
     flow_wildcards_init_exact(&match->wc);
 }
 
index a75e526..c3f198c 100644 (file)
@@ -57,21 +57,21 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
     }, {
         MFF_TUN_SRC, "tun_src", NULL,
         MF_FIELD_SIZES(be32),
-        MFM_NONE,
+        MFM_FULLY,
         MFS_IPV4,
         MFP_NONE,
-        false,
-        0, NULL,
-        0, NULL,
+        true,
+        NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC",
+        NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC",
     }, {
         MFF_TUN_DST, "tun_dst", NULL,
         MF_FIELD_SIZES(be32),
-        MFM_NONE,
+        MFM_FULLY,
         MFS_IPV4,
         MFP_NONE,
-        false,
-        0, NULL,
-        0, NULL,
+        true,
+        NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST",
+        NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST",
     }, {
         MFF_TUN_FLAGS, "tun_flags", NULL,
         MF_FIELD_SIZES(be16),
@@ -676,9 +676,11 @@ bool
 mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
 {
     switch (mf->id) {
-    case MFF_TUN_ID:
     case MFF_TUN_SRC:
+        return !wc->masks.tunnel.ip_src;
     case MFF_TUN_DST:
+        return !wc->masks.tunnel.ip_dst;
+    case MFF_TUN_ID:
     case MFF_TUN_TOS:
     case MFF_TUN_TTL:
     case MFF_TUN_FLAGS:
index 08169a1..1bcb34b 100644 (file)
@@ -325,7 +325,10 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
     SMAP_FOR_EACH (node, args) {
         if (!strcmp(node->key, "remote_ip")) {
             struct in_addr in_addr;
-            if (lookup_ip(node->value, &in_addr)) {
+            if (!strcmp(node->value, "flow")) {
+                tnl_cfg.ip_dst_flow = true;
+                tnl_cfg.ip_dst = htonl(0);
+            } else if (lookup_ip(node->value, &in_addr)) {
                 VLOG_WARN("%s: bad %s 'remote_ip'", name, type);
             } else if (ip_is_multicast(in_addr.s_addr)) {
                 VLOG_WARN("%s: multicast remote_ip="IP_FMT" not allowed",
@@ -336,7 +339,10 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
             }
         } else if (!strcmp(node->key, "local_ip")) {
             struct in_addr in_addr;
-            if (lookup_ip(node->value, &in_addr)) {
+            if (!strcmp(node->value, "flow")) {
+                tnl_cfg.ip_src_flow = true;
+                tnl_cfg.ip_src = htonl(0);
+            } else if (lookup_ip(node->value, &in_addr)) {
                 VLOG_WARN("%s: bad %s 'local_ip'", name, type);
             } else {
                 tnl_cfg.ip_src = in_addr.s_addr;
@@ -443,11 +449,16 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
         }
     }
 
-    if (!tnl_cfg.ip_dst) {
+    if (!tnl_cfg.ip_dst && !tnl_cfg.ip_dst_flow) {
         VLOG_ERR("%s: %s type requires valid 'remote_ip' argument",
                  name, type);
         return EINVAL;
     }
+    if (tnl_cfg.ip_src_flow && !tnl_cfg.ip_dst_flow) {
+        VLOG_ERR("%s: %s type requires 'remote_ip=flow' with 'local_ip=flow'",
+                 name, type);
+        return EINVAL;
+    }
     if (!tnl_cfg.ttl) {
         tnl_cfg.ttl = DEFAULT_TTL;
     }
@@ -474,10 +485,14 @@ get_tunnel_config(struct netdev_dev *dev, struct smap *args)
 
     if (tnl_cfg->ip_dst) {
         smap_add_format(args, "remote_ip", IP_FMT, IP_ARGS(tnl_cfg->ip_dst));
+    } else if (tnl_cfg->ip_dst_flow) {
+        smap_add(args, "remote_ip", "flow");
     }
 
     if (tnl_cfg->ip_src) {
         smap_add_format(args, "local_ip", IP_FMT, IP_ARGS(tnl_cfg->ip_src));
+    } else if (tnl_cfg->ip_src_flow) {
+        smap_add(args, "local_ip", "flow");
     }
 
     if (tnl_cfg->in_key_flow && tnl_cfg->out_key_flow) {
index aab9de0..8e87ae4 100644 (file)
@@ -88,6 +88,8 @@ struct netdev_tunnel_config {
 
     ovs_be16 dst_port;
 
+    bool ip_src_flow;
+    bool ip_dst_flow;
     ovs_be32 ip_src;
     ovs_be32 ip_dst;
 
index b328f02..51b6dc6 100644 (file)
@@ -690,7 +690,13 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
 
     /* Tunnel ID. */
     nxm_put_64m(b, oxm ? OXM_OF_TUNNEL_ID : NXM_NX_TUN_ID,
-               flow->tunnel.tun_id, match->wc.masks.tunnel.tun_id);
+                flow->tunnel.tun_id, match->wc.masks.tunnel.tun_id);
+
+    /* Other tunnel metadata. */
+    nxm_put_32m(b, NXM_NX_TUN_IPV4_SRC,
+                flow->tunnel.ip_src, match->wc.masks.tunnel.ip_src);
+    nxm_put_32m(b, NXM_NX_TUN_IPV4_DST,
+                flow->tunnel.ip_dst, match->wc.masks.tunnel.ip_dst);
 
     /* Registers. */
     for (i = 0; i < FLOW_N_REGS; i++) {
index 95d9b73..8d99844 100644 (file)
@@ -111,6 +111,14 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
         ds_put_format(string, " tun_id=0x%"PRIx64, ntohll(pin.fmd.tun_id));
     }
 
+    if (pin.fmd.tun_src != htonl(0)) {
+        ds_put_format(string, " tun_src="IP_FMT, IP_ARGS(pin.fmd.tun_src));
+    }
+
+    if (pin.fmd.tun_dst != htonl(0)) {
+        ds_put_format(string, " tun_dst="IP_FMT, IP_ARGS(pin.fmd.tun_dst));
+    }
+
     if (pin.fmd.metadata != htonll(0)) {
         ds_put_format(string, " metadata=0x%"PRIx64, ntohll(pin.fmd.metadata));
     }
index 44d3c4e..2ca0077 100644 (file)
@@ -1039,16 +1039,6 @@ regs_fully_wildcarded(const struct flow_wildcards *wc)
     return true;
 }
 
-static bool
-tun_parms_fully_wildcarded(const struct flow_wildcards *wc)
-{
-    return (!wc->masks.tunnel.ip_src &&
-            !wc->masks.tunnel.ip_dst &&
-            !wc->masks.tunnel.ip_ttl &&
-            !wc->masks.tunnel.ip_tos &&
-            !wc->masks.tunnel.flags);
-}
-
 /* Returns a bit-mask of ofputil_protocols that can be used for sending 'match'
  * to a switch (e.g. to add or remove a flow).  Only NXM can handle tunnel IDs,
  * registers, or fixing the Ethernet multicast bit.  Otherwise, it's better to
@@ -1060,8 +1050,9 @@ ofputil_usable_protocols(const struct match *match)
 
     BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
-    /* tunnel params other than tun_id can't be sent in a flow_mod */
-    if (!tun_parms_fully_wildcarded(wc)) {
+    /* These tunnel params can't be sent in a flow_mod */
+    if (wc->masks.tunnel.ip_ttl
+        || wc->masks.tunnel.ip_tos || wc->masks.tunnel.flags) {
         return OFPUTIL_P_NONE;
     }
 
@@ -1107,8 +1098,10 @@ ofputil_usable_protocols(const struct match *match)
             | OFPUTIL_P_OF13_OXM;
     }
 
-    /* NXM and OXM support matching tun_id. */
-    if (wc->masks.tunnel.tun_id != htonll(0)) {
+    /* NXM and OXM support matching tun_id, tun_src, and tun_dst. */
+    if (wc->masks.tunnel.tun_id != htonll(0)
+        || wc->masks.tunnel.ip_src != htonl(0)
+        || wc->masks.tunnel.ip_dst != htonl(0)) {
         return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
             | OFPUTIL_P_OF13_OXM;
     }
@@ -2450,6 +2443,8 @@ ofputil_decode_packet_in_finish(struct ofputil_packet_in *pin,
 
     pin->fmd.in_port = match->flow.in_port;
     pin->fmd.tun_id = match->flow.tunnel.tun_id;
+    pin->fmd.tun_src = match->flow.tunnel.ip_src;
+    pin->fmd.tun_dst = match->flow.tunnel.ip_dst;
     pin->fmd.metadata = match->flow.metadata;
     memcpy(pin->fmd.regs, match->flow.regs, sizeof pin->fmd.regs);
 }
@@ -2550,6 +2545,12 @@ ofputil_packet_in_to_match(const struct ofputil_packet_in *pin,
     if (pin->fmd.tun_id != htonll(0)) {
         match_set_tun_id(match, pin->fmd.tun_id);
     }
+    if (pin->fmd.tun_src != htonl(0)) {
+        match_set_tun_src(match, pin->fmd.tun_src);
+    }
+    if (pin->fmd.tun_dst != htonl(0)) {
+        match_set_tun_dst(match, pin->fmd.tun_dst);
+    }
     if (pin->fmd.metadata != htonll(0)) {
         match_set_metadata(match, pin->fmd.metadata);
     }
index 8e51655..1da8ffb 100644 (file)
@@ -218,6 +218,17 @@ struct action_xlate_ctx {
      * this flow when actions change header fields. */
     struct flow flow;
 
+    /* Flow at the last commit. */
+    struct flow base_flow;
+
+    /* Tunnel IP destination address as received.  This is stored separately
+     * as the base_flow.tunnel is cleared on init to reflect the datapath
+     * behavior.  Used to make sure not to send tunneled output to ourselves,
+     * which might lead to an infinite loop.  This could happen easily
+     * if a tunnel is marked as 'ip_remote=flow', and the flow does not
+     * actually set the tun_dst field. */
+    ovs_be32 orig_tunnel_ip_dst;
+
     /* stack for the push and pop actions.
      * Each stack element is of the type "union mf_subvalue". */
     struct ofpbuf stack;
@@ -283,7 +294,6 @@ struct action_xlate_ctx {
 
     int recurse;                /* Recursion level, via xlate_table_action. */
     bool max_resubmit_trigger;  /* Recursed too deeply during translation. */
-    struct flow base_flow;      /* Flow at the last commit. */
     uint32_t orig_skb_priority; /* Priority when packet arrived. */
     uint8_t table_id;           /* OpenFlow table ID where flow was found. */
     uint32_t sflow_n_outputs;   /* Number of output ports. */
@@ -6160,7 +6170,10 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
             xlate_report(ctx, "Tunneling decided against output");
             goto out; /* restore flow_nw_tos */
         }
-
+        if (ctx->flow.tunnel.ip_dst == ctx->orig_tunnel_ip_dst) {
+            xlate_report(ctx, "Not tunneling to our own address");
+            goto out; /* restore flow_nw_tos */
+        }
         if (ctx->resubmit_stats) {
             netdev_vport_inc_tx(ofport->up.netdev, ctx->resubmit_stats);
         }
@@ -7025,6 +7038,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
     ctx->flow = *flow;
     ctx->base_flow = ctx->flow;
     memset(&ctx->base_flow.tunnel, 0, sizeof ctx->base_flow.tunnel);
+    ctx->orig_tunnel_ip_dst = flow->tunnel.ip_dst;
     ctx->rule = rule;
     ctx->packet = packet;
     ctx->may_learn = packet != NULL;
index 31aaf3b..ffc4057 100644 (file)
@@ -43,6 +43,8 @@ struct tnl_match {
     uint32_t odp_port;
     uint32_t skb_mark;
     bool in_key_flow;
+    bool ip_src_flow;
+    bool ip_dst_flow;
 };
 
 struct tnl_port {
@@ -90,6 +92,8 @@ tnl_port_add__(const struct ofport *ofport, uint32_t odp_port,
     tnl_port->match.in_key = cfg->in_key;
     tnl_port->match.ip_src = cfg->ip_src;
     tnl_port->match.ip_dst = cfg->ip_dst;
+    tnl_port->match.ip_src_flow = cfg->ip_src_flow;
+    tnl_port->match.ip_dst_flow = cfg->ip_dst_flow;
     tnl_port->match.skb_mark = cfg->ipsec ? IPSEC_MARK : 0;
     tnl_port->match.in_key_flow = cfg->in_key_flow;
     tnl_port->match.odp_port = odp_port;
@@ -229,8 +233,12 @@ tnl_port_send(const struct tnl_port *tnl_port, struct flow *flow)
         pre_flow_str = flow_to_string(flow);
     }
 
-    flow->tunnel.ip_src = tnl_port->match.ip_src;
-    flow->tunnel.ip_dst = tnl_port->match.ip_dst;
+    if (!cfg->ip_src_flow) {
+        flow->tunnel.ip_src = tnl_port->match.ip_src;
+    }
+    if (!cfg->ip_dst_flow) {
+        flow->tunnel.ip_dst = tnl_port->match.ip_dst;
+    }
     flow->skb_mark = tnl_port->match.skb_mark;
 
     if (!cfg->out_key_flow) {
@@ -331,14 +339,36 @@ tnl_find(struct tnl_match *match_)
         return tnl_port;
     }
 
+    /* Flow-based remote */
+    match.ip_dst = 0;
+    match.ip_dst_flow = true;
+    tnl_port = tnl_find_exact(&match);
+    if (tnl_port) {
+        return tnl_port;
+    }
+
+    /* Flow-based everything */
+    match.ip_src = 0;
+    match.ip_src_flow = true;
+    tnl_port = tnl_find_exact(&match);
+    if (tnl_port) {
+        return tnl_port;
+    }
+
     return NULL;
 }
 
 static void
 tnl_match_fmt(const struct tnl_match *match, struct ds *ds)
 {
-    ds_put_format(ds, IP_FMT"->"IP_FMT, IP_ARGS(match->ip_src),
-                  IP_ARGS(match->ip_dst));
+    if (!match->ip_dst_flow) {
+        ds_put_format(ds, IP_FMT"->"IP_FMT, IP_ARGS(match->ip_src),
+                      IP_ARGS(match->ip_dst));
+    } else if (!match->ip_src_flow) {
+        ds_put_format(ds, IP_FMT"->flow", IP_ARGS(match->ip_src));
+    } else {
+        ds_put_cstr(ds, "flow->flow");
+    }
 
     if (match->in_key_flow) {
         ds_put_cstr(ds, ", key=flow");
index a87f4b5..166b03e 100644 (file)
@@ -1475,6 +1475,33 @@ OFPT_BARRIER_REPLY (OF1.2):
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+dnl This test checks that tunnel metadata is encoded in packet_in structures.
+AT_SETUP([ofproto - packet-out with tunnel metadata (OpenFlow 1.2)])
+OVS_VSWITCHD_START
+
+# Start a monitor listening for packet-ins.
+AT_CHECK([ovs-ofctl -O OpenFlow12 monitor br0 --detach --no-chdir --pidfile])
+ovs-appctl -t ovs-ofctl ofctl/send 0309000c0123456700000080
+ovs-appctl -t ovs-ofctl ofctl/barrier
+ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
+AT_CAPTURE_FILE([monitor.log])
+
+# Send a packet-out with set field actions to set some tunnel metadata, and forward to controller
+AT_CHECK([ovs-ofctl -O OpenFlow12 packet-out br0 none 'set_field:127.0.0.1->tun_src,set_field:0x01020304->tun_id,set_field:192.168.0.1->tun_dst, controller' '0001020304050010203040501234'])
+
+# Stop the monitor and check its output.
+ovs-appctl -t ovs-ofctl ofctl/barrier
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY tun_id=0x1020304 tun_src=127.0.0.1 tun_dst=192.168.0.1 (via action) data_len=14 (unbuffered)
+metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
+OFPT_BARRIER_REPLY (OF1.2):
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto - flow monitoring])
 AT_KEYWORDS([monitor])
 OVS_VSWITCHD_START
index 2eabb77..2369bd2 100644 (file)
@@ -408,6 +408,34 @@ br0 (dummy@ovs-dummy):
        br0 65534/100: (dummy)
        p1 1/1: (vxlan: remote_ip=1.1.1.1)
 ])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - set_field - tun_src/tun_dst/tun_id])
+OVS_VSWITCHD_START([dnl
+    add-port br0 p1 -- set Interface p1 type=gre options:key=flow \
+        options:remote_ip=1.1.1.1 ofport_request=1 \
+    -- add-port br0 p2 -- set Interface p2 type=gre options:key=flow \
+        options:remote_ip=flow ofport_request=2 \
+    -- add-port br0 p3 -- set Interface p3 type=gre options:key=flow \
+        options:remote_ip=flow options:local_ip=flow ofport_request=3 \
+    -- add-port br0 p4 -- set Interface p4 type=gre options:key=3 \
+        options:remote_ip=flow ofport_request=4 \
+    -- add-port br0 p5 -- set Interface p5 type=gre options:key=flow \
+        options:remote_ip=5.5.5.5 ofport_request=5])
+ADD_OF_PORTS([br0], [90])
+AT_DATA([flows.txt], [dnl
+in_port=90 actions=resubmit:1,resubmit:2,resubmit:3,resubmit:4,resubmit:5
+in_port=1 actions=set_field:42->tun_id,output:1
+in_port=2 actions=set_field:3.3.3.3->tun_dst,output:2
+in_port=3 actions=set_field:1.1.1.1->tun_src,set_field:4.4.4.4->tun_dst,output:3
+in_port=4 actions=set_field:2.2.2.2->tun_dst,output:4
+in_port=5 actions=set_field:5->tun_id
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: set(tunnel(tun_id=0x2a,src=0.0.0.0,dst=1.1.1.1,tos=0x0,ttl=64,flags(df,key))),1,set(tunnel(tun_id=0x2a,src=0.0.0.0,dst=3.3.3.3,tos=0x0,ttl=64,flags(df,key))),1,set(tunnel(tun_id=0x2a,src=1.1.1.1,dst=4.4.4.4,tos=0x0,ttl=64,flags(df,key))),1,set(tunnel(tun_id=0x3,src=0.0.0.0,dst=2.2.2.2,tos=0x0,ttl=64,flags(df,key))),1
+])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
index f46b9dc..061982b 100644 (file)
@@ -775,6 +775,17 @@ if \fImask\fR is specified, then a 1-bit in \fImask\fR indicates that the
 corresponding bit in \fItunnel-id\fR must match exactly, and a 0-bit
 wildcards that bit.
 .
+.IP \fBtun_src=\fIip\fR[\fB/\fInetmask\fR]
+.IQ \fBtun_dst=\fIip\fR[\fB/\fInetmask\fR]
+Matches tunnel IPv4 source (or destination) address \fIip\fR. Only packets
+that arrive over a tunnel will have nonzero tunnel addresses.
+The address may be specified as an IP address or host name
+(e.g. \fB192.168.1.1\fR or \fBwww.example.com\fR).  The optional
+\fInetmask\fR allows restricting a match to a masked IPv4 address.
+The netmask may be specified as a dotted quad
+(e.g. \fB192.168.1.0/255.255.255.0\fR) or as a CIDR block
+(e.g. \fB192.168.1.0/24\fR).
+.
 .IP "\fBreg\fIidx\fB=\fIvalue\fR[\fB/\fImask\fR]"
 Matches \fIvalue\fR either exactly or with optional \fImask\fR in
 register number \fIidx\fR.  The valid range of \fIidx\fR depends on
index 3388b81..4396779 100644 (file)
       </p>
 
       <column name="options" key="remote_ip">
-          Required.  The tunnel endpoint.  Only unicast endpoints are supported.
+        <p>Required.  The remote tunnel endpoint, one of:</p>
+
+        <ul>
+          <li>
+            An IPv4 address (not a DNS name), e.g. <code>192.168.0.123</code>.
+            Only unicast endpoints are supported.
+          </li>
+          <li>
+            The word <code>flow</code>.  The tunnel accepts packets from any
+            remote tunnel endpoint.  To process only packets from a specific
+            remote tunnel endpoint, the flow entries may match on the
+            <code>tun_src</code> field.  When sending packets to a
+            <code>remote_ip=flow</code> tunnel, the flow actions must
+            explicitly set the <code>tun_dst</code> field to the IP address of
+            the desired remote tunnel endpoint, e.g. with a
+            <code>set_field</code> action.
+          </li>
+        </ul>
+
+        <p>
+         The remote tunnel endpoint for any packet received from a tunnel
+         is available in the <code>tun_src</code> field for matching in the
+         flow table.
+        </p>
       </column>
 
       <column name="options" key="local_ip">
-        Optional.  The destination IP that received packets must match.
-        Default is to match all addresses.
+        <p>
+          Optional.  The tunnel destination IP that received packets must
+          match.  Default is to match all addresses.  If specified, may be one
+          of:
+        </p>
+
+        <ul>
+          <li>
+            An IPv4 address (not a DNS name), e.g. <code>192.168.12.3</code>.
+          </li>
+          <li>
+            The word <code>flow</code>.  The tunnel accepts packets sent to any
+            of the local IP addresses of the system running OVS.  To process
+            only packets sent to a specific IP address, the flow entries may
+            match on the <code>tun_dst</code> field.  When sending packets to a
+            <code>local_ip=flow</code> tunnel, the flow actions may
+            explicitly set the <code>tun_src</code> field to the desired IP
+            address, e.g. with a <code>set_field</code> action.  However, while
+            routing the tunneled packet out, the local system may override the
+            specified address with the local IP address configured for the
+            outgoing system interface.
+
+            <p>
+              This option is valid only for tunnels also configured with the
+              <code>remote_ip=flow</code> option.
+            </p>
+          </li>
+        </ul>
+
+        <p>
+          The tunnel destination IP address for any packet received from a
+          tunnel is available in the <code>tun_dst</code> field for matching in
+          the flow table.
+        </p>
       </column>
 
       <column name="options" key="in_key">