#include "tunnel.h"
#include "vlog.h"
-/* XXX:
- *
- * Disallow netdevs with names like "gre64_system" to prevent collisions. */
-
VLOG_DEFINE_THIS_MODULE(tunnel);
struct tnl_match {
ovs_be64 in_key;
ovs_be32 ip_src;
ovs_be32 ip_dst;
- uint32_t odp_port;
+ odp_port_t odp_port;
uint32_t skb_mark;
bool in_key_flow;
+ bool ip_src_flow;
+ bool ip_dst_flow;
};
struct tnl_port {
static const char *tnl_port_get_name(const struct tnl_port *);
static struct tnl_port *
-tnl_port_add__(const struct ofport *ofport, uint32_t odp_port,
+tnl_port_add__(const struct ofport *ofport, odp_port_t odp_port,
bool warn)
{
const struct netdev_tunnel_config *cfg;
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;
* must be added before they can be used by the module. 'ofport' must be a
* tunnel. */
struct tnl_port *
-tnl_port_add(const struct ofport *ofport, uint32_t odp_port)
+tnl_port_add(const struct ofport *ofport, odp_port_t odp_port)
{
return tnl_port_add__(ofport, odp_port, true);
}
* 'ofport' and 'odp_port' should be the same as would be passed to
* tnl_port_add(). */
bool
-tnl_port_reconfigure(const struct ofport *ofport, uint32_t odp_port,
+tnl_port_reconfigure(const struct ofport *ofport, odp_port_t odp_port,
struct tnl_port **tnl_portp)
{
struct tnl_port *tnl_port = *tnl_portp;
struct tnl_match match;
memset(&match, 0, sizeof match);
- match.odp_port = flow->in_port;
+ match.odp_port = flow->in_port.odp_port;
match.ip_src = flow->tunnel.ip_dst;
match.ip_dst = flow->tunnel.ip_src;
match.in_key = flow->tunnel.tun_id;
/* Given that 'flow' should be output to the ofport corresponding to
* 'tnl_port', updates 'flow''s tunnel headers and returns the actual datapath
- * port that the output should happen on. May return OVSP_NONE if the output
+ * port that the output should happen on. May return ODPP_NONE if the output
* shouldn't occur. */
-uint32_t
-tnl_port_send(const struct tnl_port *tnl_port, struct flow *flow)
+odp_port_t
+tnl_port_send(const struct tnl_port *tnl_port, struct flow *flow,
+ struct flow_wildcards *wc)
{
const struct netdev_tunnel_config *cfg;
char *pre_flow_str = NULL;
if (tnl_port == &void_tnl_port) {
- return OVSP_NONE;
+ return ODPP_NONE;
}
cfg = netdev_get_tunnel_config(tnl_port->ofport->netdev);
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) {
}
if (cfg->ttl_inherit && is_ip_any(flow)) {
+ wc->masks.nw_ttl = 0xff;
flow->tunnel.ip_ttl = flow->nw_ttl;
} else {
flow->tunnel.ip_ttl = cfg->ttl;
}
if (cfg->tos_inherit && is_ip_any(flow)) {
+ wc->masks.nw_tos = 0xff;
flow->tunnel.ip_tos = flow->nw_tos & IP_DSCP_MASK;
} else {
flow->tunnel.ip_tos = cfg->tos;
}
+ /* ECN fields are always inherited. */
+ if (is_ip_any(flow)) {
+ wc->masks.nw_tos |= IP_ECN_MASK;
+ }
+
if ((flow->nw_tos & IP_ECN_MASK) == IP_ECN_CE) {
flow->tunnel.ip_tos |= IP_ECN_ECT_0;
} else {
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");