diff options
author | 2019-12-12 08:21:34 +0000 | |
---|---|---|
committer | 2019-12-12 08:21:34 +0000 | |
commit | bf9d8b16cdf0784e95a4bd24075ba56c79b5b2c5 (patch) | |
tree | 6a186b2c00135fa4ded701a0fdc1f7ea7ae996bc | |
parent | vmd: start vms defined in vm.conf in a staggered fashion (diff) | |
download | wireguard-openbsd-bf9d8b16cdf0784e95a4bd24075ba56c79b5b2c5.tar.xz wireguard-openbsd-bf9d8b16cdf0784e95a4bd24075ba56c79b5b2c5.zip |
Refactor kernel route message handling.
OK remi@
-rw-r--r-- | usr.sbin/ospf6d/kroute.c | 249 |
1 files changed, 70 insertions, 179 deletions
diff --git a/usr.sbin/ospf6d/kroute.c b/usr.sbin/ospf6d/kroute.c index ddc2f7b74ed..8faf37c21ec 100644 --- a/usr.sbin/ospf6d/kroute.c +++ b/usr.sbin/ospf6d/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.60 2019/01/02 21:32:55 remi Exp $ */ +/* $OpenBSD: kroute.c,v 1.61 2019/12/12 08:21:34 denis Exp $ */ /* * Copyright (c) 2004 Esben Norby <norby@openbsd.org> @@ -80,7 +80,7 @@ struct kroute_node *kroute_match(struct in6_addr *); int protect_lo(void); 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_in6 *, struct sockaddr_in6 *, struct sockaddr_in6 *); void if_deladdr(u_short, struct sockaddr_in6 *, @@ -90,6 +90,7 @@ void if_announce(void *); int send_rtmsg(int, int, struct kroute *); int dispatch_rtmsg(void); int fetchtable(void); +int rtmsg_process(char *, size_t); RB_HEAD(kroute_tree, kroute_node) krt; RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare) @@ -801,7 +802,8 @@ 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, *tkr; struct iface *iface; @@ -809,7 +811,7 @@ if_change(u_short ifindex, int flags, struct if_data *ifd) wasvalid = kif_validate(ifindex); - if ((iface = kif_update(ifindex, flags, ifd, NULL)) == NULL) { + if ((iface = kif_update(ifindex, flags, ifd, sdl)) == NULL) { log_warn("if_change: kif_update(%u)", ifindex); return; } @@ -1135,12 +1137,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_in6 *sa_in6; - struct sockaddr_rtlabel *label; - struct kroute_node *kr; + char *buf; + int rv; mib[0] = CTL_NET; mib[1] = PF_ROUTE; @@ -1164,102 +1162,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; - - /* Skip ARP/ND cache and broadcast routes. */ - if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST)) - 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; - - switch (sa->sa_family) { - case AF_INET6: - kr->r.prefix = - ((struct sockaddr_in6 *)sa)->sin6_addr; - sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK]; - if (rtm->rtm_flags & RTF_STATIC) - kr->r.flags |= F_STATIC; - if (rtm->rtm_flags & RTF_BLACKHOLE) - kr->r.flags |= F_BLACKHOLE; - if (rtm->rtm_flags & RTF_REJECT) - kr->r.flags |= F_REJECT; - if (rtm->rtm_flags & RTF_DYNAMIC) - kr->r.flags |= F_DYNAMIC; - if (sa_in6 != NULL) { - if (sa_in6->sin6_len == 0) - break; - kr->r.prefixlen = - mask2prefixlen(sa_in6); - } else if (rtm->rtm_flags & RTF_HOST) - kr->r.prefixlen = 128; - else - fatalx("classful IPv6 route?!!"); - break; - default: - free(kr); - continue; - } - - kr->r.ifindex = rtm->rtm_index; - if ((sa = rti_info[RTAX_GATEWAY]) != NULL) - switch (sa->sa_family) { - case AF_INET6: - if (rtm->rtm_flags & RTF_CONNECTED) { - kr->r.flags |= F_CONNECTED; - break; - } - - sa_in6 = (struct sockaddr_in6 *)sa; - /* - * XXX The kernel provides the scope via the - * XXX kame hack instead of the scope_id field. - */ - recoverscope(sa_in6); - kr->r.nexthop = sa_in6->sin6_addr; - kr->r.scope = sa_in6->sin6_scope_id; - break; - case AF_LINK: - /* - * Traditional BSD connected routes have - * a gateway of type AF_LINK. - */ - kr->r.flags |= F_CONNECTED; - break; - } - - if (rtm->rtm_priority == kr_state.fib_prio) { - send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r); - free(kr); - } else { - if ((label = (struct sockaddr_rtlabel *) - rti_info[RTAX_LABEL]) != NULL) { - kr->r.rtlabel = - rtlabel_name2id(label->sr_label); - kr->r.ext_tag = - rtlabel_id2tag(kr->r.rtlabel); - } - kroute_insert(kr); - } - - } + rv = rtmsg_process(buf, len); free(buf); - return (0); + + return (rv); } int @@ -1267,12 +1173,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 iface *iface; - struct sockaddr *sa, *rti_info[RTAX_MAX]; + char *buf; + int rv; mib[0] = CTL_NET; mib[1] = PF_ROUTE; @@ -1295,38 +1197,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 + sizeof(ifm)); - get_rtaddrs(ifm.ifm_addrs, sa, rti_info); - - if ((iface = kif_update(ifm.ifm_index, - ifm.ifm_flags, &ifm.ifm_data, - (struct sockaddr_dl *)rti_info[RTAX_IFP])) == NULL) - 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_in6 *)rti_info[RTAX_IFA], - (struct sockaddr_in6 *)rti_info[RTAX_NETMASK], - (struct sockaddr_in6 *)rti_info[RTAX_BRD]); - break; - } - } + rv = rtmsg_process(buf, len); free(buf); - return (0); + + return (rv); } int @@ -1334,7 +1208,25 @@ dispatch_rtmsg(void) { char buf[RT_BUF_SIZE]; ssize_t n; - char *next, *lim; + + if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) { + if (errno == EAGAIN || errno == EINTR) + return (0); + log_warn("dispatch_rtmsg: read error"); + return (-1); + } + + if (n == 0) { + log_warnx("routing socket closed"); + return (-1); + } + + return (rtmsg_process(buf, n)); +} + +int +rtmsg_process(char *buf, size_t len) +{ struct rt_msghdr *rtm; struct if_msghdr ifm; struct ifa_msghdr *ifam; @@ -1348,25 +1240,15 @@ dispatch_rtmsg(void) unsigned int scope; u_short ifindex = 0; int rv; + size_t offset; + char *next; - if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) { - if (errno == EAGAIN || errno == EINTR) - return (0); - log_warn("dispatch_rtmsg: read error"); - return (-1); - } - - if (n == 0) { - log_warnx("routing socket closed"); - return (-1); - } - - lim = buf + n; - for (next = buf; next < lim; next += rtm->rtm_msglen) { + for (offset = 0; offset < len; offset += rtm->rtm_msglen) { + next = buf + offset; rtm = (struct rt_msghdr *)next; - if (lim < next + sizeof(u_short) || - lim < next + rtm->rtm_msglen) - fatalx("dispatch_rtmsg: partial rtm in buffer"); + if (len < offset + sizeof(u_short) || + len < offset + rtm->rtm_msglen) + fatalx("rtmsg_process: partial rtm in buffer"); if (rtm->rtm_version != RTM_VERSION) continue; @@ -1378,18 +1260,25 @@ dispatch_rtmsg(void) mpath = 0; prio = 0; - 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); + 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: + if (rtm->rtm_errno) /* failed attempts... */ + continue; if (rtm->rtm_tableid != kr_state.rdomain) continue; - if (rtm->rtm_pid == kr_state.pid) /* caused by us */ + if (rtm->rtm_type == RTM_GET && + rtm->rtm_pid != kr_state.pid) /* caused by us */ continue; - if (rtm->rtm_errno) /* failed attempts... */ + if ((sa = rti_info[RTAX_DST]) == NULL) continue; /* Skip ARP/ND cache and broadcast routes. */ @@ -1399,6 +1288,8 @@ dispatch_rtmsg(void) if (rtm->rtm_flags & RTF_MPATH) mpath = 1; prio = rtm->rtm_priority; + flags = (prio == kr_state.fib_prio) ? + F_OSPFD_INSERTED : F_KERNEL; switch (sa->sa_family) { case AF_INET6: @@ -1431,6 +1322,9 @@ dispatch_rtmsg(void) if ((sa = rti_info[RTAX_GATEWAY]) != NULL) { switch (sa->sa_family) { case AF_INET6: + if (rtm->rtm_flags & RTF_CONNECTED) + flags |= F_CONNECTED; + sa_in6 = (struct sockaddr_in6 *)sa; /* * XXX The kernel provides the scope @@ -1450,10 +1344,11 @@ dispatch_rtmsg(void) switch (rtm->rtm_type) { case RTM_ADD: + case RTM_GET: case RTM_CHANGE: if (IN6_IS_ADDR_UNSPECIFIED(&nexthop) && !(flags & F_CONNECTED)) { - log_warnx("dispatch_rtmsg no nexthop for %s/%u", + log_warnx("rtmsg_process no nexthop for %s/%u", log_in6addr(&prefix), prefixlen); continue; } @@ -1467,7 +1362,7 @@ dispatch_rtmsg(void) kr = okr; if (mpath && (kr = kroute_matchgw(okr, &nexthop, scope)) == NULL) { - log_warnx("dispatch_rtmsg mpath route" + log_warnx("rtmsg_process: mpath route" " not found"); /* add routes we missed out earlier */ goto add; @@ -1502,7 +1397,7 @@ dispatch_rtmsg(void) add: if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) { - log_warn("dispatch_rtmsg"); + log_warn("rtmsg_process calloc"); return (-1); } kr->r.prefix = prefix; @@ -1540,31 +1435,29 @@ add: if ((kr = kroute_find(&prefix, prefixlen, prio)) == NULL) continue; + if (!(kr->r.flags & F_KERNEL)) + continue; /* get the correct route */ okr = kr; if (mpath && (kr = kroute_matchgw(kr, &nexthop, scope)) == NULL) { - log_warnx("dispatch_rtmsg mpath route" + log_warnx("rtmsg_process mpath route" " not found"); return (-1); } - if (!(kr->r.flags & F_KERNEL)) - continue; 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_in6 *)rti_info[RTAX_IFA], @@ -1576,8 +1469,6 @@ add: 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_deladdr(ifam->ifam_index, (struct sockaddr_in6 *)rti_info[RTAX_IFA], @@ -1592,5 +1483,5 @@ add: break; } } - return (0); + return (offset); } |