-/* $OpenBSD: kroute.c,v 1.51 2017/05/30 12:42:31 friehm Exp $ */
+/* $OpenBSD: kroute.c,v 1.52 2017/06/19 19:55:57 friehm Exp $ */
/*
* Copyright (c) 2004 Esben Norby <norby@openbsd.org>
int kr_change_fib(struct kroute_node *, struct kroute *, int, int);
int kr_delete_fib(struct kroute_node *);
-struct kroute_node *kroute_find(const struct in6_addr *, u_int8_t);
+struct kroute_node *kroute_find(const struct in6_addr *, u_int8_t,
+ u_int8_t);
struct kroute_node *kroute_matchgw(struct kroute_node *,
struct in6_addr *, unsigned int);
int kroute_insert(struct kroute_node *);
kn->r.nexthop = kroute[i].nexthop;
kn->r.scope = kroute[i].scope;
kn->r.flags = kroute[i].flags | F_OSPFD_INSERTED;
+ kn->r.priority = RTP_OSPF;
kn->r.ext_tag = kroute[i].ext_tag;
rtlabel_unref(kn->r.rtlabel); /* for RTM_CHANGE */
kn->r.rtlabel = kroute[i].rtlabel;
kroute->rtlabel = rtlabel_tag2id(kroute->ext_tag);
- kr = kroute_find(&kroute->prefix, kroute->prefixlen);
- if (kr != NULL) {
- if (kr->r.flags & F_KERNEL) {
- /* a non-ospf route already exists. not a problem */
- if (!(kr->r.flags & F_BGPD_INSERTED)) {
- do {
- kr->r.flags |= F_OSPFD_INSERTED;
- kr = kr->next;
- } while (kr);
- return (0);
- }
- /*
- * XXX as long as there is no multipath support in
- * bgpd this is safe else we end up in a bad situation.
- */
- /*
- * ospf route has higher pref
- * - reset flags to the ospf ones
- * - use RTM_CHANGE
- * - zero out ifindex (this is no longer relevant)
- */
- action = RTM_CHANGE;
- } else if (kr->next == NULL) /* single path OSPF route */
- action = RTM_CHANGE;
- }
+ kr = kroute_find(&kroute->prefix, kroute->prefixlen, RTP_OSPF);
+ if (kr != NULL && kr->next == NULL && krcount == 1)
+ /* single path OSPF route */
+ action = RTM_CHANGE;
return (kr_change_fib(kr, kroute, krcount, action));
}
int
kr_delete_fib(struct kroute_node *kr)
{
- if (!(kr->r.flags & F_OSPFD_INSERTED))
- return 0;
-
- if (kr->r.flags & F_KERNEL) {
- /* remove F_OSPFD_INSERTED flag, route still exists in kernel */
- kr->r.flags &= ~F_OSPFD_INSERTED;
- return (0);
- }
+ if (kr->r.priority != RTP_OSPF)
+ log_warn("kr_delete_fib: %s/%d has wrong priority %d",
+ log_in6addr(&kr->r.prefix), kr->r.prefixlen,
+ kr->r.priority);
if (send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r) == -1)
return (-1);
{
struct kroute_node *kr, *nkr;
- if ((kr = kroute_find(&kroute->prefix, kroute->prefixlen)) ==
- NULL)
+ if ((kr = kroute_find(&kroute->prefix, kroute->prefixlen,
+ RTP_OSPF)) == NULL)
return (0);
while (kr != NULL) {
kr_state.fib_sync = 1;
RB_FOREACH(kr, kroute_tree, &krt)
- if (!(kr->r.flags & F_KERNEL))
- for (kn = kr; kn != NULL; kn = kn->next) {
+ if (kr->r.priority == RTP_OSPF)
+ for (kn = kr; kn != NULL; kn = kn->next)
send_rtmsg(kr_state.fd, RTM_ADD, &kn->r);
- }
log_info("kernel routing table coupled");
}
if (kr_state.fib_sync == 0) /* already decoupled */
return;
- RB_FOREACH(kr, kroute_tree, &krt) {
- if (!(kr->r.flags & F_KERNEL))
- for (kn = kr; kn != NULL; kn = kn->next) {
+ RB_FOREACH(kr, kroute_tree, &krt)
+ if (kr->r.priority == RTP_OSPF)
+ for (kn = kr; kn != NULL; kn = kn->next)
send_rtmsg(kr_state.fd, RTM_DELETE, &kn->r);
- }
- }
kr_state.fib_sync = 0;
void
kr_dispatch_msg(int fd, short event, void *bula)
{
+ /* XXX this is stupid */
dispatch_rtmsg();
}
struct kroute kr;
int redistribute = 0;
+ /* only the highest prio route can be redistributed */
+ if (kroute_find(&kh->r.prefix, kh->r.prefixlen, RTP_ANY) != kh)
+ return;
+
bzero(&kr, sizeof(kr));
kr.metric = UINT_MAX;
for (kn = kh; kn; kn = kn->next)
return (-1);
if (a->r.prefixlen > b->r.prefixlen)
return (1);
+
+ /* if the priority is RTP_ANY finish on the first address hit */
+ if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
+ return (0);
+ if (a->r.priority < b->r.priority)
+ return (-1);
+ if (a->r.priority > b->r.priority)
+ return (1);
return (0);
}
/* tree management */
struct kroute_node *
-kroute_find(const struct in6_addr *prefix, u_int8_t prefixlen)
+kroute_find(const struct in6_addr *prefix, u_int8_t prefixlen, u_int8_t prio)
{
struct kroute_node s;
+ struct kroute_node *kn, *tmp;
s.r.prefix = *prefix;
s.r.prefixlen = prefixlen;
-
- return (RB_FIND(kroute_tree, &krt, &s));
+ s.r.priority = prio;
+
+ kn = RB_FIND(kroute_tree, &krt, &s);
+ if (kn && prio == RTP_ANY) {
+ tmp = RB_PREV(kroute_tree, &krt, kn);
+ while (tmp) {
+ if (kroute_compare(&s, tmp) == 0)
+ kn = tmp;
+ else
+ break;
+ tmp = RB_PREV(kroute_tree, &krt, kn);
+ }
+ }
+ return (kn);
}
struct kroute_node *
if ((krh = RB_INSERT(kroute_tree, &krt, kr)) != NULL) {
/*
- * Multipath route, add at end of list and clone the
- * ospfd inserted flag.
+ * Multipath route, add at end of list.
*/
krm = krh;
- kr->r.flags |= krm->r.flags & F_OSPFD_INSERTED;
while (krm->next != NULL)
krm = krm->next;
krm->next = kr;
/* we will never match the default route */
for (i = 128; i > 0; i--) {
inet6applymask(&ina, key, i);
- if ((kr = kroute_find(&ina, i)) != NULL)
+ if ((kr = kroute_find(&ina, i, RTP_ANY)) != NULL)
return (kr);
}
/* if we don't have a match yet, try to find a default route */
- if ((kr = kroute_find(&in6addr_any, 0)) != NULL)
+ if ((kr = kroute_find(&in6addr_any, 0, RTP_ANY)) != NULL)
return (kr);
return (NULL);
bzero(&hdr, sizeof(hdr));
hdr.rtm_version = RTM_VERSION;
hdr.rtm_type = action;
- hdr.rtm_flags = RTF_UP|RTF_MPATH;
hdr.rtm_priority = RTP_OSPF;
if (action == RTM_CHANGE)
hdr.rtm_fmask = RTF_REJECT|RTF_BLACKHOLE;
+ else
+ hdr.rtm_flags = RTF_MPATH;
hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */
hdr.rtm_hdrlen = sizeof(hdr);
hdr.rtm_msglen = sizeof(hdr);
}
kr->r.flags = F_KERNEL;
+ kr->r.priority = rtm->rtm_priority;
switch (sa->sa_family) {
case AF_INET6:
kr->r.flags |= F_REJECT;
if (rtm->rtm_flags & RTF_DYNAMIC)
kr->r.flags |= F_DYNAMIC;
- if (rtm->rtm_flags & RTF_PROTO1)
- kr->r.flags |= F_BGPD_INSERTED;
if (sa_in6 != NULL) {
if (sa_in6->sin6_len == 0)
break;
break;
}
- if (rtm->rtm_flags & RTF_PROTO2) {
+ if (rtm->rtm_priority == RTP_OSPF) {
send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r);
free(kr);
} else {
struct sockaddr_rtlabel *label;
struct kroute_node *kr, *okr;
struct in6_addr prefix, nexthop;
- u_int8_t prefixlen;
+ u_int8_t prefixlen, prio;
int flags, mpath;
unsigned int scope;
u_short ifindex = 0;
prefixlen = 0;
flags = F_KERNEL;
mpath = 0;
+ prio = 0;
if (rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE ||
rtm->rtm_type == RTM_DELETE) {
if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST))
continue;
-#ifdef RTF_MPATH
if (rtm->rtm_flags & RTF_MPATH)
mpath = 1;
-#endif
+ prio = rtm->rtm_priority;
+
switch (sa->sa_family) {
case AF_INET6:
prefix =
flags |= F_REJECT;
if (rtm->rtm_flags & RTF_DYNAMIC)
flags |= F_DYNAMIC;
- if (rtm->rtm_flags & RTF_PROTO1)
- flags |= F_BGPD_INSERTED;
break;
default:
continue;
continue;
}
- if ((okr = kroute_find(&prefix, prefixlen)) !=
- NULL) {
+ if ((okr = kroute_find(&prefix, prefixlen, prio))
+ != NULL) {
/* just add new multipath routes */
if (mpath && rtm->rtm_type == RTM_ADD)
goto add;
goto add;
}
- /*
- * ospf route overridden by kernel. Preference
- * of the route is not checked because this is
- * forced -- most probably by a user.
- */
- if (kr->r.flags & F_OSPFD_INSERTED)
- flags |= F_OSPFD_INSERTED;
if (kr->r.flags & F_REDISTRIBUTED)
flags |= F_REDISTRIBUTED;
kr->r.nexthop = nexthop;
kr->r.scope = scope;
kr->r.flags = flags;
kr->r.ifindex = ifindex;
+ kr->r.priority = prio;
if ((label = (struct sockaddr_rtlabel *)
rti_info[RTAX_LABEL]) != NULL) {
}
break;
case RTM_DELETE:
- if ((kr = kroute_find(&prefix, prefixlen)) ==
+ if ((kr = kroute_find(&prefix, prefixlen, prio)) ==
NULL)
continue;
if (!(kr->r.flags & F_KERNEL))
" not found");
return (-1);
}
- /*
- * last route is getting removed request the
- * ospf route from the RDE to insert instead
- */
- if (okr == kr && kr->next == NULL &&
- kr->r.flags & F_OSPFD_INSERTED)
- main_imsg_compose_rde(IMSG_KROUTE_GET, 0,
- &kr->r, sizeof(struct kroute));
if (kroute_remove(kr) == -1)
return (-1);
break;