int eigrp_nbr_count_get(void){ struct eigrp_interface *iface; struct listnode *node, *node2, *nnode2; struct eigrp_neighbor *nbr; struct eigrp *eigrp = eigrp_lookup(); u_int32_t counter; if (eigrp == NULL) { zlog_debug("EIGRP Routing Process not enabled"); return 0; } counter=0; for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) { for (ALL_LIST_ELEMENTS(iface->nbrs, node2, nnode2, nbr)) { if (nbr->state == EIGRP_NEIGHBOR_UP){ counter++; } } } return counter; }
int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) { struct eigrp_prefix_entry *prefix = msg->prefix; struct eigrp_neighbor_entry *entry = msg->entry; if (prefix->state == EIGRP_FSM_STATE_PASSIVE) { if (!eigrp_metrics_is_same(&prefix->reported_metric, &((struct eigrp_neighbor_entry *) prefix->entries->head->data)->total_metric)) { prefix->rdistance = prefix->fdistance = prefix->distance = ((struct eigrp_neighbor_entry *) prefix->entries->head->data)->distance; prefix->reported_metric = ((struct eigrp_neighbor_entry *) prefix->entries->head->data)->total_metric; if (msg->packet_type == EIGRP_OPC_QUERY) eigrp_send_reply(msg->adv_router, msg->entry); prefix->req_action |= EIGRP_FSM_NEED_UPDATE; listnode_add((eigrp_lookup())->topology_changes_internalIPV4,prefix); } eigrp_topology_update_node_flags(prefix); eigrp_update_routing_table(prefix); } if (msg->packet_type == EIGRP_OPC_QUERY) eigrp_send_reply(msg->adv_router, prefix); return 1; }
/* ARGSUSED */ void eigrp_route_map_update(const char *notused) { int i; struct eigrp *e; e = eigrp_lookup(); if (e) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (e->route_map[i].name) e->route_map[i].map = route_map_lookup_by_name( e->route_map[i].name); } } }
void eigrp_routemap_update_redistribute(void) { int i; struct eigrp *e; e = eigrp_lookup(); if (e) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (e->route_map[i].name) e->route_map[i].map = route_map_lookup_by_name( e->route_map[i].name); } } }
/* Router-id update message from zebra. */ static int eigrp_router_id_update_zebra(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct eigrp *eigrp; struct prefix router_id; zebra_router_id_update_read(zclient->ibuf, &router_id); router_id_zebra = router_id.u.prefix4; eigrp = eigrp_lookup(); if (eigrp != NULL) eigrp_router_id_update(eigrp); return 0; }
void eigrp_if_rmap_update(struct if_rmap *if_rmap) { struct interface *ifp; struct eigrp_interface *ei, *ei2; struct listnode *node, *nnode; struct route_map *rmap; struct eigrp *e; ifp = if_lookup_by_name(if_rmap->ifname); if (ifp == NULL) return; ei = NULL; e = eigrp_lookup(); for (ALL_LIST_ELEMENTS(e->eiflist, node, nnode, ei2)) { if (strcmp(ei2->ifp->name, ifp->name) == 0) { ei = ei2; break; } } if (if_rmap->routemap[IF_RMAP_IN]) { rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]); if (rmap) ei->routemap[IF_RMAP_IN] = rmap; else ei->routemap[IF_RMAP_IN] = NULL; } else ei->routemap[EIGRP_FILTER_IN] = NULL; if (if_rmap->routemap[IF_RMAP_OUT]) { rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]); if (rmap) ei->routemap[IF_RMAP_OUT] = rmap; else ei->routemap[IF_RMAP_OUT] = NULL; } else ei->routemap[EIGRP_FILTER_OUT] = NULL; }
/** * @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); } }
void eigrp_update_send (struct eigrp_interface *ei) { struct eigrp_packet *ep; struct listnode *node, *nnode, *nnode2; struct eigrp_neighbor *nbr; struct eigrp_prefix_entry *pe; u_char has_tlv; struct access_list *alist; struct prefix_list *plist; struct access_list *alist_i; struct prefix_list *plist_i; struct eigrp *e; struct prefix_ipv4 *dest_addr; u_int16_t length = EIGRP_HEADER_LEN; ep = eigrp_packet_new(ei->ifp->mtu); /* Prepare EIGRP INIT UPDATE header */ eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei, ep->s, 0, ei->eigrp->sequence_number, 0); // encode Authentication TLV, if needed if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) { length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei); } has_tlv = 0; for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe)) { if(pe->req_action & EIGRP_FSM_NEED_UPDATE) { /* Get destination address from prefix */ dest_addr = pe->destination_ipv4; /* * Filtering */ //TODO: Work in progress /* 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 = ei->list[EIGRP_FILTER_OUT]; plist_i = 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)) { zlog_info("PROC OUT: Skipping"); //pe->reported_metric.delay = EIGRP_MAX_METRIC; zlog_info("PROC OUT Prefix: %s", inet_ntoa(dest_addr->prefix)); continue; } else { zlog_info("PROC OUT: NENastavujem metriku "); length += eigrp_add_internalTLV_to_stream(ep->s, pe); has_tlv = 1; } /* * End of filtering */ /* NULL the pointer */ dest_addr = NULL; } } if(!has_tlv) { eigrp_packet_free(ep); return; } if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) { eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_UPDATE_FLAG); } /* EIGRP Checksum */ eigrp_packet_checksum(ei, ep->s, length); ep->length = length; ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS); /*This ack number we await from neighbor*/ ep->sequence_number = ei->eigrp->sequence_number; if (IS_DEBUG_EIGRP_PACKET(0, RECV)) zlog_debug("Enqueuing Update length[%u] Seq [%u]", length, ep->sequence_number); for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) { if (nbr->state == EIGRP_NEIGHBOR_UP) { /*Put packet to retransmission queue*/ eigrp_fifo_push_head(nbr->retrans_queue, ep); if (nbr->retrans_queue->count == 1) { eigrp_send_packet_reliably(nbr); } } } }
void eigrp_update_send_EOT (struct eigrp_neighbor *nbr) { struct eigrp_packet *ep; // struct eigrp_packet *ep_multicast; u_int16_t length = EIGRP_HEADER_LEN; struct eigrp_neighbor_entry *te; struct eigrp_prefix_entry *pe; struct listnode *node, *node2, *nnode, *nnode2; struct access_list *alist; struct prefix_list *plist; struct access_list *alist_i; struct prefix_list *plist_i; struct eigrp *e; struct prefix_ipv4 *dest_addr; ep = eigrp_packet_new(nbr->ei->ifp->mtu); /* Prepare EIGRP EOT UPDATE header */ eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG, 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)) { for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te)) { if ((te->ei == nbr->ei) && (te->prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE)) continue; /* Get destination address from prefix */ dest_addr = pe->destination_ipv4; /* * Filtering */ //TODO: Work in progress /* 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)) { zlog_info("PROC OUT EOT: Skipping"); //pe->reported_metric.delay = EIGRP_MAX_METRIC; zlog_info("PROC OUT EOT Prefix: %s", inet_ntoa(dest_addr->prefix)); continue; } else { zlog_info("PROC OUT EOT: NENastavujem metriku "); length += eigrp_add_internalTLV_to_stream(ep->s, pe); } /* * End of filtering */ /* NULL the pointer */ dest_addr = NULL; } } 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); }
void eigrp_zebra_init(void) { struct zclient_options opt = {.receive_notify = false}; zclient = zclient_new_notify(master, &opt); zclient_init(zclient, ZEBRA_ROUTE_EIGRP, 0, &eigrpd_privs); zclient->zebra_connected = eigrp_zebra_connected; zclient->router_id_update = eigrp_router_id_update_zebra; zclient->interface_add = eigrp_interface_add; zclient->interface_delete = eigrp_interface_delete; zclient->interface_up = eigrp_interface_state_up; zclient->interface_down = eigrp_interface_state_down; zclient->interface_address_add = eigrp_interface_address_add; zclient->interface_address_delete = eigrp_interface_address_delete; zclient->redistribute_route_add = eigrp_zebra_read_route; zclient->redistribute_route_del = eigrp_zebra_read_route; zclient->route_notify_owner = eigrp_zebra_route_notify_owner; } /* Zebra route add and delete treatment. */ static int eigrp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct zapi_route api; struct eigrp *eigrp; if (zapi_route_decode(zclient->ibuf, &api) < 0) return -1; if (IPV4_NET127(ntohl(api.prefix.u.prefix4.s_addr))) return 0; eigrp = eigrp_lookup(); if (eigrp == NULL) return 0; if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) { } else /* if (command == ZEBRA_REDISTRIBUTE_ROUTE_DEL) */ { } return 0; } /* Inteface addition message from zebra. */ static int eigrp_interface_add(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct eigrp_interface *ei; ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); if (!ifp->info) return 0; ei = ifp->info; ei->params.type = eigrp_default_iftype(ifp); eigrp_if_update(ifp); return 0; } static int eigrp_interface_delete(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read () updates interface structure in iflist */ ifp = zebra_interface_state_read(s, vrf_id); if (ifp == NULL) return 0; if (if_is_up(ifp)) zlog_warn("Zebra: got delete of %s, but interface is still up", ifp->name); if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) zlog_debug( "Zebra: interface delete %s index %d flags %llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); if (ifp->info) eigrp_if_free(ifp->info, INTERFACE_DOWN_BY_ZEBRA); if_set_index(ifp, IFINDEX_INTERNAL); return 0; } static int eigrp_interface_address_add(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); if (c == NULL) return 0; if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) { char buf[128]; prefix2str(c->address, buf, sizeof(buf)); zlog_debug("Zebra: interface %s address add %s", c->ifp->name, buf); } eigrp_if_update(c->ifp); return 0; } static int eigrp_interface_address_delete(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct interface *ifp; struct eigrp_interface *ei; c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); if (c == NULL) return 0; if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) { char buf[128]; prefix2str(c->address, buf, sizeof(buf)); zlog_debug("Zebra: interface %s address delete %s", c->ifp->name, buf); } ifp = c->ifp; ei = ifp->info; if (!ei) return 0; /* Call interface hook functions to clean up */ eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA); connected_free(c); return 0; } static int eigrp_interface_state_up(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_if_lookup(zclient->ibuf); if (ifp == NULL) return 0; /* Interface is already up. */ if (if_is_operative(ifp)) { /* Temporarily keep ifp values. */ struct interface if_tmp; memcpy(&if_tmp, ifp, sizeof(struct interface)); zebra_interface_if_set_value(zclient->ibuf, ifp); if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) zlog_debug("Zebra: Interface[%s] state update.", ifp->name); if (if_tmp.bandwidth != ifp->bandwidth) { if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) zlog_debug( "Zebra: Interface[%s] bandwidth change %d -> %d.", ifp->name, if_tmp.bandwidth, ifp->bandwidth); // eigrp_if_recalculate_output_cost (ifp); } if (if_tmp.mtu != ifp->mtu) { if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) zlog_debug( "Zebra: Interface[%s] MTU change %u -> %u.", ifp->name, if_tmp.mtu, ifp->mtu); /* Must reset the interface (simulate down/up) when MTU * changes. */ eigrp_if_reset(ifp); } return 0; } zebra_interface_if_set_value(zclient->ibuf, ifp); if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) zlog_debug("Zebra: Interface[%s] state change to up.", ifp->name); if (ifp->info) eigrp_if_up(ifp->info); return 0; } static int eigrp_interface_state_down(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); if (ifp == NULL) return 0; if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) zlog_debug("Zebra: Interface[%s] state change to down.", ifp->name); if (ifp->info) eigrp_if_down(ifp->info); return 0; } static struct interface *zebra_interface_if_lookup(struct stream *s) { char ifname_tmp[INTERFACE_NAMSIZ]; /* Read interface name. */ stream_get(ifname_tmp, s, INTERFACE_NAMSIZ); /* And look it up. */ return if_lookup_by_name(ifname_tmp, VRF_DEFAULT); }