/* XXX:
*
- * Ability to generate actions on input for ECN
- * Ability to generate metadata for packet-outs
* Disallow netdevs with names like "gre64_system" to prevent collisions. */
VLOG_DEFINE_THIS_MODULE(tunnel);
-/* skb mark used for IPsec tunnel packets */
-#define IPSEC_MARK 1
-
struct tnl_match {
ovs_be64 in_key;
ovs_be32 ip_src;
uint32_t odp_port;
uint32_t skb_mark;
bool in_key_flow;
+ bool ip_src_flow;
+ bool ip_dst_flow;
};
struct tnl_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;
}
}
-/* Transforms 'flow' so that it appears to have been received by a tunnel
- * OpenFlow port controlled by this module instead of the datapath port it
- * actually came in on. Sets 'flow''s in_port to the appropriate OpenFlow port
- * number. Returns the 'ofport' corresponding to the new in_port.
+/* Looks in the table of tunnels for a tunnel matching the metadata in 'flow'.
+ * Returns the 'ofport' corresponding to the new in_port, or a null pointer if
+ * none is found.
*
* Callers should verify that 'flow' needs to be received by calling
- * tnl_port_should_receive() before this function.
- *
- * Leaves 'flow' untouched and returns null if unsuccessful. */
+ * tnl_port_should_receive() before this function. */
const struct ofport *
-tnl_port_receive(struct flow *flow)
+tnl_port_receive(const struct flow *flow)
{
char *pre_flow_str = NULL;
struct tnl_port *tnl_port;
return NULL;
}
- if (is_ip_any(flow)
- && ((flow->tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE)
- && (flow->nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
- VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE but is not ECN"
- " capable");
- return NULL;
- }
-
if (!VLOG_DROP_DBG(&dbg_rl)) {
pre_flow_str = flow_to_string(flow);
}
- flow->in_port = tnl_port->ofport->ofp_port;
- memset(&flow->tunnel, 0, sizeof flow->tunnel);
- flow->tunnel.tun_id = match.in_key;
-
if (pre_flow_str) {
char *post_flow_str = flow_to_string(flow);
char *tnl_str = tnl_port_fmt(tnl_port);
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) {
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");