diff mbox series

[ovs-dev] ovn-util: Remove redundant struct v46_ip.

Message ID 1603374334-4360-1-git-send-email-dceara@redhat.com
State Accepted
Headers show
Series [ovs-dev] ovn-util: Remove redundant struct v46_ip. | expand

Commit Message

Dumitru Ceara Oct. 22, 2020, 1:45 p.m. UTC
Use struct in6_addr instead and IPv4-mapped IPs.

Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2020-October/376160.html
Fixes: 719f586e4d38 ("northd: Add lflows for IPv6 NAT.")
Suggested-by: Ilya Maximets <i.maximets@ovn.org>
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
---
 ic/ovn-ic.c           | 112 ++++++++++++++++++++++++++++----------------------
 lib/ovn-util.c        |  31 +++++---------
 lib/ovn-util.h        |  15 ++-----
 northd/ovn-northd.c   |  38 ++++++++---------
 utilities/ovn-nbctl.c |   4 +-
 5 files changed, 99 insertions(+), 101 deletions(-)

Comments

0-day Robot Oct. 22, 2020, 1:59 p.m. UTC | #1
Bleep bloop.  Greetings Dumitru Ceara, I am a robot and I have tried out your patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


build:
gcc -std=gnu99 -DHAVE_CONFIG_H -I.   -I ./include  -I ./include -I ./ovn -I ./include -I ./lib -I ./lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/include -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/include -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR    -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror  -g -O2 -MT controller/pinctrl.o -MD -MP -MF $depbase.Tpo -c -o controller/pinctrl.o controller/pinctrl.c &&\
mv -f $depbase.Tpo $depbase.Po
depbase=`echo controller/patch.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
gcc -std=gnu99 -DHAVE_CONFIG_H -I.   -I ./include  -I ./include -I ./ovn -I ./include -I ./lib -I ./lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/include -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/include -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR    -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror  -g -O2 -MT controller/patch.o -MD -MP -MF $depbase.Tpo -c -o controller/patch.o controller/patch.c &&\
mv -f $depbase.Tpo $depbase.Po
depbase=`echo controller/ovn-controller.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
gcc -std=gnu99 -DHAVE_CONFIG_H -I.   -I ./include  -I ./include -I ./ovn -I ./include -I ./lib -I ./lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/include -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/include -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR    -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror  -g -O2 -MT controller/ovn-controller.o -MD -MP -MF $depbase.Tpo -c -o controller/ovn-controller.o controller/ovn-controller.c &&\
mv -f $depbase.Tpo $depbase.Po
depbase=`echo controller/physical.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
gcc -std=gnu99 -DHAVE_CONFIG_H -I.   -I ./include  -I ./include -I ./ovn -I ./include -I ./lib -I ./lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/include -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/include -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR/lib -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR -I /var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace/OVSDIR    -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror  -g -O2 -MT controller/physical.o -MD -MP -MF $depbase.Tpo -c -o controller/physical.o controller/physical.c &&\
mv -f $depbase.Tpo $depbase.Po
controller/physical.c: In function ‘put_remote_port_redirect_overlay’:
controller/physical.c:387:23: error: ‘struct ofpact_bundle’ has no member named ‘n_slaves’
             if (bundle->n_slaves >= BUNDLE_MAX_SLAVES) {
                       ^
controller/physical.c:387:37: error: ‘BUNDLE_MAX_SLAVES’ undeclared (first use in this function)
             if (bundle->n_slaves >= BUNDLE_MAX_SLAVES) {
                                     ^
controller/physical.c:387:37: note: each undeclared identifier is reported only once for each function it appears in
controller/physical.c:395:19: error: ‘struct ofpact_bundle’ has no member named ‘n_slaves’
             bundle->n_slaves++;
                   ^
make[1]: *** [controller/physical.o] Error 1
make[1]: Leaving directory `/var/lib/jenkins/jobs/0day_robot_upstream_build_ovn_from_pw/workspace'
make: *** [all] Error 2


Please check this out.  If you feel there has been an error, please email aconole@redhat.com

Thanks,
0-day Robot
Numan Siddique Nov. 11, 2020, 7:22 a.m. UTC | #2
On Thu, Oct 22, 2020 at 7:16 PM Dumitru Ceara <dceara@redhat.com> wrote:
>
> Use struct in6_addr instead and IPv4-mapped IPs.
>
> Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2020-October/376160.html
> Fixes: 719f586e4d38 ("northd: Add lflows for IPv6 NAT.")
> Suggested-by: Ilya Maximets <i.maximets@ovn.org>
> Signed-off-by: Dumitru Ceara <dceara@redhat.com>

Thanks Dumitru. I applied this patch to master.

Numan

