diff --git a/TODO b/TODO index 6b74e758..0945aac4 100644 --- a/TODO +++ b/TODO @@ -51,7 +51,5 @@ OSPF - automatic generation of external route tags (RFC1403) - RFC1587 NSSA areas - RFC2370 opaque LSA's - - respect interface MTU and try not to create larger packets unless unavoidable - AS external LSAs are in topology database of every OSPF Area - Limit export rate of external LSAs (like Gated does) - - Maximal distance is just 0xffff, but 2328 requires 0xffffff diff --git a/doc/bird.sgml b/doc/bird.sgml index 92db2921..00b449da 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1034,6 +1034,16 @@ protocol ospf <name> { <ip> eligible; }; }; + virtual link <id> + { + hello <num>; + poll <num>; + retransmit <num>; + wait <num>; + dead count <num>; + authentication [none|simple]; + password "<text>"; + }; }; } @@ -1068,6 +1078,10 @@ protocol ospf <name> { interface pattern Defines that the specified interfaces belong to the area being defined. + virtual link id + Virtual link to router with the router id. This item cannot be in the + backbone area (ID 0). + cost num Specifies output cost (metric) of an interface. Default value is 10. @@ -1163,7 +1177,7 @@ protocol ospf MyOSPF { ospf_metric1 = 100; accept; } - reject; + reject; }; area 0.0.0.0 { tick 8; @@ -1185,6 +1199,10 @@ protocol ospf MyOSPF { }; area 120 { stub yes; + networks { + 172.16.1.0/24; + 172.16.2.0/24 hidden; + } interface "-arc0" , "arc*" { type nonbroadcast; authentication none; diff --git a/nest/config.Y b/nest/config.Y index fa8b5e66..4f9b46b6 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -25,7 +25,7 @@ CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFA CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREIMPORT) CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, - RIP, OSPF, OSPF_EXT, OSPF_IA, BGP, PIPE) + RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE) CF_ENUM(T_ENUM_RTC, RTC_, UNICAST, BROADCAST, MULTICAST, ANYCAST) CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT) diff --git a/nest/route.h b/nest/route.h index 14ac9e70..0de0e0f7 100644 --- a/nest/route.h +++ b/nest/route.h @@ -253,9 +253,10 @@ typedef struct rta { #define RTS_RIP 6 /* RIP route */ #define RTS_OSPF 7 /* OSPF route */ #define RTS_OSPF_IA 8 /* OSPF inter-area route */ -#define RTS_OSPF_EXT 9 /* OSPF external route */ -#define RTS_BGP 10 /* BGP route */ -#define RTS_PIPE 11 /* Inter-table wormhole */ +#define RTS_OSPF_EXT1 9 /* OSPF external route type 1 */ +#define RTS_OSPF_EXT2 10 /* OSPF external route type 2 */ +#define RTS_BGP 11 /* BGP route */ +#define RTS_PIPE 12 /* Inter-table wormhole */ #define RTC_UNICAST 0 #define RTC_BROADCAST 1 diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 14a2480f..cbece881 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -705,7 +705,8 @@ rta_dump(rta *a) { static char *rts[] = { "RTS_DUMMY", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE", "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP", - "RTS_OSPF", "RTS_OSPF_EXT", "RTS_OSPF_IA", "RTS_BGP" }; + "RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1", + "RTS_OSPF_EXT2", "RTS_BGP" }; static char *rtc[] = { "", " BC", " MC", " AC" }; static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" }; diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 3cb99e00..459335fa 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -560,7 +560,7 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p ea->count = 4; bgp_set_attr(ea->attrs, pool, BA_ORIGIN, - (rta->source == RTS_OSPF_EXT) ? ORIGIN_INCOMPLETE : ORIGIN_IGP); + ((rta->source == RTS_OSPF_EXT1) || (rta->source == RTS_OSPF_EXT2)) ? ORIGIN_INCOMPLETE : ORIGIN_IGP); if (p->is_internal) bgp_set_attr(ea->attrs+1, pool, BA_AS_PATH, 0); diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 3a9904fb..b484d79c 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -17,7 +17,7 @@ static struct ospf_area_config *this_area; static struct iface_patt *this_ipatt; #define OSPF_PATT ((struct ospf_iface_patt *) this_ipatt) static struct nbma_node *this_nbma; -static struct area_net *this_pref; +static struct area_net_config *this_pref; CF_DECLS @@ -25,7 +25,7 @@ CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG) CF_KEYWORDS(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, RETRANSMIT) CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, NONBROADCAST, POINTOPOINT, TYPE) CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, PASSWORD, STRICT) -CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN) +CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, LINK) %type opttext @@ -78,8 +78,46 @@ ospf_area_item: | TICK expr { this_area->tick = $2 ; if($2<=0) cf_error("Tick must be greater than zero"); } | NETWORKS '{' pref_list '}' | INTERFACE ospf_iface_list + | ospf_vlink '}' ; +ospf_vlink: ospf_vlink_start ospf_vlink_opts + ; + +ospf_vlink_opts: + /* empty */ + | ospf_vlink_opts ospf_vlink_item ';' + ; + +ospf_vlink_item: + HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); } + | POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error("Poll int must be greater than zero"); } + | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); } + | TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); } + | WAIT expr { OSPF_PATT->waitint = $2 ; } + | DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); } + | AUTHENTICATION NONE { OSPF_PATT->autype = AU_NONE ; } + | AUTHENTICATION SIMPLE { OSPF_PATT->autype = AU_SIMPLE ; } + | PASSWORD TEXT { memcpy(OSPF_PATT->password, $2, 8); } + ; + +ospf_vlink_start: VIRTUAL LINK '{' + { + if (this_area->areaid == 0) cf_error("Virtual link cannot be in backbone"); + this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt)); + add_tail(&this_area->patt_list, NODE this_ipatt); + OSPF_PATT->cost = COST_D; + OSPF_PATT->helloint = HELLOINT_D; + OSPF_PATT->pollint = POLLINT_D; + OSPF_PATT->rxmtint = RXMTINT_D; + OSPF_PATT->inftransdelay = INFTRANSDELAY_D; + OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D; + OSPF_PATT->deadc = DEADC_D; + OSPF_PATT->type = OSPF_IT_VLINK; + OSPF_PATT->autype = AU_NONE; + } +; + ospf_iface_item: COST expr { OSPF_PATT->cost = $2 ; if (($2<=0) || ($2>65535)) cf_error("Cost must be in range 1-65535"); } | HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); } @@ -95,8 +133,8 @@ ospf_iface_item: | STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; } | STUB bool { OSPF_PATT->stub = $2 ; } | NEIGHBORS '{' ipa_list '}' - | AUTHENTICATION NONE { OSPF_PATT->autype=AU_NONE ; } - | AUTHENTICATION SIMPLE { OSPF_PATT->autype=AU_SIMPLE ; } + | AUTHENTICATION NONE { OSPF_PATT->autype = AU_NONE ; } + | AUTHENTICATION SIMPLE { OSPF_PATT->autype = AU_SIMPLE ; } | PASSWORD TEXT { memcpy(OSPF_PATT->password, $2, 8); } ; @@ -111,7 +149,7 @@ pref_item: pref_el: prefix ';' { - this_pref = cfg_allocz(sizeof(struct area_net)); + this_pref = cfg_allocz(sizeof(struct area_net_config)); add_tail(&this_area->net_list, NODE this_pref); this_pref->px.addr = $1.addr; this_pref->px.len = $1.len; @@ -120,7 +158,7 @@ pref_el: prefix ';' pref_hid: prefix HIDDEN ';' { - this_pref = cfg_allocz(sizeof(struct area_net)); + this_pref = cfg_allocz(sizeof(struct area_net_config)); add_tail(&this_area->net_list, NODE this_pref); this_pref->px.addr = $1.addr; this_pref->px.len = $1.len; @@ -172,7 +210,7 @@ ospf_iface_start: OSPF_PATT->strictnbma = 0; OSPF_PATT->stub = 0; init_list(&OSPF_PATT->nbma_list); - OSPF_PATT->autype=AU_NONE; + OSPF_PATT->autype = AU_NONE; } ; diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index bff8beff..c345858b 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -39,14 +39,14 @@ ospf_dbdes_send(struct ospf_neighbor *n) pkt = (struct ospf_dbdes_packet *) (ifa->ip_sk->tbuf); op = (struct ospf_packet *) pkt; fill_ospf_pkt_hdr(ifa, pkt, DBDES_P); - pkt->iface_mtu = htons(ifa->iface->mtu); /* FIXME NOT for VLINK! */ + pkt->iface_mtu = htons(ifa->iface->mtu); pkt->options = ifa->options; pkt->imms = n->myimms; pkt->ddseq = htonl(n->dds); length = sizeof(struct ospf_dbdes_packet); op->length = htons(length); ospf_pkt_finalize(ifa, op); - sk_send_to(ifa->ip_sk, length, n->ip, OSPF_PROTO); + ospf_send_to(ifa->ip_sk, length, n->ip); OSPF_TRACE(D_PACKETS, "DB_DES (I) sent to %I via %s.", n->ip, ifa->iface->name); break; @@ -79,20 +79,26 @@ ospf_dbdes_send(struct ospf_neighbor *n) for (; i > 0; i--) { struct top_hash_entry *en; - en = (struct top_hash_entry *) sn; - htonlsah(&(en->lsa), lsa); - DBG("Working on: %d\n", i); - DBG("\tX%01x %-1I %-1I %p\n", en->lsa.type, en->lsa.id, - en->lsa.rt, en->lsa_body); + + if ((n->ifa->type != OSPF_IT_VLINK) && (en->lsa.type != LSA_T_EXT)) + { + htonlsah(&(en->lsa), lsa); + DBG("Working on: %d\n", i); + DBG("\tX%01x %-1I %-1I %p\n", en->lsa.type, en->lsa.id, + en->lsa.rt, en->lsa_body); + + lsa++; + } + else i++; /* No lsa added */ if (sn == STAIL(n->ifa->oa->lsal)) - { - i--; - break; /* Should set some flag? */ - } + { + i--; + break; + } + sn = sn->next; - lsa++; } if (sn == STAIL(n->ifa->oa->lsal)) @@ -130,7 +136,7 @@ ospf_dbdes_send(struct ospf_neighbor *n) memcpy(ifa->ip_sk->tbuf, n->ldbdes, length); /* Copy last sent packet again */ - sk_send_to(ifa->ip_sk, length, n->ip, OSPF_PROTO); + ospf_send_to(ifa->ip_sk, length, n->ip); if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */ @@ -245,8 +251,6 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps, ps->imms.byte); break; } - if(ps->imms.bit.i) log("FUCK"); - case NEIGHBOR_EXCHANGE: if ((ps->imms.byte == n->imms.byte) && (ps->options == n->options) && (ntohl(ps->ddseq) == n->ddr)) diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index a318a674..c8059730 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -166,16 +166,20 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) struct ospf_hello_packet *pkt; struct ospf_packet *op; struct proto *p; - struct ospf_neighbor *neigh; + struct ospf_neighbor *neigh, *n1; u16 length; u32 *pp; - int i; + int i, send; + struct nbma_node *nb; if (timer == NULL) ifa = dirn->ifa; else ifa = (struct ospf_iface *) timer->data; + if (ifa->state == OSPF_IS_DOWN) + return; + if (ifa->stub) return; /* Don't send any packet on stub iface */ @@ -184,13 +188,13 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) p->name, ifa->iface->name); /* Now we should send a hello packet */ /* First a common packet header */ - if (ifa->type != OSPF_IT_NBMA) + if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_VLINK)) { - pkt = (struct ospf_hello_packet *) (ifa->hello_sk->tbuf); + pkt = (struct ospf_hello_packet *) (ifa->ip_sk->tbuf); } else { - pkt = (struct ospf_hello_packet *) (ifa->ip_sk->tbuf); + pkt = (struct ospf_hello_packet *) (ifa->hello_sk->tbuf); } /* Now fill ospf_hello header */ @@ -224,56 +228,55 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) ospf_pkt_finalize(ifa, op); /* And finally send it :-) */ - if (ifa->type != OSPF_IT_NBMA) + switch(ifa->type) { - sk_send(ifa->hello_sk, length); - } - else /* NBMA */ - { - struct ospf_neighbor *n1; - struct nbma_node *nb; - int send; - - if (timer == NULL) /* Response to received hello */ - { - sk_send_to(ifa->ip_sk, length, dirn->ip, OSPF_PROTO); - } - else - { - int toall = 0; - int meeli = 0; - if (ifa->state > OSPF_IS_DROTHER) - toall = 1; - if (ifa->priority > 0) - meeli = 1; - - WALK_LIST(nb, ifa->nbma_list) + case OSPF_IT_NBMA: + if (timer == NULL) /* Response to received hello */ { - send = 1; - WALK_LIST(n1, ifa->neigh_list) - { - if (ipa_compare(nb->ip, n1->ip) == 0) - { - send = 0; - break; - } - } - if ((poll == 1) && (send)) - { - if (toall || (meeli && nb->eligible)) - sk_send_to(ifa->ip_sk, length, nb->ip, OSPF_PROTO); - } + ospf_send_to(ifa->ip_sk, length, dirn->ip); } - if (poll == 0) + else { - WALK_LIST(n1, ifa->neigh_list) - { - if (toall || (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid) || - (meeli && (n1->priority > 0))) - sk_send_to(ifa->ip_sk, length, n1->ip, OSPF_PROTO); - } + int toall = 0; + int meeli = 0; + if (ifa->state > OSPF_IS_DROTHER) + toall = 1; + if (ifa->priority > 0) + meeli = 1; + + WALK_LIST(nb, ifa->nbma_list) + { + send = 1; + WALK_LIST(n1, ifa->neigh_list) + { + if (ipa_compare(nb->ip, n1->ip) == 0) + { + send = 0; + break; + } + } + if ((poll == 1) && (send)) + { + if (toall || (meeli && nb->eligible)) + ospf_send_to(ifa->ip_sk, length, nb->ip); + } + } + if (poll == 0) + { + WALK_LIST(n1, ifa->neigh_list) + { + if (toall || (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid) || + (meeli && (n1->priority > 0))) + ospf_send_to(ifa->ip_sk, length, n1->ip); + } + } } - } + break; + case OSPF_IT_VLINK: + ospf_send_to(ifa->ip_sk, length, ifa->vip); + break; + default: + sk_send(ifa->hello_sk, length); } OSPF_TRACE(D_PACKETS, "Hello sent via %s", ifa->iface->name); } diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 71b907ac..bd8cddd9 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -117,24 +117,34 @@ ospf_iface_down(struct ospf_iface *ifa) { struct ospf_neighbor *n, *nx; struct proto *p = &ifa->proto->proto; + struct proto_ospf *po = ifa->proto; + struct ospf_iface *iff; WALK_LIST_DELSAFE(n, nx, ifa->neigh_list) { OSPF_TRACE(D_EVENTS, "Removing neighbor %I", n->ip); ospf_neigh_remove(n); } - rem_node(NODE ifa); - rfree(ifa->hello_sk); rfree(ifa->dr_sk); rfree(ifa->ip_sk); - rfree(ifa->wait_timer); - rfree(ifa->hello_timer); - rfree(ifa->poll_timer); - - rfree(ifa->lock); - mb_free(ifa); + if(ifa->type == OSPF_IT_VLINK) + { + ifa->ip_sk = NULL; + ifa->iface = NULL; + return; + } + else + { + rfree(ifa->wait_timer); + rfree(ifa->hello_timer); + rfree(ifa->poll_timer); + rfree(ifa->lock); + rem_node(NODE ifa); + mb_free(ifa); + } + /* FIXME: Should I down related VLINK also? */ } /** @@ -142,7 +152,7 @@ ospf_iface_down(struct ospf_iface *ifa) * @ifa: OSPF interface * @event: event comming to state machine * - * This fully respect 9.3 of RFC 2328 except we don't use %LOOP state of + * This fully respects 9.3 of RFC 2328 except we don't use %LOOP state of * interface. */ void @@ -260,6 +270,7 @@ ospf_open_ip_socket(struct ospf_iface *ifa) ipsk->saddr = ifa->iface->addr->ip; ipsk->tos = IP_PREC_INTERNET_CONTROL; ipsk->ttl = 1; + if (ifa->type == OSPF_IT_VLINK) ipsk->ttl = 255; ipsk->rx_hook = ospf_rx_hook; ipsk->tx_hook = ospf_tx_hook; ipsk->err_hook = ospf_err_hook; @@ -307,6 +318,8 @@ ospf_iface_add(struct object_lock *lock) struct iface *iface = lock->iface; struct proto *p = &po->proto; + ifa->lock = lock; + ifa->ioprob = OSPF_I_OK; if (ifa->type != OSPF_IT_NBMA) @@ -330,12 +343,113 @@ ospf_iface_add(struct object_lock *lock) ifa->stub = 1; ifa->ioprob += OSPF_I_IP; } - ifa->lock = lock; ifa->state = OSPF_IS_DOWN; ospf_iface_sm(ifa, ISM_UP); } +void +ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ospf_area_config *ac, struct ospf_iface_patt *ip) +{ + struct proto *p = &po->proto; + struct ospf_iface *ifa; + struct nbma_node *nbma, *nb; + struct object_lock *lock; + struct ospf_area *oa; + + ifa = mb_allocz(p->pool, sizeof(struct ospf_iface)); + ifa->proto = po; + ifa->iface = iface; + + ifa->an = ac->areaid; + ifa->cost = ip->cost; + ifa->rxmtint = ip->rxmtint; + ifa->inftransdelay = ip->inftransdelay; + ifa->priority = ip->priority; + ifa->helloint = ip->helloint; + ifa->pollint = ip->pollint; + ifa->strictnbma = ip->strictnbma; + ifa->waitint = ip->waitint; + ifa->deadc = ip->deadc; + ifa->stub = ip->stub; + ifa->autype = ip->autype; + memcpy(ifa->aukey, ip->password, 8); + ifa->options = 2; /* FIXME what options? */ + + if (ip->type == OSPF_IT_UNDEF) + ifa->type = ospf_iface_clasify(ifa->iface); + else + ifa->type = ip->type; + + init_list(&ifa->neigh_list); + init_list(&ifa->nbma_list); + WALK_LIST(nb, ip->nbma_list) + { + nbma = mb_alloc(p->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); + 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); + 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); + ifa->state = OSPF_IS_DOWN; + + WALK_LIST(oa, po->area_list) + { + if (oa->areaid == ifa->an) + break; + } + + if (EMPTY_LIST(po->area_list) || (oa->areaid != ifa->an)) /* New area */ + bug("Cannot add any area to accepted Interface"); + else + ifa->oa = oa; + + if (ifa->type == OSPF_IT_VLINK) + { + ifa->oa = po->backbone; + ifa->voa = oa; + ifa->vid = ip->vid; + return; /* Don't lock, don't add sockets */ + } + + lock = olock_new(p->pool); + lock->addr = AllSPFRouters; + lock->type = OBJLOCK_IP; + lock->port = OSPF_PROTO; + lock->iface = iface; + lock->data = ifa; + lock->hook = ospf_iface_add; + + olock_acquire(lock); +} + void ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface) { @@ -344,8 +458,6 @@ ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface) struct ospf_area_config *ac; struct ospf_iface_patt *ip = NULL; struct ospf_iface *ifa; - struct object_lock *lock; - struct nbma_node *nbma, *nb; struct ospf_area *oa; DBG("%s: If notify called\n", p->name); @@ -364,90 +476,7 @@ ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface) if (ip) { OSPF_TRACE(D_EVENTS, "Using interface %s.", iface->name); - - ifa = mb_allocz(p->pool, sizeof(struct ospf_iface)); - ifa->proto = po; - ifa->iface = iface; - - ifa->an = ac->areaid; - ifa->cost = ip->cost; - ifa->rxmtint = ip->rxmtint; - ifa->inftransdelay = ip->inftransdelay; - ifa->priority = ip->priority; - ifa->helloint = ip->helloint; - ifa->pollint = ip->pollint; - ifa->strictnbma = ip->strictnbma; - ifa->waitint = ip->waitint; - ifa->deadc = ip->deadc; - ifa->stub = ip->stub; - ifa->autype = ip->autype; - memcpy(ifa->aukey, ip->password, 8); - ifa->options = 2; /* FIXME what options? */ - - if (ip->type == OSPF_IT_UNDEF) - ifa->type = ospf_iface_clasify(ifa->iface); - else - ifa->type = ip->type; - - init_list(&ifa->neigh_list); - init_list(&ifa->nbma_list); - WALK_LIST(nb, ip->nbma_list) - { - nbma = mb_alloc(p->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); - 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); - 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); - ifa->state = OSPF_IS_DOWN; - - lock = olock_new(p->pool); - lock->addr = AllSPFRouters; - lock->type = OBJLOCK_IP; - lock->port = OSPF_PROTO; - lock->iface = iface; - lock->data = ifa; - lock->hook = ospf_iface_add; - - WALK_LIST(NODE oa, po->area_list) - { - if (oa->areaid == ifa->an) - break; - } - - if (EMPTY_LIST(po->area_list) || (oa->areaid != ifa->an)) /* New area */ - bug("Cannot add any area to accepted Interface"); - else - ifa->oa = oa; - - olock_acquire(lock); + ospf_iface_new(po, iface, ac, ip); } } diff --git a/proto/ospf/iface.h b/proto/ospf/iface.h index 2c03d2a7..556024b5 100644 --- a/proto/ospf/iface.h +++ b/proto/ospf/iface.h @@ -16,5 +16,6 @@ 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_iface_info(struct ospf_iface *ifa); void ospf_iface_shutdown(struct ospf_iface *ifa); +void ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ospf_area_config *ac, struct ospf_iface_patt *ip); #endif /* _BIRD_OSPF_IFACE_H_ */ diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index 7d7238c2..bdad8665 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -78,16 +78,16 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) if (ifa->type == OSPF_IT_BCAST) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - sk_send_to(sk, len, AllSPFRouters, OSPF_PROTO); + ospf_send_to(sk, len, AllSPFRouters); else - sk_send_to(sk, len, AllDRouters, OSPF_PROTO); + ospf_send_to(sk, len, AllDRouters); } else { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); + ospf_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); else - sk_send_to_bdr(sk, len, ifa); + ospf_send_to_bdr(sk, len, ifa); } fill_ospf_pkt_hdr(n->ifa, pk, LSACK_P); @@ -104,16 +104,16 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) { - sk_send_to(sk, len, AllSPFRouters, OSPF_PROTO); + ospf_send_to(sk, len, AllSPFRouters); } else { - sk_send_to(sk, len, AllDRouters, OSPF_PROTO); + ospf_send_to(sk, len, AllDRouters); } } else { - sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); + ospf_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); } } diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index e0871c88..02718da8 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -13,8 +13,8 @@ flush_lsa(struct top_hash_entry *en, struct ospf_area *oa) { struct proto *p = &oa->po->proto; OSPF_TRACE(D_EVENTS, - "Going to remove node Type: %u, Id: %I, Rt: %I, Age: %u", - en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.age); + "Going to remove node Type: %u, Id: %I, Rt: %I, Age: %u, SN: 0x%x", + en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.age, en->lsa.sn); s_rem_node(SNODE en); if (en->lsa_body != NULL) mb_free(en->lsa_body); @@ -56,6 +56,7 @@ ospf_age(struct ospf_area *oa) en->dist = LSINFINITY; en->nhi = NULL; en->nh = ipa_from_u32(0); + en->lb = ipa_from_u32(0); DBG("Infinitying Type: %u, Id: %I, Rt: %I\n", en->lsa.type, en->lsa.id, en->lsa.rt); } @@ -164,8 +165,8 @@ htonlsab(void *h, void *n, u8 type, u16 len) case LSA_T_SUM_NET: case LSA_T_SUM_RT: { - struct ospf_lsa_summ *hs, *ns; - struct ospf_lsa_summ_net *hn, *nn; + struct ospf_lsa_sum *hs, *ns; + union ospf_lsa_sum_tm *hn, *nn; hs = h; ns = n; @@ -173,15 +174,16 @@ htonlsab(void *h, void *n, u8 type, u16 len) ns->netmask = hs->netmask; ipa_hton(ns->netmask); - hn = (struct ospf_lsa_summ_net *) (hs + 1); - nn = (struct ospf_lsa_summ_net *) (ns + 1); + hn = (union ospf_lsa_sum_tm *) (hs + 1); + nn = (union ospf_lsa_sum_tm *) (ns + 1); - for (i = 0; i < ((len - sizeof(struct ospf_lsa_summ)) / - sizeof(struct ospf_lsa_summ_net)); i++) + for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) / + sizeof(union ospf_lsa_sum_tm)); i++) { - (nn + i)->tos = (hn + i)->tos; - (nn + i)->metric = htons((hn + i)->metric); - (nn + i)->padding = 0; + (nn + i)->metric = htonl((hn + i)->metric); + //(nn + i)->tos = (hn + i)->tos; + //(nn + i)->metric = htons((hn + i)->metric); + //(nn + i)->padding = 0; } break; } @@ -202,9 +204,10 @@ htonlsab(void *h, void *n, u8 type, u16 len) for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) / sizeof(struct ospf_lsa_ext_tos)); i++) { - (nt + i)->etos = (ht + i)->etos; - (nt + i)->padding = 0; - (nt + i)->metric = htons((ht + i)->metric); + (nt + i)->etm.metric = htonl((ht + i)->etm.metric); + //(nt + i)->tos = (ht + i)->tos; + //(nt + i)->padding = 0; + //(nt + i)->metric = htons((ht + i)->metric); (nt + i)->fwaddr = (ht + i)->fwaddr; ipa_hton((nt + i)->fwaddr); (nt + i)->tag = htonl((ht + i)->tag); @@ -262,8 +265,8 @@ ntohlsab(void *n, void *h, u8 type, u16 len) case LSA_T_SUM_NET: case LSA_T_SUM_RT: { - struct ospf_lsa_summ *hs, *ns; - struct ospf_lsa_summ_net *hn, *nn; + struct ospf_lsa_sum *hs, *ns; + union ospf_lsa_sum_tm *hn, *nn; hs = h; ns = n; @@ -271,15 +274,16 @@ ntohlsab(void *n, void *h, u8 type, u16 len) hs->netmask = ns->netmask; ipa_ntoh(hs->netmask); - hn = (struct ospf_lsa_summ_net *) (hs + 1); - nn = (struct ospf_lsa_summ_net *) (ns + 1); + hn = (union ospf_lsa_sum_tm *) (hs + 1); + nn = (union ospf_lsa_sum_tm *) (ns + 1); - for (i = 0; i < ((len - sizeof(struct ospf_lsa_summ)) / - sizeof(struct ospf_lsa_summ_net)); i++) + for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) / + sizeof(union ospf_lsa_sum_tm)); i++) { - (hn + i)->tos = (nn + i)->tos; - (hn + i)->metric = ntohs((nn + i)->metric); - (hn + i)->padding = 0; + (hn + i)->metric = ntohl((nn + i)->metric); + //(hn + i)->tos = (nn + i)->tos; + //(hn + i)->metric = ntohs((nn + i)->metric); + //(hn + i)->padding = 0; } break; } @@ -300,9 +304,10 @@ ntohlsab(void *n, void *h, u8 type, u16 len) for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) / sizeof(struct ospf_lsa_ext_tos)); i++) { - (ht + i)->etos = (nt + i)->etos; - (ht + i)->padding = 0; - (ht + i)->metric = ntohs((nt + i)->metric); + (ht + i)->etm.metric = ntohl((nt + i)->etm.metric); + //(ht + i)->etos = (nt + i)->etos; + //(ht + i)->padding = 0; + //(ht + i)->metric = ntohs((nt + i)->metric); (ht + i)->fwaddr = (nt + i)->fwaddr; ipa_ntoh((ht + i)->fwaddr); (ht + i)->tag = ntohl((nt + i)->tag); diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index 98d2d06c..23622fc4 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -60,7 +60,7 @@ ospf_lsreq_send(struct ospf_neighbor *n) i) * sizeof(struct ospf_lsreq_header); op->length = htons(length); ospf_pkt_finalize(n->ifa, op); - sk_send_to(n->ifa->ip_sk, length, n->ip, OSPF_PROTO); + ospf_send_to(n->ifa->ip_sk, length, n->ip); OSPF_TRACE(D_PACKETS, "LS request sent to: %I", n->rid); } diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 2211891f..0cefdd13 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -197,17 +197,17 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn, if (ifa->type == OSPF_IT_NBMA) { if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) - sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); + ospf_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); else - sk_send_to_bdr(sk, len, ifa); + ospf_send_to_bdr(sk, len, ifa); } else { if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR) || (ifa->type == OSPF_IT_PTP)) - sk_send_to(sk, len, AllSPFRouters, OSPF_PROTO); + ospf_send_to(sk, len, AllSPFRouters); else - sk_send_to(sk, len, AllDRouters, OSPF_PROTO); + ospf_send_to(sk, len, AllDRouters); } } } @@ -253,7 +253,7 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) op->length = htons(len - SIPH); ospf_pkt_finalize(n->ifa, op); - sk_send_to(n->ifa->ip_sk, len - SIPH, n->ip, OSPF_PROTO); + ospf_send_to(n->ifa->ip_sk, len - SIPH, n->ip); OSPF_TRACE(D_PACKETS, "LS upd sent to %I (%d LSAs)", n->ip, lsano); DBG("LSupd: next packet\n"); @@ -277,7 +277,7 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) ospf_pkt_finalize(n->ifa, op); OSPF_TRACE(D_PACKETS, "LS upd sent to %I (%d LSAs)", n->ip, lsano); - sk_send_to(n->ifa->ip_sk, len - SIPH, n->ip, OSPF_PROTO); + ospf_send_to(n->ifa->ip_sk, len - SIPH, n->ip); } } diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index aca74cb2..a1049e1b 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -1,7 +1,7 @@ /* * BIRD -- OSPF * - * (c) 1999 - 2000 Ondrej Filip + * (c) 1999--2004 Ondrej Filip * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -75,6 +75,31 @@ static int ospf_rte_same(struct rte *new, struct rte *old); static void area_disp(timer *timer); static void ospf_disp(timer *timer); +static void +ospf_area_initfib(struct fib_node *fn) +{ + struct area_net *an = (struct area_net *) fn; + an->hidden = 0; + an->active = -1; /* Force to regenerate summary lsa */ + /* ac->oldactive will be rewritten by ospf_rt_spf() */ +} + +static void +add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac) +{ + struct proto_ospf *po = oa->po; + struct proto *p = &po->proto; + struct area_net_config *anet; + struct area_net *antmp; + + fib_init(&oa->net_fib, p->pool, sizeof(struct area_net), 16, ospf_area_initfib); + + WALK_LIST(anet, ac->net_list) + { + antmp = (struct area_net *) fib_get(&oa->net_fib, &anet->px.addr, anet->px.len); + antmp->hidden = anet->hidden; + } +} static int ospf_start(struct proto *p) @@ -83,13 +108,12 @@ ospf_start(struct proto *p) struct ospf_config *c = (struct ospf_config *) (p->cf); struct ospf_area_config *ac; struct ospf_area *oa; - struct area_net *anet, *antmp; po->rfc1583 = c->rfc1583; po->ebit = 0; po->tick = c->tick; - po->disp_timer = tm_new(po->proto.pool); + po->disp_timer = tm_new(p->pool); po->disp_timer->data = po; po->disp_timer->randomize = 0; po->disp_timer->hook = ospf_disp; @@ -97,8 +121,7 @@ ospf_start(struct proto *p) tm_start(po->disp_timer, 1); init_list(&(po->iface_list)); init_list(&(po->area_list)); - fib_init(&po->rtf[0], p->pool, sizeof(ort), 16, ospf_rt_initort); - fib_init(&po->rtf[1], p->pool, sizeof(ort), 16, ospf_rt_initort); + fib_init(&po->rtf, p->pool, sizeof(ort), 16, ospf_rt_initort); po->areano = 0; if (EMPTY_LIST(c->area_list)) { @@ -108,7 +131,7 @@ ospf_start(struct proto *p) WALK_LIST(ac, c->area_list) { - oa = mb_allocz(po->proto.pool, sizeof(struct ospf_area)); + oa = mb_allocz(p->pool, sizeof(struct ospf_area)); add_tail(&po->area_list, NODE oa); po->areano++; oa->stub = ac->stub; @@ -118,20 +141,27 @@ ospf_start(struct proto *p) s_init_list(&(oa->lsal)); oa->rt = NULL; oa->po = po; - oa->disp_timer = tm_new(po->proto.pool); + oa->disp_timer = tm_new(p->pool); oa->disp_timer->data = oa; oa->disp_timer->randomize = 0; oa->disp_timer->hook = area_disp; oa->disp_timer->recurrent = oa->tick; tm_start(oa->disp_timer, 2); - init_list(&oa->net_list); - WALK_LIST(anet, ac->net_list) + add_area_nets(oa, ac); + fib_init(&oa->rtr, p->pool, sizeof(ort), 16, ospf_rt_initort); + if (oa->areaid == 0) po->backbone = oa; + } + + /* Add all virtual links as interfaces */ + if(po->backbone) + { + struct ospf_iface_patt *ipatt; + WALK_LIST(ac, c->area_list) { - antmp = mb_allocz(po->proto.pool, sizeof(struct area_net)); - antmp->px.addr = anet->px.addr; - antmp->px.len = anet->px.len; - antmp->hidden = anet->hidden; - add_tail(&oa->net_list, NODE antmp); + WALK_LIST(ipatt, ac->patt_list) + { + if (ipatt->type == OSPF_IT_VLINK) ospf_iface_new(po, NULL, ac, ipatt); + } } } return PS_UP; @@ -189,42 +219,21 @@ ospf_init(struct proto_config *c) static int ospf_rte_better(struct rte *new, struct rte *old) { - /* FIXME this is wrong */ if (new->u.ospf.metric1 == LSINFINITY) return 0; - /* External paths are always longer that internal */ - if (((new->attrs->source == RTS_OSPF) - || (new->attrs->source == RTS_OSPF_IA)) - && (old->attrs->source == RTS_OSPF_EXT)) - return 1; - if (((old->attrs->source == RTS_OSPF) - || (old->attrs->source == RTS_OSPF_IA)) - && (new->attrs->source == RTS_OSPF_EXT)) - return 0; + if(new->attrs->source < old->attrs->source) return 1; + if(new->attrs->source > old->attrs->source) return 0; - if (new->u.ospf.metric2 < old->u.ospf.metric2) + if(new->attrs->source == RTS_OSPF_EXT2) { - if (old->u.ospf.metric2 == LSINFINITY) - return 0; /* Old is E1, new is E2 */ - return 1; /* Both are E2 */ + if(new->u.ospf.metric2 < old->u.ospf.metric2) return 1; + if(new->u.ospf.metric2 > old->u.ospf.metric2) return 0; } - if (new->u.ospf.metric2 > old->u.ospf.metric2) - { - if (new->u.ospf.metric2 == LSINFINITY) - return 1; /* New is E1, old is E2 */ - return 0; /* Both are E2 */ - } - - /* - * E2 metrics are the same. It means that: - * 1) Paths are E2 with same metric - * 2) Paths are E1. - */ - if (new->u.ospf.metric1 < old->u.ospf.metric1) return 1; + return 0; /* Old is shorter or same */ } @@ -466,29 +475,30 @@ ospf_get_status(struct proto *p, byte * buf) static void ospf_get_route_info(rte * rte, byte * buf, ea_list * attrs UNUSED) { - char met = ' '; - char type = ' '; + char *type = ""; - if (rte->attrs->source == RTS_OSPF_EXT) + switch(rte->attrs->source) { - met = '1'; - type = 'E'; - + case RTS_OSPF: + type = "I"; + break; + case RTS_OSPF_IA: + type = "IA"; + break; + case RTS_OSPF_EXT1: + type = "E1"; + break; + case RTS_OSPF_EXT2: + type = "E2"; + break; } - if (rte->u.ospf.metric2 != LSINFINITY) - met = '2'; - if (rte->attrs->source == RTS_OSPF_IA) - type = 'A'; - if (rte->attrs->source == RTS_OSPF) - type = 'I'; - buf += bsprintf(buf, " %c", type); - if (met != ' ') - buf += bsprintf(buf, "%c", met); + + buf += bsprintf(buf, " %s", type); buf += bsprintf(buf, " (%d/%d", rte->pref, rte->u.ospf.metric1); - if (rte->u.ospf.metric2 != LSINFINITY) + if (rte->attrs->source == RTS_OSPF_EXT2) buf += bsprintf(buf, "/%d", rte->u.ospf.metric2); buf += bsprintf(buf, ")"); - if (rte->attrs->source == RTS_OSPF_EXT && rte->u.ospf.tag) + if ((rte->attrs->source == RTS_OSPF_EXT2 || rte->attrs->source == RTS_OSPF_EXT1) && rte->u.ospf.tag) { buf += bsprintf(buf, " [%x]", rte->u.ospf.tag); } @@ -578,19 +588,8 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) } /* Change net_list */ - WALK_LIST_DELSAFE(anet, antmp, oa->net_list) - { - rem_node(NODE anet); - mb_free(anet); - } - WALK_LIST(anet, ac2->net_list) - { - antmp = mb_alloc(p->pool, sizeof(struct area_net)); - antmp->px.addr = anet->px.addr; - antmp->px.len = anet->px.len; - antmp->hidden = anet->hidden; - add_tail(&oa->net_list, NODE antmp); - } + fib_free(&oa->net_fib); + add_area_nets(oa, ac2); if (!iface_patts_equal(&ac1->patt_list, &ac2->patt_list, (void *) ospf_patt_compare)) @@ -833,9 +832,8 @@ ospf_sh(struct proto *p) struct proto_ospf *po = (struct proto_ospf *) p; struct ospf_iface *ifa; struct ospf_neighbor *n; - int ifano; - int nno; - int adjno; + int ifano, nno, adjno, firstfib; + struct area_net *anet; if (p->proto_state != PS_UP) { @@ -871,16 +869,20 @@ ospf_sh(struct proto *p) cli_msg(-1014, "\t\tNumber of LSAs in DB:\t%u", oa->gr->hash_entries); cli_msg(-1014, "\t\tNumber of neighbors:\t%u", nno); cli_msg(-1014, "\t\tNumber of adjacent neighbors:\t%u", adjno); - if (!EMPTY_LIST(oa->net_list)) + + firstfib = 1; + FIB_WALK(&oa->net_fib, nftmp) { - struct area_net *anet; - cli_msg(-1014, "\t\tArea networks:"); - WALK_LIST(anet, oa->net_list) + anet = (struct area_net *) nftmp; + if(firstfib) { - cli_msg(-1014, "\t\t\t%1I/%u\t%s", anet->px.addr, anet->px.len, - anet->hidden ? "Hidden" : "Advertise"); + cli_msg(-1014, "\t\tArea networks:"); + firstfib = 0; } + cli_msg(-1014, "\t\t\t%1I/%u\t%s\t%s", anet->fn.prefix, anet->fn.pxlen, + anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : ""); } + FIB_WALK_END; } cli_msg(0, ""); } diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 8c7eaa05..d1de12ad 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -1,7 +1,7 @@ /* * BIRD -- OSPF * - * (c) 1999 - 2000 Ondrej Filip + * (c) 1999--2004 Ondrej Filip * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -50,7 +50,7 @@ #define LSREFRESHTIME 1800 /* 30 minutes */ #define MINLSINTERVAL 5 #define MINLSARRIVAL 1 -#define LSINFINITY 0xffff /* RFC says 0xffffff ??? */ +#define LSINFINITY 0xffffff #define DEFAULT_OSPFTICK 5 #define DEFAULT_AREATICK 4 @@ -72,13 +72,18 @@ struct nbma_node int eligible; }; -struct area_net +struct area_net_config { node n; struct prefix px; int hidden; +}; + +struct area_net +{ + struct fib_node fn; + int hidden; int active; - int oldactive; }; struct ospf_area_config @@ -113,6 +118,9 @@ struct ospf_iface u32 rxmtint; /* number of seconds between LSA retransmissions */ u32 pollint; /* Poll interval */ u32 deadc; /* after "deadint" missing hellos is router dead */ + u32 vid; /* Id of peer of virtual link */ + ip_addr vip; /* IP of peer of virtual link */ + struct ospf_area *voa; /* Area wich the vlink goes through */ u16 autype; u8 aukey[8]; u8 options; @@ -299,28 +307,61 @@ struct ospf_lsa_net ip_addr netmask; }; -struct ospf_lsa_summ +struct ospf_lsa_sum { ip_addr netmask; }; -struct ospf_lsa_summ_net -{ - u8 tos; - u8 padding; - u16 metric; -}; struct ospf_lsa_ext { ip_addr netmask; }; +struct ospf_lsa_ext_etos +{ +#ifdef _BIG_ENDIAN + u8 ebit:1; + u8 tos:7; + u8 padding1; + u16 padding2; +#else + u16 padding2; + u8 padding1; + u8 tos:7; + u8 ebit:1; +#endif +}; + +#define METRIC_MASK 0x00FFFFFF +struct ospf_lsa_sum_tos +{ +#ifdef _BIG_ENDIAN + u8 tos; + u8 padding1; + u16 padding2; +#else + u16 padding2; + u8 padding1; + u8 tos; +#endif +}; + +union ospf_lsa_sum_tm +{ + struct ospf_lsa_sum_tos tos; + u32 metric; +}; + +union ospf_lsa_ext_etm +{ + struct ospf_lsa_ext_etos etos; + u32 metric; +}; + struct ospf_lsa_ext_tos { - u8 etos; - u8 padding; - u16 metric; + union ospf_lsa_ext_etm etm; ip_addr fwaddr; u32 tag; }; @@ -432,11 +473,12 @@ struct ospf_area slist lsal; /* List of all LSA's */ struct top_hash_entry *rt; /* My own router LSA */ list cand; /* List of candidates for RT calc. */ - list net_list; /* Networks to advertise or not */ + struct fib net_fib; /* Networks to advertise or not */ int stub; int trcap; /* Transit capability? */ struct proto_ospf *po; unsigned tick; + struct fib rtr; /* Routing tables for routers */ }; struct proto_ospf @@ -448,9 +490,10 @@ struct proto_ospf list iface_list; /* Interfaces we really use */ list area_list; int areano; /* Number of area I belong to */ - struct fib rtf[2]; /* Routing tables */ + struct fib rtf; /* Routing table */ int rfc1583; /* RFC1583 compatibility */ int ebit; /* Did I originate any ext lsa? */ + struct ospf_area *backbone; /* If exists */ }; struct ospf_iface_patt @@ -468,6 +511,7 @@ struct ospf_iface_patt u32 autype; u32 strictnbma; u32 stub; + u32 vid; /* must be in network byte order */ #define AU_NONE htons(0) #define AU_SIMPLE htons(1) @@ -493,6 +537,7 @@ void ospf_sh_iface(struct proto *p, char *iff); #define EA_OSPF_METRIC2 EA_CODE(EAP_OSPF, 1) #define EA_OSPF_TAG EA_CODE(EAP_OSPF, 2) +#include "proto/ospf/rt.h" #include "proto/ospf/hello.h" #include "proto/ospf/packet.h" #include "proto/ospf/iface.h" @@ -503,6 +548,5 @@ void ospf_sh_iface(struct proto *p, char *iff); #include "proto/ospf/lsupd.h" #include "proto/ospf/lsack.h" #include "proto/ospf/lsalib.h" -#include "proto/ospf/rt.h" #endif /* _BIRD_OSPF_H_ */ diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 26cc4d43..4f5db664 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -226,19 +226,26 @@ ospf_err_hook(sock * sk, int err UNUSED) } void -sk_send_to_agt(sock * sk, u16 len, struct ospf_iface *ifa, u8 state) +ospf_send_to_agt(sock * sk, u16 len, struct ospf_iface *ifa, u8 state) { struct ospf_neighbor *n; WALK_LIST(NODE n, ifa->neigh_list) if (n->state >= state) - sk_send_to(sk, len, n->ip, OSPF_PROTO); + ospf_send_to(sk, len, n->ip); } void -sk_send_to_bdr(sock * sk, u16 len, struct ospf_iface *ifa) +ospf_send_to_bdr(sock * sk, u16 len, struct ospf_iface *ifa) { if (ipa_compare(ifa->drip, ipa_from_u32(0)) != 0) - sk_send_to(sk, len, ifa->drip, OSPF_PROTO); + ospf_send_to(sk, len, ifa->drip); if (ipa_compare(ifa->bdrip, ipa_from_u32(0)) != 0) - sk_send_to(sk, len, ifa->bdrip, OSPF_PROTO); + ospf_send_to(sk, len, ifa->bdrip); } + +void +ospf_send_to(sock *sk, u16 len, ip_addr ip) +{ + sk_send_to(sk, len, ip, OSPF_PROTO); +} + diff --git a/proto/ospf/packet.h b/proto/ospf/packet.h index fa2c85d2..0742adfa 100644 --- a/proto/ospf/packet.h +++ b/proto/ospf/packet.h @@ -16,7 +16,9 @@ void ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt); int ospf_rx_hook(sock * sk, int size); void ospf_tx_hook(sock * sk); void ospf_err_hook(sock * sk, int err); -void sk_send_to_agt(sock * sk, u16 len, struct ospf_iface *ifa, u8 state); -void sk_send_to_bdr(sock * sk, u16 len, struct ospf_iface *ifa); +void ospf_send_to_agt(sock * sk, u16 len, struct ospf_iface *ifa, u8 state); +void ospf_send_to_bdr(sock * sk, u16 len, struct ospf_iface *ifa); +void ospf_send_to(sock *sk, u16 len, ip_addr ip); + #endif /* _BIRD_OSPF_PACKET_H_ */ diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 417aa7e6..0360f8b6 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -21,8 +21,6 @@ fill_ri(orta * orta) { orta->type = RTS_DUMMY; orta->capa = 0; -#define ORTA_ASBR 1 -#define ORTA_ABR 2 orta->oa = NULL; orta->metric1 = LSINFINITY; orta->metric2 = LSINFINITY; @@ -37,13 +35,20 @@ ospf_rt_initort(struct fib_node *fn) { ort *ri = (ort *) fn; fill_ri(&ri->n); - ri->dest = ORT_UNDEF; memcpy(&ri->o, &ri->n, sizeof(orta)); + ri->efn = NULL; } /* If new is better return 1 */ + +/* + * This is hard to understand: + * If rfc1583 is set to 1, it work likes normal route_better() + * But if it is set to 0, it prunes number of AS bondary + * routes before it starts the router decision + */ static int -ri_better(struct proto_ospf *po, orta * new, orta * old) +ri_better(struct proto_ospf *po, orta * new, ort *nefn, orta * old, ort *oefn, int rfc1583) { int newtype = new->type; int oldtype = old->type; @@ -54,41 +59,44 @@ ri_better(struct proto_ospf *po, orta * new, orta * old) if (old->metric1 == LSINFINITY) return 1; - if (po->rfc1583) + if(!rfc1583) { - if ((newtype == RTS_OSPF) && (new->oa->areaid == 0)) newtype = RTS_OSPF_IA; - if ((oldtype == RTS_OSPF) && (old->oa->areaid == 0)) oldtype = RTS_OSPF_IA; - } + if(new->oa->areaid == 0) newtype = RTS_OSPF_IA; + if(old->oa->areaid == 0) oldtype = RTS_OSPF_IA; +} + if (new->type < old->type) return 1; - if (new->metric2 < old->metric2) - { - if (old->metric2 == LSINFINITY) - return 0; /* Old is E1, new is E2 */ + if (new->type > old->type) + return 0; - return 1; /* Both are E2 */ - } - if (new->metric2 > old->metric2) + /* Same type */ + if(new->type == RTS_OSPF_EXT2) { - if (new->metric2 == LSINFINITY) - return 1; /* New is E1, old is E2 */ - - return 0; /* Both are E2 */ + if (new->metric2 < old->metric2) return 1; + if (new->metric2 > old->metric2) return 0; + } + + if(((new->type == RTS_OSPF_EXT2) || (new->type == RTS_OSPF_EXT1)) && (!po->rfc1583)) + { + int newtype = nefn->n.type; + int oldtype = oefn->n.type; + + if(nefn->n.oa->areaid == 0) newtype = RTS_OSPF_IA; + if(oefn->n.oa->areaid == 0) oldtype = RTS_OSPF_IA; + + if(newtype < oldtype) return 1; + if(newtype > oldtype) return 0; } - /* - * E2 metrics are the same. It means that: 1) Paths are E2 with same - * metric 2) Paths are E1. - */ if (new->metric1 < old->metric1) return 1; if (new->metric1 > old->metric1) return 0; - /* Metric 1 are the same */ if (new->oa->areaid > old->oa->areaid) return 1; /* Larger AREAID is preffered */ return 0; /* Old is shorter or same */ @@ -96,26 +104,35 @@ ri_better(struct proto_ospf *po, orta * new, orta * old) static void ri_install(struct proto_ospf *po, ip_addr prefix, int pxlen, int dest, - orta * new) + orta * new, ort * ipath) { - ort *old = (ort *) fib_get(&po->rtf[dest], &prefix, pxlen); + struct ospf_area *oa = new->oa; + ort *old; - if (ri_better(po, new, &old->n)) + if (dest == ORT_NET) { - memcpy(&old->n, new, sizeof(orta)); + struct area_net *anet; + old = (ort *) fib_get(&po->rtf, &prefix, pxlen); + if (ri_better(po, new, ipath, &old->n, old->efn, 1)) + { + memcpy(&old->n, new, sizeof(orta)); + old->efn = ipath; + } + if ((new->type == RTS_OSPF) && (anet = (struct area_net *)fib_route(&oa->net_fib, prefix, pxlen))) + anet->active = 1; + } + else + { + old = (ort *) fib_get(&oa->rtr, &prefix, pxlen); + + if (ri_better(po, new, ipath, &old->n, old->efn, 1)) + { + memcpy(&old->n, new, sizeof(orta)); + old->efn = ipath; + } } } -/** - * ospf_rt_spf - calculate internal routes - * @po: OSPF protocol - * - * Calculation of internal paths in an area is described in 16.1 of RFC 2328. - * It's based on Dijkstra's shortest path tree algorithms. - * RFC recommends to add ASBR routers into routing table. I don't do this - * and latter parts of routing table calculation look directly into LSA - * Database. This function is invoked from ospf_disp(). - */ static void ospf_rt_spfa(struct ospf_area *oa) { @@ -126,6 +143,10 @@ ospf_rt_spfa(struct ospf_area *oa) struct proto_ospf *po = oa->po; struct ospf_lsa_net *ln; orta nf; + struct ospf_iface *iface; + struct top_hash_entry *act, *tmp; + node *n; + if (oa->rt == NULL) return; @@ -149,9 +170,6 @@ ospf_rt_spfa(struct ospf_area *oa) while (!EMPTY_LIST(oa->cand)) { - struct top_hash_entry *act, *tmp; - node *n; - n = HEAD(oa->cand); act = SKIP_BACK(struct top_hash_entry, cn, n); rem_node(n); @@ -178,7 +196,7 @@ ospf_rt_spfa(struct ospf_area *oa) nf.ar = act; nf.nh = act->nh; nf.ifa = act->nhi; - ri_install(po, ipa_from_u32(act->lsa.id), 32, ORT_ROUTER, &nf); + ri_install(po, ipa_from_u32(act->lsa.id), 32, ORT_ROUTER, &nf, NULL); } rr = (struct ospf_lsa_rt_link *) (rt + 1); DBG(" Number of links: %u\n", rt->links); @@ -208,13 +226,9 @@ ospf_rt_spfa(struct ospf_area *oa) nf.nh = act->nh; nf.ifa = act->nhi; ri_install(po, ipa_from_u32(rtl->id), - ipa_mklen(ipa_from_u32(rtl->data)), ORT_NET, &nf); + ipa_mklen(ipa_from_u32(rtl->data)), ORT_NET, &nf, NULL); break; - case LSART_VLNK: /* FIXME !!!!!!!! */ - DBG("Ignoring\n"); - continue; - break; case LSART_NET: tmp = ospf_hash_find(oa->gr, rtl->id, rtl->id, LSA_T_NET); if (tmp == NULL) @@ -222,6 +236,8 @@ ospf_rt_spfa(struct ospf_area *oa) else DBG("Found. :-)\n"); break; + + case LSART_VLNK: case LSART_PTP: tmp = ospf_hash_find(oa->gr, rtl->id, rtl->id, LSA_T_RT); DBG("PTP found.\n"); @@ -247,7 +263,7 @@ ospf_rt_spfa(struct ospf_area *oa) nf.nh = act->nh; nf.ifa = act->nhi; ri_install(po, ipa_and(ipa_from_u32(act->lsa.id), ln->netmask), - ipa_mklen(ln->netmask), ORT_NET, &nf); + ipa_mklen(ln->netmask), ORT_NET, &nf, NULL); rts = (u32 *) (ln + 1); for (i = 0; i < (act->lsa.length - sizeof(struct ospf_lsa_header) - @@ -264,9 +280,244 @@ ospf_rt_spfa(struct ospf_area *oa) break; } } + + /* Find new/lost VLINK peers */ + WALK_LIST(iface, po->iface_list) + { + if ((iface->type == OSPF_IT_VLINK) && (iface->voa == oa)) + { + if ((tmp = ospf_hash_find(oa->gr, iface->vid, iface->vid, LSA_T_RT)) && + ipa_equal(tmp->lb, IPA_NONE)) + { + DBG("Vlink peer found\n"); + ospf_iface_sm(iface, ISM_UP); /* FIXME: Add slave iface! */ + } + else + { + DBG("Vlink peer not found\n"); + ospf_iface_sm(iface, ISM_DOWN); + } + } + } } +static int +link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entry *pre) +{ + u32 i, *rts; + struct ospf_lsa_net *ln; + struct ospf_lsa_rt *rt; + struct ospf_lsa_rt_link *rtl, *rr; + if(!pre) return 0; + if(!fol) return 0; + switch (fol->lsa.type) + { + case LSA_T_RT: + rt = (struct ospf_lsa_rt *) fol->lsa_body; + rr = (struct ospf_lsa_rt_link *) (rt + 1); + for (i = 0; i < rt->links; i++) + { + rtl = (rr + i); + switch (rtl->type) + { + case LSART_STUB: + break; + case LSART_NET: + if (ospf_hash_find(oa->gr, rtl->id, rtl->id, LSA_T_NET) == pre) + { + fol->lb = ipa_from_u32(rtl->data); + return 1; + } + break; + case LSART_VLNK: + case LSART_PTP: + if (ospf_hash_find(oa->gr, rtl->id, rtl->id, LSA_T_RT) == pre) + { + fol->lb = ipa_from_u32(rtl->data); + return 1; + } + break; + default: + log("Unknown link type in router lsa."); + break; + } + } + break; + case LSA_T_NET: + ln = fol->lsa_body; + rts = (u32 *) (ln + 1); + for (i = 0; i < (fol->lsa.length - sizeof(struct ospf_lsa_header) - + sizeof(struct ospf_lsa_net)) / sizeof(u32); i++) + { + if (ospf_hash_find(oa->gr, *(rts + i), *(rts + i), LSA_T_RT) == pre) + { + return 1; + } + } + break; + default: + log("Unknown link type in router lsa."); + } + return 0; +} + +static void +ospf_rt_sum_tr(struct ospf_area *oa) +{ + struct proto *p = &oa->po->proto; + struct proto_ospf *po = oa->po; + struct ospf_area *bb, *atmp; + ip_addr *mask, ip, abrip; + struct top_hash_entry *en; + int mlen = -1, type = -1; + union ospf_lsa_sum_tm *tm; + ort *re = NULL, *abr; + orta nf; + + bb = NULL; + + WALK_LIST(atmp, po->area_list) + { + if(atmp->areaid == 0) + { + bb = atmp; + break; + } + } + + if(!bb) return; + + WALK_SLIST(en, oa->lsal) + { + if (en->lsa.age == LSA_MAXAGE) + continue; + if (en->dist == LSINFINITY) + continue; + + if (en->lsa.rt == p->cf->global->router_id) + continue; + + if((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET)) + continue; + + mask = (ip_addr *)en->lsa_body; + + if (en->lsa.type == LSA_T_SUM_NET) + { + mlen = ipa_mklen(*mask); + ip = ipa_and(ipa_from_u32(en->lsa.id), *mask); + type = ORT_NET; + re = (ort *) fib_find(&po->rtf, &ip, 32); + } + + if (en->lsa.type == LSA_T_SUM_RT) + { + ip = ipa_from_u32(en->lsa.id); + mlen = 32; + type = ORT_ROUTER; + re = (ort *) fib_find(&bb->rtr, &ip, 32); + } + if(!re) continue; + if(re->n.oa->areaid != 0) continue; + if((re->n.type != RTS_OSPF) && (re->n.type != RTS_OSPF_IA)) continue; + + abrip = ipa_from_u32(en->lsa.rt); + + abr = fib_find(&oa->rtr, &abrip, 32); + if(!abr) continue; + + tm = (union ospf_lsa_sum_tm *)(mask + 1); + + nf.type = re->n.type; + nf.capa = ORTA_ABR; + nf.metric1 = abr->n.metric1 + (tm->metric & METRIC_MASK); + nf.metric2 = LSINFINITY; + nf.oa = oa; + nf.ar = abr->n.ar; + nf.nh = abr->n.nh; + nf.ifa = abr->n.ifa; + ri_install(po, ip, mlen, type, &nf, NULL); + } +} + + +static void +ospf_rt_sum(struct ospf_area *oa) +{ + struct proto_ospf *po = oa->po; + struct proto *p = &po->proto; + struct top_hash_entry *en; + ip_addr *mask, ip, abrip; + struct area_net *anet; + orta nf; + ort *re, *abr; + int mlen = -1, type = -1; + union ospf_lsa_sum_tm *tm; + + OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area routes"); + + WALK_SLIST(en, oa->lsal) + { + /* Page 169 (1) */ + if (en->lsa.age == LSA_MAXAGE) + continue; + if (en->dist == LSINFINITY) + continue; + + /* Page 169 (2) */ + if (en->lsa.rt == p->cf->global->router_id) + continue; + + if((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET)) + continue; + + mask = (ip_addr *)en->lsa_body; + + if (en->lsa.type == LSA_T_SUM_NET) + { + mlen = ipa_mklen(*mask); + ip = ipa_and(ipa_from_u32(en->lsa.id), *mask); + /* Page 169 (3) */ + if ((anet = fib_route(&oa->net_fib, ip, mlen)) && anet->active) + continue; + type = ORT_NET; + } + + if (en->lsa.type == LSA_T_SUM_RT) + { + ip = ipa_from_u32(en->lsa.id); + mlen = 32; + type = ORT_ROUTER; + } + abrip = ipa_from_u32(en->lsa.rt); + + if (!(abr = (ort *) fib_find(&oa->rtr, &abrip, 32))) continue; + if (abr->n.metric1 == LSINFINITY) continue; + if (!(abr->n.capa & ORTA_ABR)) continue; + + tm = (union ospf_lsa_sum_tm *)(mask + 1); + + nf.type = RTS_OSPF_IA; + nf.capa = ORTA_ABR; + nf.metric1 = abr->n.metric1 + (tm->metric & METRIC_MASK); + nf.metric2 = LSINFINITY; + nf.oa = oa; + nf.ar = abr->n.ar; + nf.nh = abr->n.nh; + nf.ifa = abr->n.ifa; + ri_install(po, ip, mlen, type, &nf, NULL); + } +} + +/** + * ospf_rt_spf - calculate internal routes + * @po: OSPF protocol + * + * Calculation of internal paths in an area is described in 16.1 of RFC 2328. + * It's based on Dijkstra's shortest path tree algorithms. + * This function is invoked from ospf_disp(). + */ void ospf_rt_spf(struct proto_ospf *po) { @@ -274,12 +525,14 @@ ospf_rt_spf(struct proto_ospf *po) struct ospf_area *oa; int i; ort *ri; + struct area_net *anet; + + if (po->areano == 0) return; OSPF_TRACE(D_EVENTS, "Starting routing table calculation"); /* Invalidate old routing table */ - for (i = 0; i < 2; i++) - FIB_WALK(&po->rtf[i], nftmp) + FIB_WALK(&po->rtf, nftmp) { ri = (ort *) nftmp; memcpy(&ri->o, &ri->n, sizeof(orta)); /* Backup old data */ @@ -290,25 +543,44 @@ ospf_rt_spf(struct proto_ospf *po) WALK_LIST(oa, po->area_list) { + FIB_WALK(&oa->rtr, nftmp) + { + ri = (ort *) nftmp; + memcpy(&ri->o, &ri->n, sizeof(orta)); /* Backup old data */ + fill_ri(&ri->n); + } + FIB_WALK_END; + + fib_free(&oa->rtr); + fib_init(&oa->rtr, p->pool, sizeof(ort), 16, ospf_rt_initort); + + FIB_WALK(&oa->net_fib, nftmp) + { + anet = (struct area_net *) nftmp; + anet->active = 0; + } + FIB_WALK_END; ospf_rt_spfa(oa); } - if (po->areano > 1) + if (po->areano == 1) { - //ospf_rt_sum(oa); + ospf_rt_sum(HEAD(po->area_list)); } else { - WALK_LIST(oa, po->area_list) - { - //if (oa->id == 0) ospf_rt_sum(oa); - } + if (po->backbone) ospf_rt_sum(po->backbone); /* And if backbone is not connected? */ + } - WALK_LIST(oa, po->area_list) + WALK_LIST(oa, po->area_list) + { + if (oa->trcap && (oa->areaid != 0)) { - //if (oa->trcap == 1) ospf_rt_sum(oa); + ospf_rt_sum_tr(oa); + break; } } + WALK_LIST(oa, po->area_list) { if (!oa->stub) @@ -333,7 +605,7 @@ static void ospf_ext_spfa(struct ospf_area *oa) { struct proto_ospf *po = oa->po; - ort *nf1, *nf2; + ort *nf1, *nf2, *nfh; orta nfa; struct top_hash_entry *en; struct proto *p = &po->proto; @@ -345,6 +617,7 @@ ospf_ext_spfa(struct ospf_area *oa) int met1, met2; neighbor *nn; struct ospf_lsa_rt *rt; + struct ospf_area *atmp; OSPF_TRACE(D_EVENTS, "Starting routing table calculation for ext routes"); @@ -364,7 +637,7 @@ ospf_ext_spfa(struct ospf_area *oa) DBG("%s: Working on LSA. ID: %I, RT: %I, Type: %u, Mask %I\n", p->name, en->lsa.id, en->lsa.rt, en->lsa.type, le->netmask); - if (lt->metric == LSINFINITY) + if ((lt->etm.metric & METRIC_MASK) == LSINFINITY) continue; ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask); mlen = ipa_mklen(le->netmask); @@ -382,7 +655,16 @@ ospf_ext_spfa(struct ospf_area *oa) rtid = ipa_from_u32(en->lsa.rt); - if (!(nf1 = fib_find(&po->rtf[ORT_ROUTER], &rtid, 32))) + nf1 = NULL; + WALK_LIST(atmp, po->area_list) + { + nfh = fib_find(&atmp->rtr, &rtid, 32); + if(nfh == NULL) continue; + if(nf1 == NULL) nf1 = nfh; + else if(ri_better(po, &nfh->n, NULL, &nf1->n, NULL, po->rfc1583)) nf1 = nfh; + } + + if (!nf1) continue; /* No AS boundary router found */ if (nf1->n.metric1 == LSINFINITY) @@ -393,34 +675,39 @@ ospf_ext_spfa(struct ospf_area *oa) if (ipa_compare(lt->fwaddr, ipa_from_u32(0)) == 0) { - if (lt->etos > 0) + if (lt->etm.etos.ebit) { /* FW address == 0 */ met1 = nf1->n.metric1; - met2 = lt->metric; + met2 = (lt->etm.metric & METRIC_MASK); } else { - met1 = nf1->n.metric1 + lt->metric; + met1 = nf1->n.metric1 + (lt->etm.metric & METRIC_MASK); met2 = LSINFINITY; } + nh = nf1->n.nh; nhi = nf1->n.ifa; + nfh = nf1; } else { /* FW address !=0 */ - if (!(nf2 = fib_route(&po->rtf[ORT_NET], lt->fwaddr, 32))) + nf2 = fib_route(&po->rtf, lt->fwaddr, 32); + + if (!nf2) { DBG("Cannot find network route (GW=%I)\n", lt->fwaddr); continue; } - if (lt->etos > 0) + + if (lt->etm.etos.ebit) { met1 = nf2->n.metric1; - met2 = lt->metric; + met2 = (lt->etm.metric & METRIC_MASK); } else { - met1 = nf2->n.metric1 + lt->metric; + met1 = nf2->n.metric1 + (lt->etm.metric & METRIC_MASK); met2 = LSINFINITY; } @@ -434,9 +721,12 @@ ospf_ext_spfa(struct ospf_area *oa) nh = nf2->n.nh; nhi = nf2->n.ifa; } + + nfh = nf2; } - nfa.type = RTS_OSPF_EXT; + nfa.type = RTS_OSPF_EXT2; + if(met2 == LSINFINITY) nfa.type = RTS_OSPF_EXT1; nfa.capa = 0; nfa.metric1 = met1; nfa.metric2 = met2; @@ -445,7 +735,7 @@ ospf_ext_spfa(struct ospf_area *oa) nfa.nh = nh; nfa.ifa = nhi; nfa.tag = lt->tag; - ri_install(po, ip, mlen, ORT_NET, &nfa); + ri_install(po, ip, mlen, ORT_NET, &nfa, nfh); } } @@ -463,16 +753,20 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, return; if (en->lsa.age == LSA_MAXAGE) return; - /* FIXME Does it have link back? Test it! */ + if (en->color == INSPF) return; if (dist >= en->dist) return; /* - * FIXME The line above is not a bug, but we don't support multiple + * FIXME The line above (=) is not a bug, but we don't support multiple * next hops. I'll start as soon as nest will */ + + if (!link_back(oa, en, par)) + return; + DBG(" Adding candidate: rt: %I, id: %I, type: %u\n", en->lsa.rt, en->lsa.id, en->lsa.type); @@ -520,7 +814,6 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, add_tail(l, &en->cn); } } - /* FIXME Some VLINK stuff should be here */ } static void @@ -607,30 +900,20 @@ rt_sync(struct proto_ospf *po) { struct proto *p = &po->proto; struct fib_iterator fit; - struct fib *fib = &po->rtf[ORT_NET]; + struct fib *fib = &po->rtf; ort *nf; + struct ospf_area *oa; + struct area_net *anet; + + OSPF_TRACE(D_EVENTS, "Starting routing table synchronisation"); DBG("Now syncing my rt table with nest's\n"); FIB_ITERATE_INIT(&fit, fib); -again: +again1: FIB_ITERATE_START(fib, &fit, nftmp) { nf = (ort *) nftmp; - if (nf->n.metric1 == LSINFINITY) - { - net *ne; - - ne = net_get(p->table, nf->fn.prefix, nf->fn.pxlen); - DBG("Deleting rt entry %I\n (IP: %I, GW: %I)\n", - nf->fn.prefix, ip, nf->nh); - rte_update(p->table, ne, p, NULL); - - /* Now delete my fib */ - FIB_ITERATE_PUT(&fit, nftmp); - fib_delete(fib, nftmp); - goto again; - } - else if (memcmp(&nf->n, &nf->o, sizeof(orta))) + if (memcmp(&nf->n, &nf->o, sizeof(orta))) { /* Some difference */ net *ne; rta a0; @@ -648,17 +931,59 @@ again: a0.iface = nf->n.ifa; a0.gw = nf->n.nh; ne = net_get(p->table, nf->fn.prefix, nf->fn.pxlen); - e = rte_get_temp(&a0); - e->u.ospf.metric1 = nf->n.metric1; - e->u.ospf.metric2 = nf->n.metric2; - e->u.ospf.tag = nf->n.tag; - e->pflags = 0; - e->net = ne; - e->pref = p->preference; - DBG("Modifying rt entry %I\n (IP: %I, GW: %I)\n", + check_sum_lsa(po, nf, ORT_NET); + if (nf->n.metric1 < LSINFINITY) + { + e = rte_get_temp(&a0); + e->u.ospf.metric1 = nf->n.metric1; + e->u.ospf.metric2 = nf->n.metric2; + e->u.ospf.tag = nf->n.tag; + e->pflags = 0; + e->net = ne; + e->pref = p->preference; + DBG("Modifying rt entry %I\n (IP: %I, GW: %I)\n", nf->fn.prefix, ip, nf->nh); - rte_update(p->table, ne, p, e); + rte_update(p->table, ne, p, e); + } + else + { + rte_update(p->table, ne, p, NULL); + FIB_ITERATE_PUT(&fit, nftmp); + fib_delete(fib, nftmp); + goto again1; + } } } FIB_ITERATE_END(nftmp); + + WALK_LIST(oa, po->area_list) + { + FIB_ITERATE_INIT(&fit, &oa->rtr); +again2: + FIB_ITERATE_START(&oa->rtr, &fit, nftmp) + { + nf = (ort *) nftmp; + if (memcmp(&nf->n, &nf->o, sizeof(orta))) + { /* Some difference */ + check_sum_lsa(po, nf, ORT_ROUTER); + if(nf->n.metric1 >= LSINFINITY) + { + FIB_ITERATE_PUT(&fit, nftmp); + fib_delete(&oa->rtr, nftmp); + goto again2; + } + } + } + FIB_ITERATE_END(nftmp); + + /* Check condensed summary LSAs */ + FIB_WALK(&oa->net_fib, nftmp) + { + anet = (struct area_net *) nftmp; + if((!anet->hidden) && anet->active && (!oa->trcap)) + originate_sum_lsa(oa, &anet->fn, ORT_NET, 1); + else flush_sum_lsa(oa, &anet->fn, ORT_NET); + } + FIB_WALK_END; + } } diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h index ca3d0572..f7b33303 100644 --- a/proto/ospf/rt.h +++ b/proto/ospf/rt.h @@ -10,10 +10,16 @@ #ifndef _BIRD_OSPF_RT_H_ #define _BIRD_OSPF_RT_H_ +#define ORT_UNDEF -1 +#define ORT_ROUTER 1 +#define ORT_NET 0 + typedef struct orta { int type; int capa; +#define ORTA_ASBR 1 +#define ORTA_ABR 2 struct ospf_area *oa; int metric1; int metric2; @@ -27,12 +33,9 @@ orta; typedef struct ort { struct fib_node fn; - int dest; -#define ORT_UNDEF -1 -#define ORT_ROUTER 1 -#define ORT_NET 0 orta n; orta o; + struct ort *efn; /* For RFC1583 */ } ort; diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index f1e691cc..215765e6 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -1,8 +1,8 @@ /* * BIRD -- OSPF Topological Database * - * (c) 1999 Martin Mares - * (c) 1999 - 2004 Ondrej Filip + * (c) 1999 Martin Mares + * (c) 1999--2004 Ondrej Filip * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -25,7 +25,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length) { struct proto_ospf *po = oa->po; struct ospf_iface *ifa; - int j = 0, k = 0, v = 0; + int j = 0, k = 0; u16 i = 0; struct ospf_lsa_rt *rt; struct ospf_lsa_rt_link *ln; @@ -39,8 +39,6 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length) if ((ifa->an == oa->areaid) && (ifa->state != OSPF_IS_DOWN)) { i++; - if (ifa->type == OSPF_IT_VLINK) - v = 1; } } rt = mb_allocz(po->proto.pool, sizeof(struct ospf_lsa_rt) + @@ -49,7 +47,6 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length) rt->veb.bit.b = 1; if ((po->ebit) && (!oa->stub)) rt->veb.bit.e = 1; - rt->veb.bit.v = v; ln = (struct ospf_lsa_rt_link *) (rt + 1); WALK_LIST(ifa, po->iface_list) @@ -83,7 +80,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length) } else { - ln->id = ipa_to_u32(ifa->iface->addr->ip); + ln->data = ipa_to_u32(ifa->iface->addr->ip); } } else @@ -97,9 +94,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length) ln->data = 0xffffffff; } else - { i--; /* No link added */ - } } break; case OSPF_IT_BCAST: @@ -140,14 +135,21 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length) } } break; - case OSPF_IT_VLINK: /* FIXME Add virtual links! */ - i--; - break; + case OSPF_IT_VLINK: + neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); + if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) + { + ln->type = LSART_VLNK; + ln->id = neigh->rid; + ln->metric = ifa->cost; + ln->notos = 0; + rt->veb.bit.v = 1; + } + else + i--; /* No link added */ + break; } } - if (ifa->type == OSPF_IT_VLINK) - v = 1; - ln = (ln + 1); } rt->links = i; *length = i * sizeof(struct ospf_lsa_rt_link) + sizeof(struct ospf_lsa_rt) + @@ -305,6 +307,7 @@ originate_net_lsa(struct ospf_iface *ifa) ifa->orignet = 0; } + static void * originate_ext_lsa_body(net * n, rte * e, struct proto_ospf *po, struct ea_list *attrs) @@ -325,15 +328,16 @@ originate_ext_lsa_body(net * n, rte * e, struct proto_ospf *po, if (m1 != LSINFINITY) { - et->etos = 0; - et->metric = m1; + et->etm.metric = m1; + et->etm.etos.tos = 0; + et->etm.etos.ebit = 0; } else { - et->etos = 0x80; - et->metric = m2; + et->etm.metric = m2; + et->etm.etos.tos = 0; + et->etm.etos.ebit = 1; } - et->padding = 0; et->tag = tag; if (ipa_compare(e->attrs->gw, ipa_from_u32(0)) != 0) { @@ -371,6 +375,175 @@ max_ext_lsa(unsigned pxlen) return i; } +void +flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type) +{ + struct proto_ospf *po = oa->po; + struct proto *p = &po->proto; + struct top_hash_entry *en; + u32 rtid = po->proto.cf->global->router_id; + struct ospf_lsa_header lsa; + int max, i; + struct ospf_lsa_sum *sum = NULL; + union ospf_lsa_sum_tm *tm; + + lsa.rt = rtid; + lsa.type = LSA_T_SUM_NET; + if (type == ORT_ROUTER) + lsa.type = LSA_T_SUM_RT; + + max = max_ext_lsa(fn->pxlen); + + for (i = 0; i < max; i++) + { + lsa.id = ipa_to_u32(fn->prefix) + i; + if ((en = ospf_hash_find_header(oa->gr, &lsa)) != NULL) + { + sum = en->lsa_body; + if (fn->pxlen == ipa_mklen(sum->netmask)) + { + en->lsa.age = LSA_MAXAGE; + en->lsa.sn = LSA_MAXSEQNO; + OSPF_TRACE(D_EVENTS, "Flushing summary lsa."); + ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1); + if (can_flush_lsa(oa)) flush_lsa(en, oa); + break; + } + } + } +} + + + + +void +originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric) +{ + struct proto_ospf *po = oa->po; + struct proto *p = &po->proto; + struct top_hash_entry *en; + u32 rtid = po->proto.cf->global->router_id; + struct ospf_lsa_header lsa; + void *body = NULL; + int i, max, mlen = fn->pxlen, found = 0, free = -1; + struct ospf_lsa_sum *sum = NULL; + union ospf_lsa_sum_tm *tm; + lsa.type = LSA_T_SUM_NET; + + if (type == ORT_ROUTER) + { + lsa.type = LSA_T_SUM_RT; + mlen = 0; + } + + lsa.age = 0; + lsa.rt = rtid; + lsa.sn = LSA_INITSEQNO; + lsa.length = sizeof(struct ospf_lsa_sum) + sizeof(union ospf_lsa_sum_tm) + + sizeof(struct ospf_lsa_header); + + max = max_ext_lsa(fn->pxlen); + for (i = 0; i < max; i++) + { + lsa.id = ipa_to_u32(fn->prefix) + i; + if ((en = ospf_hash_find_header(oa->gr, &lsa)) == NULL) + { + if (free < 0) free = i; + } + else + { + sum = en->lsa_body; + if (mlen == ipa_mklen(sum->netmask)) + { + tm = (union ospf_lsa_sum_tm *) (sum + 1); + if (tm->metric == (unsigned)metric) return; /* No reason for origination */ + lsa.sn = en->lsa.sn + 1; + free = en->lsa.id; + break; + } + } + } + + if(free < 0) + { + log("%s: got more routes for one /%d network then %d, ignoring", p->name, + fn->pxlen, max); + return; + } + lsa.id = free; + + sum = en->lsa_body; + tm = (union ospf_lsa_sum_tm *) (sum + 1); + + OSPF_TRACE(D_EVENTS, "Originating summary (type %d) lsa for %I/%d.", lsa.type, fn->prefix, + fn->pxlen); + + sum = mb_alloc(p->pool, sizeof(struct ospf_lsa_sum) + sizeof(union ospf_lsa_sum_tm)); + sum->netmask = ipa_mkmask(mlen); + tm = (union ospf_lsa_sum_tm *) (sum + 1); + tm->metric = metric; + tm->tos.tos = 0; + + lsasum_calculate(&lsa, body); + en = lsa_install_new(&lsa, body, oa); + ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1); +} + +void +check_sum_lsa(struct proto_ospf *po, ort *nf, int dest) +{ + struct proto *p = &po->proto; + struct ospf_area *oa; + struct area_net *anet; + int flush, mlen; + ip_addr ip; + + if (po->areano < 2) return; + + if ((nf->n.type > RTS_OSPF_IA) && (nf->o.type > RTS_OSPF_IA)) return; + + WALK_LIST(oa, po->area_list) + { + flush = 0; + if ((nf->n.metric1 >= LSINFINITY) || (nf->n.type > RTS_OSPF_IA)) + flush = 1; + if ((dest == ORT_ROUTER) && (!(nf->n.capa & ORTA_ABR))) + flush = 1; + if (nf->n.oa->areaid == oa->areaid) + flush = 1; + /* FIXME: Test next hop - is it in actual area? */ + if ((dest == ORT_ROUTER) && oa->stub) + flush = 1; + /* FIXME stub for networks? */ + + mlen = nf->fn.pxlen; + ip = ipa_and(nf->fn.prefix, ipa_mkmask(mlen)); + if((!oa->trcap) && fib_route(&oa->net_fib, ip, mlen)) /* The route fits into some area */ + flush = 1; + + if(flush) /* FIXME Go on... */ + { + flush_sum_lsa(oa, &nf->fn, dest); + continue; + } + originate_sum_lsa(oa, &nf->fn, dest, nf->n.metric1); + } +} + +void +check_sum_areas(struct proto_ospf *po) +{ + struct proto *p = &po->proto; + struct ospf_area *oa; + struct area_net *anet; + + WALK_LIST(oa, po->area_list) + { + ; /* FIXME */ + } +} + + /** * originate_ext_lsa - new route received from nest and filters * @n: network prefix and mask @@ -397,8 +570,7 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po, struct proto *p = &po->proto; struct ospf_area *oa; struct ospf_lsa_ext *ext1, *ext2; - int i; - int max; + int i, max; OSPF_TRACE(D_EVENTS, "Originating Ext lsa for %I/%d.", n->n.prefix, n->n.pxlen); @@ -408,6 +580,7 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po, lsa.type = LSA_T_EXT; lsa.rt = rtid; lsa.sn = LSA_INITSEQNO; + body = originate_ext_lsa_body(n, e, po, attrs); lsa.length = sizeof(struct ospf_lsa_ext) + sizeof(struct ospf_lsa_ext_tos) + sizeof(struct ospf_lsa_header); @@ -440,9 +613,12 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po, lsasum_calculate(&lsa, body); WALK_LIST(oa, po->area_list) { - en = lsa_install_new(&lsa, body, oa); - ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1); - body = originate_ext_lsa_body(n, e, po, attrs); + if (!oa->stub) + { + en = lsa_install_new(&lsa, body, oa); + ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1); + body = originate_ext_lsa_body(n, e, po, attrs); + } } mb_free(body); @@ -617,6 +793,7 @@ ospf_hash_get(struct top_graph *f, u32 lsa, u32 rtr, u32 type) e->dist = LSINFINITY; e->nhi = NULL; e->nh = ipa_from_u32(0); + e->lb = ipa_from_u32(0); e->lsa.id = lsa; e->lsa.rt = rtr; e->lsa.type = type; diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index 55ecb4fe..c6031c5e 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -1,7 +1,7 @@ /* * BIRD -- OSPF * - * (c) 1999 - 2004 Ondrej Filip + * (c) 1999--2004 Ondrej Filip * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -21,15 +21,15 @@ struct top_hash_entry void *lsa_body; bird_clock_t inst_t; /* Time of installation into DB */ ip_addr nh; /* Next hop */ + ip_addr lb; /* Link back */ struct iface *nhi; - u16 dist; /* Distance from the root */ + u32 dist; /* Distance from the root */ u16 ini_age; u8 color; #define OUTSPF 0 #define CANDIDATE 1 #define INSPF 2 u8 padding; - u16 padding2; }; struct top_graph @@ -62,5 +62,11 @@ int can_flush_lsa(struct ospf_area *oa); int max_ext_lsa(unsigned pxlen); void originate_ext_lsa(net * n, rte * e, struct proto_ospf *po, struct ea_list *attrs); +void check_sum_lsa(struct proto_ospf *po, ort *nf, int); +void originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric); +void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type); + + + #endif /* _BIRD_OSPF_TOPOLOGY_H_ */