summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2010-10-15 13:18:46 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2010-10-15 13:18:46 +0000
commit487219e3152fe1690999d03f2592aad7a2caa63c (patch)
tree43cda2e49ef2da609e63401d798bae5263909fd5
parent9793ed57e8fbc4d4f3465d56872597587e7afd2b (diff)
Rework the kroute framework of ldpd. ldpd is different from the other
routing daemons. Change the way the kroute tree is indexed (by FEC with a linked list in case there is a priority conflict -- same route + nexthop at different priorities). This needs a mpath capable MPLS routing table. Still work in progress but works a lot better in close meshed networks.
-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);