> ---
>  ic/ovn-ic.c           | 112 ++++++++++++++++++++++++++++----------------------
>  lib/ovn-util.c        |  31 +++++---------
>  lib/ovn-util.h        |  15 ++-----
>  northd/ovn-northd.c   |  38 ++++++++---------
>  utilities/ovn-nbctl.c |   4 +-
>  5 files changed, 99 insertions(+), 101 deletions(-)
>
> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
> index 923969f..ba28bc9 100644
> --- a/ic/ovn-ic.c
> +++ b/ic/ovn-ic.c
> @@ -817,9 +817,9 @@ struct ic_router_info {
>  /* Represents an interconnection route entry. */
>  struct ic_route_info {
>      struct hmap_node node;
> -    struct v46_ip prefix;
> +    struct in6_addr prefix;
>      unsigned int plen;
> -    struct v46_ip nexthop;
> +    struct in6_addr nexthop;
>
>      /* Either nb_route or nb_lrp is set and the other one must be NULL.
>       * - For a route that is learned from IC-SB, or a static route that is
> @@ -832,23 +832,23 @@ struct ic_route_info {
>  };
>
>  static uint32_t
> -ic_route_hash(const struct v46_ip *prefix, unsigned int plen,
> -              const struct v46_ip *nexthop)
> +ic_route_hash(const struct in6_addr *prefix, unsigned int plen,
> +              const struct in6_addr *nexthop)
>  {
>      uint32_t basis = hash_bytes(prefix, sizeof *prefix, (uint32_t)plen);
>      return hash_bytes(nexthop, sizeof *nexthop, basis);
>  }
>
>  static struct ic_route_info *
> -ic_route_find(struct hmap *routes, const struct v46_ip *prefix,
> -              unsigned int plen, const struct v46_ip *nexthop)
> +ic_route_find(struct hmap *routes, const struct in6_addr *prefix,
> +              unsigned int plen, const struct in6_addr *nexthop)
>  {
>      struct ic_route_info *r;
>      uint32_t hash = ic_route_hash(prefix, plen, nexthop);
>      HMAP_FOR_EACH_WITH_HASH (r, node, hash, routes) {
> -        if (ip46_equals(&r->prefix, prefix) &&
> +        if (ipv6_addr_equals(&r->prefix, prefix) &&
>              r->plen == plen &&
> -            ip46_equals(&r->nexthop, nexthop)) {
> +            ipv6_addr_equals(&r->nexthop, nexthop)) {
>              return r;
>          }
>      }
> @@ -870,8 +870,8 @@ ic_router_find(struct hmap *ic_lrs, const struct nbrec_logical_router *lr)
>
>  static bool
>  parse_route(const char *s_prefix, const char *s_nexthop,
> -            struct v46_ip *prefix, unsigned int *plen,
> -            struct v46_ip *nexthop)
> +            struct in6_addr *prefix, unsigned int *plen,
> +            struct in6_addr *nexthop)
>  {
>      if (!ip46_parse_cidr(s_prefix, prefix, plen)) {
>          return false;
> @@ -886,7 +886,7 @@ static bool
>  add_to_routes_learned(struct hmap *routes_learned,
>                        const struct nbrec_logical_router_static_route *nb_route)
>  {
> -    struct v46_ip prefix, nexthop;
> +    struct in6_addr prefix, nexthop;
>      unsigned int plen;
>      if (!parse_route(nb_route->ip_prefix, nb_route->nexthop,
>                       &prefix, &plen, &nexthop)) {
> @@ -903,62 +903,60 @@ add_to_routes_learned(struct hmap *routes_learned,
>  }
>
>  static bool
> -get_nexthop_from_lport_addresses(int family,
> +get_nexthop_from_lport_addresses(bool is_v4,
>                                   const struct lport_addresses *laddr,
> -                                 struct v46_ip *nexthop)
> +                                 struct in6_addr *nexthop)
>  {
> -    memset(nexthop, 0, sizeof *nexthop);
> -    nexthop->family = family;
> -    if (family == AF_INET) {
> +    if (is_v4) {
>          if (!laddr->n_ipv4_addrs) {
>              return false;
>          }
> -        nexthop->ipv4 = laddr->ipv4_addrs[0].addr;
> +        in6_addr_set_mapped_ipv4(nexthop, laddr->ipv4_addrs[0].addr);
>          return true;
>      }
>
>      /* ipv6 */
>      if (laddr->n_ipv6_addrs) {
> -        nexthop->ipv6 = laddr->ipv6_addrs[0].addr;
> +        *nexthop = laddr->ipv6_addrs[0].addr;
>          return true;
>      }
>
>      /* ipv6 link local */
> -    in6_generate_lla(laddr->ea, &nexthop->ipv6);
> +    in6_generate_lla(laddr->ea, nexthop);
>      return true;
>  }
>
>  static bool
> -prefix_is_link_local(struct v46_ip *prefix, unsigned int plen)
> +prefix_is_link_local(struct in6_addr *prefix, unsigned int plen)
>  {
> -    if (prefix->family == AF_INET) {
> +    if (IN6_IS_ADDR_V4MAPPED(prefix)) {
>          /* Link local range is "169.254.0.0/16". */
>          if (plen < 16) {
>              return false;
>          }
>          ovs_be32 lla;
>          inet_pton(AF_INET, "169.254.0.0", &lla);
> -        return ((prefix->ipv4 & htonl(0xffff0000)) == lla);
> +        return ((in6_addr_get_mapped_ipv4(prefix) & htonl(0xffff0000)) == lla);
>      }
>
>      /* ipv6, link local range is "fe80::/10". */
>      if (plen < 10) {
>          return false;
>      }
> -    return (((prefix->ipv6.s6_addr[0] & 0xff) == 0xfe) &&
> -            ((prefix->ipv6.s6_addr[1] & 0xc0) == 0x80));
> +    return (((prefix->s6_addr[0] & 0xff) == 0xfe) &&
> +            ((prefix->s6_addr[1] & 0xc0) == 0x80));
>  }
>
>  static bool
>  prefix_is_black_listed(const struct smap *nb_options,
> -                       struct v46_ip *prefix,
> +                       struct in6_addr *prefix,
>                         unsigned int plen)
>  {
>      const char *blacklist = smap_get(nb_options, "ic-route-blacklist");
>      if (!blacklist || !blacklist[0]) {
>          return false;
>      }
> -    struct v46_ip bl_prefix;
> +    struct in6_addr bl_prefix;
>      unsigned int bl_plen;
>      char *cur, *next, *start;
>      next = start = xstrdup(blacklist);
> @@ -971,7 +969,7 @@ prefix_is_black_listed(const struct smap *nb_options,
>              continue;
>          }
>
> -        if (bl_prefix.family != prefix->family) {
> +        if (IN6_IS_ADDR_V4MAPPED(&bl_prefix) != IN6_IS_ADDR_V4MAPPED(prefix)) {
>              continue;
>          }
>
> @@ -980,16 +978,19 @@ prefix_is_black_listed(const struct smap *nb_options,
>              continue;
>          }
>
> -        if (prefix->family == AF_INET) {
> +        if (IN6_IS_ADDR_V4MAPPED(prefix)) {
> +            ovs_be32 bl_prefix_v4 = in6_addr_get_mapped_ipv4(&bl_prefix);
> +            ovs_be32 prefix_v4 = in6_addr_get_mapped_ipv4(prefix);
>              ovs_be32 mask = be32_prefix_mask(bl_plen);
> -            if ((prefix->ipv4 & mask) != (bl_prefix.ipv4 & mask)) {
> +
> +            if ((prefix_v4 & mask) != (bl_prefix_v4 & mask)) {
>                  continue;
>              }
>          } else {
>              struct in6_addr mask = ipv6_create_mask(bl_plen);
>              for (int i = 0; i < 16 && mask.s6_addr[i] != 0; i++) {
> -                if ((prefix->ipv6.s6_addr[i] & mask.s6_addr[i])
> -                    != (bl_prefix.ipv6.s6_addr[i] & mask.s6_addr[i])) {
> +                if ((prefix->s6_addr[i] & mask.s6_addr[i])
> +                    != (bl_prefix.s6_addr[i] & mask.s6_addr[i])) {
>                      continue;
>                  }
>              }
> @@ -1003,7 +1004,7 @@ prefix_is_black_listed(const struct smap *nb_options,
>
>  static bool
>  route_need_advertise(const char *policy,
> -                     struct v46_ip *prefix,
> +                     struct in6_addr *prefix,
>                       unsigned int plen,
>                       const struct smap *nb_options)
>  {
> @@ -1036,7 +1037,7 @@ add_to_routes_ad(struct hmap *routes_ad,
>                   const struct lport_addresses *nexthop_addresses,
>                   const struct smap *nb_options)
>  {
> -    struct v46_ip prefix, nexthop;
> +    struct in6_addr prefix, nexthop;
>      unsigned int plen;
>      if (!parse_route(nb_route->ip_prefix, nb_route->nexthop,
>                       &prefix, &plen, &nexthop)) {
> @@ -1047,7 +1048,7 @@ add_to_routes_ad(struct hmap *routes_ad,
>          return;
>      }
>
> -    if (!get_nexthop_from_lport_addresses(prefix.family,
> +    if (!get_nexthop_from_lport_addresses(IN6_IS_ADDR_V4MAPPED(&prefix),
>                                            nexthop_addresses,
>                                            &nexthop)) {
>          return;
> @@ -1068,7 +1069,7 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
>                           const struct lport_addresses *nexthop_addresses,
>                           const struct smap *nb_options)
>  {
> -    struct v46_ip prefix, nexthop;
> +    struct in6_addr prefix, nexthop;
>      unsigned int plen;
>      if (!ip46_parse_cidr(network, &prefix, &plen)) {
>          return;
> @@ -1080,14 +1081,29 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
>          return;
>      }
>
> -    if (!get_nexthop_from_lport_addresses(prefix.family,
> +    if (!get_nexthop_from_lport_addresses(IN6_IS_ADDR_V4MAPPED(&prefix),
>                                            nexthop_addresses,
>                                            &nexthop)) {
>          return;
>      }
>
> -    VLOG_DBG("Route ad: direct network %s of lrp %s, nexthop "IP_FMT,
> -             network, nb_lrp->name, IP_ARGS(nexthop.ipv4));
> +    if (VLOG_IS_DBG_ENABLED()) {
> +        struct ds msg = DS_EMPTY_INITIALIZER;
> +
> +        ds_put_format(&msg, "Route ad: direct network %s of lrp %s, nexthop ",
> +                      network, nb_lrp->name);
> +
> +        if (IN6_IS_ADDR_V4MAPPED(&nexthop)) {
> +            ds_put_format(&msg, IP_FMT,
> +                          IP_ARGS(in6_addr_get_mapped_ipv4(&nexthop)));
> +        } else {
> +            ipv6_format_addr(&nexthop, &msg);
> +        }
> +
> +        VLOG_DBG("%s", ds_cstr(&msg));
> +        ds_destroy(&msg);
> +    }
> +
>      struct ic_route_info *ic_route = xzalloc(sizeof *ic_route);
>      ic_route->prefix = prefix;
>      ic_route->plen = plen;
> @@ -1098,7 +1114,7 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
>  }
>
>  static bool
> -route_need_learn(struct v46_ip *prefix,
> +route_need_learn(struct in6_addr *prefix,
>                   unsigned int plen,
>                   const struct smap *nb_options)
>  {
> @@ -1133,7 +1149,7 @@ sync_learned_route(struct ic_context *ctx,
>          if (isb_route->availability_zone == az) {
>              continue;
>          }
> -        struct v46_ip prefix, nexthop;
> +        struct in6_addr prefix, nexthop;
>          unsigned int plen;
>          if (!parse_route(isb_route->ip_prefix, isb_route->nexthop,
>                           &prefix, &plen, &nexthop)) {
> @@ -1228,7 +1244,7 @@ advertise_route(struct ic_context *ctx,
>              continue;
>          }
>
> -        struct v46_ip prefix, nexthop;
> +        struct in6_addr prefix, nexthop;
>          unsigned int plen;
>
>          if (!parse_route(isb_route->ip_prefix, isb_route->nexthop,
> @@ -1264,17 +1280,17 @@ advertise_route(struct ic_context *ctx,
>          icsbrec_route_set_availability_zone(isb_route, az);
>
>          char *prefix_s, *nexthop_s;
> -        if (route_adv->prefix.family == AF_INET) {
> -            prefix_s = xasprintf(IP_FMT "/%d",
> -                                 IP_ARGS(route_adv->prefix.ipv4),
> -                                 route_adv->plen);
> -            nexthop_s = xasprintf(IP_FMT, IP_ARGS(route_adv->nexthop.ipv4));
> +        if (IN6_IS_ADDR_V4MAPPED(&route_adv->prefix)) {
> +            ovs_be32 ipv4 = in6_addr_get_mapped_ipv4(&route_adv->prefix);
> +            ovs_be32 nh = in6_addr_get_mapped_ipv4(&route_adv->nexthop);
> +            prefix_s = xasprintf(IP_FMT "/%d", IP_ARGS(ipv4), route_adv->plen);
> +            nexthop_s = xasprintf(IP_FMT, IP_ARGS(nh));
>          } else {
>              char network_s[INET6_ADDRSTRLEN];
> -            inet_ntop(AF_INET6, &route_adv->prefix.ipv6, network_s,
> +            inet_ntop(AF_INET6, &route_adv->prefix, network_s,
>                        INET6_ADDRSTRLEN);
>              prefix_s = xasprintf("%s/%d", network_s, route_adv->plen);
> -            inet_ntop(AF_INET6, &route_adv->nexthop.ipv6, network_s,
> +            inet_ntop(AF_INET6, &route_adv->nexthop, network_s,
>                        INET6_ADDRSTRLEN);
>              nexthop_s = xstrdup(network_s);
>          }
> diff --git a/lib/ovn-util.c b/lib/ovn-util.c
> index 1daf665..9ed9991 100644
> --- a/lib/ovn-util.c
> +++ b/lib/ovn-util.c
> @@ -568,33 +568,24 @@ ovn_chassis_redirect_name(const char *port_name)
>  }
>
>  bool
> -ip46_parse_cidr(const char *str, struct v46_ip *prefix, unsigned int *plen)
> +ip46_parse_cidr(const char *str, struct in6_addr *prefix, unsigned int *plen)
>  {
> -    memset(prefix, 0, sizeof *prefix);
> +    ovs_be32 ipv4;
> +    char *error = ip_parse_cidr(str, &ipv4, plen);
>
> -    char *error = ip_parse_cidr(str, &prefix->ipv4, plen);
>      if (!error) {
> -        prefix->family = AF_INET;
> +        in6_addr_set_mapped_ipv4(prefix, ipv4);
>          return true;
>      }
>      free(error);
> -    error = ipv6_parse_cidr(str, &prefix->ipv6, plen);
> +    error = ipv6_parse_cidr(str, prefix, plen);
>      if (!error) {
> -        prefix->family = AF_INET6;
>          return true;
>      }
>      free(error);
>      return false;
>  }
>
> -bool
> -ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2)
> -{
> -    return (addr1->family == addr2->family &&
> -            (addr1->family == AF_INET ? addr1->ipv4 == addr2->ipv4 :
> -             IN6_ARE_ADDR_EQUAL(&addr1->ipv6, &addr2->ipv6)));
> -}
> -
>  /* The caller must free the returned string. */
>  char *
>  normalize_ipv4_prefix(ovs_be32 ipv4, unsigned int plen)
> @@ -609,12 +600,12 @@ normalize_ipv4_prefix(ovs_be32 ipv4, unsigned int plen)
>
>  /* The caller must free the returned string. */
>  char *
> -normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen)
> +normalize_ipv6_prefix(const struct in6_addr *ipv6, unsigned int plen)
>  {
>      char network_s[INET6_ADDRSTRLEN];
>
>      struct in6_addr mask = ipv6_create_mask(plen);
> -    struct in6_addr network = ipv6_addr_bitand(&ipv6, &mask);
> +    struct in6_addr network = ipv6_addr_bitand(ipv6, &mask);
>
>      inet_ntop(AF_INET6, &network, network_s, INET6_ADDRSTRLEN);
>      if (plen == 128) {
> @@ -625,12 +616,12 @@ normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen)
>  }
>
>  char *
> -normalize_v46_prefix(const struct v46_ip *prefix, unsigned int plen)
> +normalize_v46_prefix(const struct in6_addr *prefix, unsigned int plen)
>  {
> -    if (prefix->family == AF_INET) {
> -        return normalize_ipv4_prefix(prefix->ipv4, plen);
> +    if (IN6_IS_ADDR_V4MAPPED(prefix)) {
> +        return normalize_ipv4_prefix(in6_addr_get_mapped_ipv4(prefix), plen);
>      } else {
> -        return normalize_ipv6_prefix(prefix->ipv6, plen);
> +        return normalize_ipv6_prefix(prefix, plen);
>      }
>  }
>
> diff --git a/lib/ovn-util.h b/lib/ovn-util.h
> index 1d22a69..8aef48a 100644
> --- a/lib/ovn-util.h
> +++ b/lib/ovn-util.h
> @@ -137,21 +137,12 @@ get_sb_port_group_name(const char *nb_pg_name, int64_t dp_tunnel_key,
>  char *ovn_chassis_redirect_name(const char *port_name);
>  void ovn_set_pidfile(const char *name);
>
> -/* An IPv4 or IPv6 address */
> -struct v46_ip {
> -    int family;
> -    union {
> -        ovs_be32 ipv4;
> -        struct in6_addr ipv6;
> -    };
> -};
> -bool ip46_parse_cidr(const char *str, struct v46_ip *prefix,
> +bool ip46_parse_cidr(const char *str, struct in6_addr *prefix,
>                       unsigned int *plen);
> -bool ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2);
>
>  char *normalize_ipv4_prefix(ovs_be32 ipv4, unsigned int plen);
> -char *normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen);
> -char *normalize_v46_prefix(const struct v46_ip *prefix, unsigned int plen);
> +char *normalize_ipv6_prefix(const struct in6_addr *ipv6, unsigned int plen);
> +char *normalize_v46_prefix(const struct in6_addr *prefix, unsigned int plen);
>
>  /* Temporary util function until ovs library has smap_get_unit. */
>  unsigned int ovn_smap_get_uint(const struct smap *smap, const char *key,
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index 1ca037f..c2447fd 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -7651,7 +7651,7 @@ build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od,
>
>  struct parsed_route {
>      struct ovs_list list_node;
> -    struct v46_ip prefix;
> +    struct in6_addr prefix;
>      unsigned int plen;
>      bool is_src_route;
>      uint32_t hash;
> @@ -7673,7 +7673,7 @@ parsed_routes_add(struct ovs_list *routes,
>                    const struct nbrec_logical_router_static_route *route)
>  {
>      /* Verify that the next hop is an IP address with an all-ones mask. */
> -    struct v46_ip nexthop;
> +    struct in6_addr nexthop;
>      unsigned int plen;
>      if (!ip46_parse_cidr(route->nexthop, &nexthop, &plen)) {
>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> @@ -7682,8 +7682,8 @@ parsed_routes_add(struct ovs_list *routes,
>                       UUID_ARGS(&route->header_.uuid));
>          return NULL;
>      }
> -    if ((nexthop.family == AF_INET && plen != 32) ||
> -        (nexthop.family == AF_INET6 && plen != 128)) {
> +    if ((IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 32) ||
> +        (!IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 128)) {
>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
>          VLOG_WARN_RL(&rl, "bad next hop mask %s in static route"
>                       UUID_FMT, route->nexthop,
> @@ -7692,7 +7692,7 @@ parsed_routes_add(struct ovs_list *routes,
>      }
>
>      /* Parse ip_prefix */
> -    struct v46_ip prefix;
> +    struct in6_addr prefix;
>      if (!ip46_parse_cidr(route->ip_prefix, &prefix, &plen)) {
>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
>          VLOG_WARN_RL(&rl, "bad 'ip_prefix' %s in static route"
> @@ -7702,7 +7702,7 @@ parsed_routes_add(struct ovs_list *routes,
>      }
>
>      /* Verify that ip_prefix and nexthop have same address familiy. */
> -    if (prefix.family != nexthop.family) {
> +    if (IN6_IS_ADDR_V4MAPPED(&prefix) != IN6_IS_ADDR_V4MAPPED(&nexthop)) {
>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
>          VLOG_WARN_RL(&rl, "Address family doesn't match between 'ip_prefix' %s"
>                       " and 'nexthop' %s in static route"UUID_FMT,
> @@ -7743,7 +7743,7 @@ struct ecmp_route_list_node {
>  struct ecmp_groups_node {
>      struct hmap_node hmap_node; /* In ecmp_groups */
>      uint16_t id; /* starts from 1 */
> -    struct v46_ip prefix;
> +    struct in6_addr prefix;
>      unsigned int plen;
>      bool is_src_route;
>      uint16_t route_count;
> @@ -7794,7 +7794,7 @@ ecmp_groups_find(struct hmap *ecmp_groups, struct parsed_route *route)
>  {
>      struct ecmp_groups_node *eg;
>      HMAP_FOR_EACH_WITH_HASH (eg, hmap_node, route->hash, ecmp_groups) {
> -        if (ip46_equals(&eg->prefix, &route->prefix) &&
> +        if (ipv6_addr_equals(&eg->prefix, &route->prefix) &&
>              eg->plen == route->plen &&
>              eg->is_src_route == route->is_src_route) {
>              return eg;
> @@ -7841,7 +7841,7 @@ unique_routes_remove(struct hmap *unique_routes,
>  {
>      struct unique_routes_node *ur;
>      HMAP_FOR_EACH_WITH_HASH (ur, hmap_node, route->hash, unique_routes) {
> -        if (ip46_equals(&route->prefix, &ur->route->prefix) &&
> +        if (ipv6_addr_equals(&route->prefix, &ur->route->prefix) &&
>              route->plen == ur->route->plen &&
>              route->is_src_route == ur->route->is_src_route) {
>              hmap_remove(unique_routes, &ur->hmap_node);
> @@ -7865,15 +7865,15 @@ unique_routes_destroy(struct hmap *unique_routes)
>  }
>
>  static char *
> -build_route_prefix_s(const struct v46_ip *prefix, unsigned int plen)
> +build_route_prefix_s(const struct in6_addr *prefix, unsigned int plen)
>  {
>      char *prefix_s;
> -    if (prefix->family == AF_INET) {
> -        prefix_s = xasprintf(IP_FMT, IP_ARGS(prefix->ipv4 &
> +    if (IN6_IS_ADDR_V4MAPPED(prefix)) {
> +        prefix_s = xasprintf(IP_FMT, IP_ARGS(in6_addr_get_mapped_ipv4(prefix) &
>                                               be32_prefix_mask(plen)));
>      } else {
>          struct in6_addr mask = ipv6_create_mask(plen);
> -        struct in6_addr network = ipv6_addr_bitand(&prefix->ipv6, &mask);
> +        struct in6_addr network = ipv6_addr_bitand(prefix, &mask);
>          prefix_s = xmalloc(INET6_ADDRSTRLEN);
>          inet_ntop(AF_INET6, &network, prefix_s, INET6_ADDRSTRLEN);
>      }
> @@ -7987,7 +7987,7 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
>       */
>      ds_put_format(&match, "inport == %s && ip%s.%s == %s",
>                    out_port->json_key,
> -                  route->prefix.family == AF_INET ? "4" : "6",
> +                  IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "4" : "6",
>                    route->is_src_route ? "dst" : "src",
>                    cidr);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100,
> @@ -8026,7 +8026,7 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
>      ds_put_format(&actions, "ip.ttl--; flags.loopback = 1; "
>                    "eth.src = %s; %sreg1 = %s; outport = %s; next;",
>                    out_port->lrp_networks.ea_s,
> -                  route->prefix.family == AF_INET ? "" : "xx",
> +                  IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "" : "xx",
>                    port_ip, out_port->json_key);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING, 100,
>                             ds_cstr(&match), ds_cstr(&actions),
> @@ -8048,7 +8048,7 @@ build_ecmp_route_flow(struct hmap *lflows, struct ovn_datapath *od,
>                        struct hmap *ports, struct ecmp_groups_node *eg)
>
>  {
> -    bool is_ipv4 = (eg->prefix.family == AF_INET);
> +    bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix);
>      uint16_t priority;
>      struct ecmp_route_list_node *er;
>      struct ds route_match = DS_EMPTY_INITIALIZER;
> @@ -8182,13 +8182,13 @@ build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od,
>  {
>      const char *lrp_addr_s = NULL;
>      struct ovn_port *out_port = NULL;
> -    bool is_ipv4 = (route_->prefix.family == AF_INET);
>
>      const struct nbrec_logical_router_static_route *route = route_->route;
>
>      /* Find the outgoing port. */
> -    if (!find_static_route_outport(od, ports, route, is_ipv4, &lrp_addr_s,
> -                                   &out_port)) {
> +    if (!find_static_route_outport(od, ports, route,
> +                                   IN6_IS_ADDR_V4MAPPED(&route_->prefix),
> +                                   &lrp_addr_s, &out_port)) {
>          return;
>      }
>
> diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
> index abc674f..aad6a36 100644
> --- a/utilities/ovn-nbctl.c
> +++ b/utilities/ovn-nbctl.c
> @@ -3559,7 +3559,7 @@ normalize_ipv6_prefix_str(const char *orig_prefix)
>          free(error);
>          return NULL;
>      }
> -    return normalize_ipv6_prefix(ipv6, plen);
> +    return normalize_ipv6_prefix(&ipv6, plen);
>  }
>
>  /* The caller must free the returned string. */
> @@ -3596,7 +3596,7 @@ normalize_ipv6_addr_str(const char *orig_addr)
>          return NULL;
>      }
>
> -    return normalize_ipv6_prefix(ipv6, 128);
> +    return normalize_ipv6_prefix(&ipv6, 128);
>  }
>
>  /* Similar to normalize_prefix_str but must be an un-masked address.
> --
> 1.8.3.1
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
diff mbox series

Patch

diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index 923969f..ba28bc9 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -817,9 +817,9 @@  struct ic_router_info {
 /* Represents an interconnection route entry. */
 struct ic_route_info {
     struct hmap_node node;
-    struct v46_ip prefix;
+    struct in6_addr prefix;
     unsigned int plen;
-    struct v46_ip nexthop;
+    struct in6_addr nexthop;
 
     /* Either nb_route or nb_lrp is set and the other one must be NULL.
      * - For a route that is learned from IC-SB, or a static route that is
@@ -832,23 +832,23 @@  struct ic_route_info {
 };
 
 static uint32_t
-ic_route_hash(const struct v46_ip *prefix, unsigned int plen,
-              const struct v46_ip *nexthop)
+ic_route_hash(const struct in6_addr *prefix, unsigned int plen,
+              const struct in6_addr *nexthop)
 {
     uint32_t basis = hash_bytes(prefix, sizeof *prefix, (uint32_t)plen);
     return hash_bytes(nexthop, sizeof *nexthop, basis);
 }
 
 static struct ic_route_info *
-ic_route_find(struct hmap *routes, const struct v46_ip *prefix,
-              unsigned int plen, const struct v46_ip *nexthop)
+ic_route_find(struct hmap *routes, const struct in6_addr *prefix,
+              unsigned int plen, const struct in6_addr *nexthop)
 {
     struct ic_route_info *r;
     uint32_t hash = ic_route_hash(prefix, plen, nexthop);
     HMAP_FOR_EACH_WITH_HASH (r, node, hash, routes) {
-        if (ip46_equals(&r->prefix, prefix) &&
+        if (ipv6_addr_equals(&r->prefix, prefix) &&
             r->plen == plen &&
-            ip46_equals(&r->nexthop, nexthop)) {
+            ipv6_addr_equals(&r->nexthop, nexthop)) {
             return r;
         }
     }
@@ -870,8 +870,8 @@  ic_router_find(struct hmap *ic_lrs, const struct nbrec_logical_router *lr)
 
 static bool
 parse_route(const char *s_prefix, const char *s_nexthop,
-            struct v46_ip *prefix, unsigned int *plen,
-            struct v46_ip *nexthop)
+            struct in6_addr *prefix, unsigned int *plen,
+            struct in6_addr *nexthop)
 {
     if (!ip46_parse_cidr(s_prefix, prefix, plen)) {
         return false;
@@ -886,7 +886,7 @@  static bool
 add_to_routes_learned(struct hmap *routes_learned,
                       const struct nbrec_logical_router_static_route *nb_route)
 {
-    struct v46_ip prefix, nexthop;
+    struct in6_addr prefix, nexthop;
     unsigned int plen;
     if (!parse_route(nb_route->ip_prefix, nb_route->nexthop,
                      &prefix, &plen, &nexthop)) {
@@ -903,62 +903,60 @@  add_to_routes_learned(struct hmap *routes_learned,
 }
 
 static bool
-get_nexthop_from_lport_addresses(int family,
+get_nexthop_from_lport_addresses(bool is_v4,
                                  const struct lport_addresses *laddr,
-                                 struct v46_ip *nexthop)
+                                 struct in6_addr *nexthop)
 {
-    memset(nexthop, 0, sizeof *nexthop);
-    nexthop->family = family;
-    if (family == AF_INET) {
+    if (is_v4) {
         if (!laddr->n_ipv4_addrs) {
             return false;
         }
-        nexthop->ipv4 = laddr->ipv4_addrs[0].addr;
+        in6_addr_set_mapped_ipv4(nexthop, laddr->ipv4_addrs[0].addr);
         return true;
     }
 
     /* ipv6 */
     if (laddr->n_ipv6_addrs) {
-        nexthop->ipv6 = laddr->ipv6_addrs[0].addr;
+        *nexthop = laddr->ipv6_addrs[0].addr;
         return true;
     }
 
     /* ipv6 link local */
-    in6_generate_lla(laddr->ea, &nexthop->ipv6);
+    in6_generate_lla(laddr->ea, nexthop);
     return true;
 }
 
 static bool
-prefix_is_link_local(struct v46_ip *prefix, unsigned int plen)
+prefix_is_link_local(struct in6_addr *prefix, unsigned int plen)
 {
-    if (prefix->family == AF_INET) {
+    if (IN6_IS_ADDR_V4MAPPED(prefix)) {
         /* Link local range is "169.254.0.0/16". */
         if (plen < 16) {
             return false;
         }
         ovs_be32 lla;
         inet_pton(AF_INET, "169.254.0.0", &lla);
-        return ((prefix->ipv4 & htonl(0xffff0000)) == lla);
+        return ((in6_addr_get_mapped_ipv4(prefix) & htonl(0xffff0000)) == lla);
     }
 
     /* ipv6, link local range is "fe80::/10". */
     if (plen < 10) {
         return false;
     }
-    return (((prefix->ipv6.s6_addr[0] & 0xff) == 0xfe) &&
-            ((prefix->ipv6.s6_addr[1] & 0xc0) == 0x80));
+    return (((prefix->s6_addr[0] & 0xff) == 0xfe) &&
+            ((prefix->s6_addr[1] & 0xc0) == 0x80));
 }
 
 static bool
 prefix_is_black_listed(const struct smap *nb_options,
-                       struct v46_ip *prefix,
+                       struct in6_addr *prefix,
                        unsigned int plen)
 {
     const char *blacklist = smap_get(nb_options, "ic-route-blacklist");
     if (!blacklist || !blacklist[0]) {
         return false;
     }
-    struct v46_ip bl_prefix;
+    struct in6_addr bl_prefix;
     unsigned int bl_plen;
     char *cur, *next, *start;
     next = start = xstrdup(blacklist);
@@ -971,7 +969,7 @@  prefix_is_black_listed(const struct smap *nb_options,
             continue;
         }
 
-        if (bl_prefix.family != prefix->family) {
+        if (IN6_IS_ADDR_V4MAPPED(&bl_prefix) != IN6_IS_ADDR_V4MAPPED(prefix)) {
             continue;
         }
 
@@ -980,16 +978,19 @@  prefix_is_black_listed(const struct smap *nb_options,
             continue;
         }
 
-        if (prefix->family == AF_INET) {
+        if (IN6_IS_ADDR_V4MAPPED(prefix)) {
+            ovs_be32 bl_prefix_v4 = in6_addr_get_mapped_ipv4(&bl_prefix);
+            ovs_be32 prefix_v4 = in6_addr_get_mapped_ipv4(prefix);
             ovs_be32 mask = be32_prefix_mask(bl_plen);
-            if ((prefix->ipv4 & mask) != (bl_prefix.ipv4 & mask)) {
+
+            if ((prefix_v4 & mask) != (bl_prefix_v4 & mask)) {
                 continue;
             }
         } else {
             struct in6_addr mask = ipv6_create_mask(bl_plen);
             for (int i = 0; i < 16 && mask.s6_addr[i] != 0; i++) {
-                if ((prefix->ipv6.s6_addr[i] & mask.s6_addr[i])
-                    != (bl_prefix.ipv6.s6_addr[i] & mask.s6_addr[i])) {
+                if ((prefix->s6_addr[i] & mask.s6_addr[i])
+                    != (bl_prefix.s6_addr[i] & mask.s6_addr[i])) {
                     continue;
                 }
             }
@@ -1003,7 +1004,7 @@  prefix_is_black_listed(const struct smap *nb_options,
 
 static bool
 route_need_advertise(const char *policy,
-                     struct v46_ip *prefix,
+                     struct in6_addr *prefix,
                      unsigned int plen,
                      const struct smap *nb_options)
 {
@@ -1036,7 +1037,7 @@  add_to_routes_ad(struct hmap *routes_ad,
                  const struct lport_addresses *nexthop_addresses,
                  const struct smap *nb_options)
 {
-    struct v46_ip prefix, nexthop;
+    struct in6_addr prefix, nexthop;
     unsigned int plen;
     if (!parse_route(nb_route->ip_prefix, nb_route->nexthop,
                      &prefix, &plen, &nexthop)) {
@@ -1047,7 +1048,7 @@  add_to_routes_ad(struct hmap *routes_ad,
         return;
     }
 
-    if (!get_nexthop_from_lport_addresses(prefix.family,
+    if (!get_nexthop_from_lport_addresses(IN6_IS_ADDR_V4MAPPED(&prefix),
                                           nexthop_addresses,
                                           &nexthop)) {
         return;
@@ -1068,7 +1069,7 @@  add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
                          const struct lport_addresses *nexthop_addresses,
                          const struct smap *nb_options)
 {
-    struct v46_ip prefix, nexthop;
+    struct in6_addr prefix, nexthop;
     unsigned int plen;
     if (!ip46_parse_cidr(network, &prefix, &plen)) {
         return;
@@ -1080,14 +1081,29 @@  add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
         return;
     }
 
-    if (!get_nexthop_from_lport_addresses(prefix.family,
+    if (!get_nexthop_from_lport_addresses(IN6_IS_ADDR_V4MAPPED(&prefix),
                                           nexthop_addresses,
                                           &nexthop)) {
         return;
     }
 
-    VLOG_DBG("Route ad: direct network %s of lrp %s, nexthop "IP_FMT,
-             network, nb_lrp->name, IP_ARGS(nexthop.ipv4));
+    if (VLOG_IS_DBG_ENABLED()) {
+        struct ds msg = DS_EMPTY_INITIALIZER;
+
+        ds_put_format(&msg, "Route ad: direct network %s of lrp %s, nexthop ",
+                      network, nb_lrp->name);
+
+        if (IN6_IS_ADDR_V4MAPPED(&nexthop)) {
+            ds_put_format(&msg, IP_FMT,
+                          IP_ARGS(in6_addr_get_mapped_ipv4(&nexthop)));
+        } else {
+            ipv6_format_addr(&nexthop, &msg);
+        }
+
+        VLOG_DBG("%s", ds_cstr(&msg));
+        ds_destroy(&msg);
+    }
+
     struct ic_route_info *ic_route = xzalloc(sizeof *ic_route);
     ic_route->prefix = prefix;
     ic_route->plen = plen;
@@ -1098,7 +1114,7 @@  add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
 }
 
 static bool
-route_need_learn(struct v46_ip *prefix,
+route_need_learn(struct in6_addr *prefix,
                  unsigned int plen,
                  const struct smap *nb_options)
 {
@@ -1133,7 +1149,7 @@  sync_learned_route(struct ic_context *ctx,
         if (isb_route->availability_zone == az) {
             continue;
         }
-        struct v46_ip prefix, nexthop;
+        struct in6_addr prefix, nexthop;
         unsigned int plen;
         if (!parse_route(isb_route->ip_prefix, isb_route->nexthop,
                          &prefix, &plen, &nexthop)) {
@@ -1228,7 +1244,7 @@  advertise_route(struct ic_context *ctx,
             continue;
         }
 
-        struct v46_ip prefix, nexthop;
+        struct in6_addr prefix, nexthop;
         unsigned int plen;
 
         if (!parse_route(isb_route->ip_prefix, isb_route->nexthop,
@@ -1264,17 +1280,17 @@  advertise_route(struct ic_context *ctx,
         icsbrec_route_set_availability_zone(isb_route, az);
 
         char *prefix_s, *nexthop_s;
-        if (route_adv->prefix.family == AF_INET) {
-            prefix_s = xasprintf(IP_FMT "/%d",
-                                 IP_ARGS(route_adv->prefix.ipv4),
-                                 route_adv->plen);
-            nexthop_s = xasprintf(IP_FMT, IP_ARGS(route_adv->nexthop.ipv4));
+        if (IN6_IS_ADDR_V4MAPPED(&route_adv->prefix)) {
+            ovs_be32 ipv4 = in6_addr_get_mapped_ipv4(&route_adv->prefix);
+            ovs_be32 nh = in6_addr_get_mapped_ipv4(&route_adv->nexthop);
+            prefix_s = xasprintf(IP_FMT "/%d", IP_ARGS(ipv4), route_adv->plen);
+            nexthop_s = xasprintf(IP_FMT, IP_ARGS(nh));
         } else {
             char network_s[INET6_ADDRSTRLEN];
-            inet_ntop(AF_INET6, &route_adv->prefix.ipv6, network_s,
+            inet_ntop(AF_INET6, &route_adv->prefix, network_s,
                       INET6_ADDRSTRLEN);
             prefix_s = xasprintf("%s/%d", network_s, route_adv->plen);
-            inet_ntop(AF_INET6, &route_adv->nexthop.ipv6, network_s,
+            inet_ntop(AF_INET6, &route_adv->nexthop, network_s,
                       INET6_ADDRSTRLEN);
             nexthop_s = xstrdup(network_s);
         }
diff --git a/lib/ovn-util.c b/lib/ovn-util.c
index 1daf665..9ed9991 100644
--- a/lib/ovn-util.c
+++ b/lib/ovn-util.c
@@ -568,33 +568,24 @@  ovn_chassis_redirect_name(const char *port_name)
 }
 
 bool
-ip46_parse_cidr(const char *str, struct v46_ip *prefix, unsigned int *plen)
+ip46_parse_cidr(const char *str, struct in6_addr *prefix, unsigned int *plen)
 {
-    memset(prefix, 0, sizeof *prefix);
+    ovs_be32 ipv4;
+    char *error = ip_parse_cidr(str, &ipv4, plen);
 
-    char *error = ip_parse_cidr(str, &prefix->ipv4, plen);
     if (!error) {
-        prefix->family = AF_INET;
+        in6_addr_set_mapped_ipv4(prefix, ipv4);
         return true;
     }
     free(error);
-    error = ipv6_parse_cidr(str, &prefix->ipv6, plen);
+    error = ipv6_parse_cidr(str, prefix, plen);
     if (!error) {
-        prefix->family = AF_INET6;
         return true;
     }
     free(error);
     return false;
 }
 
-bool
-ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2)
-{
-    return (addr1->family == addr2->family &&
-            (addr1->family == AF_INET ? addr1->ipv4 == addr2->ipv4 :
-             IN6_ARE_ADDR_EQUAL(&addr1->ipv6, &addr2->ipv6)));
-}
-
 /* The caller must free the returned string. */
 char *
 normalize_ipv4_prefix(ovs_be32 ipv4, unsigned int plen)
@@ -609,12 +600,12 @@  normalize_ipv4_prefix(ovs_be32 ipv4, unsigned int plen)
 
 /* The caller must free the returned string. */
 char *
-normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen)
+normalize_ipv6_prefix(const struct in6_addr *ipv6, unsigned int plen)
 {
     char network_s[INET6_ADDRSTRLEN];
 
     struct in6_addr mask = ipv6_create_mask(plen);
-    struct in6_addr network = ipv6_addr_bitand(&ipv6, &mask);
+    struct in6_addr network = ipv6_addr_bitand(ipv6, &mask);
 
     inet_ntop(AF_INET6, &network, network_s, INET6_ADDRSTRLEN);
     if (plen == 128) {
@@ -625,12 +616,12 @@  normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen)
 }
 
 char *
-normalize_v46_prefix(const struct v46_ip *prefix, unsigned int plen)
+normalize_v46_prefix(const struct in6_addr *prefix, unsigned int plen)
 {
-    if (prefix->family == AF_INET) {
-        return normalize_ipv4_prefix(prefix->ipv4, plen);
+    if (IN6_IS_ADDR_V4MAPPED(prefix)) {
+        return normalize_ipv4_prefix(in6_addr_get_mapped_ipv4(prefix), plen);
     } else {
-        return normalize_ipv6_prefix(prefix->ipv6, plen);
+        return normalize_ipv6_prefix(prefix, plen);
     }
 }
 
diff --git a/lib/ovn-util.h b/lib/ovn-util.h
index 1d22a69..8aef48a 100644
--- a/lib/ovn-util.h
+++ b/lib/ovn-util.h
@@ -137,21 +137,12 @@  get_sb_port_group_name(const char *nb_pg_name, int64_t dp_tunnel_key,
 char *ovn_chassis_redirect_name(const char *port_name);
 void ovn_set_pidfile(const char *name);
 
-/* An IPv4 or IPv6 address */
-struct v46_ip {
-    int family;
-    union {
-        ovs_be32 ipv4;
-        struct in6_addr ipv6;
-    };
-};
-bool ip46_parse_cidr(const char *str, struct v46_ip *prefix,
+bool ip46_parse_cidr(const char *str, struct in6_addr *prefix,
                      unsigned int *plen);
-bool ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2);
 
 char *normalize_ipv4_prefix(ovs_be32 ipv4, unsigned int plen);
-char *normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen);
-char *normalize_v46_prefix(const struct v46_ip *prefix, unsigned int plen);
+char *normalize_ipv6_prefix(const struct in6_addr *ipv6, unsigned int plen);
+char *normalize_v46_prefix(const struct in6_addr *prefix, unsigned int plen);
 
 /* Temporary util function until ovs library has smap_get_unit. */
 unsigned int ovn_smap_get_uint(const struct smap *smap, const char *key,
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 1ca037f..c2447fd 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -7651,7 +7651,7 @@  build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od,
 
 struct parsed_route {
     struct ovs_list list_node;
-    struct v46_ip prefix;
+    struct in6_addr prefix;
     unsigned int plen;
     bool is_src_route;
     uint32_t hash;
@@ -7673,7 +7673,7 @@  parsed_routes_add(struct ovs_list *routes,
                   const struct nbrec_logical_router_static_route *route)
 {
     /* Verify that the next hop is an IP address with an all-ones mask. */
-    struct v46_ip nexthop;
+    struct in6_addr nexthop;
     unsigned int plen;
     if (!ip46_parse_cidr(route->nexthop, &nexthop, &plen)) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
@@ -7682,8 +7682,8 @@  parsed_routes_add(struct ovs_list *routes,
                      UUID_ARGS(&route->header_.uuid));
         return NULL;
     }
-    if ((nexthop.family == AF_INET && plen != 32) ||
-        (nexthop.family == AF_INET6 && plen != 128)) {
+    if ((IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 32) ||
+        (!IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 128)) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
         VLOG_WARN_RL(&rl, "bad next hop mask %s in static route"
                      UUID_FMT, route->nexthop,
@@ -7692,7 +7692,7 @@  parsed_routes_add(struct ovs_list *routes,
     }
 
     /* Parse ip_prefix */
-    struct v46_ip prefix;
+    struct in6_addr prefix;
     if (!ip46_parse_cidr(route->ip_prefix, &prefix, &plen)) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
         VLOG_WARN_RL(&rl, "bad 'ip_prefix' %s in static route"
@@ -7702,7 +7702,7 @@  parsed_routes_add(struct ovs_list *routes,
     }
 
     /* Verify that ip_prefix and nexthop have same address familiy. */
-    if (prefix.family != nexthop.family) {
+    if (IN6_IS_ADDR_V4MAPPED(&prefix) != IN6_IS_ADDR_V4MAPPED(&nexthop)) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
         VLOG_WARN_RL(&rl, "Address family doesn't match between 'ip_prefix' %s"
                      " and 'nexthop' %s in static route"UUID_FMT,
@@ -7743,7 +7743,7 @@  struct ecmp_route_list_node {
 struct ecmp_groups_node {
     struct hmap_node hmap_node; /* In ecmp_groups */
     uint16_t id; /* starts from 1 */
-    struct v46_ip prefix;
+    struct in6_addr prefix;
     unsigned int plen;
     bool is_src_route;
     uint16_t route_count;
@@ -7794,7 +7794,7 @@  ecmp_groups_find(struct hmap *ecmp_groups, struct parsed_route *route)
 {
     struct ecmp_groups_node *eg;
     HMAP_FOR_EACH_WITH_HASH (eg, hmap_node, route->hash, ecmp_groups) {
-        if (ip46_equals(&eg->prefix, &route->prefix) &&
+        if (ipv6_addr_equals(&eg->prefix, &route->prefix) &&
             eg->plen == route->plen &&
             eg->is_src_route == route->is_src_route) {
             return eg;
@@ -7841,7 +7841,7 @@  unique_routes_remove(struct hmap *unique_routes,
 {
     struct unique_routes_node *ur;
     HMAP_FOR_EACH_WITH_HASH (ur, hmap_node, route->hash, unique_routes) {
-        if (ip46_equals(&route->prefix, &ur->route->prefix) &&
+        if (ipv6_addr_equals(&route->prefix, &ur->route->prefix) &&
             route->plen == ur->route->plen &&
             route->is_src_route == ur->route->is_src_route) {
             hmap_remove(unique_routes, &ur->hmap_node);
@@ -7865,15 +7865,15 @@  unique_routes_destroy(struct hmap *unique_routes)
 }
 
 static char *
-build_route_prefix_s(const struct v46_ip *prefix, unsigned int plen)
+build_route_prefix_s(const struct in6_addr *prefix, unsigned int plen)
 {
     char *prefix_s;
-    if (prefix->family == AF_INET) {
-        prefix_s = xasprintf(IP_FMT, IP_ARGS(prefix->ipv4 &
+    if (IN6_IS_ADDR_V4MAPPED(prefix)) {
+        prefix_s = xasprintf(IP_FMT, IP_ARGS(in6_addr_get_mapped_ipv4(prefix) &
                                              be32_prefix_mask(plen)));
     } else {
         struct in6_addr mask = ipv6_create_mask(plen);
-        struct in6_addr network = ipv6_addr_bitand(&prefix->ipv6, &mask);
+        struct in6_addr network = ipv6_addr_bitand(prefix, &mask);
         prefix_s = xmalloc(INET6_ADDRSTRLEN);
         inet_ntop(AF_INET6, &network, prefix_s, INET6_ADDRSTRLEN);
     }
@@ -7987,7 +7987,7 @@  add_ecmp_symmetric_reply_flows(struct hmap *lflows,
      */
     ds_put_format(&match, "inport == %s && ip%s.%s == %s",
                   out_port->json_key,
-                  route->prefix.family == AF_INET ? "4" : "6",
+                  IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "4" : "6",
                   route->is_src_route ? "dst" : "src",
                   cidr);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100,
@@ -8026,7 +8026,7 @@  add_ecmp_symmetric_reply_flows(struct hmap *lflows,
     ds_put_format(&actions, "ip.ttl--; flags.loopback = 1; "
                   "eth.src = %s; %sreg1 = %s; outport = %s; next;",
                   out_port->lrp_networks.ea_s,
-                  route->prefix.family == AF_INET ? "" : "xx",
+                  IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "" : "xx",
                   port_ip, out_port->json_key);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING, 100,
                            ds_cstr(&match), ds_cstr(&actions),
@@ -8048,7 +8048,7 @@  build_ecmp_route_flow(struct hmap *lflows, struct ovn_datapath *od,
                       struct hmap *ports, struct ecmp_groups_node *eg)
 
 {
-    bool is_ipv4 = (eg->prefix.family == AF_INET);
+    bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix);
     uint16_t priority;
     struct ecmp_route_list_node *er;
     struct ds route_match = DS_EMPTY_INITIALIZER;
@@ -8182,13 +8182,13 @@  build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od,
 {
     const char *lrp_addr_s = NULL;
     struct ovn_port *out_port = NULL;
-    bool is_ipv4 = (route_->prefix.family == AF_INET);
 
     const struct nbrec_logical_router_static_route *route = route_->route;
 
     /* Find the outgoing port. */
-    if (!find_static_route_outport(od, ports, route, is_ipv4, &lrp_addr_s,
-                                   &out_port)) {
+    if (!find_static_route_outport(od, ports, route,
+                                   IN6_IS_ADDR_V4MAPPED(&route_->prefix),
+                                   &lrp_addr_s, &out_port)) {
         return;
     }
 
diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
index abc674f..aad6a36 100644
--- a/utilities/ovn-nbctl.c
+++ b/utilities/ovn-nbctl.c
@@ -3559,7 +3559,7 @@  normalize_ipv6_prefix_str(const char *orig_prefix)
         free(error);
         return NULL;
     }
-    return normalize_ipv6_prefix(ipv6, plen);
+    return normalize_ipv6_prefix(&ipv6, plen);
 }
 
 /* The caller must free the returned string. */
@@ -3596,7 +3596,7 @@  normalize_ipv6_addr_str(const char *orig_addr)
         return NULL;
     }
 
-    return normalize_ipv6_prefix(ipv6, 128);
+    return normalize_ipv6_prefix(&ipv6, 128);
 }
 
 /* Similar to normalize_prefix_str but must be an un-masked address.