n->lsrr_timer->hook=lsrr_timer_hook;
n->lsrr_timer->recurrent=ifa->rxmtint;
DBG("%s: Installing lsrr timer.\n", p->name);
+ init_list(&n->ackl);
+ n->ackd_timer=tm_new(p->pool);
+ n->ackd_timer->data=n;
+ n->ackd_timer->randomize=0;
+ n->ackd_timer->hook=ackd_timer_hook;
+ n->ackd_timer->recurrent=ifa->rxmtint/2; /* FIXME use some config? */
+ DBG("%s: Installing ackd timer.\n", p->name);
}
ospf_neigh_sm(n, INM_HELLOREC);
#include "ospf.h"
+/* Note, that h is in network endianity! */
void
-ospf_lsack_tx(struct ospf_neighbor *n)
+ospf_lsack_direct_tx(struct ospf_neighbor *n,struct ospf_lsa_header *h)
{
- /* FIXME Go on! */
+ struct ospf_packet *op;
+ struct ospf_lsack_packet *pk;
+ sock *sk=n->ifa->ip_sk;
+ u16 len;
+
+ pk=(struct ospf_lsack_packet *)sk->tbuf;
+ op=(struct ospf_packet *)sk->tbuf;
+
+ fill_ospf_pkt_hdr(n->ifa, pk, LSUPD);
+
+ memcpy(pk+1,h,sizeof(struct ospf_lsa_header));
+ len=sizeof(struct ospf_lsack_packet)+sizeof(struct ospf_lsa_header);
+ op->length=htons(len);
+ ospf_pkt_finalize(n->ifa, op);
+ sk_send_to(sk,len, n->ip, OSPF_PROTO);
+}
+
+void
+ospf_lsa_delay(struct ospf_neighbor *n,struct ospf_lsa_header *h,
+ struct proto *p)
+{
+ struct lsah_n *no;
+
+ no=mb_alloc(p->pool,sizeof(struct lsah_n));
+ memcpy(&no->lsa,h,sizeof(struct ospf_lsa_header));
+ add_tail(&n->ackl, NODE no);
+
+}
+
+void
+ackd_timer_hook(timer *t)
+{
+ struct ospf_neighbor *n=t->data;
+ if(!EMPTY_LIST(n->ackl)) ospf_lsack_delay_tx(n);
+}
+
+void
+ospf_lsack_delay_tx(struct ospf_neighbor *n)
+{
+ struct ospf_packet *op;
+ struct ospf_lsack_packet *pk;
+ sock *sk;
+ u16 len,i=0;
+ struct ospf_lsa_header *h;
+ struct lsah_n *no;
+ struct ospf_iface *ifa=n->ifa;
+
+ if(ifa->type==OSPF_IT_BCAST)
+ {
+ sk=ifa->hello_sk;
+ }
+ else
+ {
+ sk=ifa->ip_sk;
+ }
+
+ pk=(struct ospf_lsack_packet *)sk->tbuf;
+ op=(struct ospf_packet *)sk->tbuf;
+
+ fill_ospf_pkt_hdr(n->ifa, pk, LSUPD);
+ h=(struct ospf_lsa_header *)(pk+1);
+
+ while(!EMPTY_LIST(n->ackl))
+ {
+ no=(struct lsah_n *)HEAD(n->ackl);
+ memcpy(h+i,&no->lsa, sizeof(struct ospf_lsa_header));
+ i++;
+ rem_node(NODE n);
+ if((i*sizeof(struct ospf_lsa_header)+sizeof(struct ospf_lsack_packet)-SIPH)>
+ n->ifa->iface->mtu)
+ {
+ if(!EMPTY_LIST(n->ackl))
+ {
+ len=sizeof(struct ospf_lsack_packet)+i*sizeof(struct ospf_lsa_header);
+ op->length=htons(len);
+ ospf_pkt_finalize(n->ifa, op);
+ 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);
+ }
+ else
+ {
+ sk_send_to(sk ,len, AllDRouters, OSPF_PROTO);
+ }
+ }
+ else
+ {
+ sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE);
+ }
+
+ fill_ospf_pkt_hdr(n->ifa, pk, LSUPD);
+ h=(struct ospf_lsa_header *)(pk+1);
+ i=0;
+ }
+ }
+ }
+
+ len=sizeof(struct ospf_lsack_packet)+i*sizeof(struct ospf_lsa_header);
+ op->length=htons(len);
+ ospf_pkt_finalize(n->ifa, op);
+ 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);
+ }
+ else
+ {
+ sk_send_to(sk ,len, AllDRouters, OSPF_PROTO);
+ }
+ }
+ else
+ {
+ sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE);
+ }
}
+
+
void
ospf_lsack_rx(struct ospf_lsack_packet *ps, struct proto *p,
struct ospf_iface *ifa, u16 size)
ospf_hash_delete(n->lsrth,en);
}
}
-
-void
-add_ack_list(struct ospf_neighbor *n,struct ospf_lsa_header *lsa)
-{
- /* FIXME Go on */
-}
-
#ifndef _BIRD_OSPF_LSACK_H_
#define _BIRD_OSPF_LSACK_H_
+struct lsah_n {
+ node n;
+ struct ospf_lsa_header lsa;
+};
-void ospf_lsack_tx(struct ospf_neighbor *n);
+void ospf_lsack_direct_tx(struct ospf_neighbor *n,struct ospf_lsa_header *h);
void ospf_lsack_rx(struct ospf_lsack_packet *ps, struct proto *p,
struct ospf_iface *ifa, u16 size);
-void add_ack_list(struct ospf_neighbor *n,struct ospf_lsa_header *lsa);
-
+void ackd_timer_hook(timer *t);
+void ospf_lsack_delay_tx(struct ospf_neighbor *n);
+void ospf_lsa_delay(struct ospf_neighbor *n,struct ospf_lsa_header *h,
+ struct proto *p);
#endif /* _BIRD_OSPF_LSACK_H_ */
if(ifa->type==OSPF_IT_NBMA)
{
- struct ospf_neighbor *nnn;
- WALK_LIST(NODE nnn,ifa->neigh_list)
- {
- if(nnn->state>NEIGHBOR_EXSTART)
- sk_send_to(sk,len, nnn->ip, OSPF_PROTO);
- }
+ sk_send_to_agt(sk ,len, ifa, NEIGHBOR_EXCHANGE);
}
else
{
/* pg 143 (4) */
if((lsatmp.age==LSA_MAXAGE)&&(lsadb==NULL))
{
- struct ospf_neighbor *n=NULL;
- struct ospf_iface *ifa=NULL;
int flag=0;
+ struct ospf_iface *ifatmp;
- WALK_LIST(NODE ifa,po->iface_list)
- WALK_LIST(NODE ntmp,ifa->neigh_list)
+ WALK_LIST(NODE ifatmp,po->iface_list)
+ WALK_LIST(NODE ntmp,ifatmp->neigh_list)
if((ntmp->state==NEIGHBOR_EXCHANGE)&&
(ntmp->state==NEIGHBOR_LOADING))
flag=1;
if(flag==0)
{
- add_ack_list(n,lsa);
+ ospf_lsack_direct_tx(n,lsa);
+
continue;
}
}
lsadb=lsa_install_new(&lsatmp,body, oa);
DBG("New LSA installed in DB\n");
- /* FIXME 144 (5e) ack */
+ if(ifa->state==OSPF_IS_BACKUP)
+ {
+ if(ifa->drid==n->rid) ospf_lsa_delay(n, lsa, p);
+ }
+ else if(ifa->drid==n->rid) ospf_lsa_delay(n, lsa, p);
/* FIXME 145 (5f) self originated? */
continue;
{
struct top_hash_entry *en;
if((en=ospf_hash_find_header(n->lsrth,&lsadb->lsa))!=NULL)
+ {
s_rem_node(SNODE en);
- /* FIXME ack_lsa() */
+ if(ifa->state==OSPF_IS_BACKUP)
+ {
+ if(n->rid==ifa->drid) ospf_lsa_delay(n, lsa, p);
+ }
+ }
+ else
+ {
+ ospf_lsack_direct_tx(n,lsa);
+ }
continue;
}
/* pg145 (8) */
- if((lsadb->lsa.age==LSA_MAXAGE)&&(lsadb->lsa.sn==LSA_MAXSEQNO)) continue;
+ if((lsadb->lsa.age==LSA_MAXAGE)&&(lsadb->lsa.sn==LSA_MAXSEQNO))
+ {
+ continue;
+ }
{
list l;
s_init(&(n->lsrqi), &(n->lsrql));
s_init(&(n->lsrti), &(n->lsrtl));
tm_start(n->lsrr_timer,n->ifa->rxmtint);
+ tm_start(n->ackd_timer,n->ifa->rxmtint/2);
}
else die("NEGDONE and I'm not in EXSTART?\n");
break;
void *ldbdes; /* Last database description packet */
timer *rxmt_timer; /* RXMT timer */
timer *lsrr_timer; /* Link state requiest retransmition timer */
+ list ackl;
+ timer *ackd_timer; /* Delayed ack timer */
};
/* Definitions for interface state machine */
DBG("%s: Err_Hook called on interface %s\n", p->name,sk->iface->name);
}
+void
+sk_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);
+}
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);
#endif /* _BIRD_OSPF_PACKET_H_ */