/* RIP peer support * Copyright (C) 2000 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "prefix.h" #include "command.h" #include "linklist.h" #include "thread.h" #include "memory.h" #include "ripd/ripd.h" /* Linked list of RIP peer. */ struct list *peer_list; static struct rip_peer * rip_peer_new (void) { return XCALLOC (MTYPE_RIP_PEER, sizeof (struct rip_peer)); } static void rip_peer_free (struct rip_peer *peer) { XFREE (MTYPE_RIP_PEER, peer); } struct rip_peer * rip_peer_lookup (struct in_addr *addr) { struct rip_peer *peer; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { if (IPV4_ADDR_SAME (&peer->addr, addr)) return peer; } return NULL; } struct rip_peer * rip_peer_lookup_next (struct in_addr *addr) { struct rip_peer *peer; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { if (htonl (peer->addr.s_addr) > htonl (addr->s_addr)) return peer; } return NULL; } /* RIP peer is timeout. */ static int rip_peer_timeout (struct thread *t) { struct rip_peer *peer; peer = THREAD_ARG (t); listnode_delete (peer_list, peer); rip_peer_free (peer); return 0; } /* Get RIP peer. At the same time update timeout thread. */ static struct rip_peer * rip_peer_get (struct in_addr *addr) { struct rip_peer *peer; peer = rip_peer_lookup (addr); if (peer) { if (peer->t_timeout) thread_cancel (peer->t_timeout); } else { peer = rip_peer_new (); peer->addr = *addr; listnode_add_sort (peer_list, peer); } /* Update timeout thread. */ peer->t_timeout = thread_add_timer (master, rip_peer_timeout, peer, RIP_PEER_TIMER_DEFAULT); /* Last update time set. */ time (&peer->uptime); return peer; } void rip_peer_update (struct sockaddr_in *from, u_char version) { struct rip_peer *peer; peer = rip_peer_get (&from->sin_addr); peer->version = version; } void rip_peer_bad_route (struct sockaddr_in *from) { struct rip_peer *peer; peer = rip_peer_get (&from->sin_addr); peer->recv_badroutes++; } void rip_peer_bad_packet (struct sockaddr_in *from) { struct rip_peer *peer; peer = rip_peer_get (&from->sin_addr); peer->recv_badpackets++; } /* Display peer uptime. */ static char * rip_peer_uptime (struct rip_peer *peer, char *buf, size_t len) { time_t uptime; struct tm *tm; /* If there is no connection has been done before print `never'. */ if (peer->uptime == 0) { snprintf (buf, len, "never "); return buf; } /* Get current time. */ uptime = time (NULL); uptime -= peer->uptime; tm = gmtime (&uptime); /* Making formatted timer strings. */ #define ONE_DAY_SECOND 60*60*24 #define ONE_WEEK_SECOND 60*60*24*7 if (uptime < ONE_DAY_SECOND) snprintf (buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); else if (uptime < ONE_WEEK_SECOND) snprintf (buf, len, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); else snprintf (buf, len, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); return buf; } void rip_peer_display (struct vty *vty) { struct rip_peer *peer; struct listnode *node, *nnode; #define RIP_UPTIME_LEN 25 char timebuf[RIP_UPTIME_LEN]; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { vty_out (vty, " %-16s %9d %9d %9d %s%s", inet_ntoa (peer->addr), peer->recv_badpackets, peer->recv_badroutes, ZEBRA_RIP_DISTANCE_DEFAULT, rip_peer_uptime (peer, timebuf, RIP_UPTIME_LEN), VTY_NEWLINE); } } static int rip_peer_list_cmp (struct rip_peer *p1, struct rip_peer *p2) { return htonl (p1->addr.s_addr) > htonl (p2->addr.s_addr); } void rip_peer_init (void) { peer_list = list_new (); peer_list->cmp = (int (*)(void *, void *)) rip_peer_list_cmp; }