summaryrefslogtreecommitdiff
path: root/zebra/rt_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/rt_netlink.c')
-rw-r--r--zebra/rt_netlink.c194
1 files changed, 110 insertions, 84 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index e28fe5630a..f05025e630 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -240,13 +240,27 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
void *gate = NULL;
void *prefsrc = NULL; /* IPv4 preferred source host address */
void *src = NULL; /* IPv6 srcdest source prefix */
+ enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
rtm = NLMSG_DATA(h);
if (startup && h->nlmsg_type != RTM_NEWROUTE)
return 0;
- if (startup && rtm->rtm_type != RTN_UNICAST)
+ switch (rtm->rtm_type) {
+ case RTN_UNICAST:
+ break;
+ case RTN_BLACKHOLE:
+ bh_type = BLACKHOLE_NULL;
+ break;
+ case RTN_UNREACHABLE:
+ bh_type = BLACKHOLE_REJECT;
+ break;
+ case RTN_PROHIBIT:
+ bh_type = BLACKHOLE_ADMINPROHIB;
+ break;
+ default:
return 0;
+ }
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
if (len < 0)
@@ -365,11 +379,39 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
afi = AFI_IP6;
if (h->nlmsg_type == RTM_NEWROUTE) {
- if (!tb[RTA_MULTIPATH])
+ if (!tb[RTA_MULTIPATH]) {
+ struct nexthop nh;
+ size_t sz = (afi == AFI_IP) ? 4 : 16;
+
+ memset(&nh, 0, sizeof(nh));
+
+ if (bh_type == BLACKHOLE_UNSPEC) {
+ if (index && !gate)
+ nh.type = NEXTHOP_TYPE_IFINDEX;
+ else if (index && gate)
+ nh.type = (afi == AFI_IP)
+ ? NEXTHOP_TYPE_IPV4_IFINDEX
+ : NEXTHOP_TYPE_IPV6_IFINDEX;
+ else if (!index && gate)
+ nh.type = (afi == AFI_IP)
+ ? NEXTHOP_TYPE_IPV4
+ : NEXTHOP_TYPE_IPV6;
+ else {
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = bh_type;
+ }
+ } else {
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = bh_type;
+ }
+ nh.ifindex = index;
+ if (prefsrc)
+ memcpy(&nh.src, prefsrc, sz);
+ if (gate)
+ memcpy(&nh.gate, gate, sz);
rib_add(afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
- 0, flags, &p, NULL, gate, prefsrc, index, table,
- metric, mtu, 0);
- else {
+ 0, flags, &p, NULL, &nh, table, metric, mtu, 0);
+ } else {
/* This is a multipath route */
struct route_entry *re;
@@ -444,41 +486,43 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
NULL, re);
}
} else {
- if (!tb[RTA_MULTIPATH])
- rib_delete(afi, SAFI_UNICAST, vrf_id,
- ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, gate,
- index, table, metric);
- else {
- struct rtnexthop *rtnh =
- (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]);
-
- len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
-
- for (;;) {
- if (len < (int)sizeof(*rtnh)
- || rtnh->rtnh_len > len)
- break;
-
- gate = NULL;
- if (rtnh->rtnh_len > sizeof(*rtnh)) {
- memset(tb, 0, sizeof(tb));
- netlink_parse_rtattr(
- tb, RTA_MAX, RTNH_DATA(rtnh),
- rtnh->rtnh_len - sizeof(*rtnh));
- if (tb[RTA_GATEWAY])
- gate = RTA_DATA(
- tb[RTA_GATEWAY]);
+ if (!tb[RTA_MULTIPATH]) {
+ struct nexthop nh;
+ size_t sz = (afi == AFI_IP) ? 4 : 16;
+
+ memset(&nh, 0, sizeof(nh));
+ if (bh_type == BLACKHOLE_UNSPEC) {
+ if (index && !gate)
+ nh.type = NEXTHOP_TYPE_IFINDEX;
+ else if (index && gate)
+ nh.type =
+ (afi == AFI_IP)
+ ? NEXTHOP_TYPE_IPV4_IFINDEX
+ : NEXTHOP_TYPE_IPV6_IFINDEX;
+ else if (!index && gate)
+ nh.type = (afi == AFI_IP)
+ ? NEXTHOP_TYPE_IPV4
+ : NEXTHOP_TYPE_IPV6;
+ else {
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = BLACKHOLE_UNSPEC;
}
-
- if (gate)
- rib_delete(afi, SAFI_UNICAST, vrf_id,
- ZEBRA_ROUTE_KERNEL, 0, flags,
- &p, NULL, gate, index,
- table, metric);
-
- len -= NLMSG_ALIGN(rtnh->rtnh_len);
- rtnh = RTNH_NEXT(rtnh);
+ } else {
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = bh_type;
}
+ nh.ifindex = index;
+ if (gate)
+ memcpy(&nh.gate, gate, sz);
+ rib_delete(afi, SAFI_UNICAST, vrf_id,
+ ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, &nh,
+ table, metric);
+ } else {
+ /* XXX: need to compare the entire list of nexthops
+ * here for NLM_F_APPEND stupidity */
+ rib_delete(afi, SAFI_UNICAST, vrf_id,
+ ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, NULL,
+ table, metric);
}
}
@@ -558,8 +602,8 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl,
if (IS_ZEBRA_DEBUG_KERNEL) {
struct interface *ifp;
- strcpy(sbuf, inet_ntoa(m->sg.src));
- strcpy(gbuf, inet_ntoa(m->sg.grp));
+ strlcpy(sbuf, inet_ntoa(m->sg.src), sizeof(sbuf));
+ strlcpy(gbuf, inet_ntoa(m->sg.grp), sizeof(gbuf));
for (count = 0; count < oif_count; count++) {
ifp = if_lookup_by_index(oif[count], vrf);
char temp[256];
@@ -609,18 +653,10 @@ int netlink_route_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
if (len < 0)
return -1;
- switch (rtm->rtm_type) {
- case RTN_UNICAST:
- netlink_route_change_read_unicast(snl, h, ns_id, startup);
- break;
- case RTN_MULTICAST:
+ if (rtm->rtm_type == RTN_MULTICAST)
netlink_route_change_read_multicast(snl, h, ns_id, startup);
- break;
- default:
- return 0;
- break;
- }
-
+ else
+ netlink_route_change_read_unicast(snl, h, ns_id, startup);
return 0;
}
@@ -1207,7 +1243,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
struct sockaddr_nl snl;
struct nexthop *nexthop = NULL;
unsigned int nexthop_num;
- int discard;
+ int discard = 0;
int family = PREFIX_FAMILY(p);
const char *routedesc;
int setsrc = 0;
@@ -1238,24 +1274,23 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
req.r.rtm_protocol = get_rt_proto(re->type);
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.r.rtm_type = RTN_UNICAST;
- if ((re->flags & ZEBRA_FLAG_BLACKHOLE)
- || (re->flags & ZEBRA_FLAG_REJECT))
+ if (re->nexthop_num == 1
+ && re->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
discard = 1;
- else
- discard = 0;
-
- if (cmd == RTM_NEWROUTE) {
- if (discard) {
- if (re->flags & ZEBRA_FLAG_BLACKHOLE)
- req.r.rtm_type = RTN_BLACKHOLE;
- else if (re->flags & ZEBRA_FLAG_REJECT)
- req.r.rtm_type = RTN_UNREACHABLE;
- else
- assert(RTN_BLACKHOLE
- != RTN_UNREACHABLE); /* false */
- } else
- req.r.rtm_type = RTN_UNICAST;
+
+ switch (re->nexthop->bh_type) {
+ case BLACKHOLE_ADMINPROHIB:
+ req.r.rtm_type = RTN_PROHIBIT;
+ break;
+ case BLACKHOLE_REJECT:
+ req.r.rtm_type = RTN_UNREACHABLE;
+ break;
+ default:
+ req.r.rtm_type = RTN_BLACKHOLE;
+ break;
+ }
}
addattr_l(&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
@@ -1280,6 +1315,9 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
addattr32(&req.n, sizeof req, RTA_TABLE, re->table);
}
+ if (discard)
+ goto skip;
+
if (re->mtu || re->nexthop_mtu) {
char buf[NL_PKT_BUF_SIZE];
struct rtattr *rta = (void *)buf;
@@ -1293,21 +1331,6 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
RTA_PAYLOAD(rta));
}
- if (discard) {
- if (cmd == RTM_NEWROUTE)
- for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
- /* We shouldn't encounter recursive nexthops on
- * discard routes,
- * but it is probably better to handle that case
- * correctly anyway.
- */
- if (CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_RECURSIVE))
- continue;
- }
- goto skip;
- }
-
/* Count overall nexthops so we can decide whether to use singlepath
* or multipath case. */
nexthop_num = 0;
@@ -1553,6 +1576,8 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
int kernel_route_rib(struct prefix *p, struct prefix *src_p,
struct route_entry *old, struct route_entry *new)
{
+ assert(old || new);
+
if (!old && new)
return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 0);
if (old && !new)
@@ -2005,7 +2030,8 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
* itself
*/
if (IS_ZEBRA_IF_VLAN(ifp)) {
- link_if = zif->link;
+ link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+ zif->link_ifindex);
if (!link_if)
return 0;
} else if (IS_ZEBRA_IF_BRIDGE(ifp))