summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/ldpd/kroute.c203
1 files changed, 95 insertions, 108 deletions
diff --git a/usr.sbin/ldpd/kroute.c b/usr.sbin/ldpd/kroute.c
index 4e1c72432c2..9e64e75ac58 100644
--- a/usr.sbin/ldpd/kroute.c
+++ b/usr.sbin/ldpd/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.22 2010/10/07 12:38:00 claudio Exp $ */
+/* $OpenBSD: kroute.c,v 1.23 2010/10/15 13:18:45 claudio Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -67,12 +67,10 @@ int kr_redist_eval(struct kroute *);
void kr_redistribute(struct kroute_node *);
int kroute_compare(struct kroute_node *, struct kroute_node *);
int kif_compare(struct kif_node *, struct kif_node *);
-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, struct in_addr);
-struct kroute_node *kroute_matchgw(struct kroute_node *, struct in_addr);
+struct kroute_node *kroute_find_any(in_addr_t, u_int8_t);
+struct kroute_node *kroute_matchprio(struct kroute_node *, u_int8_t);
int kroute_insert(struct kroute_node *);
int kroute_remove(struct kroute_node *);
void kroute_clear(void);
@@ -187,11 +185,25 @@ kr_init(int fs)
}
int
-kr_change_fib(struct kroute_node *kr, struct kroute *kroute, int action)
+kr_change(struct kroute *kroute)
{
+ struct kroute_node *kr;
+ int action = RTM_ADD;
+
+ kr = kroute_find_fec(kroute->prefix.s_addr, kroute->prefixlen,
+ kroute->nexthop);
+
+ if (kr == NULL) {
+ log_warnx("kr_change: lost FEC %s/%d",
+ inet_ntoa(kroute->prefix), kroute->prefixlen);
+ return (-1);
+ }
+
+ if (kr->r.flags & F_LDPD_INSERTED)
+ action = RTM_CHANGE;
+
kr->r.local_label = kroute->local_label;
kr->r.remote_label = kroute->remote_label;
- kr->r.nexthop.s_addr = kroute->nexthop.s_addr;
kr->r.flags = kr->r.flags | F_LDPD_INSERTED;
/* send update */
@@ -208,64 +220,34 @@ kr_change_fib(struct kroute_node *kr, struct kroute *kroute, int action)
}
int
-kr_change(struct kroute *kroute)
+kr_delete(struct kroute *kroute)
{
struct kroute_node *kr;
- int action = RTM_ADD;
+ int update = 0;
kr = kroute_find_fec(kroute->prefix.s_addr, kroute->prefixlen,
kroute->nexthop);
+ if (kr == NULL)
+ return (0);
- if (kr == NULL) {
- log_warnx("kr_change: lost FEC %s/%d",
- inet_ntoa(kroute->prefix), kroute->prefixlen);
- return (-1);
- }
-
- if (kr->r.flags & F_LDPD_INSERTED)
- action = RTM_CHANGE;
-
- return (kr_change_fib(kr, kroute, action));
-}
-
-int
-kr_delete_fib(struct kroute_node *kr)
-{
if (!(kr->r.flags & F_LDPD_INSERTED))
return (0);
-
- /* remove F_LDPD_INSERTED flag, route still exists in kernel */
- kr->r.flags &= ~F_LDPD_INSERTED;
+ if (kr->r.nexthop.s_addr != INADDR_ANY &&
+ kr->r.remote_label != NO_LABEL)
+ update = 1;
/* kill MPLS LSP */
if (send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r, AF_MPLS) == -1)
return (-1);
- if (kroute_remove(kr) == -1)
- return (-1);
-
- return (0);
-}
-
-int
-kr_delete(struct kroute *kroute)
-{
- struct kroute_node *kr, *nkr;
-
- kr = kroute_find_fec(kroute->prefix.s_addr, kroute->prefixlen,
- kroute->nexthop);
- if (kr == NULL)
- return (0);
+ kr->r.flags &= ~F_LDPD_INSERTED;
+ kr->r.local_label = NO_LABEL;
+ kr->r.remote_label = NO_LABEL;
- if (kr_delete_fib(kr) == -1)
+ if (update &&
+ send_rtmsg(kr_state.fd, RTM_CHANGE, &kr->r, AF_INET) == -1)
return (-1);
- while (kr != NULL) {
- nkr = kr->next;
- if (kr_delete_fib(kr) == -1)
- return (-1);
- kr = nkr;
- }
return (0);
}
@@ -458,7 +440,8 @@ kr_redistribute(struct kroute_node *kh)
struct kroute_node *kn;
/* only the highest prio route can be redistributed */
- if (kroute_find(kh->r.prefix.s_addr, kh->r.prefixlen, RTP_ANY) != kh)
+ if (kroute_find_fec(kh->r.prefix.s_addr, kh->r.prefixlen,
+ kh->r.nexthop) != kh)
return;
for (kn = kh; kn; kn = kn->next)
@@ -470,6 +453,7 @@ kr_reload(void)
{
struct kroute_node *kr;
+ /* XXX this does not make sense in ldpd */
RB_FOREACH(kr, kroute_tree, &krt) {
if (kr->r.flags & F_REDISTRIBUTED)
kr_redistribute(kr);
@@ -489,12 +473,9 @@ kroute_compare(struct kroute_node *a, struct kroute_node *b)
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)
+ if (ntohl(a->r.nexthop.s_addr) < ntohl(b->r.nexthop.s_addr))
return (-1);
- if (a->r.priority > b->r.priority)
+ if (ntohl(a->r.nexthop.s_addr) > ntohl(b->r.nexthop.s_addr))
return (1);
return (0);
}
@@ -507,60 +488,44 @@ kif_compare(struct kif_node *a, struct kif_node *b)
/* tree management */
struct kroute_node *
-kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio)
+kroute_find_fec(in_addr_t prefix, u_int8_t prefixlen, struct in_addr nexthop)
{
struct kroute_node s;
- struct kroute_node *kn, *tmp;
s.r.prefix.s_addr = prefix;
s.r.prefixlen = prefixlen;
- 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);
+ s.r.nexthop.s_addr = nexthop.s_addr;
+
+ return (RB_FIND(kroute_tree, &krt, &s));
}
struct kroute_node *
-kroute_find_fec(in_addr_t prefix, u_int8_t prefixlen, struct in_addr nexthop)
+kroute_find_any(in_addr_t prefix, u_int8_t prefixlen)
{
struct kroute_node s;
- struct kroute_node *kn, *kr;
+ struct kroute_node *kn, *best = NULL;
s.r.prefix.s_addr = prefix;
s.r.prefixlen = prefixlen;
- s.r.priority = 0; /* trick to use RB_NFIND */
+ s.r.nexthop.s_addr = 0;
kn = RB_NFIND(kroute_tree, &krt, &s);
while (kn) {
- if ((kr = kroute_matchgw(kn, nexthop)))
- return (kr);
+ if (!best || best->r.priority > kn->r.priority)
+ best = kn;
kn = RB_NEXT(kroute_tree, &krt, kn);
if (kn == NULL || kn->r.prefix.s_addr != prefix ||
kn->r.prefixlen != prefixlen)
- return (NULL);
+ break;
}
- return (NULL);
+ return (best);
}
struct kroute_node *
-kroute_matchgw(struct kroute_node *kr, struct in_addr nh)
+kroute_matchprio(struct kroute_node *kr, u_int8_t prio)
{
- in_addr_t nexthop;
-
- nexthop = nh.s_addr;
-
while (kr) {
- if (kr->r.nexthop.s_addr == nexthop)
+ if (kr->r.priority == prio)
return (kr);
kr = kr->next;
}
@@ -571,20 +536,38 @@ kroute_matchgw(struct kroute_node *kr, struct in_addr nh)
int
kroute_insert(struct kroute_node *kr)
{
- struct kroute_node *krm;
+ struct kroute_node *krm, *krh;
- if ((krm = RB_INSERT(kroute_tree, &krt, kr)) != NULL) {
+ if ((krh = RB_INSERT(kroute_tree, &krt, kr)) != NULL) {
/*
- * Multipath route, add at end of list.
+ * Multiple FEC, add to ordered list
*/
- while (krm->next != NULL)
- krm = krm->next;
- krm->next = kr;
- kr->next = NULL; /* to be sure */
+ if (kr->r.priority < krh->r.priority) {
+ /* head element */
+ if (RB_REMOVE(kroute_tree, &krt, krh) == NULL) {
+ log_warnx("kroute_insert failed to del %s/%u",
+ inet_ntoa(krh->r.prefix), krh->r.prefixlen);
+ return (-1);
+ }
+ if (RB_INSERT(kroute_tree, &krt, kr) != NULL) {
+ log_warnx("kroute_insert failed to add %s/%u",
+ inet_ntoa(kr->r.prefix), kr->r.prefixlen);
+ return (-1);
+ }
+ kr->next = krh;
+ krh = kr;
+ } else {
+ for (krm = krh; krm->next != NULL &&
+ krm->next->r.priority < kr->r.priority;
+ krm = krm->next)
+ ;
+ kr->next = krm->next;
+ krm->next = kr;
+ }
} else
- krm = kr;
+ krh = kr;
- kr_redistribute(krm);
+ kr_redistribute(krh);
return (0);
}
@@ -628,6 +611,14 @@ kroute_remove(struct kroute_node *kr)
kr_redist_remove(&kr->r);
+ /* kill MPLS LSP if one was installed */
+ if (kr->r.flags & F_LDPD_INSERTED)
+ if (send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r, AF_MPLS) ==
+ -1) {
+ free(kr);
+ return (-1);
+ }
+
free(kr);
return (0);
}
@@ -757,14 +748,12 @@ kroute_match(in_addr_t key)
/* we will never match the default route */
for (i = 32; i > 0; i--)
- if ((kr = kroute_find(key & prefixlen2mask(i), i,
- RTP_ANY)) != NULL)
+ if ((kr = kroute_find_any(key & prefixlen2mask(i), i)) != NULL)
return (kr);
/* if we don't have a match yet, try to find a default route */
- if ((kr = kroute_find(0, 0, RTP_ANY)) != NULL)
+ if ((kr = kroute_find_any(0, 0)) != NULL)
return (kr);
-
return (NULL);
}
@@ -960,6 +949,7 @@ send_rtmsg(int fd, int action, struct kroute *kroute, u_int32_t family)
hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */
hdr.rtm_msglen = sizeof(hdr);
hdr.rtm_hdrlen = sizeof(struct rt_msghdr);
+ hdr.rtm_priority = kroute->priority;
/* adjust iovec */
iov[iovcnt].iov_base = &hdr;
iov[iovcnt++].iov_len = sizeof(hdr);
@@ -971,8 +961,7 @@ send_rtmsg(int fd, int action, struct kroute *kroute, u_int32_t family)
label_in.smpls_label =
htonl(kroute->local_label << MPLS_LABEL_OFFSET);
/* adjust header */
- hdr.rtm_flags |= RTF_MPLS;
- hdr.rtm_priority = RTP_DEFAULT;
+ hdr.rtm_flags |= RTF_MPLS | RTF_MPATH;
hdr.rtm_addrs |= RTA_DST;
hdr.rtm_msglen += sizeof(label_in);
/* adjust iovec */
@@ -984,7 +973,6 @@ send_rtmsg(int fd, int action, struct kroute *kroute, u_int32_t family)
dst.sin_family = AF_INET;
dst.sin_addr.s_addr = kroute->prefix.s_addr;
/* adjust header */
- hdr.rtm_priority = kroute->priority;
hdr.rtm_addrs |= RTA_DST;
hdr.rtm_msglen += sizeof(dst);
/* adjust iovec */
@@ -1270,12 +1258,12 @@ rtmsg_process(char *buf, int len)
continue;
}
- if ((okr = kroute_find(prefix.s_addr, prefixlen, prio))
+ if ((okr = kroute_find_fec(prefix.s_addr, prefixlen,
+ nexthop))
!= NULL) {
/* get the correct route */
kr = okr;
- if ((mpath || prio == RTP_OSPF) &&
- (kr = kroute_matchgw(okr, nexthop)) ==
+ if ((kr = kroute_matchprio(okr, prio)) ==
NULL) {
log_warnx("mpath route not found");
/* add routes we missed out earlier */
@@ -1289,7 +1277,7 @@ rtmsg_process(char *buf, int len)
kr->r.ifindex = ifindex;
/* just readd, the RDE will care */
- kr_redistribute(kr);
+ kr_redistribute(okr);
} else {
add:
if ((kr = calloc(1,
@@ -1310,13 +1298,12 @@ add:
}
break;
case RTM_DELETE:
- if ((kr = kroute_find(prefix.s_addr, prefixlen, prio))
- == NULL)
+ if ((kr = kroute_find_fec(prefix.s_addr, prefixlen,
+ nexthop)) == NULL)
continue;
/* get the correct route */
okr = kr;
- if (mpath &&
- (kr = kroute_matchgw(kr, nexthop)) == NULL) {
+ if ((kr = kroute_matchprio(kr, prio)) == NULL) {
log_warnx("dispatch_rtmsg mpath route"
" not found");
return (-1);