/*EIGRP SIA-QUERY read function*/ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph, struct stream *s, struct eigrp_interface *ei, int size) { struct eigrp_neighbor *nbr; struct TLV_IPv4_Internal_type *tlv; uint16_t type; /* increment statistics. */ ei->siaQuery_in++; /* get neighbor struct */ nbr = eigrp_nbr_get(ei, eigrph, iph); /* neighbor must be valid, eigrp_nbr_get creates if none existed */ assert(nbr); nbr->recv_sequence_number = ntohl(eigrph->sequence); while (s->endp > s->getp) { type = stream_getw(s); if (type == EIGRP_TLV_IPv4_INT) { struct prefix dest_addr; stream_set_getp(s, s->getp - sizeof(uint16_t)); tlv = eigrp_read_ipv4_tlv(s); dest_addr.family = AFI_IP; dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( eigrp->topology_table, &dest_addr); /* If the destination exists (it should, but one never * know)*/ if (dest != NULL) { struct eigrp_fsm_action_message msg; struct eigrp_nexthop_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); msg.packet_type = EIGRP_OPC_SIAQUERY; msg.eigrp = eigrp; msg.data_type = EIGRP_INT; msg.adv_router = nbr; msg.metrics = tlv->metric; msg.entry = entry; msg.prefix = dest; eigrp_fsm_event(&msg); } eigrp_IPv4_InternalTLV_free(tlv); } } eigrp_hello_send_ack(nbr); }
/** * @fn eigrp_update_receive_GR_ask * * @param[in] eigrp EIGRP process * @param[in] nbr Neighbor update of who we received * @param[in] nbr_prefixes Prefixes which weren't advertised * * @return void * * @par * Function is used for notifying FSM about prefixes which * weren't advertised by neighbor: * We will send message to FSM with prefix delay set to infinity. */ static void eigrp_update_receive_GR_ask (struct eigrp *eigrp, struct eigrp_neighbor *nbr, struct list *nbr_prefixes) { struct listnode *node1; struct eigrp_prefix_entry *prefix; struct TLV_IPv4_Internal_type *tlv_max; /* iterate over all prefixes which weren't advertised by neighbor */ for (ALL_LIST_ELEMENTS_RO(nbr_prefixes, node1, prefix)) { zlog_debug("GR receive: Neighbor not advertised %s/%d", inet_ntoa(prefix->destination_ipv4->prefix), prefix->destination_ipv4->prefixlen); /* create internal IPv4 TLV with infinite delay */ tlv_max = eigrp_IPv4_InternalTLV_new(); tlv_max->type = EIGRP_TLV_IPv4_INT; tlv_max->length = 28U; tlv_max->metric = prefix->reported_metric; /* set delay to MAX */ tlv_max->metric.delay = EIGRP_MAX_METRIC; tlv_max->destination = prefix->destination_ipv4->prefix; tlv_max->prefix_length = prefix->destination_ipv4->prefixlen; /* prepare message for FSM */ struct eigrp_fsm_action_message *fsm_msg; fsm_msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, sizeof(struct eigrp_fsm_action_message)); struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(prefix->entries, nbr); fsm_msg->packet_type = EIGRP_OPC_UPDATE; fsm_msg->eigrp = eigrp; fsm_msg->data_type = EIGRP_TLV_IPv4_INT; fsm_msg->adv_router = nbr; fsm_msg->data.ipv4_int_type = tlv_max; fsm_msg->entry = entry; fsm_msg->prefix = prefix; /* send message to FSM */ int event = eigrp_get_fsm_event(fsm_msg); eigrp_fsm_event(fsm_msg, event); /* free memory used by TLV */ eigrp_IPv4_InternalTLV_free (tlv_max); } }
/** * @fn eigrp_update_send_GR_part * * @param[in] nbr contains neighbor who would receive Graceful restart * * @return void * * @par * Function used for sending Graceful restart Update packet * and if there are multiple chunks, send only one of them. * It is called from thread. Do not call it directly. * * Uses nbr_gr_packet_type from neighbor. */ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) { struct eigrp_packet *ep; u_int16_t length = EIGRP_HEADER_LEN; struct listnode *node, *nnode; struct eigrp_prefix_entry *pe; struct prefix_ipv4 *dest_addr; struct eigrp *e; struct access_list *alist, *alist_i; struct prefix_list *plist, *plist_i; struct list *prefixes; u_int32_t flags; unsigned int send_prefixes; struct TLV_IPv4_Internal_type *tlv_max; /* get prefixes to send to neighbor */ prefixes = nbr->nbr_gr_prefixes_send; send_prefixes = 0; length = EIGRP_HEADER_LEN; /* if there already were last packet chunk, we won't continue */ if(nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_LAST) return; /* if this is first packet chunk, we need to decide, * if there will be one or more chunks */ if(nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_FIRST) { if(prefixes->count <= EIGRP_TLV_MAX_IPv4) { /* there will be only one chunk */ flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG + EIGRP_EOT_FLAG; nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST; } else { /* there will be more chunks */ flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG; nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA; } } else { /* this is not first chunk, and we need to decide, * if there will be more chunks */ if(prefixes->count <= EIGRP_TLV_MAX_IPv4) { /* this is last chunk */ flags = EIGRP_EOT_FLAG; nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST; } else { /* there will be more chunks */ flags = 0; nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA; } } ep = eigrp_packet_new(nbr->ei->ifp->mtu); /* Prepare EIGRP Graceful restart UPDATE header */ eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, flags, nbr->ei->eigrp->sequence_number, nbr->recv_sequence_number); // encode Authentication TLV, if needed if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) { length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); } for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe)) { /* * Filtering */ dest_addr = pe->destination_ipv4; /* get list from eigrp process */ e = eigrp_lookup(); /* Get access-lists and prefix-lists from process and interface */ alist = e->list[EIGRP_FILTER_OUT]; plist = e->prefix[EIGRP_FILTER_OUT]; alist_i = nbr->ei->list[EIGRP_FILTER_OUT]; plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT]; /* Check if any list fits */ if ((alist && access_list_apply (alist, (struct prefix *) dest_addr) == FILTER_DENY)|| (plist && prefix_list_apply (plist, (struct prefix *) dest_addr) == FILTER_DENY)|| (alist_i && access_list_apply (alist_i, (struct prefix *) dest_addr) == FILTER_DENY)|| (plist_i && prefix_list_apply (plist_i, (struct prefix *) dest_addr) == FILTER_DENY)) { /* do not send filtered route */ zlog_info("Filtered prefix %s won't be sent out.", inet_ntoa(dest_addr->prefix)); } else { /* sending route which wasn't filtered */ length += eigrp_add_internalTLV_to_stream(ep->s, pe); send_prefixes++; } alist = e->list[EIGRP_FILTER_IN]; plist = e->prefix[EIGRP_FILTER_IN]; alist_i = nbr->ei->list[EIGRP_FILTER_IN]; plist_i = nbr->ei->prefix[EIGRP_FILTER_IN]; /* Check if any list fits */ if ((alist && access_list_apply (alist, (struct prefix *) dest_addr) == FILTER_DENY)|| (plist && prefix_list_apply (plist, (struct prefix *) dest_addr) == FILTER_DENY)|| (alist_i && access_list_apply (alist_i, (struct prefix *) dest_addr) == FILTER_DENY)|| (plist_i && prefix_list_apply (plist_i, (struct prefix *) dest_addr) == FILTER_DENY)) { /* do not send filtered route */ zlog_info("Filtered prefix %s will be removed.", inet_ntoa(dest_addr->prefix)); tlv_max = eigrp_IPv4_InternalTLV_new(); tlv_max->type = EIGRP_TLV_IPv4_INT; tlv_max->length = 28U; tlv_max->metric = pe->reported_metric; /* set delay to MAX */ tlv_max->metric.delay = EIGRP_MAX_METRIC; tlv_max->destination = pe->destination_ipv4->prefix; tlv_max->prefix_length = pe->destination_ipv4->prefixlen; /* prepare message for FSM */ struct eigrp_fsm_action_message *fsm_msg; fsm_msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, sizeof(struct eigrp_fsm_action_message)); struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(pe->entries, nbr); fsm_msg->packet_type = EIGRP_OPC_UPDATE; fsm_msg->eigrp = e; fsm_msg->data_type = EIGRP_TLV_IPv4_INT; fsm_msg->adv_router = nbr; fsm_msg->data.ipv4_int_type = tlv_max; fsm_msg->entry = entry; fsm_msg->prefix = pe; /* send message to FSM */ int event = eigrp_get_fsm_event(fsm_msg); eigrp_fsm_event(fsm_msg, event); /* free memory used by TLV */ eigrp_IPv4_InternalTLV_free (tlv_max); } /* * End of filtering */ /* NULL the pointer */ dest_addr = NULL; /* delete processed prefix from list */ listnode_delete(prefixes, pe); /* if there are enough prefixes, send packet */ if(send_prefixes >= EIGRP_TLV_MAX_IPv4) break; } /* compute Auth digest */ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) { eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG); } /* EIGRP Checksum */ eigrp_packet_checksum(nbr->ei, ep->s, length); ep->length = length; ep->dst.s_addr = nbr->src.s_addr; /*This ack number we await from neighbor*/ ep->sequence_number = nbr->ei->eigrp->sequence_number; if (IS_DEBUG_EIGRP_PACKET(0, RECV)) zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]", ep->length, ep->sequence_number, inet_ntoa(ep->dst)); /*Put packet to retransmission queue*/ eigrp_fifo_push_head(nbr->retrans_queue, ep); if (nbr->retrans_queue->count == 1) { eigrp_send_packet_reliably(nbr); } }
/* * EIGRP UPDATE read function */ void eigrp_update_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph, struct stream * s, struct eigrp_interface *ei, int size) { struct eigrp_neighbor *nbr; struct TLV_IPv4_Internal_type *tlv; struct eigrp_prefix_entry *pe; struct eigrp_neighbor_entry *ne; u_int32_t flags; u_int16_t type; uint16_t length; u_char same; struct access_list *alist; struct prefix_list *plist; struct eigrp *e; u_char graceful_restart; u_char graceful_restart_final; struct list *nbr_prefixes; int ret; /* increment statistics. */ ei->update_in++; /* get neighbor struct */ nbr = eigrp_nbr_get(ei, eigrph, iph); /* neighbor must be valid, eigrp_nbr_get creates if none existed */ assert(nbr); flags = ntohl(eigrph->flags); if (flags & EIGRP_CR_FLAG) { return; } same = 0; graceful_restart = 0; graceful_restart_final = 0; if((nbr->recv_sequence_number) == (ntohl(eigrph->sequence))) same = 1; nbr->recv_sequence_number = ntohl(eigrph->sequence); if (IS_DEBUG_EIGRP_PACKET(0, RECV)) zlog_debug("Processing Update size[%u] int(%s) nbr(%s) seq [%u] flags [%0x]", size, ifindex2ifname(nbr->ei->ifp->ifindex), inet_ntoa(nbr->src), nbr->recv_sequence_number, flags); if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG+EIGRP_EOT_FLAG)) && (!same)) { /* Graceful restart Update received with all routes */ zlog_info("Neighbor %s (%s) is resync: peer graceful-restart", inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); /* get all prefixes from neighbor from topology table */ nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr); graceful_restart = 1; graceful_restart_final = 1; } else if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG)) && (!same)) { /* Graceful restart Update received, routes also in next packet */ zlog_info("Neighbor %s (%s) is resync: peer graceful-restart", inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); /* get all prefixes from neighbor from topology table */ nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr); /* save prefixes to neighbor for later use */ nbr->nbr_gr_prefixes = nbr_prefixes; graceful_restart = 1; graceful_restart_final = 0; } else if((flags == (EIGRP_EOT_FLAG)) && (!same)) { /* If there was INIT+RS Update packet before, * consider this as GR EOT */ if(nbr->nbr_gr_prefixes != NULL) { /* this is final packet of GR */ nbr_prefixes = nbr->nbr_gr_prefixes; nbr->nbr_gr_prefixes = NULL; graceful_restart = 1; graceful_restart_final = 1; } } else if((flags == (0)) && (!same)) { /* If there was INIT+RS Update packet before, * consider this as GR not final packet */ if(nbr->nbr_gr_prefixes != NULL) { /* this is GR not final route packet */ nbr_prefixes = nbr->nbr_gr_prefixes; graceful_restart = 1; graceful_restart_final = 0; } } else if((flags & EIGRP_INIT_FLAG) && (!same)) { /* When in pending state, send INIT update only if it wasn't already sent before (only if init_sequence is 0) */ if((nbr->state == EIGRP_NEIGHBOR_PENDING) && (nbr->init_sequence_number == 0)) eigrp_update_send_init(nbr); if (nbr->state == EIGRP_NEIGHBOR_UP) { eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN); eigrp_topology_neighbor_down(nbr->ei->eigrp,nbr); nbr->recv_sequence_number = ntohl(eigrph->sequence); zlog_info("Neighbor %s (%s) is down: peer restarted", inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING); zlog_info("Neighbor %s (%s) is pending: new adjacency", inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); eigrp_update_send_init(nbr); } } /*If there is topology information*/ while (s->endp > s->getp) { type = stream_getw(s); if (type == EIGRP_TLV_IPv4_INT) { stream_set_getp(s, s->getp - sizeof(u_int16_t)); tlv = eigrp_read_ipv4_tlv(s); /*searching if destination exists */ struct prefix_ipv4 *dest_addr; dest_addr = prefix_ipv4_new(); dest_addr->prefix = tlv->destination; dest_addr->prefixlen = tlv->prefix_length; struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( eigrp->topology_table, dest_addr); /*if exists it comes to DUAL*/ if (dest != NULL) { /* remove received prefix from neighbor prefix list if in GR */ if(graceful_restart) remove_received_prefix_gr(nbr_prefixes, dest); struct eigrp_fsm_action_message *msg; msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, sizeof(struct eigrp_fsm_action_message)); struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); msg->packet_type = EIGRP_OPC_UPDATE; msg->eigrp = eigrp; msg->data_type = EIGRP_TLV_IPv4_INT; msg->adv_router = nbr; msg->data.ipv4_int_type = tlv; msg->entry = entry; msg->prefix = dest; int event = eigrp_get_fsm_event(msg); eigrp_fsm_event(msg, event); } else { /*Here comes topology information save*/ pe = eigrp_prefix_entry_new(); pe->serno = eigrp->serno; pe->destination_ipv4 = dest_addr; pe->af = AF_INET; pe->state = EIGRP_FSM_STATE_PASSIVE; pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE; ne = eigrp_neighbor_entry_new(); ne->ei = ei; ne->adv_router = nbr; ne->reported_metric = tlv->metric; ne->reported_distance = eigrp_calculate_metrics(eigrp, &tlv->metric); //TODO: Work in progress /* * Filtering */ e = eigrp_lookup(); /* get access-list from eigrp process */ alist = e->list[EIGRP_FILTER_IN]; zlog_info("PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix)); if (alist) { zlog_info ("ALIST PROC IN: %s", alist->name); } else { zlog_info("ALIST PROC IN je prazdny"); } /* Check if access-list fits */ if (alist && access_list_apply (alist, (struct prefix *) dest_addr) == FILTER_DENY) { /* If yes, set reported metric to Max */ zlog_info("PROC alist IN: Skipping"); //ne->reported_metric.delay = EIGRP_MAX_METRIC; zlog_info("PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix)); eigrp_IPv4_InternalTLV_free (tlv); continue; } else { zlog_info("PROC alist IN: NENastavujem metriku "); } plist = e->prefix[EIGRP_FILTER_IN]; if (plist) { zlog_info ("PLIST PROC IN: %s", plist->name); } else { zlog_info("PLIST PROC IN je prazdny"); } /* Check if prefix-list fits */ if (plist && prefix_list_apply (plist, (struct prefix *) dest_addr) == FILTER_DENY) { /* If yes, set reported metric to Max */ zlog_info("PLIST PROC IN: Skipping"); //ne->reported_metric.delay = EIGRP_MAX_METRIC; zlog_info("PLIST PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix)); eigrp_IPv4_InternalTLV_free (tlv); continue; } else { zlog_info("PLIST PROC IN: NENastavujem metriku "); } //Check route-map /*if (e->routemap[EIGRP_FILTER_IN]) { ret = route_map_apply (e->routemap[EIGRP_FILTER_IN], (struct prefix *)dest_addr, RMAP_EIGRP, NULL); if (ret == RMAP_DENYMATCH) { zlog_debug ("%s is filtered by route-map",inet_ntoa (dest_addr->prefix)); continue; } }*/ /*Get access-list from current interface */ zlog_info("Checking access_list on interface: %s",ei->ifp->name); alist = ei->list[EIGRP_FILTER_IN]; if (alist) { zlog_info ("ALIST INT IN: %s", alist->name); } else { zlog_info("ALIST INT IN je prazdny"); } /* Check if access-list fits */ if (alist && access_list_apply (alist, (struct prefix *) dest_addr) == FILTER_DENY) { /* If yes, set reported metric to Max */ zlog_info("INT alist IN: Skipping"); //ne->reported_metric.delay = EIGRP_MAX_METRIC; zlog_info("INT IN Prefix: %s", inet_ntoa(dest_addr->prefix)); eigrp_IPv4_InternalTLV_free (tlv); continue; } else { zlog_info("INT IN: NENastavujem metriku "); } plist = ei->prefix[EIGRP_FILTER_IN]; if (plist) { zlog_info ("PLIST INT IN: %s", plist->name); } else { zlog_info("PLIST INT IN je prazdny"); } /* Check if prefix-list fits */ if (plist && prefix_list_apply (plist, (struct prefix *) dest_addr) == FILTER_DENY) { /* If yes, set reported metric to Max */ zlog_info("PLIST INT IN: Skipping"); //ne->reported_metric.delay = EIGRP_MAX_METRIC; zlog_info("PLIST INT IN Prefix: %s", inet_ntoa(dest_addr->prefix)); eigrp_IPv4_InternalTLV_free (tlv); continue; } else { zlog_info("PLIST INT IN: NENastavujem metriku "); } //Check route-map /*if (ei->routemap[EIGRP_FILTER_IN]) { ret = route_map_apply (ei->routemap[EIGRP_FILTER_IN], (struct prefix *)dest_addr, RMAP_EIGRP, NULL); if (ret == RMAP_DENYMATCH) { zlog_debug ("%s is filtered by route-map",inet_ntoa (dest_addr->prefix)); continue; } }*/ /* * End of filtering */ ne->distance = eigrp_calculate_total_metrics(eigrp, ne); zlog_info("<DEBUG PROC IN Distance: %x", ne->distance); zlog_info("<DEBUG PROC IN Delay: %x", ne->total_metric.delay); pe->fdistance = pe->distance = pe->rdistance = ne->distance; ne->prefix = pe; ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG; eigrp_prefix_entry_add(eigrp->topology_table, pe); eigrp_neighbor_entry_add(pe, ne); pe->distance = pe->fdistance = pe->rdistance = ne->distance; pe->reported_metric = ne->total_metric; eigrp_topology_update_node_flags(pe); pe->req_action |= EIGRP_FSM_NEED_UPDATE; listnode_add(eigrp->topology_changes_internalIPV4, pe); } eigrp_IPv4_InternalTLV_free (tlv); } } /* ask about prefixes not present in GR update, * if this is final GR packet */ if(graceful_restart_final) { eigrp_update_receive_GR_ask(eigrp, nbr, nbr_prefixes); } /* * We don't need to send separate Ack for INIT Update. INIT will be acked in EOT Update. */ if ((nbr->state == EIGRP_NEIGHBOR_UP) && !(flags == EIGRP_INIT_FLAG)) { eigrp_hello_send_ack(nbr); } eigrp_query_send_all(eigrp); eigrp_update_send_all(eigrp, ei); }
/*EIGRP QUERY read function*/ void eigrp_query_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph, struct stream * s, struct eigrp_interface *ei, int size) { struct eigrp_neighbor *nbr; struct TLV_IPv4_Internal_type *tlv; struct eigrp_prefix_entry *temp_tn; struct eigrp_neighbor_entry *temp_te; u_int16_t type; /* increment statistics. */ ei->query_in++; /* get neighbor struct */ nbr = eigrp_nbr_get(ei, eigrph, iph); /* neighbor must be valid, eigrp_nbr_get creates if none existed */ assert(nbr); nbr->recv_sequence_number = ntohl(eigrph->sequence); while (s->endp > s->getp) { type = stream_getw(s); if (type == EIGRP_TLV_IPv4_INT) { stream_set_getp(s, s->getp - sizeof(u_int16_t)); tlv = eigrp_read_ipv4_tlv(s); struct prefix_ipv4 *dest_addr; dest_addr = prefix_ipv4_new(); dest_addr->prefix = tlv->destination; dest_addr->prefixlen = tlv->prefix_length; struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( eigrp->topology_table, dest_addr); /* If the destination exists (it should, but one never know)*/ if (dest != NULL) { struct eigrp_fsm_action_message *msg; msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, sizeof(struct eigrp_fsm_action_message)); struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup( dest->entries, nbr); msg->packet_type = EIGRP_OPC_QUERY; msg->eigrp = eigrp; msg->data_type = EIGRP_TLV_IPv4_INT; msg->adv_router = nbr; msg->data.ipv4_int_type = tlv; msg->entry = entry; msg->prefix = dest; int event = eigrp_get_fsm_event(msg); eigrp_fsm_event(msg, event); } eigrp_IPv4_InternalTLV_free (tlv); } } eigrp_hello_send_ack(nbr); eigrp_query_send_all(eigrp); eigrp_update_send_all(eigrp,nbr->ei); }