diff --git a/doc/bird.sgml b/doc/bird.sgml index 3722e489..5441e31e 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1015,15 +1015,18 @@ protocol ospf <name> { { cost <num>; hello <num>; + poll <num>; retransmit <num>; priority <num>; wait <num>; dead count <num>; type [broadcast|nonbroadcast|pointopoint]; + strict nonbroadcast <switch>; authetication [none|simple]; password "<text>"; neighbors { <ip>; + <ip> eligible; }; }; }; @@ -1062,6 +1065,10 @@ protocol ospf <name> { routers on the same network need to have the same hello interval. Default value is 10. + poll num + Specifies interval in seconds between sending of Hello messages for + some neighbors on NBMA netwok. Default value is 20. + retransmit num Specifies interval in seconds between retransmissions of unacknowledged updates. Default value is 5. @@ -1107,7 +1114,12 @@ protocol ospf <name> { neighbors { A set of neighbors to which Hello messages on nonbroadcast networks - are to be sent. + are to be sent. Some of them could be marked as eligible. + + strict nonbroadcast switch + If set, don't send hello to any undefined neighbor. This switch + is ignored on on any non-NBMA network. Default is No. + Attributes @@ -1156,10 +1168,12 @@ protocol ospf MyOSPF { interface "-arc0" , "arc*" { type nonbroadcast; authentication none; - wait 50; - dead count 6; + strict nonbroadcast no; + wait 120; + poll 40; + dead count 8; neighbors { - 192.168.120.1; + 192.168.120.1 eligible; 192.168.120.2; 192.168.120.10; }; diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index c7802380..50ba371a 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -23,7 +23,8 @@ CF_DECLS 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(NEIGHBORS, NONE, SIMPLE, AUTHENTICATION, PASSWORD) +CF_KEYWORDS(NEIGHBORS, NONE, SIMPLE, AUTHENTICATION, PASSWORD, STRICT) +CF_KEYWORDS(ELIGIBLE, POLL) %type opttext @@ -77,6 +78,7 @@ ospf_area_item: ospf_iface_item: COST expr { OSPF_PATT->cost = $2 ; if($2<=0) cf_error("Cost must be greater than zero"); } | HELLO expr { OSPF_PATT->helloint = $2 ; if($2<=0) cf_error("Hello int must be greater than zero"); } + | 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) cf_error("Transmit delay must be greater than zero"); } | PRIORITY expr { OSPF_PATT->priority = $2 ; } @@ -85,6 +87,7 @@ ospf_iface_item: | TYPE BROADCAST { OSPF_PATT->type = OSPF_IT_BCAST ; } | TYPE NONBROADCAST { OSPF_PATT->type = OSPF_IT_NBMA ; } | TYPE POINTOPOINT { OSPF_PATT->type = OSPF_IT_PTP ; } + | STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; } | NEIGHBORS '{' ipa_list '}' | AUTHENTICATION NONE { OSPF_PATT->autype=AU_NONE ; } | AUTHENTICATION SIMPLE { OSPF_PATT->autype=AU_SIMPLE ; } @@ -96,12 +99,26 @@ ipa_list: /* empty */ | ipa_list ipa_item ; + +ipa_item: + ipa_el; + | ipa_ne; -ipa_item: IPA ';' +ipa_el: IPA ';' { this_nbma = cfg_allocz(sizeof(struct nbma_node)); add_tail(&OSPF_PATT->nbma_list, NODE this_nbma); this_nbma->ip=$1; + this_nbma->eligible=0; + } +; + +ipa_ne: IPA ELIGIBLE ';' + { + this_nbma = cfg_allocz(sizeof(struct nbma_node)); + add_tail(&OSPF_PATT->nbma_list, NODE this_nbma); + this_nbma->ip=$1; + this_nbma->eligible=1; } ; @@ -112,12 +129,14 @@ ospf_iface_start: 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->priority = PRIORITY_D; OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D; OSPF_PATT->deadc = DEADC_D; OSPF_PATT->type = OSPF_IT_UNDEF; + OSPF_PATT->strictnbma = 0; init_list(&OSPF_PATT->nbma_list); OSPF_PATT->autype=AU_NONE; } diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index d902bbdd..94326c5d 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -40,6 +40,13 @@ restart_hellotim(struct ospf_iface *ifa) tm_start(ifa->hello_timer,ifa->helloint); } +void +restart_polltim(struct ospf_iface *ifa) +{ + if(ifa->poll_timer) + tm_start(ifa->poll_timer,ifa->pollint); +} + void restart_waittim(struct ospf_iface *ifa) { @@ -56,6 +63,7 @@ ospf_hello_rx(struct ospf_hello_packet *ps, struct proto *p, ip_addr olddr,oldbdr; ip_addr mask; char *beg=": Bad OSPF hello packet from ", *rec=" received: "; + int eligible=0; nrid=ntohl(((struct ospf_packet *)ps)->routerid); @@ -90,6 +98,36 @@ ospf_hello_rx(struct ospf_hello_packet *ps, struct proto *p, if((n=find_neigh(ifa, nrid))==NULL) { + if((ifa->type==OSPF_IT_NBMA)) + { + struct nbma_node *nn; + int found=0; + + WALK_LIST(nn,ifa->nbma_list) + { + if(ipa_compare(faddr,nn->ip)==0) + { + found=1; + break; + } + } + if((found==0)&&(ifa->strictnbma)) + { + OSPF_TRACE(D_EVENTS, "Ignoring new neighbor: %I on %s.", faddr, + ifa->iface->name); + return; + } + if(found) + { + eligible=nn->eligible; + if(((ps->priority==0)&&eligible)||((ps->priority>0)&&(eligible==0))) + { + OSPF_TRACE(D_EVENTS, "Eligibility mismatch for neighbor: %I on %s", + faddr, ifa->iface->name); + return; + } + } + } OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s.", faddr, ifa->iface->name); n=mb_allocz(p->pool, sizeof(struct ospf_neighbor)); @@ -177,11 +215,27 @@ ospf_hello_rx(struct ospf_hello_packet *ps, struct proto *p, ospf_int_sm(ifa, ISM_NEICH); } + if(ifa->type!=OSPF_IT_NBMA) + { + if((ifa->priority==0)&&(n->priority>0)) hello_send(NULL,0, n); + } ospf_neigh_sm(n, INM_HELLOREC); } +void +poll_timer_hook(timer *timer) +{ + hello_send(timer,1, NULL); +} + void hello_timer_hook(timer *timer) +{ + hello_send(timer,0, NULL); +} + +void +hello_send(timer *timer,int poll, struct ospf_neighbor *dirn) { struct ospf_iface *ifa; struct ospf_hello_packet *pkt; @@ -192,9 +246,11 @@ hello_timer_hook(timer *timer) u32 *pp; u8 i; - ifa=(struct ospf_iface *)timer->data; + if(timer==NULL) ifa=dirn->ifa; + else ifa=(struct ospf_iface *)timer->data; + p=(struct proto *)(ifa->proto); - DBG("%s: Hello timer fired on interface %s.\n", + DBG("%s: Hello/Poll timer fired on interface %s.\n", p->name, ifa->iface->name); /* Now we should send a hello packet */ /* First a common packet header */ @@ -248,20 +304,44 @@ hello_timer_hook(timer *timer) struct nbma_node *nb; int send; - WALK_LIST(nb,ifa->nbma_list) + if(timer==NULL) /* Response to received hello */ { - send=1; - WALK_LIST(n1, ifa->neigh_list) + 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) { - if(ipa_compare(nb->ip,n1->ip)==0) + send=1; + WALK_LIST(n1, ifa->neigh_list) + { + if(ipa_compare(nb->ip,n1->ip)==0) + { + send=0; + break; + } + } + if((poll==1)&&(send)) { - send=0; - break; + if(toall||(meeli&&nb->eligible)) + sk_send_to(ifa->ip_sk, length, nb->ip, OSPF_PROTO); } } - if(send) sk_send_to(ifa->ip_sk, length, nb->ip, OSPF_PROTO); + if(poll==0) + { + 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); + } + } } - sk_send_to_agt(ifa->ip_sk, length, ifa, NEIGHBOR_DOWN); } OSPF_TRACE(D_PACKETS, "Hello sent via %s",ifa->iface->name); } diff --git a/proto/ospf/hello.h b/proto/ospf/hello.h index fe53c104..4a5d5042 100644 --- a/proto/ospf/hello.h +++ b/proto/ospf/hello.h @@ -13,10 +13,13 @@ void install_inactim(struct ospf_neighbor *n); void restart_inactim(struct ospf_neighbor *n); void restart_hellotim(struct ospf_iface *ifa); +void restart_polltim(struct ospf_iface *ifa); void restart_waittim(struct ospf_iface *ifa); void ospf_hello_rx(struct ospf_hello_packet *ps, struct proto *p, struct ospf_iface *ifa, int size, ip_addr faddr); void hello_timer_hook(timer *timer); +void poll_timer_hook(timer *timer); void wait_timer_hook(timer *timer); +void hello_send(timer *timer,int poll, struct ospf_neighbor *dirn); #endif /* _BIRD_OSPF_HELLO_H_ */ diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 172a60ab..4c0e2866 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -122,6 +122,11 @@ downint(struct ospf_iface *ifa) tm_stop(ifa->hello_timer); rfree(ifa->hello_timer); } + if(ifa->poll_timer!=NULL) + { + tm_stop(ifa->poll_timer); + rfree(ifa->poll_timer); + } rfree(ifa->lock); mb_free(ifa); } @@ -151,6 +156,7 @@ ospf_int_sm(struct ospf_iface *ifa, int event) { /* Now, nothing should be adjacent */ restart_hellotim(ifa); + restart_polltim(ifa); if((ifa->type==OSPF_IT_PTP) || (ifa->type==OSPF_IT_VLINK)) { iface_chstate(ifa, OSPF_IS_PTP); @@ -358,13 +364,20 @@ void ospf_iface_info(struct ospf_iface *ifa) { int x; + char *strict="(strict)"; + + if((ifa->type!=OSPF_IT_NBMA)||(ifa->strictnbma==0)) strict=""; cli_msg(-1015,"Interface \"%s\":", ifa->iface->name); cli_msg(-1015,"\tArea: %I (%u)", ifa->oa->areaid, ifa->oa->areaid); - cli_msg(-1015,"\tType: %s", ospf_it[ifa->type]); + cli_msg(-1015,"\tType: %s %s", ospf_it[ifa->type], strict); cli_msg(-1015,"\tState: %s", ospf_is[ifa->state]); cli_msg(-1015,"\tPriority: %u", ifa->priority); cli_msg(-1015,"\tCost: %u", ifa->cost); cli_msg(-1015,"\tHello timer: %u", ifa->helloint); + if(ifa->type==OSPF_IT_NBMA) + { + cli_msg(-1015,"\tPoll timer: %u", ifa->pollint); + } cli_msg(-1015,"\tWait timer: %u", ifa->waitint); cli_msg(-1015,"\tDead timer: %u", ifa->deadc*ifa->helloint); cli_msg(-1015,"\tRetransmit timer: %u", ifa->rxmtint); @@ -412,6 +425,8 @@ ospf_ifa_add(struct object_lock *lock) 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->autype=ip->autype; @@ -453,6 +468,7 @@ ospf_ifa_add(struct object_lock *lock) { nbma=mb_alloc(p->pool,sizeof(struct nbma_node)); nbma->ip=nb->ip; + nbma->eligible=nb->eligible; add_tail(&ifa->nbma_list, NODE nbma); } @@ -464,6 +480,17 @@ ospf_ifa_add(struct object_lock *lock) 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; diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 8854d8da..6a7c753b 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -62,6 +62,7 @@ struct ospf_config { struct nbma_node { node n; ip_addr ip; + int eligible; }; struct ospf_area_config { @@ -91,6 +92,7 @@ struct ospf_iface { u8 priority; /* A router priority for DR election */ u16 helloint; /* number of seconds between hello sending */ u16 waitint; /* number of sec before changing state from wait */ + u16 pollint; /* Poll interval */ u32 deadc; /* after "deadint" missing hellos is router dead */ u16 autype; u8 aukey[8]; @@ -100,6 +102,7 @@ struct ospf_iface { ip_addr bdrip; /* Backup DR */ u32 bdrid; u8 type; /* OSPF view of type */ + u8 strictnbma; /* Can I talk with unknown neighbors? */ #define OSPF_IT_BCAST 0 #define OSPF_IT_NBMA 1 #define OSPF_IT_PTP 2 @@ -115,12 +118,14 @@ struct ospf_iface { #define OSPF_IS_DR 6 /* I'm DR */ timer *wait_timer; /* WAIT timer */ timer *hello_timer; /* HELLOINT timer */ + timer *poll_timer; /* Poll Interval - for NBMA */ /* Default values for interface parameters */ #define COST_D 10 #define RXMTINT_D 5 #define INFTRANSDELAY_D 1 #define PRIORITY_D 1 #define HELLOINT_D 10 +#define POLLINT_D 20 #define DEADC_D 4 #define WAIT_DMH 4 /* Value of Wait timer - not found it in RFC * - using 4*HELLO @@ -377,12 +382,14 @@ struct ospf_iface_patt { int cost; int helloint; int rxmtint; + int pollint; int inftransdelay; int priority; int waitint; int deadc; int type; int autype; + int strictnbma; #define AU_NONE 0 #define AU_SIMPLE 1 #define AU_CRYPT 2