📄 ospfh_flood.c
字号:
/* OSPF Link State Acknowledgment message read -- RFC2328 Section 13.7. */
void
ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
struct stream *s, struct ospf *top, u_int16_t size)
{
struct ospf_neighbor *nbr;
struct mpls_te_link *lp;
struct in_addr source;
source.s_addr=iph->sourceIP.s_addr; /*@*/
/* increment statistics. */
top->ls_ack_in++;
nbr = ospf_nbr_lookup_by_addr (top->nbrlist, &source); /*@*/
if (nbr == NULL)
return;
while (size >= 120)
{
struct ospf_lsa *lsa, *lsr;
lsa=malloc(sizeof(struct ospf_lsa));
ospf_lsa_new(lsa);
lsa->data = (struct lsa_header *) STREAM_PNT (s);
stream_forward(s,sizeof(struct lsa_header));
lp= (struct mpls_te_link *) stream_pnt (s);
lsa->lp=lp;
size -= 120;
stream_forward (s, 100);
if (lsa->data->type < OSPF_MIN_LSA || lsa->data->type >= OSPF_MAX_LSA)
{
lsa->data = NULL;
ospf_lsa_discard (lsa);
continue;
}
lsr = ospf_ls_retransmit_lookup (nbr, lsa);
if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum)
{ospf_ls_retransmit_delete (nbr, lsr);
// OSPF_TIMER_OFF(nbr->t_ls_upd);
printf("remove a lsa from %s 's retx.\n",inet_ntoa(nbr->nbr_id));
}
lsa->data = NULL;
ospf_lsa_discard (lsa);
}
}
void
ospf_ls_ack_send (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) /*保留nbr*/
{
if (listcount (nbr->top->ls_ack_direct.ls_ack) == 0)
nbr->top->ls_ack_direct.dst = nbr->nbr_id;
listnode_add (nbr->top->ls_ack_direct.ls_ack, ospf_lsa_lock(lsa));
ospf_ls_ack_send_list(nbr->top, nbr->top->ls_ack_direct.ls_ack); /*@?*/
}
void
ospf_ls_ack_send_list (struct ospf *top, struct list *ack) /*@*/
{
struct thread_master *master;
struct ospf* ospf_top;
struct ospf_packet *op;
u_int16_t length;
ospf_top=top;
master=top->master;
length = OSPF_HEADER_SIZE;
op = ospf_packet_new (top->mtu);
/* Prepare OSPF common header. */
ospf_make_header (OSPF_MSG_LS_ACK, top, op->s);
/* Prepare OSPF Link State Acknowledgment body. */
length += ospf_make_ls_ack (ack, op->s); /*@*/
/* Fill OSPF header. */
ospf_fill_header (op->s, length);
/* Set packet length. */
op->length = length;
/* Set destination IP address. */
// op->dst = dst;
/* Add packet to the interface output queue. */
//ospf_packet_add (oi, op);
ospf_fifo_push (top->outbuf, op);
/* Hook thread to write packet. */
OSPFH_WRITE_ON();
}
int
ospf_make_ls_ack (struct list *ack, struct stream *s)
{
struct listnode *node;
struct listnode *next;
unsigned long delta = stream_get_putp(s) + 20; //Different from zebra: +24
u_int16_t length = OSPF_LS_ACK_MIN_SIZE;
struct ospf_lsa *lsa;
int count;
count = ack->count;
for (node = ack->head; node; node = next)
{
if (count)
{
lsa = node->data;
next = node->next;
if (length + delta > OSPF_PACKET_MAX) /*@*/
break;
stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
stream_put(s,lsa->lp,sizeof(struct mpls_te_link));
length += (OSPF_LSA_HEADER_SIZE+sizeof(struct mpls_te_link));
listnode_delete (ack, lsa);
ospf_lsa_unlock (lsa);
count--;
}
else
break;
}
return length;
}
void ospf_ls_ack_send_delayed (struct ospf * top)
{
// struct in_addr dst;
// dst = ((struct ospf_neighbor *)(top->nbrlist->head->data))->nbr_id; not used
// dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
while (listcount (top->ls_ack_direct.ls_ack))
ospf_ls_ack_send_list (top, top->ls_ack_direct.ls_ack);
}
int
ospf_ls_ack_timer (struct thread *thread) /*@not used*/
{
struct ospf *top;
struct thread_master* master;
top = THREAD_ARG (thread);
top->t_ls_ack = NULL;
master=top->master;
/* Send Link State Acknowledgment. */
if (listcount (top->ls_ack_direct.ls_ack) > 0)
ospf_ls_ack_send_delayed (top); /*@*/
/* Set LS Ack timer. */
OSPF_ISM_TIMER_ON (top->t_ls_ack, ospf_ls_ack_timer, top->v_ls_ack);
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
int
ospf_flood (struct ospf_neighbor *nbr, struct ospf_lsa *current,
struct ospf_lsa *new, struct ospf *top) /*@*/
{
struct timeval now;
int lsa_ack_flag;
int num;
int layer;
u_char index;
struct thread_master* master;
/*a*/
master=top->master;
lsa_ack_flag = 0;
/* Get current time. */
gettimeofday (&now, NULL);
/* If there is already a database copy, and if the
database copy was received via flooding and installed less
than MinLSArrival seconds ago, discard the new LSA
(without acknowledging it). */
if (current != NULL) /* -- endo. */
{
if (tv_cmp (tv_sub (now, current->tv_recv),int2tv (OSPF_MIN_LS_ARRIVAL)) < 0)
return -1;
}
/* Flood the new LSA out . */
lsa_ack_flag = ospf_flood_through_area (top, nbr, new) ;
layer=id_to_layernum(top->speaker_rc_id);
/* Remove the current database copy from all neighbors' Link state
retransmission lists. */
if (current)
{
ospf_ls_retransmit_delete_nbr_all (top, current); /*@*/
}
/* Do some internal house keeping that is needed here */
SET_FLAG (new->flags, OSPF_LSA_RECEIVED);
ospf_lsa_is_self_originated (new, top); /* Let it set the flag */ /*@*/
/* Install the new LSA in the link state database
(replacing the current database copy). This may cause the
routing table calculation to be scheduled. In addition,
timestamp the new LSA with the current time. The flooding
procedure cannot overwrite the newly installed LSA until
MinLSArrival seconds have elapsed. */
num=id_to_layernum(new->data->adv_router); /*@*/
index=ospf_lsa_install (num, new);
/*触发feed_up/feed_down*/
if(id_to_layernum(top->speaker_rc_id)!=OSPF_MAX_LAYERNUM)
OSPF_TIMER_OFF(top->t_ls_feed_up_timer);
OSPF_ISM_TIMER_ON (top->t_ls_feed_up_timer,ospfh_feed_up_timer,top->v_ls_feed_up); /*@*/
if(id_to_layernum(top->speaker_rc_id)!=1)
ospfh_feed_down_send(top,layer,index-1,new);
/* Update statistics value for OSPF-MIB. */
ospf_ls_ack_send(nbr,new);
top->rx_lsa_count++;
return 0;
}
int
ospf_flood_through_area (struct ospf* top,struct ospf_neighbor *inbr,
struct ospf_lsa *lsa)
{
int lsa_ack_flag = 0;
if (ospf_flood_out (top, inbr, lsa))
lsa_ack_flag = 1;
return (lsa_ack_flag);
}
/* OSPF LSA flooding -- RFC2328 Section 13.3. */
int
ospf_flood_out (struct ospf *top,
struct ospf_neighbor *inbr,
struct ospf_lsa *lsa)
{
struct ospf_neighbor *onbr;
struct listnode *rn;
int retx_flag;
struct list * update;
/* Remember if new LSA is added to a retransmit list. */
retx_flag = 0;
/* Each of the neighbors are examined,
to determine whether they must receive the new LSA. The following
steps are executed for each neighbor: */
for (rn = top->nbrlist->head; rn; rn = rn->next)
{
/*struct ospf_lsa *ls_req;*/
if (rn->data == NULL)
continue;
onbr = rn->data;
/*delete some nbr state check here*/
/* If the new LSA was received from this neighbor,examine the next neighbor. */
if (inbr)
if (IPV4_ADDR_SAME (&inbr->nbr_id, &onbr->nbr_id))
continue;
/* Add the new LSA to the Link state retransmission list
for the adjacency. The LSA will be retransmitted
at intervals until an acknowledgment is seen from
the neighbor. */
ospf_ls_retransmit_add (onbr, lsa);
retx_flag = 1;
}
/* If in the previous step, the LSA was NOT added to any of
the Link state retransmission lists, there is no need to
flood . */
if (retx_flag == 0)
return ;
/* The LSA must be flooded out the interface. Send a Link State
Update packet (including the new LSA as contents) out the
interface. The LSA's LS age must be incremented by InfTransDelay
(which must be > 0) when it is copied into the outgoing Link
State Update packet (until the LS age field reaches the maximum
value of MaxAge). */
/* RFC2328 Section 13.3
On non-broadcast networks, separate Link State Update
packets must be sent, as unicasts, to each adjacent neighbor
(i.e., those in state Exchange or greater). The destination
IP addresses for these packets are the neighbors' IP
addresses. */
update = list_new ();
listnode_add (update, ospf_lsa_lock(lsa));
ospf_ls_upd_send (onbr, update, OSPF_SEND_PACKET_INDIRECT);
list_delete (update);
return 0;
}
/* Remove All neighbor/interface's Link State Retransmit list . */
void
ospf_ls_retransmit_delete_nbr_all (struct ospf *top,
struct ospf_lsa *lsa)
{
struct listnode *rn;
struct ospf_neighbor *nbr;
struct ospf_lsa *lsr;
for (rn =(top->nbrlist)->head; rn; rn = rn->next)
/* If LSA find in LS-retransmit list, then remove it. */
if ((nbr = rn->data) != NULL)
{
lsr = ospf_ls_retransmit_lookup (nbr, lsa);
/* If LSA find in ls-retransmit list, remove it. */
if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum)
ospf_ls_retransmit_delete (nbr, lsr);
}
}
/* Remove LSA from neighbor's ls-request list. */
void
ospf_ls_retransmit_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
{
struct list *ls_rxmt;
ls_rxmt=nbr->ls_rxmt;
lsa->retransmit_counter--;
listnode_delete(ls_rxmt, lsa);
ospf_lsa_unlock(lsa);
}
/* Lookup LSA from neighbor's ls-retransmit list. */
struct ospf_lsa *
ospf_ls_retransmit_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
{
struct list *ls_rxmt;
struct ospf_lsa *match;
ls_rxmt=nbr->ls_rxmt;
match = ospf_lsa_lookup_in_list (ls_rxmt, lsa);
//ospfh_lsalist_install(ls_rxmt,id_to_layernum (lsah->adv_router));
return match;
}
/* Add LSA to be retransmitted to neighbor's ls-retransmit list. */
void
ospf_ls_retransmit_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
{
struct ospf_lsa *old;
old = ospf_ls_retransmit_lookup (nbr, lsa);
if (ospf_lsa_more_recent (old, lsa) < 0)
{
if (old)
{
old->retransmit_counter--;
listnode_delete (nbr->ls_rxmt, old);
ospf_lsa_unlock(old);
}
lsa->retransmit_counter++;
listnode_add (nbr->ls_rxmt, ospf_lsa_lock(lsa));
printf("lsa added to %s 's retxlist\n",inet_ntoa(nbr->nbr_id));
}
}
/* Do the LSA acking specified in table 19, Section 13.5, row 2
* This get called from ospf_flood_out_interface. Declared inline
* for speed. */
void
ospf_flood_delayed_lsa_ack (struct ospf *top, struct ospf_lsa *lsa) //temp
{
/* LSA is more recent than database copy, but was not
flooded back out receiving interface.
/* Whether LSA is more recent or not, and whether this is in
response to the LSA being sent out recieving interface has been
worked out previously */
/* Schedule a delayed LSA Ack to be sent */
listnode_add (top->ls_ack_direct.ls_ack, ospf_lsa_lock(lsa)); /*@*/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -