From patchwork Mon Nov 30 18:53:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thadeu Lima de Souza Cascardo X-Patchwork-Id: 550298 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (li376-54.members.linode.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id 0027B1401F0 for ; Tue, 1 Dec 2015 05:53:21 +1100 (AEDT) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id 63987105B0; Mon, 30 Nov 2015 10:53:20 -0800 (PST) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx1e4.cudamail.com (mx1.cudamail.com [69.90.118.67]) by archives.nicira.com (Postfix) with ESMTPS id 5C99510239 for ; Mon, 30 Nov 2015 10:53:19 -0800 (PST) Received: from bar5.cudamail.com (unknown [192.168.21.12]) by mx1e4.cudamail.com (Postfix) with ESMTPS id D4D361E0363 for ; Mon, 30 Nov 2015 11:53:18 -0700 (MST) X-ASG-Debug-ID: 1448909597-09eadd4a316c9f0001-byXFYA Received: from mx1-pf1.cudamail.com ([192.168.24.1]) by bar5.cudamail.com with ESMTP id UHjsqzxHHZFhqfP5 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 30 Nov 2015 11:53:17 -0700 (MST) X-Barracuda-Envelope-From: cascardo@redhat.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.24.1 Received: from unknown (HELO mx1.redhat.com) (209.132.183.28) by mx1-pf1.cudamail.com with ESMTPS (DHE-RSA-AES256-SHA encrypted); 30 Nov 2015 18:53:16 -0000 Received-SPF: pass (mx1-pf1.cudamail.com: SPF record at _spf1.redhat.com designates 209.132.183.28 as permitted sender) X-Barracuda-Apparent-Source-IP: 209.132.183.28 X-Barracuda-RBL-IP: 209.132.183.28 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id 882C212BBD for ; Mon, 30 Nov 2015 18:53:15 +0000 (UTC) Received: from indiana.gru.redhat.com (ovpn-113-103.phx2.redhat.com [10.3.113.103]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id tAUIrCHt023185 for ; Mon, 30 Nov 2015 13:53:14 -0500 X-CudaMail-Envelope-Sender: cascardo@redhat.com From: Thadeu Lima de Souza Cascardo To: dev@openvswitch.org X-CudaMail-MID: CM-E1-1129070558 X-CudaMail-DTE: 113015 X-CudaMail-Originating-IP: 209.132.183.28 Date: Mon, 30 Nov 2015 16:53:03 -0200 X-ASG-Orig-Subj: [##CM-E1-1129070558##][PATCH v3 2/5] ofproto-dpif-xlate: Support IPv6 when sending to tunnel Message-Id: <1448909586-32165-2-git-send-email-cascardo@redhat.com> In-Reply-To: <1448909586-32165-1-git-send-email-cascardo@redhat.com> References: <1448909586-32165-1-git-send-email-cascardo@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-GBUdb-Analysis: 0, 209.132.183.28, Ugly c=0 p=0 Source New X-MessageSniffer-Rules: 0-0-0-21767-c X-Barracuda-Connect: UNKNOWN[192.168.24.1] X-Barracuda-Start-Time: 1448909597 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 X-Barracuda-Spam-Score: 0.60 X-Barracuda-Spam-Status: No, SCORE=0.60 using per-user scores of TAG_LEVEL=3.5 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=4.0 tests=BSF_SC5_MJ1963, RDNS_NONE X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.24856 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.10 RDNS_NONE Delivered to trusted network by a host with no rDNS 0.50 BSF_SC5_MJ1963 Custom Rule MJ1963 Subject: [ovs-dev] [PATCH v3 2/5] ofproto-dpif-xlate: Support IPv6 when sending to tunnel X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" When doing push/pop and building tunnel header, do IPv6 route lookups and send Neighbor Solicitations if needed. v2: Implement compose_nd as suggested by Flavio Leitner. Use ipv6_string_mapped for xlate_report. Do not use tnl_arp_lookup any more. Signed-off-by: Thadeu Lima de Souza Cascardo Cc: Flavio Leitner --- lib/packets.c | 30 ++++++++++++++ lib/packets.h | 24 +++++++++++ ofproto/ofproto-dpif-xlate.c | 95 ++++++++++++++++++++++++++++++-------------- 3 files changed, 120 insertions(+), 29 deletions(-) diff --git a/lib/packets.c b/lib/packets.c index 1bb6acc..5a1179e 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -1177,6 +1177,36 @@ compose_arp(struct dp_packet *b, uint16_t arp_op, dp_packet_set_l3(b, arp); } +void +compose_nd(struct dp_packet *b, const struct eth_addr eth_src, + struct in6_addr * ipv6_src, struct in6_addr * ipv6_dst) +{ + struct in6_addr sn_addr; + struct eth_addr eth_dst; + struct ovs_nd_msg *ns; + struct ovs_nd_opt *nd_opt; + + in6_addr_solicited_node(&sn_addr, ipv6_dst); + ipv6_multicast_to_ethernet(ð_dst, &sn_addr); + + eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, + IPV6_HEADER_LEN + ICMP6_HEADER_LEN + ND_OPT_LEN); + packet_set_ipv6(b, IPPROTO_ICMPV6, + ALIGNED_CAST(ovs_be32 *, ipv6_src->s6_addr), + ALIGNED_CAST(ovs_be32 *, sn_addr.s6_addr), + 0, 0, 255); + + ns = dp_packet_l4(b); + nd_opt = &ns->options[0]; + + ns->icmph.icmp6_type = ND_NEIGHBOR_SOLICIT; + ns->icmph.icmp6_code = 0; + + nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; + packet_set_nd(b, ALIGNED_CAST(ovs_be32 *, ipv6_dst->s6_addr), + eth_src, eth_addr_zero); +} + uint32_t packet_csum_pseudoheader(const struct ip_header *ip) { diff --git a/lib/packets.h b/lib/packets.h index 0f846c6..003e3dd 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -921,6 +921,28 @@ static inline bool ipv6_addr_is_multicast(const struct in6_addr *ip) { } static inline void +in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6) +{ + union ovs_16aligned_in6_addr *taddr = (void *) addr; + memset(taddr->be16, 0, sizeof(taddr->be16)); + taddr->be16[0] = htons(0xff02); + taddr->be16[5] = htons(0x1); + taddr->be16[6] = htons(0xff00); + memcpy(&addr->s6_addr[13], &ip6->s6_addr[13], 3); +} + +static inline void +ipv6_multicast_to_ethernet(struct eth_addr *eth, const struct in6_addr *ip6) +{ + eth->ea[0] = 0x33; + eth->ea[1] = 0x33; + eth->ea[2] = ip6->s6_addr[12]; + eth->ea[3] = ip6->s6_addr[13]; + eth->ea[4] = ip6->s6_addr[14]; + eth->ea[5] = ip6->s6_addr[15]; +} + +static inline void in6_addr_set_mapped_ipv4(struct in6_addr *addr, ovs_be32 ip4) { union ovs_16aligned_in6_addr *taddr = (void *) addr; @@ -1010,6 +1032,8 @@ void compose_arp(struct dp_packet *, uint16_t arp_op, const struct eth_addr arp_sha, const struct eth_addr arp_tha, bool broadcast, ovs_be32 arp_spa, ovs_be32 arp_tpa); +void compose_nd(struct dp_packet *, const struct eth_addr eth_src, + struct in6_addr *, struct in6_addr *); uint32_t packet_csum_pseudoheader(const struct ip_header *); #endif /* packets.h */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 7378d67..cf184e4 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -54,6 +54,7 @@ #include "ofproto/ofproto-dpif-sflow.h" #include "ofproto/ofproto-dpif.h" #include "ofproto/ofproto-provider.h" +#include "packets.h" #include "ovs-router.h" #include "tnl-ports.h" #include "tunnel.h" @@ -2698,21 +2699,24 @@ process_special(struct xlate_ctx *ctx, const struct xport *xport) static int tnl_route_lookup_flow(const struct flow *oflow, - ovs_be32 *ip, struct xport **out_port) + struct in6_addr *ip, struct xport **out_port) { char out_dev[IFNAMSIZ]; struct xbridge *xbridge; struct xlate_cfg *xcfg; - ovs_be32 gw; + struct in6_addr gw; + struct in6_addr dst; - if (!ovs_router_lookup4(oflow->tunnel.ip_dst, out_dev, &gw)) { + dst = flow_tnl_dst(&oflow->tunnel); + if (!ovs_router_lookup(&dst, out_dev, &gw)) { return -ENOENT; } - if (gw) { + if (ipv6_addr_is_set(&gw) && + (!IN6_IS_ADDR_V4MAPPED(&gw) || in6_addr_get_mapped_ipv4(&gw))) { *ip = gw; } else { - *ip = oflow->tunnel.ip_dst; + *ip = dst; } xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp); @@ -2753,6 +2757,19 @@ compose_table_xlate(struct xlate_ctx *ctx, const struct xport *out_dev, } static void +tnl_send_nd_request(struct xlate_ctx *ctx, const struct xport *out_dev, + const struct eth_addr eth_src, + struct in6_addr * ipv6_src, struct in6_addr * ipv6_dst) +{ + struct dp_packet packet; + + dp_packet_init(&packet, 0); + compose_nd(&packet, eth_src, ipv6_src, ipv6_dst); + compose_table_xlate(ctx, out_dev, &packet); + dp_packet_uninit(&packet); +} + +static void tnl_send_arp_request(struct xlate_ctx *ctx, const struct xport *out_dev, const struct eth_addr eth_src, ovs_be32 ip_src, ovs_be32 ip_dst) @@ -2773,19 +2790,24 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport, { struct ovs_action_push_tnl tnl_push_data; struct xport *out_dev = NULL; - ovs_be32 s_ip, d_ip = 0; - struct in6_addr s_ip6; + ovs_be32 s_ip = 0, d_ip = 0; + struct in6_addr s_ip6 = in6addr_any; + struct in6_addr d_ip6 = in6addr_any; struct eth_addr smac; struct eth_addr dmac; int err; + char buf_sip6[INET6_ADDRSTRLEN]; + char buf_dip6[INET6_ADDRSTRLEN]; - err = tnl_route_lookup_flow(flow, &d_ip, &out_dev); + err = tnl_route_lookup_flow(flow, &d_ip6, &out_dev); if (err) { xlate_report(ctx, "native tunnel routing failed"); return err; } - xlate_report(ctx, "tunneling to "IP_FMT" via %s", - IP_ARGS(d_ip), netdev_get_name(out_dev->netdev)); + + xlate_report(ctx, "tunneling to %s via %s", + ipv6_string_mapped(buf_dip6, &d_ip6), + netdev_get_name(out_dev->netdev)); /* Use mac addr of bridge port of the peer. */ err = netdev_get_etheraddr(out_dev->netdev, &smac); @@ -2794,34 +2816,49 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport, return err; } - err = netdev_get_in4(out_dev->netdev, (struct in_addr *) &s_ip, NULL); - if (err) { - xlate_report(ctx, "tunnel output device lacks IPv4 address"); - return err; + d_ip = in6_addr_get_mapped_ipv4(&d_ip6); + if (d_ip) { + err = netdev_get_in4(out_dev->netdev, (struct in_addr *) &s_ip, NULL); + if (err) { + xlate_report(ctx, "tunnel output device lacks IPv4 address"); + return err; + } + in6_addr_set_mapped_ipv4(&s_ip6, s_ip); + } else { + err = netdev_get_in6(out_dev->netdev, &s_ip6); + if (err) { + xlate_report(ctx, "tunnel output device lacks IPv6 address"); + return err; + } } - err = tnl_arp_lookup(out_dev->xbridge->name, d_ip, &dmac); + err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac); if (err) { - xlate_report(ctx, "ARP cache miss for "IP_FMT" on bridge %s, " - "sending ARP request", - IP_ARGS(d_ip), out_dev->xbridge->name); - tnl_send_arp_request(ctx, out_dev, smac, s_ip, d_ip); + xlate_report(ctx, "neighbor cache miss for %s on bridge %s, " + "sending %s request", + buf_dip6, out_dev->xbridge->name, d_ip ? "ARP" : "ND"); + if (d_ip) { + tnl_send_arp_request(ctx, out_dev, smac, s_ip, d_ip); + } else { + tnl_send_nd_request(ctx, out_dev, smac, &s_ip6, &d_ip6); + } return err; } + if (ctx->xin->xcache) { struct xc_entry *entry; entry = xlate_cache_add_entry(ctx->xin->xcache, XC_TNL_NEIGH); ovs_strlcpy(entry->u.tnl_neigh_cache.br_name, out_dev->xbridge->name, sizeof entry->u.tnl_neigh_cache.br_name); - in6_addr_set_mapped_ipv4(&entry->u.tnl_neigh_cache.d_ipv6, d_ip); + entry->u.tnl_neigh_cache.d_ipv6 = d_ip6; } - xlate_report(ctx, "tunneling from "ETH_ADDR_FMT" "IP_FMT - " to "ETH_ADDR_FMT" "IP_FMT, - ETH_ADDR_ARGS(smac), IP_ARGS(s_ip), - ETH_ADDR_ARGS(dmac), IP_ARGS(d_ip)); - in6_addr_set_mapped_ipv4(&s_ip6, s_ip); + xlate_report(ctx, "tunneling from "ETH_ADDR_FMT" %s" + " to "ETH_ADDR_FMT" %s", + ETH_ADDR_ARGS(smac), ipv6_string_mapped(buf_sip6, &s_ip6), + ETH_ADDR_ARGS(dmac), buf_dip6); + err = tnl_port_build_header(xport->ofport, flow, dmac, smac, &s_ip6, &tnl_push_data); if (err) { @@ -3025,7 +3062,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, } if (xport->is_tunnel) { - ovs_be32 dst; + struct in6_addr dst; /* Save tunnel metadata so that changes made due to * the Logical (tunnel) Port are not visible for any further * matches, while explicit set actions on tunnel metadata are. @@ -3036,8 +3073,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, xlate_report(ctx, "Tunneling decided against output"); goto out; /* restore flow_nw_tos */ } - dst = in6_addr_get_mapped_ipv4(&ctx->orig_tunnel_ipv6_dst); - if (flow->tunnel.ip_dst == dst) { + dst = flow_tnl_dst(&flow->tunnel); + if (ipv6_addr_equals(&dst, &ctx->orig_tunnel_ipv6_dst)) { xlate_report(ctx, "Not tunneling to our own address"); goto out; /* restore flow_nw_tos */ } @@ -5019,6 +5056,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) .xin = xin, .xout = xout, .base_flow = *flow, + .orig_tunnel_ipv6_dst = flow_tnl_dst(&flow->tunnel), .xbridge = xbridge, .stack = OFPBUF_STUB_INITIALIZER(stack_stub), .rule = xin->rule, @@ -5051,7 +5089,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) .action_set_has_group = false, .action_set = OFPBUF_STUB_INITIALIZER(action_set_stub), }; - in6_addr_set_mapped_ipv4(&ctx.orig_tunnel_ipv6_dst, flow->tunnel.ip_dst); /* 'base_flow' reflects the packet as it came in, but we need it to reflect * the packet as the datapath will treat it for output actions: