From d9e7e1b13d69fa50d1979576c418c579f05463c6 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 13 Nov 2010 14:19:23 +0100 Subject: [PATCH] Adds support for iface link detection to OSPF. --- proto/ospf/config.Y | 4 +- proto/ospf/iface.c | 281 ++++++++++++++++++++++-------------------- proto/ospf/iface.h | 2 +- proto/ospf/ospf.c | 17 ++- proto/ospf/ospf.h | 16 +-- proto/ospf/topology.c | 54 ++++---- 6 files changed, 203 insertions(+), 171 deletions(-) diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 5caba006..49d65942 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -192,13 +192,14 @@ ospf_iface_item: | TYPE POINTOPOINT { OSPF_PATT->type = OSPF_IT_PTP ; } | STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; } | STUB bool { OSPF_PATT->stub = $2 ; } + | LINK bool { OSPF_PATT->use_link = $2 ; } | NEIGHBORS '{' ipa_list '}' | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; } | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; } | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; } | RX BUFFER LARGE { OSPF_PATT->rxbuf = OSPF_RXBUF_LARGE ; } | RX BUFFER NORMAL { OSPF_PATT->rxbuf = OSPF_RXBUF_NORMAL ; } - | RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if ($3 < OSPF_RXBUF_MINSIZE) cf_error("Buffer size is too small") ; } + | RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if (($3 < OSPF_RXBUF_MINSIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); } | password_list ; @@ -275,6 +276,7 @@ ospf_iface_start: OSPF_PATT->type = OSPF_IT_UNDEF; OSPF_PATT->strictnbma = 0; OSPF_PATT->stub = 0; + OSPF_PATT->use_link = 1; init_list(&OSPF_PATT->nbma_list); OSPF_PATT->autype = OSPF_AUTH_NONE; reset_passwords(); diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index b31e4098..072e1c71 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -60,10 +60,7 @@ rxbufsize(struct ospf_iface *ifa) static int ospf_sk_open(struct ospf_iface *ifa) { - sock *sk; - struct proto *p = &ifa->oa->po->proto; - - sk = sk_new(p->pool); + sock *sk = sk_new(ifa->pool); sk->type = SK_IP; sk->dport = OSPF_PROTO; sk->saddr = IPA_NONE; @@ -162,72 +159,6 @@ ospf_sk_leave_dr(struct ospf_iface *ifa) ifa->sk_dr = 0; } -static inline void -ospf_sk_close(struct ospf_iface *ifa) -{ - ASSERT(ifa->sk); - - rfree(ifa->sk); - ifa->sk = NULL; -} - - -/** - * ospf_iface_chstate - handle changes of interface state - * @ifa: OSPF interface - * @state: new state - * - * Many actions must be taken according to interface state changes. New network - * LSAs must be originated, flushed, new multicast sockets to listen for messages for - * %ALLDROUTERS have to be opened, etc. - */ -void -ospf_iface_chstate(struct ospf_iface *ifa, u8 state) -{ - struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; - u8 oldstate = ifa->state; - - if (oldstate != state) - { - ifa->state = state; - - if (ifa->type == OSPF_IT_VLINK) - { - OSPF_TRACE(D_EVENTS, - "Changing state of virtual link %R from \"%s\" into \"%s\".", - ifa->vid, ospf_is[oldstate], ospf_is[state]); - } - else - { - OSPF_TRACE(D_EVENTS, - "Changing state of iface: %s from \"%s\" into \"%s\".", - ifa->iface->name, ospf_is[oldstate], ospf_is[state]); - if (ifa->iface->flags & IF_MULTICAST) - { - if ((ifa->type != OSPF_IT_NBMA) && (ifa->ioprob == OSPF_I_OK) && - ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))) - ospf_sk_join_dr(ifa); - else - ospf_sk_leave_dr(ifa); - - if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL)) - { - ifa->net_lsa->lsa.age = LSA_MAXAGE; - if (state >= OSPF_IS_WAITING) - { - ospf_lsupd_flush_nlsa(po, ifa->net_lsa); - } - if (can_flush_lsa(po)) - flush_lsa(ifa->net_lsa, po); - ifa->net_lsa = NULL; - } - } - // FIXME flushling of link LSA - } - } -} - static void ospf_iface_down(struct ospf_iface *ifa) { @@ -254,6 +185,15 @@ ospf_iface_down(struct ospf_iface *ifa) ospf_neigh_remove(n); } + if (ifa->hello_timer) + tm_stop(ifa->hello_timer); + + if (ifa->poll_timer) + tm_stop(ifa->poll_timer); + + if (ifa->wait_timer) + tm_stop(ifa->wait_timer); + if (ifa->type == OSPF_IT_VLINK) { ifa->vifa = NULL; @@ -262,18 +202,70 @@ ospf_iface_down(struct ospf_iface *ifa) ifa->sk = NULL; ifa->cost = 0; ifa->vip = IPA_NONE; + } +} + + +static void +ospf_iface_remove(struct ospf_iface *ifa) +{ + ospf_iface_sm(ifa, ISM_DOWN); + rem_node(NODE ifa); + rfree(ifa->pool); +} + +/** + * ospf_iface_chstate - handle changes of interface state + * @ifa: OSPF interface + * @state: new state + * + * Many actions must be taken according to interface state changes. New network + * LSAs must be originated, flushed, new multicast sockets to listen for messages for + * %ALLDROUTERS have to be opened, etc. + */ +void +ospf_iface_chstate(struct ospf_iface *ifa, u8 state) +{ + struct proto_ospf *po = ifa->oa->po; + struct proto *p = &po->proto; + u8 oldstate = ifa->state; + + if (oldstate == state) return; - } + + ifa->state = state; + + if (ifa->type == OSPF_IT_VLINK) + OSPF_TRACE(D_EVENTS, "Changing state of virtual link %R from %s to %s", + ifa->vid, ospf_is[oldstate], ospf_is[state]); else + OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s", + ifa->iface->name, ospf_is[oldstate], ospf_is[state]); + + if (ifa->type == OSPF_IT_BCAST) { - ospf_sk_close(ifa); - rfree(ifa->wait_timer); - rfree(ifa->hello_timer); - rfree(ifa->poll_timer); - rfree(ifa->lock); - rem_node(NODE ifa); - mb_free(ifa); + if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR)) + ospf_sk_join_dr(ifa); + else + ospf_sk_leave_dr(ifa); } + + if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL)) + { + ifa->net_lsa->lsa.age = LSA_MAXAGE; + if (state >= OSPF_IS_WAITING) + ospf_lsupd_flush_nlsa(po, ifa->net_lsa); + + if (can_flush_lsa(po)) + flush_lsa(ifa->net_lsa, po); + ifa->net_lsa = NULL; + } + + if ((oldstate > OSPF_IS_LOOP) && (state <= OSPF_IS_LOOP)) + ospf_iface_down(ifa); + + schedule_rt_lsa(ifa->oa); + // FIXME flushling of link LSA } /** @@ -281,21 +273,22 @@ ospf_iface_down(struct ospf_iface *ifa) * @ifa: OSPF interface * @event: event comming to state machine * - * This fully respects 9.3 of RFC 2328 except we don't use %LOOP state of - * interface. + * This fully respects 9.3 of RFC 2328 except we have slightly + * different handling of %DOWN and %LOOP state. We remove intefaces + * that are %DOWN. %DOWN state is used when an interface is waiting + * for a lock. %LOOP state is used when an interface does not have a + * link. */ void ospf_iface_sm(struct ospf_iface *ifa, int event) { - struct ospf_area *oa = ifa->oa; - DBG("SM on %s %s. Event is '%s'\n", (ifa->type == OSPF_IT_VLINK) ? "vlink" : "iface", ifa->iface ? ifa->iface->name : "(none)" , ospf_ism[event]); switch (event) { case ISM_UP: - if (ifa->state == OSPF_IS_DOWN) + if (ifa->state <= OSPF_IS_LOOP) { /* Now, nothing should be adjacent */ if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_VLINK)) @@ -319,10 +312,10 @@ ospf_iface_sm(struct ospf_iface *ifa, int event) tm_start(ifa->poll_timer, ifa->pollint); hello_timer_hook(ifa->hello_timer); + schedule_link_lsa(ifa); } - schedule_link_lsa(ifa); - schedule_rt_lsa(ifa->oa); break; + case ISM_BACKS: case ISM_WAITF: if (ifa->state == OSPF_IS_WAITING) @@ -330,6 +323,7 @@ ospf_iface_sm(struct ospf_iface *ifa, int event) bdr_election(ifa); } break; + case ISM_NEICH: if ((ifa->state == OSPF_IS_DROTHER) || (ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) @@ -338,19 +332,22 @@ ospf_iface_sm(struct ospf_iface *ifa, int event) schedule_rt_lsa(ifa->oa); } break; + + case ISM_LOOP: + if (ifa->sk && ifa->use_link) + ospf_iface_chstate(ifa, OSPF_IS_LOOP); + break; + + case ISM_UNLOOP: + /* Immediate go UP */ + if (ifa->state == OSPF_IS_LOOP) + ospf_iface_sm(ifa, ISM_UP); + break; + case ISM_DOWN: ospf_iface_chstate(ifa, OSPF_IS_DOWN); - ospf_iface_down(ifa); - schedule_rt_lsa(oa); break; - /* - case ISM_LOOP: - ospf_iface_chstate(ifa, OSPF_IS_LOOP); - break; - case ISM_UNLOOP: - ospf_iface_chstate(ifa, OSPF_IS_DOWN); - break; - */ + default: bug("OSPF_I_SM - Unknown event?"); break; @@ -391,8 +388,6 @@ ospf_iface_add(struct object_lock *lock) struct proto_ospf *po = ifa->oa->po; struct proto *p = &po->proto; - ifa->lock = lock; - if (ospf_sk_open(ifa)) { if (ifa->type != OSPF_IT_NBMA) @@ -405,8 +400,8 @@ ospf_iface_add(struct object_lock *lock) ifa->stub = 1; } - ifa->state = OSPF_IS_DOWN; - ospf_iface_sm(ifa, ISM_UP); + /* Do iface UP, unless there is no link and we use link detection */ + ospf_iface_sm(ifa, (ifa->use_link && !(ifa->iface->flags & IF_LINK_UP)) ? ISM_LOOP : ISM_UP); } void @@ -414,6 +409,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr, struct ospf_area_config *ac, struct ospf_iface_patt *ip) { struct proto *p = &po->proto; + struct pool *pool = rp_new(p->pool, "OSPF Interface"); struct ospf_iface *ifa; struct nbma_node *nbma, *nb; struct object_lock *lock; @@ -422,9 +418,10 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr, if (ip->type != OSPF_IT_VLINK) OSPF_TRACE(D_EVENTS, "Adding interface %s", iface->name); - ifa = mb_allocz(p->pool, sizeof(struct ospf_iface)); + ifa = mb_allocz(pool, sizeof(struct ospf_iface)); ifa->iface = iface; ifa->addr = addr; + ifa->pool = pool; ifa->cost = ip->cost; ifa->rxmtint = ip->rxmtint; @@ -438,6 +435,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr, ifa->stub = ospf_iface_stubby(ip, addr); ifa->ioprob = OSPF_I_OK; ifa->rxbuf = ip->rxbuf; + ifa->use_link = ip->use_link; #ifdef OSPFv2 ifa->autype = ip->autype; @@ -475,40 +473,41 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr, if (!ipa_in_net(nb->ip, addr->prefix, addr->pxlen)) continue; - nbma = mb_alloc(p->pool, sizeof(struct nbma_node)); + nbma = mb_alloc(pool, sizeof(struct nbma_node)); nbma->ip = nb->ip; nbma->eligible = nb->eligible; add_tail(&ifa->nbma_list, NODE nbma); } - /* Add hello timer */ - ifa->hello_timer = tm_new(p->pool); + DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint); + ifa->hello_timer = tm_new(pool); ifa->hello_timer->data = ifa; ifa->hello_timer->randomize = 0; ifa->hello_timer->hook = hello_timer_hook; ifa->hello_timer->recurrent = ifa->helloint; - DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint); if (ifa->type == OSPF_IT_NBMA) { - ifa->poll_timer = tm_new(p->pool); + DBG("%s: Installing poll timer. (%u)\n", p->name, ifa->pollint); + ifa->poll_timer = tm_new(pool); ifa->poll_timer->data = ifa; ifa->poll_timer->randomize = 0; ifa->poll_timer->hook = poll_timer_hook; ifa->poll_timer->recurrent = ifa->pollint; - DBG("%s: Installing poll timer. (%u)\n", p->name, ifa->pollint); } - else - ifa->poll_timer = NULL; - ifa->wait_timer = tm_new(p->pool); - ifa->wait_timer->data = ifa; - ifa->wait_timer->randomize = 0; - ifa->wait_timer->hook = wait_timer_hook; - ifa->wait_timer->recurrent = 0; - DBG("%s: Installing wait timer. (%u)\n", p->name, ifa->waitint); - add_tail(&((struct proto_ospf *) p)->iface_list, NODE ifa); + if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA)) + { + DBG("%s: Installing wait timer. (%u)\n", p->name, ifa->waitint); + ifa->wait_timer = tm_new(pool); + ifa->wait_timer->data = ifa; + ifa->wait_timer->randomize = 0; + ifa->wait_timer->hook = wait_timer_hook; + ifa->wait_timer->recurrent = 0; + } + ifa->state = OSPF_IS_DOWN; + add_tail(&po->iface_list, NODE ifa); ifa->oa = NULL; WALK_LIST(oa, po->area_list) @@ -539,7 +538,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr, * Therefore, we store such info to lock->addr field. */ - lock = olock_new(p->pool); + lock = olock_new(pool); #ifdef OSPFv2 lock->addr = ifa->addr->prefix; #else /* OSPFv3 */ @@ -597,7 +596,7 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a) WALK_LIST_DELSAFE(ifa, ifx, po->iface_list) { if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a)) - ospf_iface_sm(ifa, ISM_DOWN); + ospf_iface_remove(ifa); /* See a note in ospf_iface_notify() */ } } @@ -675,7 +674,7 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a) WALK_LIST_DELSAFE(ifa, ifx, po->iface_list) { if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a)) - ospf_iface_sm(ifa, ISM_DOWN); + ospf_iface_remove(ifa); /* See a note in ospf_iface_notify() */ } } @@ -725,34 +724,42 @@ ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa) } } +static void +ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa) +{ + if (flags & IF_CHANGE_DOWN) + { + ospf_iface_remove(ifa); + return; + } + + if (flags & IF_CHANGE_LINK) + ospf_iface_sm(ifa, (ifa->iface->flags & IF_LINK_UP) ? ISM_UNLOOP : ISM_LOOP); + + if (flags & IF_CHANGE_MTU) + ospf_iface_change_mtu(po, ifa); +} + void -ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface) +ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface) { struct proto_ospf *po = (struct proto_ospf *) p; - DBG("%s: If notify called\n", p->name); if (iface->flags & IF_IGNORE) return; - if (flags & IF_CHANGE_DOWN) - { - struct ospf_iface *ifa, *ifx; - WALK_LIST_DELSAFE(ifa, ifx, po->iface_list) - if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface)) - ospf_iface_sm(ifa, ISM_DOWN); + /* Going up means that there are no such ifaces yet */ + if (flags & IF_CHANGE_UP) + return; - /* We use here that even shutting down iface also shuts down - the vlinks, but vlinks are not freed and stays in the - iface_list even when down */ - } + struct ospf_iface *ifa, *ifx; + WALK_LIST_DELSAFE(ifa, ifx, po->iface_list) + if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface)) + ospf_iface_notify(po, flags, ifa); - if (flags & IF_CHANGE_MTU) - { - struct ospf_iface *ifa; - WALK_LIST(ifa, po->iface_list) - if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface)) - ospf_iface_change_mtu(po, ifa); - } + /* We use here that even shutting down iface also shuts down + the vlinks, but vlinks are not freed and stays in the + iface_list even when down */ } void diff --git a/proto/ospf/iface.h b/proto/ospf/iface.h index 05f3e46e..38a81486 100644 --- a/proto/ospf/iface.h +++ b/proto/ospf/iface.h @@ -13,7 +13,7 @@ void ospf_iface_chstate(struct ospf_iface *ifa, u8 state); void ospf_iface_sm(struct ospf_iface *ifa, int event); struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what); -void ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface); +void ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface); void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a); void ospf_iface_info(struct ospf_iface *ifa); void ospf_iface_shutdown(struct ospf_iface *ifa); diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index a2a38f4b..d9d8b7c4 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -269,7 +269,7 @@ ospf_init(struct proto_config *c) p->reload_routes = ospf_reload_routes; p->accept_ra_types = RA_OPTIMAL; p->rt_notify = ospf_rt_notify; - p->if_notify = ospf_iface_notify; + p->if_notify = ospf_if_notify; p->ifa_notify = ospf_ifa_notify; p->rte_better = ospf_rte_better; p->rte_same = ospf_rte_same; @@ -728,7 +728,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) } /* POLL TIMER */ - if (oldip->pollint != newip->pollint) + if ((oldip->pollint != newip->pollint) && ifa->poll_timer) { ifa->pollint = newip->helloint; ifa->poll_timer->recurrent = ifa->pollint; @@ -758,6 +758,15 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) ospf_iface_change_mtu(po, ifa); } + /* LINK */ + if (oldip->use_link != newip->use_link) + { + ifa->use_link = newip->use_link; + + if (!(ifa->iface->flags & IF_LINK_UP)) + ospf_iface_sm(ifa, ifa->use_link ? ISM_LOOP : ISM_UNLOOP); + } + /* strict nbma */ if ((oldip->strictnbma == 0) && (newip->strictnbma != 0)) { @@ -819,7 +828,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) } /* WAIT */ - if (oldip->waitint != newip->waitint) + if ((oldip->waitint != newip->waitint) && ifa->wait_timer) { ifa->waitint = newip->waitint; if (ifa->wait_timer->expires != 0) @@ -890,7 +899,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) } if (!found) { - nb1 = mb_alloc(p->pool, sizeof(struct nbma_node)); + nb1 = mb_alloc(ifa->pool, sizeof(struct nbma_node)); nb1->ip = nb2->ip; nb1->eligible = nb2->eligible; add_tail(&ifa->nbma_list, NODE nb1); diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 34b05452..30922faf 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -162,7 +162,7 @@ struct ospf_iface struct iface *iface; /* Nest's iface */ struct ifa *addr; /* IP prefix associated with that OSPF iface */ struct ospf_area *oa; - struct object_lock *lock; + pool *pool; sock *sk; /* IP socket (for DD ...) */ list neigh_list; /* List of neigbours */ u32 cost; /* Cost of iface */ @@ -187,8 +187,8 @@ struct ospf_iface #endif ip_addr drip; /* Designated router */ - u32 drid; ip_addr bdrip; /* Backup DR */ + u32 drid; u32 bdrid; #ifdef OSPFv3 @@ -207,7 +207,7 @@ struct ospf_iface u8 stub; /* Inactive interface */ u8 state; /* Interface state machine */ #define OSPF_IS_DOWN 0 /* Not working */ -#define OSPF_IS_LOOP 1 /* Should never happen */ +#define OSPF_IS_LOOP 1 /* Iface with no link */ #define OSPF_IS_WAITING 2 /* Waiting for Wait timer */ #define OSPF_IS_PTP 3 /* PTP operational */ #define OSPF_IS_DROTHER 4 /* I'm on BCAST or NBMA and I'm not DR */ @@ -243,7 +243,8 @@ struct ospf_iface #define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */ u8 sk_spf; /* Socket is a member of SPFRouters group */ u8 sk_dr; /* Socket is a member of DRouters group */ - u32 rxbuf; + u16 rxbuf; /* Buffer size */ + u8 use_link; /* Whether iface link change is used */ }; struct ospf_md5 @@ -678,8 +679,8 @@ struct ospf_neighbor #define ISM_WAITF 1 /* Wait timer fired */ #define ISM_BACKS 2 /* Backup seen */ #define ISM_NEICH 3 /* Neighbor change */ -// #define ISM_LOOP 4 /* Loop indicated */ -// #define ISM_UNLOOP 5 /* Unloop indicated */ +#define ISM_LOOP 4 /* Link down */ +#define ISM_UNLOOP 5 /* Link up */ #define ISM_DOWN 6 /* Interface down */ /* Definitions for neighbor state machine */ @@ -751,7 +752,8 @@ struct ospf_iface_patt u32 strictnbma; u32 stub; u32 vid; - u32 rxbuf; + u16 rxbuf; + u8 use_link; #define OSPF_RXBUF_NORMAL 0 #define OSPF_RXBUF_LARGE 1 #define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */ diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 1ea1df1b..51e96c7f 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -241,9 +241,6 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) continue; - /* BIRD does not support interface loops */ - ASSERT(ifa->state != OSPF_IS_LOOP); - switch (ifa->type) { case OSPF_IT_PTP: /* RFC2328 - 12.4.1.1 */ @@ -303,11 +300,24 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) continue; ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); - ln->type = LSART_STUB; - ln->id = ipa_to_u32(ifa->addr->prefix); - ln->data = ipa_to_u32(ipa_mkmask(ifa->addr->pxlen)); - ln->metric = ifa->cost; - ln->padding = 0; + if (ifa->state == OSPF_IS_LOOP) + { + /* Host stub entry */ + ln->type = LSART_STUB; + ln->id = ipa_to_u32(ifa->addr->ip); + ln->data = 0xffffffff; + ln->metric = 0; + ln->padding = 0; + } + else + { + /* Network stub entry */ + ln->type = LSART_STUB; + ln->id = ipa_to_u32(ifa->addr->prefix); + ln->data = ipa_to_u32(ipa_mkmask(ifa->addr->pxlen)); + ln->metric = ifa->cost; + ln->padding = 0; + } i++; } @@ -384,9 +394,6 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) continue; - /* BIRD does not support interface loops */ - ASSERT(ifa->state != OSPF_IS_LOOP); - /* RFC5340 - 4.4.3.2 */ switch (ifa->type) { @@ -1144,6 +1151,13 @@ update_link_lsa(struct ospf_iface *ifa) ifa->origlink = 0; } +static inline void +lsa_put_prefix(struct proto_ospf *po, ip_addr prefix, u32 pxlen, u32 cost) +{ + put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(pxlen)), prefix, pxlen, + (pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA, cost); +} + static void * originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) { @@ -1154,7 +1168,6 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) int host_addr = 0; int net_lsa; int i = 0; - u8 flags; ASSERT(po->lsab_used == 0); lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix)); @@ -1189,12 +1202,14 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) configured_stubnet(oa, a)) continue; - flags = (a->pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA; - put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(a->pxlen)), - a->ip, a->pxlen, flags, ifa->cost); + if (ifa->state == OSPF_IS_LOOP) + lsa_put_prefix(po, a->ip, MAX_PREFIX_LENGTH, 0); + else + lsa_put_prefix(po, a->prefix, a->pxlen, ifa->cost); i++; - if (flags & OPT_PX_LA) + if ((ifa->state == OSPF_IS_LOOP) || + (a->pxlen == MAX_PREFIX_LENGTH)) host_addr = 1; } } @@ -1203,8 +1218,7 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) which will be used as a vlink endpoint. */ if (oa->ac && !EMPTY_LIST(oa->ac->vlink_list) && !host_addr && vlink_addr) { - put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(MAX_PREFIX_LENGTH)), - vlink_addr->ip, MAX_PREFIX_LENGTH, OPT_PX_LA, 0); + lsa_put_prefix(po, vlink_addr->ip, MAX_PREFIX_LENGTH, 0); i++; } @@ -1213,9 +1227,7 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) WALK_LIST(sn, oa->ac->stubnet_list) if (!sn->hidden) { - flags = (sn->px.len < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA; - put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(sn->px.len)), - sn->px.addr, sn->px.len, flags, sn->cost); + lsa_put_prefix(po, sn->px.addr, sn->px.len, sn->cost); i++; }