Skip to content

Commit

Permalink
route-table: Support parsing RTA_VIA attribute.
Browse files Browse the repository at this point in the history
It is possible to add routes for IPv4 destinations using an IPv6
address for next hop.

In such configurations the next hop information is provided in the
RTA_VIA attribute instead of the RTA_GATEWAY attribute.

Signed-off-by: Frode Nordahl <[email protected]>
Signed-off-by: 0-day Robot <[email protected]>
  • Loading branch information
fnordahl authored and ovsrobot committed Jan 13, 2025
1 parent 7726fc4 commit 4ae83e8
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 0 deletions.
12 changes: 12 additions & 0 deletions lib/netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@
#include "openvswitch/vlog.h"
#include "util.h"

#ifdef HAVE_NETLINK
#include <linux/rtnetlink.h>
#else
/* RTA_VIA */
struct rtvia {
sa_family_t rtvia_family;
uint8_t rtvia_addr[];
};
#endif

VLOG_DEFINE_THIS_MODULE(netlink);

/* A single (bad) Netlink message can in theory dump out many, many log
Expand Down Expand Up @@ -819,6 +829,7 @@ min_attr_len(enum nl_attr_type type)
case NL_A_IPV6: return 16;
case NL_A_NESTED: return 0;
case NL_A_LL_ADDR: return 6; /* ETH_ALEN */
case NL_A_RTA_VIA: return sizeof(struct rtvia) + sizeof(struct in_addr);
case N_NL_ATTR_TYPES: default: OVS_NOT_REACHED();
}
}
Expand All @@ -840,6 +851,7 @@ max_attr_len(enum nl_attr_type type)
case NL_A_IPV6: return 16;
case NL_A_NESTED: return SIZE_MAX;
case NL_A_LL_ADDR: return 20; /* INFINIBAND_ALEN */
case NL_A_RTA_VIA: return sizeof(struct rtvia) + sizeof(struct in6_addr);
case N_NL_ATTR_TYPES: default: OVS_NOT_REACHED();
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ enum nl_attr_type
NL_A_IPV6,
NL_A_NESTED,
NL_A_LL_ADDR,
NL_A_RTA_VIA,
N_NL_ATTR_TYPES
};

Expand Down
47 changes: 47 additions & 0 deletions lib/route-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ COVERAGE_DEFINE(route_table_dump);
struct route_data_nexthop {
struct ovs_list nexthop_node;

sa_family_t family;
struct in6_addr addr;
char ifname[IFNAMSIZ]; /* Interface name. */
};
Expand Down Expand Up @@ -276,6 +277,7 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
[RTA_PREFSRC] = { .type = NL_A_U32, .optional = true },
[RTA_TABLE] = { .type = NL_A_U32, .optional = true },
[RTA_PRIORITY] = { .type = NL_A_U32, .optional = true },
[RTA_VIA] = { .type = NL_A_RTA_VIA, .optional = true },
};

static const struct nl_policy policy6[] = {
Expand All @@ -286,6 +288,7 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
[RTA_PREFSRC] = { .type = NL_A_IPV6, .optional = true },
[RTA_TABLE] = { .type = NL_A_U32, .optional = true },
[RTA_PRIORITY] = { .type = NL_A_U32, .optional = true },
[RTA_VIA] = { .type = NL_A_RTA_VIA, .optional = true },
};

struct nlattr *attrs[ARRAY_SIZE(policy)];
Expand All @@ -310,6 +313,7 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,

ovs_list_init(&change->rd.nexthops);
rdnh = &change->rd._primary_next_hop;
rdnh->family = rtm->rtm_family;
ovs_list_insert(&change->rd.nexthops, &rdnh->nexthop_node);

change->relevant = true;
Expand Down Expand Up @@ -384,6 +388,49 @@ route_table_parse__(struct ofpbuf *buf, size_t ofs,
if (attrs[RTA_PRIORITY]) {
change->rd.rta_priority = nl_attr_get_u32(attrs[RTA_PRIORITY]);
}
if (attrs[RTA_VIA]) {
const struct rtvia *rtvia = nl_attr_get(attrs[RTA_VIA]);
ovs_be32 addr;

if (attrs[RTA_GATEWAY]) {
VLOG_DBG_RL(&rl, "route message can not contain both "
"RTA_GATEWAY and RTA_VIA");
goto error_out;
}

rdnh->family = rtvia->rtvia_family;

switch (rdnh->family) {
case AF_INET:
if (nl_attr_get_size(attrs[RTA_VIA])
- sizeof *rtvia < sizeof addr) {
VLOG_DBG_RL(&rl, "got short message while parsing RTA_VIA "
"attribute for family AF_INET");
goto error_out;
}
memcpy(&addr, rtvia->rtvia_addr, sizeof addr);
in6_addr_set_mapped_ipv4(&rdnh->addr, addr);
break;
case AF_INET6:
if (nl_attr_get_size(attrs[RTA_VIA])
- sizeof *rtvia < sizeof rdnh->addr) {
VLOG_DBG_RL(&rl, "got short message while parsing RTA_VIA "
"attribute for family AF_INET6");
goto error_out;
}
memcpy(&rdnh->addr, rtvia->rtvia_addr, sizeof rdnh->addr);
break;
default:
VLOG_DBG_RL(&rl, "unsupported address family, %d, "
"in via attribute", rdnh->family);
goto error_out;
}
}
if (!attrs[RTA_OIF] && !attrs[RTA_GATEWAY] && !attrs[RTA_VIA]) {
VLOG_DBG_RL(&rl, "route message needs an RTA_OIF, RTA_GATEWAY or "
"RTA_VIA attribute");
goto error_out;
}
} else {
VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message");
goto error_out;
Expand Down
20 changes: 20 additions & 0 deletions tests/system-route.at
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,26 @@ Cached: fc00:db8:beef::13/128 dev br0 GW fc00:db8:cafe::1 SRC fc00:db8:cafe::2])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ovs-route - add system route - ipv4 via ipv6 nexthop])
AT_KEYWORDS([route])
OVS_TRAFFIC_VSWITCHD_START()
AT_CHECK([ovs-vsctl set bridge br0 other-config:hwaddr=00:53:00:00:00:42])
AT_CHECK([ip link set br0 up])

AT_CHECK([ip addr add 192.168.9.2/24 dev br0], [0], [stdout])

AT_CHECK([ip route add 192.168.10.12/32 \
via inet6 fe80::253:ff:fe00:51 dev br0], [0], [stdout])

AT_CHECK([ovs-appctl revalidator/wait])

OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | \
grep -E '192.168.10.12/32' | sort], [dnl
Cached: 192.168.10.12/32 dev br0 GW fe80::253:ff:fe00:51 SRC fe80::253:ff:fe00:42])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

dnl Checks that OVS doesn't use routes from non-standard tables.
AT_SETUP([ovs-route - route tables])
AT_KEYWORDS([route])
Expand Down

0 comments on commit 4ae83e8

Please sign in to comment.