📄 ospfh_flood.c
字号:
#include "ospfh.h"
#include "ospfh_patch.h"
/* OSPF Link State Update message read -- RFC2328 Section 13. */
void
ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
struct stream *s, u_int16_t size, struct ospf *top) /*@*/
{
struct ospf_neighbor *nbr;
struct lsa_header *lsah;
struct list *lsas;
struct listnode *node, *next;
struct ospf_lsa *lsa = NULL;
struct in_addr source;
source.s_addr=iph->sourceIP.s_addr;
/* unsigned long ls_req_found = 0; */
/* Dis-assemble the stream, update each entry, re-encapsulate for flooding */
/* Increment statistics. */
top->ls_upd_in++; /*@*/
/* Check neighbor. */
nbr = ospf_nbr_lookup_by_addr (top->nbrlist, &source); /*@*/
if (nbr == NULL)
return;
/* Get list of LSAs from Link State Update packet. - Also performs Stages
* 1 (validate LSA checksum) and 2 (check for LSA consistent type)
* of section 13.
*/
lsas = ospf_ls_upd_list_lsa (nbr, s, size); /*@*/
/* Process each LSA received in the one packet. */
for (node = lsas->head; node; node = next)
{
struct ospf_lsa *ls_ret, *current;
int ret = 1;
int lsalayernum=0;
next = node->next;
lsa = (struct ospf_lsa*)(node->data);
listnode_delete (lsas, lsa); /* We don't need it in list anymore */
/* Validate Checksum - Done above by ospf_ls_upd_list_lsa() */
/* LSA Type - Done above by ospf_ls_upd_list_lsa() */
/* Find the LSA in the current database. */
lsah = lsa->data;
lsalayernum=id_to_layernum (lsah->adv_router);
current=ospf_lsa_lookup_in_lsdb(lsalayernum,lsa); /*@数据库接口提供。需要在第lsalayernum层的
lsdb里面寻找此lsa的实例*/
/* If the LSA's LS age is equal to MaxAge, and there is cur rently
no instance of the LSA in the router's link state database,
then take the following actions. */
if (IS_LSA_MAXAGE(lsa) && !current ) /*@*/
{
/* Response Link State Acknowledgment. */
ospf_ls_ack_send (nbr, lsa);
ospf_lsa_discard (lsa);
continue; //different from zebra
}
/* (5) Find the instance of this LSA that is currently contained
in the router's link state database. If there is no
database copy, or the received LSA is more recent than
the database copy the following steps must be performed. */
// ospf_flood (nbr, current, lsa, top);//temp
if (current==NULL ||( ret = ospf_lsa_more_recent (current, lsa) < 0)) /*@ lsa.c 1*/
{
/* Actual flooding procedure. */
if (ospf_flood (nbr, current, lsa, top) < 0) /*@*/
ospf_lsa_discard (lsa);
continue;
}
/* If the received LSA is the same instance as the database copy
(i.e., neither one is more recent) the following two steps
should be performed: */
if (ret == 0)
{
/* If the LSA is listed in the Link state retransmission list
for the receiving adjacency, the router itself is expecting
an acknowledgment for this LSA. The router should treat the
received LSA as an acknowledgment by removing the LSA from
the Link state retransmission list. This is termed an
"implied acknowledgment". */
ls_ret = ospf_ls_retransmit_lookup (nbr, lsa);
if (ls_ret != NULL)
{
ospf_ls_retransmit_delete (nbr, ls_ret);
ospf_ls_ack_send (nbr, lsa);
ospf_lsa_discard (lsa);
}
else
/* Acknowledge the receipt of the LSA by sending a
Link State Acknowledgment packet back out the receiving
interface. */
{
ospf_ls_ack_send (nbr, lsa);
ospf_lsa_discard (lsa);
}
}
/* The database copy is more recent. If the database copy
has LS age equal to MaxAge and LS sequence number equal to
MaxSequenceNumber, simply discard the received LSA without
acknowledging it. (In this case, the LSA's LS sequence number is
wrapping, and the MaxSequenceNumber LSA must be completely
flushed before any new LSA instance can be introduced). */
else if (ret > 0) /* Database copy is more recent */
{
if (IS_LSA_MAXAGE (current) &&
(current->data->ls_seqnum == htonl (OSPF_MAX_SEQUENCE_NUMBER)))
{
ospf_lsa_discard (lsa);
}
/* Otherwise, as long as the database copy has not been sent in a
Link State Update within the last MinLSArrival seconds, send the
database copy back to the sending neighbor, encapsulated within
a Link State Update Packet. The Link State Update Packet should
be sent directly to the neighbor. In so doing, do not put the
database copy of the LSA on the neighbor's link state
retransmission list, and do not acknowledge the received (less
recent) LSA instance. */
else
{
struct timeval now;
gettimeofday (&now, NULL);
if (tv_cmp (tv_sub (now, current->tv_orig),
int2tv (OSPF_MIN_LS_ARRIVAL)) > 0)
/* Trap NSSA type later.*/
{
struct list *update;
update=list_new();
listnode_add(update, ospf_lsa_lock(current));
ospf_ls_upd_send (nbr, update, OSPF_SEND_PACKET_DIRECT); /*@*/
list_delete(update);
}
ospf_lsa_discard (lsa);
}
}
// break;//temp
}
list_delete (lsas);
}
int id_to_layernum (struct in_addr id) /*@根据id判断层数,*/
{
int k=0;
if(id.s_net==0){k++;}
if(id.s_host==0){k++;}
if(id.s_lh==0){k++;}
if(id.s_impno==0){k++;}
return k;
}
/* Get the list of LSAs from Link State Update packet.
And process some validation -- RFC2328 Section 13. (1)-(2). */
static struct list*
ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s,u_int16_t size) /*@*/
{
u_int16_t count=1;
u_int32_t length;
struct lsa_header *lsah;
struct ospf_lsa *lsa;
struct list *lsas;
struct mpls_te_link *lp;
lsas = list_new ();
count = stream_getl (s); /*get the number of LSAs in the packet*/
size -= OSPF_LS_UPD_MIN_SIZE; /* # LSAs */
for (; size >= OSPF_LSA_HEADER_SIZE && count > 0; size -= length, stream_forward (s, length), count--)
{
lsah = (struct lsa_header *) stream_pnt (s);
stream_forward(s,sizeof(struct lsa_header));
lp= (struct mpls_te_link *) stream_pnt (s);
length =ntohs(lsah->length);
if (length > size)
break;
/*
* What if the received LSA's age is greater than MaxAge?
* Treat it as a MaxAge case -- endo.
*/
if (lsah->ls_age > OSPF_LSA_MAXAGE)
lsah->ls_age = OSPF_LSA_MAXAGE;
/* Create OSPF LSA instance. */
lsa=malloc(sizeof(struct ospf_lsa));
ospf_lsa_new(lsa);
lsa->data = ospf_lsa_data_new (length);
memcpy (lsa->data, lsah, length);
lsa->lp=lp;
listnode_add (lsas, lsa);
}
return lsas;
}
struct ospf_neighbor *
ospf_nbr_lookup_by_addr (struct list *nbrlist,
struct in_addr *addr)
{
struct listnode *node;
struct ospf_neighbor *nbr;
int count = nbrlist->count;
for (node = nbrlist->head; node; node = node->next)
{
if(count)
{
count--;
nbr = node->data;
if (addr->s_addr == nbr->nbr_id.s_addr)
return nbr;
}
break;
}
return NULL;
}
/* Send Link State Update with an LSA. */
void
ospf_ls_upd_send (struct ospf_neighbor *nbr, struct list *update, int flag) /*@*/
{
struct thread_master *master;
struct ospf* ospf_top; /*@*/
//struct ospf_interface *oi;
struct in_addr addr;
struct ospf_packet *op;
// struct listnode *node;
// int i;
u_int16_t length = OSPF_HEADER_SIZE;
//oi=nbr->oi;
ospf_top=nbr->top;
master=nbr->top->master; /*@*/
/* Decide destination address. */
if (flag == OSPF_SEND_PACKET_DIRECT)
addr=nbr->nbr_id;
else if (flag == OSPF_SEND_PACKET_INDIRECT)
// addr.s_addr = htonl (OSPF_ALLSPFROUTERS);
addr=nbr->nbr_id;
op = ospf_packet_new (nbr->top->mtu); /*@*/
/* Prepare OSPF common header. */
ospf_make_header (OSPF_MSG_LS_UPD, nbr->top, op->s); /*@*/
/* Prepare OSPF Link State Update body. */
length += ospf_make_ls_upd (nbr->top, update, op->s); /*@*/
/* Fill OSPF header. */
ospf_fill_header (op->s, length); /*@*/
/* Set packet length. */
op->length = length;
/* Decide destination address. */
// op->dst.s_addr = addr.s_addr; 广播
/* Add packet to the interface output queue. */
//ospf_packet_add (oi, op);
ospf_fifo_push (nbr->top->outbuf, op); /*@*/
/* Hook thread to write packet. */
OSPFH_WRITE_ON();
/* Add Link State Request Retransmission Timer. */
OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
}
int
ospf_make_ls_upd (struct ospf *top, struct list *update, struct stream *s) /*@*/
{
u_int16_t length = OSPF_LS_UPD_MIN_SIZE;
unsigned long delta = stream_get_putp (s);
unsigned long pp;
struct lsa_header *lsah;
u_int16_t ls_age;
int count = 0;
struct ospf_lsa *lsa;
struct listnode *n;
pp = stream_get_putp (s);
ospf_output_forward (s, 4);
while((n = update->head) != NULL)
{
lsa = n->data;
/* Check packet size. */
if (length + delta + ntohs(lsa->data->length) <= OSPF_PACKET_MAX) /*@*/
{
/* Keep pointer to LS age. */
lsah = (struct lsa_header *) (s->data + stream_get_putp (s));
/* Put LSA to Link State Update */
stream_put (s, lsa->data, LSA_HEADER_SIZE);
stream_put(s,lsa->lp,sizeof(struct mpls_te_link));
/* Set LS age. */
/* each hop must increment an lsa_age by transmit_delay
of OSPF interface */
ls_age = ls_age_increment (lsa, top->transmit_delay); /*@lsa age 增加*/
// lsah->ls_age = htons (ls_age);
length +=ntohs(lsa->data->length);
count++;
list_delete_node (update, n);
ospf_lsa_unlock (lsa);
}
}
/* Now set #LSAs. */
stream_set_putp (s, pp);
stream_putl (s, count);
stream_set_putp (s, s->endp);
return length;
}
int
ls_age_increment (struct ospf_lsa *lsa, int delay)
{
int age;
age = IS_LSA_MAXAGE (lsa) ? OSPF_LSA_MAXAGE : LS_AGE (lsa) + delay;
return (age > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : age);
}
/* Cyclic timer function. Fist registered in ospf_nbr_new () in
ospf_neighbor.c */
int
ospf_ls_upd_timer (struct thread *thread) /*@*/
{
struct ospf_neighbor *nbr;
struct thread_master* master;
nbr = THREAD_ARG (thread);
nbr->t_ls_upd = NULL;
master=nbr->top->master;
/* Send Link State Update. */
if (nbr->ls_rxmt->count > 0)
{
struct list *update;
struct list *ls_rxmt;
struct timeval now;
int retransmit_interval;
struct listnode *rn;
gettimeofday (&now, NULL);
retransmit_interval = nbr->top->retransmit_interval;
ls_rxmt = nbr->ls_rxmt;
update = list_new ();
for (rn = ls_rxmt->head ; rn; rn = rn->next)
{
struct ospf_lsa *lsa;
if ((lsa = rn->data) != NULL)
/* Don't retransmit an LSA if we received it within
the last RxmtInterval seconds - this is to allow the
neighbour a chance to acknowledge the LSA as it may
have ben just received before the retransmit timer
fired. This is a small tweak to what is in the RFC,
but it will cut out out a lot of retransmit traffic
- MAG */
if (tv_cmp (tv_sub (now, lsa->tv_recv),
int2tv (retransmit_interval)) >= 0)
{ listnode_add (update, ospf_lsa_lock(rn->data));
ospf_ls_upd_send (nbr, update, OSPF_SEND_PACKET_DIRECT);
}
}
// if (listcount (update) > 0)
// ospf_ls_upd_send (nbr, update, OSPF_SEND_PACKET_DIRECT);
list_delete (update);
}
/* Set LS Update retransmission timer. */
// OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* OSPF Link State Acknowledgment message read -- RFC2328 Section 13.7. */
void
ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -