summaryrefslogtreecommitdiff
path: root/ofproto
diff options
context:
space:
mode:
authorYifeng Sun <pkusunyifeng@gmail.com>2019-09-05 10:40:28 -0700
committerBen Pfaff <blp@ovn.org>2019-09-25 12:18:14 -0700
commitdc0bd12f5b0444e34bf56fbbed556c0f1201c4f2 (patch)
treead8b55c2b2e28e752f4ce398bb6a8cf9b7d0510c /ofproto
parentc7051413b71f7e2e6f3330ec1ba94f27e0a91d02 (diff)
downloadopenvswitch-dc0bd12f5b0444e34bf56fbbed556c0f1201c4f2.tar.gz
userspace: Enable non-bridge port as tunnel endpoint.
For userspace datapath, currently only the bridge itself, the LOCAL port, can be the tunnel endpoint to encap/decap tunnel packets. This patch enables non-bridge port as tunnel endpoint. One use case is for users to create a bridge and a vtep port as tap, and configure underlay IP at vtep port as the tunnel endpoint. This patch causes failure for test "ptap - L3 over patch port". This is because this test is already using non-bridge port gre1 as tunnel endpoint. In this test, a flow is added to redirect tunnel packets to gre1 port, as shown below: ovs-ofctl add-flow br1 in_port=p1,actions=output=gre1 It later generates a datapath flow which matches an extra eth field: - recirc_id(0),...,eth_type(0x0800),... + recirc_id(0),...,eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),... With this patch, this flow need only a NORMAL action. Signed-off-by: William Tu <u9012063@gmail.com> Co-authored-by: William Tu <u9012063@gmail.com> Signed-off-by: Yifeng Sun <pkusunyifeng@gmail.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'ofproto')
-rw-r--r--ofproto/ofproto-dpif-xlate.c56
1 files changed, 45 insertions, 11 deletions
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 17800f3c8..9c2f44784 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -3410,6 +3410,19 @@ tnl_route_lookup_flow(const struct xlate_ctx *ctx,
}
}
}
+
+ /* If tunnel IP isn't configured on bridges, then we search all ports. */
+ HMAP_FOR_EACH (xbridge, hmap_node, &ctx->xcfg->xbridges) {
+ struct xport *port;
+
+ HMAP_FOR_EACH (port, ofp_node, &xbridge->xports) {
+ if (!strncmp(netdev_get_name(port->netdev),
+ out_dev, IFNAMSIZ)) {
+ *out_port = port;
+ return 0;
+ }
+ }
+ }
return -ENOENT;
}
@@ -3972,6 +3985,16 @@ is_nd_dst_correct(const struct flow *flow, const struct in6_addr *ipv6_addr)
IN6_ARE_ADDR_EQUAL(&flow->ipv6_dst, ipv6_addr);
}
+static bool
+is_neighbor_reply_matched(const struct flow *flow, struct in6_addr *ip_addr)
+{
+ return ((IN6_IS_ADDR_V4MAPPED(ip_addr) &&
+ flow->dl_type == htons(ETH_TYPE_ARP) &&
+ in6_addr_get_mapped_ipv4(ip_addr) == flow->nw_dst) ||
+ (!IN6_IS_ADDR_V4MAPPED(ip_addr) &&
+ is_nd_dst_correct(flow, ip_addr)));
+}
+
/* Function verifies if the ARP reply or Neighbor Advertisement represented by
* 'flow' addresses the 'xbridge' of 'ctx'. Returns true if the ARP TA or
* neighbor discovery destination is in the list of configured IP addresses of
@@ -3986,11 +4009,7 @@ is_neighbor_reply_correct(const struct xlate_ctx *ctx, const struct flow *flow)
/* Verify if 'nw_dst' of ARP or 'ipv6_dst' of ICMPV6 is in the list. */
for (i = 0; xbridge_addr && i < xbridge_addr->n_addr; i++) {
struct in6_addr *ip_addr = &xbridge_addr->addr[i];
- if ((IN6_IS_ADDR_V4MAPPED(ip_addr) &&
- flow->dl_type == htons(ETH_TYPE_ARP) &&
- in6_addr_get_mapped_ipv4(ip_addr) == flow->nw_dst) ||
- (!IN6_IS_ADDR_V4MAPPED(ip_addr) &&
- is_nd_dst_correct(flow, ip_addr))) {
+ if (is_neighbor_reply_matched(flow, ip_addr)) {
/* Found a match. */
ret = true;
break;
@@ -3998,20 +4017,35 @@ is_neighbor_reply_correct(const struct xlate_ctx *ctx, const struct flow *flow)
}
xbridge_addr_unref(xbridge_addr);
+
+ /* If not found in bridge's IPs, search in its ports. */
+ if (!ret) {
+ struct in6_addr *ip_addr, *mask;
+ struct xport *port;
+ int error, n_in6;
+
+ HMAP_FOR_EACH (port, ofp_node, &ctx->xbridge->xports) {
+ error = netdev_get_addr_list(port->netdev, &ip_addr,
+ &mask, &n_in6);
+ if (!error && is_neighbor_reply_matched(flow, ip_addr)) {
+ /* Found a match. */
+ ret = true;
+ break;
+ }
+ }
+ }
return ret;
}
static bool
-terminate_native_tunnel(struct xlate_ctx *ctx, ofp_port_t ofp_port,
- struct flow *flow, struct flow_wildcards *wc,
- odp_port_t *tnl_port)
+terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow,
+ struct flow_wildcards *wc, odp_port_t *tnl_port)
{
*tnl_port = ODPP_NONE;
/* XXX: Write better Filter for tunnel port. We can use in_port
* in tunnel-port flow to avoid these checks completely. */
- if (ofp_port == OFPP_LOCAL &&
- ovs_native_tunneling_is_on(ctx->xbridge->ofproto)) {
+ if (ovs_native_tunneling_is_on(ctx->xbridge->ofproto)) {
*tnl_port = tnl_port_map_lookup(flow, wc);
/* If no tunnel port was found and it's about an ARP or ICMPv6 packet,
@@ -4155,7 +4189,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
native_tunnel_output(ctx, xport, flow, odp_port, truncate);
flow->tunnel = flow_tnl; /* Restore tunnel metadata */
- } else if (terminate_native_tunnel(ctx, ofp_port, flow, wc,
+ } else if (terminate_native_tunnel(ctx, flow, wc,
&odp_tnl_port)) {
/* Intercept packet to be received on native tunnel port. */
nl_msg_put_odp_port(ctx->odp_actions, OVS_ACTION_ATTR_TUNNEL_POP,