From: Jarno Rajahalme Date: Thu, 9 May 2013 12:24:16 +0000 (+0300) Subject: OpenFlow-level flow-based tunneling support. X-Git-Tag: sliver-openvswitch-1.10.90-3~16^2~1 X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=0ad90c845b7e82090a846fbe9f927e8d1c84cfc9 OpenFlow-level flow-based tunneling support. 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 Signed-off-by: Ben Pfaff --- diff --git a/NEWS b/NEWS index 8536a140f..4cb4499a8 100644 --- 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 diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 8c9fab1e1..5ca343e1a 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -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. ## */ /* ## --------------------- ## */ diff --git a/lib/flow.c b/lib/flow.c index e4154a711..3c12984cf 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -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; diff --git a/lib/flow.h b/lib/flow.h index 6e169d68e..0fdf4ef97 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -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. */ diff --git a/lib/match.c b/lib/match.c index fc3c54061..512253ec2 100644 --- a/lib/match.c +++ b/lib/match.c @@ -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); } diff --git a/lib/meta-flow.c b/lib/meta-flow.c index a75e52644..c3f198cd3 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -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: diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 08169a1b4..1bcb34b07 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -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) { diff --git a/lib/netdev.h b/lib/netdev.h index aab9de097..8e87ae49b 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -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; diff --git a/lib/nx-match.c b/lib/nx-match.c index b328f026f..51b6dc645 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -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++) { diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 95d9b7310..8d99844a5 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -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)); } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 44d3c4efa..2ca007715 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -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); } diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 8e51655de..1da8ffbdd 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -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; diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c index 31aaf3b1c..ffc4057ac 100644 --- a/ofproto/tunnel.c +++ b/ofproto/tunnel.c @@ -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"); diff --git a/tests/ofproto.at b/tests/ofproto.at index a87f4b5fa..166b03e42 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -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 diff --git a/tests/tunnel.at b/tests/tunnel.at index 2eabb77a7..2369bd275 100644 --- a/tests/tunnel.at +++ b/tests/tunnel.at @@ -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 diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index f46b9dc08..061982b1c 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -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 diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 3388b81a6..4396779ba 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -1294,12 +1294,67 @@

- Required. The tunnel endpoint. Only unicast endpoints are supported. +

Required. The remote tunnel endpoint, one of:

+ +
    +
  • + An IPv4 address (not a DNS name), e.g. 192.168.0.123. + Only unicast endpoints are supported. +
  • +
  • + The word flow. 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 + tun_src field. When sending packets to a + remote_ip=flow tunnel, the flow actions must + explicitly set the tun_dst field to the IP address of + the desired remote tunnel endpoint, e.g. with a + set_field action. +
  • +
+ +

+ The remote tunnel endpoint for any packet received from a tunnel + is available in the tun_src field for matching in the + flow table. +

- Optional. The destination IP that received packets must match. - Default is to match all addresses. +

+ Optional. The tunnel destination IP that received packets must + match. Default is to match all addresses. If specified, may be one + of: +

+ +
    +
  • + An IPv4 address (not a DNS name), e.g. 192.168.12.3. +
  • +
  • + The word flow. 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 tun_dst field. When sending packets to a + local_ip=flow tunnel, the flow actions may + explicitly set the tun_src field to the desired IP + address, e.g. with a set_field 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. + +

    + This option is valid only for tunnels also configured with the + remote_ip=flow option. +

    +
  • +
+ +

+ The tunnel destination IP address for any packet received from a + tunnel is available in the tun_dst field for matching in + the flow table. +