From c52ef59fedc4ce81afc842990980c8384d6dfce3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 19 May 2015 17:47:24 -0700 Subject: [PATCH] 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 --- lib/nexthop.h | 1 + zebra/rt_netlink.c | 82 +++++++++++++++++++++++++++++++++++------- zebra/zebra_rib.c | 13 ++++++- zebra/zebra_routemap.c | 2 +- 4 files changed, 83 insertions(+), 15 deletions(-) diff --git a/lib/nexthop.h b/lib/nexthop.h index b3a128a2a8..b375c55b95 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -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. * diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ea2d42ab3b..7c6b3782a5 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -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), diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index a9f31b1a06..cd9f7005cc 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -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); diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 3668448f73..ae30b6971e 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -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; } -- 2.39.5