diff options
Diffstat (limited to 'usr.sbin/ldpd/kroute.c')
-rw-r--r-- | usr.sbin/ldpd/kroute.c | 349 |
1 files changed, 156 insertions, 193 deletions
diff --git a/usr.sbin/ldpd/kroute.c b/usr.sbin/ldpd/kroute.c index 677f789998a..f033f539d90 100644 --- a/usr.sbin/ldpd/kroute.c +++ b/usr.sbin/ldpd/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.14 2010/06/21 19:43:36 claudio Exp $ */ +/* $OpenBSD: kroute.c,v 1.15 2010/06/30 02:09:22 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -71,7 +71,7 @@ int kr_change_fib(struct kroute_node *, struct kroute *, int); int kr_delete_fib(struct kroute_node *); struct kroute_node *kroute_find(in_addr_t, u_int8_t, u_int8_t); -struct kroute_node *kroute_find_fec(in_addr_t, u_int8_t, in_addr_t); +struct kroute_node *kroute_find_fec(in_addr_t, u_int8_t, struct in_addr); struct kroute_node *kroute_matchgw(struct kroute_node *, struct in_addr); int kroute_insert(struct kroute_node *); int kroute_remove(struct kroute_node *); @@ -90,9 +90,11 @@ struct kroute_node *kroute_match(in_addr_t); int protect_lo(void); u_int8_t prefixlen_classful(in_addr_t); void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); -void if_change(u_short, int, struct if_data *); +void if_change(u_short, int, struct if_data *, struct sockaddr_dl *); void if_newaddr(u_short, struct sockaddr_in *, struct sockaddr_in *, struct sockaddr_in *); +void if_deladdr(u_short, struct sockaddr_in *, struct sockaddr_in *, + struct sockaddr_in *); void if_announce(void *); int send_rtmsg(int, int, struct kroute *, u_int32_t); @@ -220,7 +222,7 @@ kr_change(struct kroute *kroute) int action = RTM_ADD; kr = kroute_find_fec(kroute->prefix.s_addr, kroute->prefixlen, - kroute->nexthop.s_addr); + kroute->nexthop); if (kr == NULL) { log_warnx("kr_change: lost FEC %s/%d", @@ -261,7 +263,7 @@ kr_delete(struct kroute *kroute) struct kroute_node *kr, *nkr; kr = kroute_find_fec(kroute->prefix.s_addr, kroute->prefixlen, - kroute->nexthop.s_addr); + kroute->nexthop); if (kr == NULL) return (0); @@ -564,10 +566,10 @@ kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio) } struct kroute_node * -kroute_find_fec(in_addr_t prefix, u_int8_t prefixlen, in_addr_t nexthop) +kroute_find_fec(in_addr_t prefix, u_int8_t prefixlen, struct in_addr nexthop) { struct kroute_node s; - struct kroute_node *kn; + struct kroute_node *kn, *kr; s.r.prefix.s_addr = prefix; s.r.prefixlen = prefixlen; @@ -575,16 +577,14 @@ kroute_find_fec(in_addr_t prefix, u_int8_t prefixlen, in_addr_t nexthop) kn = RB_NFIND(kroute_tree, &krt, &s); while (kn) { - if (kn->r.nexthop.s_addr == nexthop) - break; + if ((kr = kroute_matchgw(kn, nexthop))) + return (kr); kn = RB_NEXT(kroute_tree, &krt, kn); if (kn == NULL || kn->r.prefix.s_addr != prefix || - kn->r.prefixlen != prefixlen) { - kn = NULL; - break; - } + kn->r.prefixlen != prefixlen) + return (NULL); } - return (kn); + return (NULL); } struct kroute_node * @@ -794,9 +794,14 @@ kif_update(u_short ifindex, int flags, struct if_data *ifd, { struct kif_node *kif; - if ((kif = kif_find(ifindex)) == NULL) + if ((kif = kif_find(ifindex)) == NULL) { if ((kif = kif_insert(ifindex)) == NULL) return (NULL); + kif->k.nh_reachable = (flags & IFF_UP) && + (LINK_STATE_IS_UP(ifd->ifi_link_state) || + (ifd->ifi_link_state == LINK_STATE_UNKNOWN && + ifd->ifi_type != IFT_CARP)); + } kif->k.flags = flags; kif->k.link_state = ifd->ifi_link_state; @@ -926,13 +931,14 @@ get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) } void -if_change(u_short ifindex, int flags, struct if_data *ifd) +if_change(u_short ifindex, int flags, struct if_data *ifd, + struct sockaddr_dl *sdl) { - struct kroute_node *kr; + struct kroute_node *kr, *tkr; struct kif *kif; u_int8_t reachable; - if ((kif = kif_update(ifindex, flags, ifd, NULL)) == NULL) { + if ((kif = kif_update(ifindex, flags, ifd, sdl)) == NULL) { log_warn("if_change: kif_update(%u)", ifindex); return; } @@ -952,13 +958,15 @@ if_change(u_short ifindex, int flags, struct if_data *ifd) /* update redistribute list */ RB_FOREACH(kr, kroute_tree, &krt) { - if (kr->r.ifindex == ifindex) { - if (reachable) - kr->r.flags &= ~F_DOWN; - else - kr->r.flags |= F_DOWN; + for (tkr = kr; tkr != NULL; tkr = tkr->next) { + if (tkr->r.ifindex == ifindex) { + if (reachable) + tkr->r.flags &= ~F_DOWN; + else + tkr->r.flags |= F_DOWN; - kr_redistribute(kr); + kr_redistribute(tkr); + } } } } @@ -992,6 +1000,32 @@ if_newaddr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask, } void +if_deladdr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask, + struct sockaddr_in *brd) +{ + struct kif_node *kif; + struct kif_addr *ka, *nka; + + if (ifa == NULL || ifa->sin_family != AF_INET) + return; + if ((kif = kif_find(ifindex)) == NULL) { + log_warnx("if_deladdr: corresponding if %i not found", ifindex); + return; + } + + for (ka = TAILQ_FIRST(&kif->addrs); ka != NULL; ka = nka) { + nka = TAILQ_NEXT(ka, entry); + + if (ka->addr.s_addr == ifa->sin_addr.s_addr) { + TAILQ_REMOVE(&kif->addrs, ka, entry); + /* XXX inform engine about if change? */ + free(ka); + return; + } + } +} + +void if_announce(void *msg) { struct if_announcemsghdr *ifan; @@ -1176,12 +1210,8 @@ fetchtable(void) { size_t len; int mib[7]; - char *buf, *next, *lim; - struct rt_msghdr *rtm; - struct sockaddr *sa, *rti_info[RTAX_MAX]; - struct sockaddr_in *sa_in; - struct sockaddr_mpls *sa_mpls; - struct kroute_node *kr; + char *buf; + int rv; mib[0] = CTL_NET; mib[1] = AF_ROUTE; @@ -1205,78 +1235,10 @@ fetchtable(void) return (-1); } - lim = buf + len; - for (next = buf; next < lim; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); - get_rtaddrs(rtm->rtm_addrs, sa, rti_info); - - if ((sa = rti_info[RTAX_DST]) == NULL) - continue; - - if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */ - continue; - - if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) { - log_warn("fetchtable"); - free(buf); - return (-1); - } - - kr->r.flags = F_KERNEL; - kr->r.priority = rtm->rtm_priority; - kr->r.local_label = NO_LABEL; - kr->r.remote_label = NO_LABEL; - - switch (sa->sa_family) { - case AF_INET: - kr->r.prefix.s_addr = - ((struct sockaddr_in *)sa)->sin_addr.s_addr; - sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK]; - if (rtm->rtm_flags & RTF_STATIC) - kr->r.flags |= F_STATIC; - if (rtm->rtm_flags & RTF_DYNAMIC) - kr->r.flags |= F_DYNAMIC; - if (sa_in != NULL) { - if (sa_in->sin_len == 0) - break; - kr->r.prefixlen = - mask2prefixlen(sa_in->sin_addr.s_addr); - } else if (rtm->rtm_flags & RTF_HOST) - kr->r.prefixlen = 32; - else - kr->r.prefixlen = - prefixlen_classful(kr->r.prefix.s_addr); - break; - default: - free(kr); - continue; - } - - kr->r.ifindex = rtm->rtm_index; - if ((sa = rti_info[RTAX_GATEWAY]) != NULL) - switch (sa->sa_family) { - case AF_INET: - kr->r.nexthop.s_addr = - ((struct sockaddr_in *)sa)->sin_addr.s_addr; - break; - case AF_LINK: - kr->r.flags |= F_CONNECTED; - break; - } - - if ((sa_mpls = (struct sockaddr_mpls *)rti_info[RTAX_SRC]) - != NULL) - kr->r.local_label = - ntohl(sa_mpls->smpls_label) >> MPLS_LABEL_OFFSET; - - kroute_insert(kr); - - } + rv = rtmsg_process(buf, len); free(buf); - return (0); + + return (rv); } int @@ -1284,12 +1246,8 @@ fetchifs(u_short ifindex) { size_t len; int mib[6]; - char *buf, *next, *lim; - struct rt_msghdr *rtm; - struct if_msghdr ifm; - struct ifa_msghdr *ifam; - struct kif *kif = NULL; - struct sockaddr *sa, *rti_info[RTAX_MAX]; + char *buf; + int rv; mib[0] = CTL_NET; mib[1] = AF_ROUTE; @@ -1312,45 +1270,10 @@ fetchifs(u_short ifindex) return (-1); } - lim = buf + len; - for (next = buf; next < lim; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - switch (rtm->rtm_type) { - case RTM_IFINFO: - bcopy(rtm, &ifm, sizeof ifm); - sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); - get_rtaddrs(ifm.ifm_addrs, sa, rti_info); - - if ((kif = kif_update(ifm.ifm_index, - ifm.ifm_flags, &ifm.ifm_data, - (struct sockaddr_dl *)rti_info[RTAX_IFP])) == NULL) - fatal("fetchifs"); - - kif->nh_reachable = (kif->flags & IFF_UP) && - (LINK_STATE_IS_UP(ifm.ifm_data.ifi_link_state) || - (ifm.ifm_data.ifi_link_state == - LINK_STATE_UNKNOWN && - ifm.ifm_data.ifi_type != IFT_CARP)); - break; - case RTM_NEWADDR: - ifam = (struct ifa_msghdr *)rtm; - if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | - RTA_BRD)) == 0) - break; - sa = (struct sockaddr *)(ifam + 1); - get_rtaddrs(ifam->ifam_addrs, sa, rti_info); - - if_newaddr(ifam->ifam_index, - (struct sockaddr_in *)rti_info[RTAX_IFA], - (struct sockaddr_in *)rti_info[RTAX_NETMASK], - (struct sockaddr_in *)rti_info[RTAX_BRD]); - break; - } - } + rv = rtmsg_process(buf, len); free(buf); - return (0); + + return (rv); } int @@ -1358,18 +1281,6 @@ dispatch_rtmsg(void) { char buf[RT_BUF_SIZE]; ssize_t n; - char *next, *lim; - struct rt_msghdr *rtm; - struct if_msghdr ifm; - struct ifa_msghdr *ifam; - struct sockaddr *sa, *rti_info[RTAX_MAX]; - struct sockaddr_in *sa_in; - struct kroute_node *kr; - struct in_addr prefix, nexthop; - u_int8_t prefixlen; - u_int8_t prio; - int flags; - u_short ifindex = 0; if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) { log_warn("dispatch_rtmsg: read error"); @@ -1381,8 +1292,28 @@ dispatch_rtmsg(void) return (-1); } - lim = buf + n; - for (next = buf; next < lim; next += rtm->rtm_msglen) { + return (rtmsg_process(buf, n)); +} + +int +rtmsg_process(char *buf, int len) +{ + struct rt_msghdr *rtm; + struct if_msghdr ifm; + struct ifa_msghdr *ifam; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + struct sockaddr_in *sa_in; + struct kroute_node *kr, *okr; + struct in_addr prefix, nexthop; + u_int8_t prefixlen, prio; + int flags, mpath; + u_short ifindex = 0; + + int offset; + char *next; + + for (offset = 0; offset < len; offset += rtm->rtm_msglen) { + next = buf + offset; rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; @@ -1391,25 +1322,39 @@ dispatch_rtmsg(void) prefixlen = 0; flags = F_KERNEL; nexthop.s_addr = 0; + mpath = 0; + prio = 0; + + sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); - prio = rtm->rtm_priority; - if (rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE || - rtm->rtm_type == RTM_DELETE) { - sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); - get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + switch (rtm->rtm_type) { + case RTM_ADD: + case RTM_GET: + case RTM_CHANGE: + case RTM_DELETE: + prefix.s_addr = 0; + prefixlen = 0; + nexthop.s_addr = 0; + mpath = 0; + prio = 0; - if (rtm->rtm_tableid != 0) + if (rtm->rtm_errno) /* failed attempts... */ continue; - if (rtm->rtm_pid == kr_state.pid) /* caused by us */ + if (rtm->rtm_tableid != 0) continue; - if (rtm->rtm_errno) /* failed attempts... */ + if ((sa = rti_info[RTAX_DST]) == NULL) continue; if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */ continue; + if (rtm->rtm_flags & RTF_MPATH) + mpath = 1; + prio = rtm->rtm_priority; + switch (sa->sa_family) { case AF_INET: prefix.s_addr = @@ -1427,6 +1372,10 @@ dispatch_rtmsg(void) prefixlen_classful(prefix.s_addr); if (rtm->rtm_flags & RTF_STATIC) flags |= F_STATIC; + if (rtm->rtm_flags & RTF_BLACKHOLE) + flags |= F_BLACKHOLE; + if (rtm->rtm_flags & RTF_REJECT) + flags |= F_REJECT; if (rtm->rtm_flags & RTF_DYNAMIC) flags |= F_DYNAMIC; break; @@ -1450,24 +1399,28 @@ dispatch_rtmsg(void) switch (rtm->rtm_type) { case RTM_ADD: + case RTM_GET: case RTM_CHANGE: if (nexthop.s_addr == 0 && !(flags & F_CONNECTED)) { - log_warnx("dispatch_rtmsg no nexthop for %s/%u", + log_warnx("no nexthop for %s/%u", inet_ntoa(prefix), prefixlen); continue; } - if ((kr = kroute_find(prefix.s_addr, prefixlen, - prio)) != NULL) { - /* - * ldp route overridden by kernel. Preference - * of the route is not checked because this is - * forced -- most probably by a user. - */ + if ((okr = kroute_find(prefix.s_addr, prefixlen, prio)) + != NULL) { + /* get the correct route */ + kr = okr; + if ((mpath || prio == RTP_OSPF) && + (kr = kroute_matchgw(okr, nexthop)) == + NULL) { + log_warnx("mpath route not found"); + /* add routes we missed out earlier */ + goto add; + } + if (kr->r.flags & F_LDPD_INSERTED) flags |= F_LDPD_INSERTED; - if (kr->r.flags & F_REDISTRIBUTED) - flags |= F_REDISTRIBUTED; kr->r.nexthop.s_addr = nexthop.s_addr; kr->r.flags = flags; kr->r.ifindex = ifindex; @@ -1480,9 +1433,10 @@ dispatch_rtmsg(void) /* just readd, the RDE will care */ kr_redistribute(kr); } else { +add: if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) { - log_warn("dispatch_rtmsg"); + log_warn("dispatch calloc"); return (-1); } kr->r.prefix.s_addr = prefix.s_addr; @@ -1498,41 +1452,49 @@ dispatch_rtmsg(void) } break; case RTM_DELETE: - if ((kr = kroute_find(prefix.s_addr, prefixlen, - prio)) == NULL) + if ((kr = kroute_find(prefix.s_addr, prefixlen, prio)) + == NULL) continue; if (!(kr->r.flags & F_KERNEL)) continue; - - if (kr->r.flags & F_LDPD_INSERTED) { - main_imsg_compose_lde(IMSG_NETWORK_DEL, 0, - &kr->r, sizeof(struct kroute)); - - send_rtmsg(kr_state.fd, RTM_DELETE, - &kr->r, AF_MPLS); + /* get the correct route */ + okr = kr; + if (mpath && + (kr = kroute_matchgw(kr, nexthop)) == NULL) { + log_warnx("dispatch_rtmsg mpath route" + " not found"); + return (-1); } - if (kroute_remove(kr) == -1) return (-1); break; case RTM_IFINFO: memcpy(&ifm, next, sizeof(ifm)); - if_change(ifm.ifm_index, ifm.ifm_flags, - &ifm.ifm_data); + if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data, + (struct sockaddr_dl *)rti_info[RTAX_IFP]); break; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)rtm; if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | RTA_BRD)) == 0) break; - sa = (struct sockaddr *)(ifam + 1); - get_rtaddrs(ifam->ifam_addrs, sa, rti_info); if_newaddr(ifam->ifam_index, (struct sockaddr_in *)rti_info[RTAX_IFA], (struct sockaddr_in *)rti_info[RTAX_NETMASK], (struct sockaddr_in *)rti_info[RTAX_BRD]); break; + case RTM_DELADDR: + ifam = (struct ifa_msghdr *)rtm; + if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | + RTA_BRD)) == 0) + break; + + if_deladdr(ifam->ifam_index, + (struct sockaddr_in *)rti_info[RTAX_IFA], + (struct sockaddr_in *)rti_info[RTAX_NETMASK], + (struct sockaddr_in *)rti_info[RTAX_BRD]); + break; case RTM_IFANNOUNCE: if_announce(next); break; @@ -1541,5 +1503,6 @@ dispatch_rtmsg(void) break; } } - return (0); + + return (offset); } |