On Thu, Oct 22, 2015 at 03:29:06PM -0200, Thadeu Lima de Souza Cascardo wrote: > When doing push/pop and building tunnel header, do IPv6 route lookups and send > Neighbor Solicitations if needed. > > Signed-off-by: Thadeu Lima de Souza Cascardo <casca...@redhat.com> > --- > lib/packets.h | 22 +++++++ > ofproto/ofproto-dpif-xlate.c | 136 > +++++++++++++++++++++++++++++++++---------- > 2 files changed, 126 insertions(+), 32 deletions(-) > > diff --git a/lib/packets.h b/lib/packets.h > index 2b01d9d..9dbbe4c 100644 > --- a/lib/packets.h > +++ b/lib/packets.h > @@ -918,6 +918,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; > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c > index 8552396..5b47a20 100644 > --- a/ofproto/ofproto-dpif-xlate.c > +++ b/ofproto/ofproto-dpif-xlate.c > @@ -21,6 +21,7 @@ > #include <net/if.h> > #include <sys/socket.h> > #include <netinet/in.h> > +#include <netinet/icmp6.h> > > #include "tnl-arp-cache.h" > #include "bfd.h" > @@ -54,6 +55,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" > @@ -2659,21 +2661,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); > @@ -2714,6 +2719,44 @@ 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; > + 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); > + > + dp_packet_init(&packet, 0); > + dp_packet_clear(&packet); > + > + eth_compose(&packet, eth_dst, eth_src, ETH_TYPE_IPV6, > + IPV6_HEADER_LEN + ICMP6_HEADER_LEN + ND_OPT_LEN); > + packet_set_ipv6(&packet, 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(&packet); > + 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(&packet, ALIGNED_CAST(ovs_be32 *, ipv6_dst->s6_addr), > + eth_src, eth_addr_zero); > + > + compose_table_xlate(ctx, out_dev, &packet); > + dp_packet_uninit(&packet); > +} > + > +static void
Looks like it could build ND in packet.c (not tested) diff --git a/lib/packets.c b/lib/packets.c index 25fdbd3..1432f4a 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -1119,6 +1119,39 @@ 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); + + dp_packet_init(b, 0); + dp_packet_clear(b); + + 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 *, ipv6_dst->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 f43648d..818bd03 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -1025,6 +1025,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 0381c8a..baa5ad1 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -21,7 +21,6 @@ #include <net/if.h> #include <sys/socket.h> #include <netinet/in.h> -#include <netinet/icmp6.h> #include "tnl-arp-cache.h" #include "bfd.h" @@ -2724,34 +2723,9 @@ tnl_send_nd_request(struct xlate_ctx *ctx, const struct xport *out_dev, struct in6_addr * ipv6_src, struct in6_addr * ipv6_dst) { struct dp_packet packet; - 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); dp_packet_init(&packet, 0); - dp_packet_clear(&packet); - - eth_compose(&packet, eth_dst, eth_src, ETH_TYPE_IPV6, - IPV6_HEADER_LEN + ICMP6_HEADER_LEN + ND_OPT_LEN); - packet_set_ipv6(&packet, 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(&packet); - 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(&packet, ALIGNED_CAST(ovs_be32 *, ipv6_dst->s6_addr), - eth_src, eth_addr_zero); - + compose_nd(&packet, eth_src, ipv6_src, ipv6_dst); compose_table_xlate(ctx, out_dev, &packet); dp_packet_uninit(&packet); } fbl _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev