diff options
Diffstat (limited to 'eigrpd/eigrp_neighbor.c')
-rw-r--r-- | eigrpd/eigrp_neighbor.c | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c new file mode 100644 index 0000000..25209c3 --- /dev/null +++ b/eigrpd/eigrp_neighbor.c @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * EIGRP Neighbor Handling. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + */ + +#include <zebra.h> + +#include "linklist.h" +#include "prefix.h" +#include "memory.h" +#include "command.h" +#include "frrevent.h" +#include "stream.h" +#include "table.h" +#include "log.h" +#include "keychain.h" +#include "vty.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_errors.h" + +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_NEIGHBOR, "EIGRP neighbor"); + +struct eigrp_neighbor *eigrp_nbr_new(struct eigrp_interface *ei) +{ + struct eigrp_neighbor *nbr; + + /* Allcate new neighbor. */ + nbr = XCALLOC(MTYPE_EIGRP_NEIGHBOR, sizeof(struct eigrp_neighbor)); + + /* Relate neighbor to the interface. */ + nbr->ei = ei; + + /* Set default values. */ + eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN); + + return nbr; +} + +/** + *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree, + * proto_item *ti) + * + * @par + * Create a new neighbor structure and initalize it. + */ +static struct eigrp_neighbor *eigrp_nbr_add(struct eigrp_interface *ei, + struct eigrp_header *eigrph, + struct ip *iph) +{ + struct eigrp_neighbor *nbr; + + nbr = eigrp_nbr_new(ei); + nbr->src = iph->ip_src; + + return nbr; +} + +struct eigrp_neighbor *eigrp_nbr_get(struct eigrp_interface *ei, + struct eigrp_header *eigrph, + struct ip *iph) +{ + struct eigrp_neighbor *nbr; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) { + if (iph->ip_src.s_addr == nbr->src.s_addr) { + return nbr; + } + } + + nbr = eigrp_nbr_add(ei, eigrph, iph); + listnode_add(ei->nbrs, nbr); + + return nbr; +} + +/** + * @fn eigrp_nbr_lookup_by_addr + * + * @param[in] ei EIGRP interface + * @param[in] nbr_addr Address of neighbor + * + * @return void + * + * @par + * Function is used for neighbor lookup by address + * in specified interface. + */ +struct eigrp_neighbor *eigrp_nbr_lookup_by_addr(struct eigrp_interface *ei, + struct in_addr *addr) +{ + struct eigrp_neighbor *nbr; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) { + if (addr->s_addr == nbr->src.s_addr) { + return nbr; + } + } + + return NULL; +} + +/** + * @fn eigrp_nbr_lookup_by_addr_process + * + * @param[in] eigrp EIGRP process + * @param[in] nbr_addr Address of neighbor + * + * @return void + * + * @par + * Function is used for neighbor lookup by address + * in whole EIGRP process. + */ +struct eigrp_neighbor *eigrp_nbr_lookup_by_addr_process(struct eigrp *eigrp, + struct in_addr nbr_addr) +{ + struct eigrp_interface *ei; + struct listnode *node, *node2, *nnode2; + struct eigrp_neighbor *nbr; + + /* iterate over all eigrp interfaces */ + for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { + /* iterate over all neighbors on eigrp interface */ + for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr)) { + /* compare if neighbor address is same as arg address */ + if (nbr->src.s_addr == nbr_addr.s_addr) { + return nbr; + } + } + } + + return NULL; +} + + +/* Delete specified EIGRP neighbor from interface. */ +void eigrp_nbr_delete(struct eigrp_neighbor *nbr) +{ + eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN); + if (nbr->ei) + eigrp_topology_neighbor_down(nbr->ei->eigrp, nbr); + + /* Cancel all events. */ /* Thread lookup cost would be negligible. */ + event_cancel_event(master, nbr); + eigrp_fifo_free(nbr->multicast_queue); + eigrp_fifo_free(nbr->retrans_queue); + EVENT_OFF(nbr->t_holddown); + + if (nbr->ei) + listnode_delete(nbr->ei->nbrs, nbr); + XFREE(MTYPE_EIGRP_NEIGHBOR, nbr); +} + +void holddown_timer_expired(struct event *thread) +{ + struct eigrp_neighbor *nbr = EVENT_ARG(thread); + struct eigrp *eigrp = nbr->ei->eigrp; + + zlog_info("Neighbor %pI4 (%s) is down: holding time expired", &nbr->src, + ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id)); + nbr->state = EIGRP_NEIGHBOR_DOWN; + eigrp_nbr_delete(nbr); +} + +uint8_t eigrp_nbr_state_get(struct eigrp_neighbor *nbr) +{ + return (nbr->state); +} + +void eigrp_nbr_state_set(struct eigrp_neighbor *nbr, uint8_t state) +{ + nbr->state = state; + + if (eigrp_nbr_state_get(nbr) == EIGRP_NEIGHBOR_DOWN) { + // reset all the seq/ack counters + nbr->recv_sequence_number = 0; + nbr->init_sequence_number = 0; + nbr->retrans_counter = 0; + + // Kvalues + nbr->K1 = EIGRP_K1_DEFAULT; + nbr->K2 = EIGRP_K2_DEFAULT; + nbr->K3 = EIGRP_K3_DEFAULT; + nbr->K4 = EIGRP_K4_DEFAULT; + nbr->K5 = EIGRP_K5_DEFAULT; + nbr->K6 = EIGRP_K6_DEFAULT; + + // hold time.. + nbr->v_holddown = EIGRP_HOLD_INTERVAL_DEFAULT; + EVENT_OFF(nbr->t_holddown); + + /* out with the old */ + if (nbr->multicast_queue) + eigrp_fifo_free(nbr->multicast_queue); + if (nbr->retrans_queue) + eigrp_fifo_free(nbr->retrans_queue); + + /* in with the new */ + nbr->retrans_queue = eigrp_fifo_new(); + nbr->multicast_queue = eigrp_fifo_new(); + + nbr->crypt_seqnum = 0; + } +} + +const char *eigrp_nbr_state_str(struct eigrp_neighbor *nbr) +{ + const char *state; + switch (nbr->state) { + case EIGRP_NEIGHBOR_DOWN: + state = "Down"; + break; + case EIGRP_NEIGHBOR_PENDING: + state = "Waiting for Init"; + break; + case EIGRP_NEIGHBOR_UP: + state = "Up"; + break; + default: + state = "Unknown"; + break; + } + + return (state); +} + +void eigrp_nbr_state_update(struct eigrp_neighbor *nbr) +{ + switch (nbr->state) { + case EIGRP_NEIGHBOR_DOWN: { + /*Start Hold Down Timer for neighbor*/ + // EVENT_OFF(nbr->t_holddown); + // EVENT_TIMER_ON(master, nbr->t_holddown, + // holddown_timer_expired, + // nbr, nbr->v_holddown); + break; + } + case EIGRP_NEIGHBOR_PENDING: { + /*Reset Hold Down Timer for neighbor*/ + EVENT_OFF(nbr->t_holddown); + event_add_timer(master, holddown_timer_expired, nbr, + nbr->v_holddown, &nbr->t_holddown); + break; + } + case EIGRP_NEIGHBOR_UP: { + /*Reset Hold Down Timer for neighbor*/ + EVENT_OFF(nbr->t_holddown); + event_add_timer(master, holddown_timer_expired, nbr, + nbr->v_holddown, &nbr->t_holddown); + break; + } + } +} + +int eigrp_nbr_count_get(struct eigrp *eigrp) +{ + struct eigrp_interface *iface; + struct listnode *node, *node2, *nnode2; + struct eigrp_neighbor *nbr; + uint32_t counter; + + 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; +} + +/** + * @fn eigrp_nbr_hard_restart + * + * @param[in] nbr Neighbor who would receive hard restart + * @param[in] vty Virtual terminal for log output + * @return void + * + * @par + * Function used for executing hard restart for neighbor: + * Send Hello packet with Peer Termination TLV with + * neighbor's address, set it's state to DOWN and delete the neighbor + */ +void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty) +{ + struct eigrp *eigrp = nbr->ei->eigrp; + + zlog_debug("Neighbor %pI4 (%s) is down: manually cleared", &nbr->src, + ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id)); + if (vty != NULL) { + vty_time_print(vty, 0); + vty_out(vty, "Neighbor %pI4 (%s) is down: manually cleared\n", + &nbr->src, + ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id)); + } + + /* send Hello with Peer Termination TLV */ + eigrp_hello_send(nbr->ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR, + &(nbr->src)); + /* set neighbor to DOWN */ + nbr->state = EIGRP_NEIGHBOR_DOWN; + /* delete neighbor */ + eigrp_nbr_delete(nbr); +} + +int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor *ne, + struct eigrp_interface *ei) +{ + if (ne->distance == EIGRP_MAX_METRIC) + return 0; + + return (ne->ei == ei); +} |