diff options
Diffstat (limited to 'zebra/rt_netlink.c')
| -rw-r--r-- | zebra/rt_netlink.c | 194 |
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)) |
