zebra-set-src-routemap.patch

Honor setting source via route map and pushing that to the kernel.

With recursive routes, the ability to set the source IP address of a route
via a routemap has been broken. This patch fixes that.

To allow route map to set a source and then to unapply the route map and
have the source be taken out, I've introduced a new field in the nexthop
data structure called rmap_src. This field is zero'd before invoking the
route map apply function.

Today, no protocol daemon specifies the src in its route update to zebra.
If that happens, I didn't want to stomp on it and so have left the src
field intact instead of reusing that for the routemap to play with.

Signed-off-by: Dinesh G Dutt <ddutt@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2015-05-19 17:47:24 -07:00
parent b5d58c32bb
commit c52ef59fed
4 changed files with 83 additions and 15 deletions

View File

@ -68,6 +68,7 @@ struct nexthop
/* Nexthop address */
union g_addr gate;
union g_addr src;
union g_addr rmap_src; /* Src is set via routemap */
/* Nexthops obtained by recursive resolution.
*

View File

@ -1466,7 +1466,8 @@ _netlink_route_build_singlepath(
struct nexthop *nexthop,
struct nlmsghdr *nlmsg,
struct rtmsg *rtmsg,
size_t req_size)
size_t req_size,
int cmd)
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
rtmsg->rtm_flags |= RTNH_F_ONLINK;
@ -1475,7 +1476,11 @@ _netlink_route_build_singlepath(
{
addattr_l (nlmsg, req_size, RTA_GATEWAY,
&nexthop->gate.ipv4, bytelen);
if (nexthop->src.ipv4.s_addr)
if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
addattr_l (nlmsg, req_size, RTA_PREFSRC,
&nexthop->rmap_src.ipv4, bytelen);
else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
addattr_l (nlmsg, req_size, RTA_PREFSRC,
&nexthop->src.ipv4, bytelen);
@ -1508,7 +1513,10 @@ _netlink_route_build_singlepath(
{
addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
if (nexthop->src.ipv4.s_addr)
if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
addattr_l (nlmsg, req_size, RTA_PREFSRC,
&nexthop->rmap_src.ipv4, bytelen);
else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
addattr_l (nlmsg, req_size, RTA_PREFSRC,
&nexthop->src.ipv4, bytelen);
@ -1569,8 +1577,10 @@ _netlink_route_build_multipath(
&nexthop->gate.ipv4, bytelen);
rtnh->rtnh_len += sizeof (struct rtattr) + 4;
if (nexthop->src.ipv4.s_addr)
*src = &nexthop->src;
if (nexthop->rmap_src.ipv4.s_addr)
*src = &nexthop->rmap_src;
else if (nexthop->src.ipv4.s_addr)
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("netlink_route_multipath() (%s): "
@ -1601,8 +1611,12 @@ _netlink_route_build_multipath(
|| nexthop->type == NEXTHOP_TYPE_IFNAME)
{
rtnh->rtnh_ifindex = nexthop->ifindex;
if (nexthop->src.ipv4.s_addr)
if (nexthop->rmap_src.ipv4.s_addr)
*src = &nexthop->rmap_src;
else if (nexthop->src.ipv4.s_addr)
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("netlink_route_multipath() (%s): "
"nexthop via if %u", routedesc, nexthop->ifindex);
@ -1667,6 +1681,8 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
int nexthop_num;
int discard;
const char *routedesc;
int setsrc = 0;
union g_addr src;
struct
{
@ -1754,7 +1770,23 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
{
/* This only works for IPv4 now */
if (!setsrc)
{
if (nexthop->rmap_src.ipv4.s_addr != 0)
{
src.ipv4 = nexthop->rmap_src.ipv4;
setsrc = 1;
}
else if (nexthop->src.ipv4.s_addr != 0)
{
src.ipv4 = nexthop->src.ipv4;
setsrc = 1;
}
}
continue;
}
if ((cmd == RTM_NEWROUTE
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
@ -1766,7 +1798,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
_netlink_route_debug(cmd, p, nexthop, routedesc, family);
_netlink_route_build_singlepath(routedesc, bytelen,
nexthop, &req.n, &req.r,
sizeof req);
sizeof req, cmd);
if (cmd == RTM_NEWROUTE)
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
@ -1775,13 +1807,15 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
break;
}
}
if (setsrc && (cmd == RTM_NEWROUTE))
addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
}
else
{
char buf[NL_PKT_BUF_SIZE];
struct rtattr *rta = (void *) buf;
struct rtnexthop *rtnh;
union g_addr *src = NULL;
union g_addr *src1 = NULL;
rta->rta_type = RTA_MULTIPATH;
rta->rta_len = RTA_LENGTH (0);
@ -1794,7 +1828,23 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
break;
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
{
/* This only works for IPv4 now */
if (!setsrc)
{
if (nexthop->rmap_src.ipv4.s_addr != 0)
{
src.ipv4 = nexthop->rmap_src.ipv4;
setsrc = 1;
}
else if (nexthop->src.ipv4.s_addr != 0)
{
src.ipv4 = nexthop->src.ipv4;
setsrc = 1;
}
}
continue;
}
if ((cmd == RTM_NEWROUTE
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
@ -1807,15 +1857,21 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
_netlink_route_debug(cmd, p, nexthop,
routedesc, family);
_netlink_route_build_multipath(routedesc, bytelen,
nexthop, rta, rtnh, &src);
nexthop, rta, rtnh, &src1);
rtnh = RTNH_NEXT (rtnh);
if (cmd == RTM_NEWROUTE)
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
if (!setsrc && src1)
{
src.ipv4 = src1->ipv4;
setsrc = 1;
}
}
}
if (src)
addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
if (setsrc && (cmd == RTM_NEWROUTE))
addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
if (rta->rta_len > RTA_LENGTH (0))
addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),

View File

@ -1184,6 +1184,9 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
if (!family)
family = info->afi;
memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
/* It'll get set if required inside */
ret = zebra_route_map_check(family, rib->type, &rn->p, nexthop);
if (ret == RMAP_DENYMATCH)
{
@ -1195,6 +1198,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
}
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
@ -1211,6 +1215,7 @@ static int
nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
{
struct nexthop *nexthop;
union g_addr prev_src;
unsigned int prev_active, prev_index, new_active, old_num_nh;
old_num_nh = rib->nexthop_active_num;
@ -1220,12 +1225,18 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
{
/* No protocol daemon provides src and so we're skipping tracking it */
prev_src = nexthop->rmap_src;
prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
prev_index = nexthop->ifindex;
if ((new_active = nexthop_active_check (rn, rib, nexthop, set)))
rib->nexthop_active_num++;
/* Don't allow src setting on IPv6 addr for now */
if (prev_active != new_active ||
prev_index != nexthop->ifindex)
prev_index != nexthop->ifindex ||
((nexthop->type >= NEXTHOP_TYPE_IFINDEX &&
nexthop->type < NEXTHOP_TYPE_IPV6) &&
prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr))
{
SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);

View File

@ -1301,7 +1301,7 @@ route_set_src (void *rule, struct prefix *prefix,
if (type == RMAP_ZEBRA)
{
nh_data = (struct nh_rmap_obj *)object;
nh_data->nexthop->src = *(union g_addr *)rule;
nh_data->nexthop->rmap_src = *(union g_addr *)rule;
}
return RMAP_OKAY;
}