Note that because there's been no prerequisite on the outer protocol, we cannot add it now. Instead, treat the ipv4 and ipv6 dst fields in the way that either both are null, or at most one of them is non-null.
Signed-off-by: Jiri Benc <jb...@redhat.com> --- lib/dpif.c | 6 ++++-- lib/flow.c | 19 ++++++++++++++----- lib/match.c | 34 ++++++++++++++++++++++++++++++++++ lib/match.h | 6 ++++++ lib/odp-util.c | 30 ++++++++++++++++++++++++++---- lib/odp-util.h | 6 ++++-- lib/packets.h | 2 ++ ofproto/tunnel.c | 9 +++++++-- ofproto/tunnel.h | 2 +- 9 files changed, 98 insertions(+), 16 deletions(-) diff --git a/lib/dpif.c b/lib/dpif.c index b8f30a50349c..a8bf69f16d17 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1102,8 +1102,10 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet **packets, int cnt, struct ofpbuf execute_actions; uint64_t stub[256 / 8]; struct pkt_metadata *md = &packet->md; + bool dst_set; - if (md->tunnel.ip_dst) { + dst_set = md->tunnel.ip_dst || ipv6_addr_is_set(&md->tunnel.ipv6_dst); + if (dst_set) { /* The Linux kernel datapath throws away the tunnel information * that we supply as metadata. We have to use a "set" action to * supply it. */ @@ -1124,7 +1126,7 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet **packets, int cnt, aux->error = dpif_execute(aux->dpif, &execute); log_execute_message(aux->dpif, &execute, true, aux->error); - if (md->tunnel.ip_dst) { + if (dst_set) { ofpbuf_uninit(&execute_actions); } break; diff --git a/lib/flow.c b/lib/flow.c index e54280a45f40..752cf5f15c50 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -432,7 +432,7 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) uint8_t nw_frag, nw_tos, nw_ttl, nw_proto; /* Metadata. */ - if (md->tunnel.ip_dst) { + if (md->tunnel.ip_dst || ipv6_addr_is_set(&md->tunnel.ipv6_dst)) { miniflow_push_words(mf, tunnel, &md->tunnel, sizeof md->tunnel / sizeof(uint64_t)); } @@ -920,12 +920,17 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc, /* Update this function whenever struct flow changes. */ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); - if (flow->tunnel.ip_dst) { + if (flow->tunnel.ip_dst || ipv6_addr_is_set(&flow->tunnel.ipv6_dst)) { if (flow->tunnel.flags & FLOW_TNL_F_KEY) { WC_MASK_FIELD(wc, tunnel.tun_id); } - WC_MASK_FIELD(wc, tunnel.ip_src); - WC_MASK_FIELD(wc, tunnel.ip_dst); + if (flow->tunnel.ip_dst) { + WC_MASK_FIELD(wc, tunnel.ip_src); + WC_MASK_FIELD(wc, tunnel.ip_dst); + } else { + WC_MASK_FIELD(wc, tunnel.ipv6_src); + WC_MASK_FIELD(wc, tunnel.ipv6_dst); + } WC_MASK_FIELD(wc, tunnel.flags); WC_MASK_FIELD(wc, tunnel.ip_tos); WC_MASK_FIELD(wc, tunnel.ip_ttl); @@ -1019,7 +1024,11 @@ flow_wc_map(const struct flow *flow) /* Update this function whenever struct flow changes. */ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); - uint64_t map = (flow->tunnel.ip_dst) ? MINIFLOW_MAP(tunnel) : 0; + uint64_t map = 0; + + if (flow->tunnel.ip_dst || ipv6_addr_is_set(&flow->tunnel.ipv6_dst)) { + map |= MINIFLOW_MAP(tunnel); + } /* Metadata fields that can appear on packet input. */ map |= MINIFLOW_MAP(skb_priority) | MINIFLOW_MAP(pkt_mark) diff --git a/lib/match.c b/lib/match.c index 7d0b4095fa99..8ea4af8e2455 100644 --- a/lib/match.c +++ b/lib/match.c @@ -186,6 +186,36 @@ match_set_tun_dst_masked(struct match *match, ovs_be32 dst, ovs_be32 mask) } void +match_set_tun_ipv6_src(struct match *match, const struct in6_addr *src) +{ + match->flow.tunnel.ipv6_src = *src; + match->wc.masks.tunnel.ipv6_src = in6addr_exact; +} + +void +match_set_tun_ipv6_src_masked(struct match *match, const struct in6_addr *src, + const struct in6_addr *mask) +{ + match->flow.tunnel.ipv6_src = ipv6_addr_bitand(src, mask); + match->wc.masks.tunnel.ipv6_src = *mask; +} + +void +match_set_tun_ipv6_dst(struct match *match, const struct in6_addr *dst) +{ + match->flow.tunnel.ipv6_dst = *dst; + match->wc.masks.tunnel.ipv6_dst = in6addr_exact; +} + +void +match_set_tun_ipv6_dst_masked(struct match *match, const struct in6_addr *dst, + const struct in6_addr *mask) +{ + match->flow.tunnel.ipv6_dst = ipv6_addr_bitand(dst, mask); + match->wc.masks.tunnel.ipv6_dst = *mask; +} + +void match_set_tun_ttl(struct match *match, uint8_t ttl) { match_set_tun_ttl_masked(match, ttl, UINT8_MAX); @@ -877,6 +907,10 @@ format_flow_tunnel(struct ds *s, const struct match *match) format_be64_masked(s, "tun_id", tnl->tun_id, wc->masks.tunnel.tun_id); format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src); format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst); + format_ipv6_netmask(s, "tun_ipv6_src", &tnl->ipv6_src, + &wc->masks.tunnel.ipv6_src); + format_ipv6_netmask(s, "tun_ipv6_dst", &tnl->ipv6_dst, + &wc->masks.tunnel.ipv6_dst); if (wc->masks.tunnel.gbp_id) { format_be16_masked(s, "tun_gbp_id", tnl->gbp_id, diff --git a/lib/match.h b/lib/match.h index 663330451330..0b794b3f9c24 100644 --- a/lib/match.h +++ b/lib/match.h @@ -65,6 +65,12 @@ void match_set_tun_src(struct match *match, ovs_be32 src); void match_set_tun_src_masked(struct match *match, ovs_be32 src, ovs_be32 mask); void match_set_tun_dst(struct match *match, ovs_be32 dst); void match_set_tun_dst_masked(struct match *match, ovs_be32 dst, ovs_be32 mask); +void match_set_tun_ipv6_src(struct match *, const struct in6_addr *); +void match_set_tun_ipv6_src_masked(struct match *, const struct in6_addr *, + const struct in6_addr *); +void match_set_tun_ipv6_dst(struct match *, const struct in6_addr *); +void match_set_tun_ipv6_dst_masked(struct match *, const struct in6_addr *, + const struct in6_addr *); void match_set_tun_ttl(struct match *match, uint8_t ttl); void match_set_tun_ttl_masked(struct match *match, uint8_t ttl, uint8_t mask); void match_set_tun_tos(struct match *match, uint8_t tos); diff --git a/lib/odp-util.c b/lib/odp-util.c index c9349307dec5..93c019c71168 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -1366,6 +1366,12 @@ odp_tun_key_from_attr(const struct nlattr *attr, struct flow_tnl *tun) case OVS_TUNNEL_KEY_ATTR_IPV4_DST: tun->ip_dst = nl_attr_get_be32(a); break; + case OVS_TUNNEL_KEY_ATTR_IPV6_SRC: + tun->ipv6_src = nl_attr_get_in6_addr(a); + break; + case OVS_TUNNEL_KEY_ATTR_IPV6_DST: + tun->ipv6_dst = nl_attr_get_in6_addr(a); + break; case OVS_TUNNEL_KEY_ATTR_TOS: tun->ip_tos = nl_attr_get_u8(a); break; @@ -1450,6 +1456,12 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key) if (tun_key->ip_dst) { nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_IPV4_DST, tun_key->ip_dst); } + if (ipv6_addr_is_set(&tun_key->ipv6_src)) { + nl_msg_put_in6_addr(a, OVS_TUNNEL_KEY_ATTR_IPV6_SRC, &tun_key->ipv6_src); + } + if (ipv6_addr_is_set(&tun_key->ipv6_dst)) { + nl_msg_put_in6_addr(a, OVS_TUNNEL_KEY_ATTR_IPV6_DST, &tun_key->ipv6_dst); + } if (tun_key->ip_tos) { nl_msg_put_u8(a, OVS_TUNNEL_KEY_ATTR_TOS, tun_key->ip_tos); } @@ -1513,6 +1525,8 @@ odp_mask_is_exact(enum ovs_key_attr attr, const void *mask, size_t size) && tun_mask->tun_id == OVS_BE64_MAX && tun_mask->ip_src == OVS_BE32_MAX && tun_mask->ip_dst == OVS_BE32_MAX + && ipv6_mask_is_exact(&tun_mask->ipv6_src) + && ipv6_mask_is_exact(&tun_mask->ipv6_dst) && tun_mask->ip_tos == UINT8_MAX && tun_mask->ip_ttl == UINT8_MAX && tun_mask->tp_src == OVS_BE16_MAX @@ -1868,6 +1882,10 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma, format_be64(ds, "tun_id", key.tun_id, MASK(mask, tun_id), verbose); format_ipv4(ds, "src", key.ip_src, MASK(mask, ip_src), verbose); format_ipv4(ds, "dst", key.ip_dst, MASK(mask, ip_dst), verbose); + format_in6_addr(ds, "ipv6_src", &key.ipv6_src, MASK(mask, ipv6_src), + verbose); + format_in6_addr(ds, "ipv6_dst", &key.ipv6_dst, MASK(mask, ipv6_dst), + verbose); format_u8x(ds, "tos", key.ip_tos, MASK(mask, ip_tos), verbose); format_u8u(ds, "ttl", key.ip_ttl, MASK(mask, ip_ttl), verbose); format_be16(ds, "tp_src", key.tp_src, MASK(mask, tp_src), verbose); @@ -2740,6 +2758,8 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names, SCAN_FIELD("tun_id=", be64, tun_id); SCAN_FIELD("src=", ipv4, ip_src); SCAN_FIELD("dst=", ipv4, ip_dst); + SCAN_FIELD("ipv6_src=", in6_addr, ipv6_src); + SCAN_FIELD("ipv6_dst=", in6_addr, ipv6_dst); SCAN_FIELD("tos=", u8, ip_tos); SCAN_FIELD("ttl=", u8, ip_ttl); SCAN_FIELD("tp_src=", be16, tp_src); @@ -2962,7 +2982,8 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *flow, nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, data->skb_priority); - if (flow->tunnel.ip_dst || export_mask) { + if (flow->tunnel.ip_dst || ipv6_addr_is_set(&flow->tunnel.ipv6_dst) + || export_mask) { tun_key_to_attr(buf, &data->tunnel); } @@ -3159,7 +3180,7 @@ odp_key_from_pkt_metadata(struct ofpbuf *buf, const struct pkt_metadata *md) { nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, md->skb_priority); - if (md->tunnel.ip_dst) { + if (md->tunnel.ip_dst || ipv6_addr_is_set(&md->tunnel.ipv6_dst)) { tun_key_to_attr(buf, &md->tunnel); } @@ -3975,8 +3996,9 @@ void commit_odp_tunnel_action(const struct flow *flow, struct flow *base, struct ofpbuf *odp_actions) { - /* A valid IPV4_TUNNEL must have non-zero ip_dst. */ - if (flow->tunnel.ip_dst) { + /* A valid IPV4_TUNNEL must have non-zero ip_dst; a valid IPv6 tunnel + * must have non-zero ipv6_dst. */ + if (flow->tunnel.ip_dst || ipv6_addr_is_set(&flow->tunnel.ipv6_dst)) { if (!memcmp(&base->tunnel, &flow->tunnel, sizeof base->tunnel)) { return; } diff --git a/lib/odp-util.h b/lib/odp-util.h index 4f0e794539b6..4aafa1460a10 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -109,6 +109,8 @@ void odp_portno_names_destroy(struct hmap *portno_names); * - OVS_TUNNEL_KEY_ATTR_ID 8 -- 4 12 * - OVS_TUNNEL_KEY_ATTR_IPV4_SRC 4 -- 4 8 * - OVS_TUNNEL_KEY_ATTR_IPV4_DST 4 -- 4 8 + * - OVS_TUNNEL_KEY_ATTR_IPV6_SRC 16 -- 4 20 + * - OVS_TUNNEL_KEY_ATTR_IPV6_DST 16 -- 4 20 * - OVS_TUNNEL_KEY_ATTR_TOS 1 3 4 8 * - OVS_TUNNEL_KEY_ATTR_TTL 1 3 4 8 * - OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT 0 -- 4 4 @@ -129,12 +131,12 @@ void odp_portno_names_destroy(struct hmap *portno_names); * OVS_KEY_ATTR_ICMPV6 2 2 4 8 * OVS_KEY_ATTR_ND 28 -- 4 32 * ---------------------------------------------------------- - * total 488 + * total 528 * * We include some slack space in case the calculation isn't quite right or we * add another field and forget to adjust this value. */ -#define ODPUTIL_FLOW_KEY_BYTES 512 +#define ODPUTIL_FLOW_KEY_BYTES 576 BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); /* A buffer with sufficient size and alignment to hold an nlattr-formatted flow diff --git a/lib/packets.h b/lib/packets.h index 385971903ce3..71e133e29c34 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -36,6 +36,8 @@ struct flow_tnl { ovs_be64 tun_id; ovs_be32 ip_src; ovs_be32 ip_dst; + struct in6_addr ipv6_src; + struct in6_addr ipv6_dst; uint16_t flags; uint8_t ip_tos; uint8_t ip_ttl; diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c index 3ea0eb44f92a..ccef40a59668 100644 --- a/ofproto/tunnel.c +++ b/ofproto/tunnel.c @@ -366,8 +366,13 @@ tnl_xlate_init(const struct flow *base_flow, struct flow *flow, if (tnl_port_should_receive(flow)) { if (wc) { wc->masks.tunnel.tun_id = OVS_BE64_MAX; - wc->masks.tunnel.ip_src = OVS_BE32_MAX; - wc->masks.tunnel.ip_dst = OVS_BE32_MAX; + if (flow->tunnel.ip_dst) { + wc->masks.tunnel.ip_src = OVS_BE32_MAX; + wc->masks.tunnel.ip_dst = OVS_BE32_MAX; + } else { + wc->masks.tunnel.ipv6_src = in6addr_exact; + wc->masks.tunnel.ipv6_dst = in6addr_exact; + } wc->masks.tunnel.flags = (FLOW_TNL_F_DONT_FRAGMENT | FLOW_TNL_F_CSUM | FLOW_TNL_F_KEY); diff --git a/ofproto/tunnel.h b/ofproto/tunnel.h index 6181762b2e1a..db2e203df04a 100644 --- a/ofproto/tunnel.h +++ b/ofproto/tunnel.h @@ -47,7 +47,7 @@ odp_port_t tnl_port_send(const struct ofport_dpif *, struct flow *, static inline bool tnl_port_should_receive(const struct flow *flow) { - return flow->tunnel.ip_dst != 0; + return flow->tunnel.ip_dst != 0 || ipv6_addr_is_set(&flow->tunnel.ipv6_dst); } int tnl_port_build_header(const struct ofport_dpif *ofport, -- 1.8.3.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev