1 /* $OpenBSD: neighbor.c,v 1.10 2016/09/02 16:44:33 renato Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <string.h> 22 #include <stdlib.h> 23 24 #include "eigrpd.h" 25 #include "eigrpe.h" 26 #include "rde.h" 27 #include "log.h" 28 29 static __inline int nbr_compare(struct nbr *, struct nbr *); 30 static __inline int nbr_pid_compare(struct nbr *, struct nbr *); 31 static void nbr_update_peerid(struct nbr *); 32 static void nbr_timeout(int, short, void *); 33 static void nbr_stop_timeout(struct nbr *); 34 35 RB_GENERATE(nbr_addr_head, nbr, addr_tree, nbr_compare) 36 RB_GENERATE(nbr_pid_head, nbr, pid_tree, nbr_pid_compare) 37 38 struct nbr_pid_head nbrs_by_pid = RB_INITIALIZER(&nbrs_by_pid); 39 40 static __inline int 41 nbr_compare(struct nbr *a, struct nbr *b) 42 { 43 if (a->ei->iface->ifindex < b->ei->iface->ifindex) 44 return (-1); 45 if (a->ei->iface->ifindex > b->ei->iface->ifindex) 46 return (1); 47 48 return (eigrp_addrcmp(a->ei->eigrp->af, &a->addr, &b->addr)); 49 } 50 51 static __inline int 52 nbr_pid_compare(struct nbr *a, struct nbr *b) 53 { 54 return (a->peerid - b->peerid); 55 } 56 57 struct nbr * 58 nbr_new(struct eigrp_iface *ei, union eigrpd_addr *addr, uint16_t holdtime, 59 int self) 60 { 61 struct eigrp *eigrp = ei->eigrp; 62 struct nbr *nbr; 63 64 if (!self) 65 log_debug("%s: interface %s addr %s as %u", __func__, 66 ei->iface->name, log_addr(eigrp->af, addr), eigrp->as); 67 68 if ((nbr = calloc(1, sizeof(*nbr))) == NULL) 69 fatal("nbr_new"); 70 71 nbr->ei = ei; 72 TAILQ_INSERT_TAIL(&ei->nbr_list, nbr, entry); 73 nbr->addr = *addr; 74 nbr->peerid = 0; 75 nbr->hello_holdtime = holdtime; 76 nbr->flags = F_EIGRP_NBR_PENDING; 77 if (self) 78 nbr->flags |= F_EIGRP_NBR_SELF; 79 TAILQ_INIT(&nbr->update_list); 80 TAILQ_INIT(&nbr->query_list); 81 TAILQ_INIT(&nbr->reply_list); 82 TAILQ_INIT(&nbr->retrans_list); 83 84 if (RB_INSERT(nbr_addr_head, &eigrp->nbrs, nbr) != NULL) 85 fatalx("nbr_new: RB_INSERT(eigrp->nbrs) failed"); 86 87 /* timeout handling */ 88 if (!self) { 89 evtimer_set(&nbr->ev_ack, rtp_ack_timer, nbr); 90 evtimer_set(&nbr->ev_hello_timeout, nbr_timeout, nbr); 91 nbr_start_timeout(nbr); 92 } 93 94 return (nbr); 95 } 96 97 void 98 nbr_init(struct nbr *nbr) 99 { 100 struct timeval now; 101 struct rde_nbr rnbr; 102 103 nbr->flags &= ~F_EIGRP_NBR_PENDING; 104 105 gettimeofday(&now, NULL); 106 nbr->uptime = now.tv_sec; 107 108 nbr_update_peerid(nbr); 109 110 memset(&rnbr, 0, sizeof(rnbr)); 111 rnbr.addr = nbr->addr; 112 rnbr.ifaceid = nbr->ei->ifaceid; 113 if (nbr->flags & F_EIGRP_NBR_SELF) 114 rnbr.flags = F_RDE_NBR_SELF|F_RDE_NBR_LOCAL; 115 116 /* rde is not aware of pending nbrs */ 117 eigrpe_imsg_compose_rde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rnbr, 118 sizeof(rnbr)); 119 } 120 121 void 122 nbr_del(struct nbr *nbr) 123 { 124 struct eigrp *eigrp = nbr->ei->eigrp; 125 struct packet *pkt; 126 127 if (!(nbr->flags & F_EIGRP_NBR_SELF)) 128 log_debug("%s: addr %s", __func__, 129 log_addr(eigrp->af, &nbr->addr)); 130 131 eigrpe_imsg_compose_rde(IMSG_NEIGHBOR_DOWN, nbr->peerid, 0, NULL, 0); 132 133 nbr_stop_timeout(nbr); 134 135 /* clear retransmission list */ 136 while ((pkt = TAILQ_FIRST(&nbr->retrans_list)) != NULL) 137 rtp_packet_del(pkt); 138 139 if (nbr->peerid) 140 RB_REMOVE(nbr_pid_head, &nbrs_by_pid, nbr); 141 RB_REMOVE(nbr_addr_head, &eigrp->nbrs, nbr); 142 TAILQ_REMOVE(&nbr->ei->nbr_list, nbr, entry); 143 144 free(nbr); 145 } 146 147 static void 148 nbr_update_peerid(struct nbr *nbr) 149 { 150 static uint32_t peercnt = NBR_CNTSTART; 151 152 if (nbr->peerid) 153 RB_REMOVE(nbr_pid_head, &nbrs_by_pid, nbr); 154 155 /* get next unused peerid */ 156 while (nbr_find_peerid(++peercnt)) 157 ; 158 nbr->peerid = peercnt; 159 160 if (RB_INSERT(nbr_pid_head, &nbrs_by_pid, nbr) != NULL) 161 fatalx("nbr_new: RB_INSERT(nbrs_by_pid) failed"); 162 } 163 164 struct nbr * 165 nbr_find(struct eigrp_iface *ei, union eigrpd_addr *addr) 166 { 167 struct nbr n; 168 struct eigrp_iface i; 169 struct eigrp e; 170 171 e.af = ei->eigrp->af; 172 e.as = ei->eigrp->as; 173 i.eigrp = &e; 174 i.iface = ei->iface; 175 n.ei = &i; 176 n.addr = *addr; 177 178 return (RB_FIND(nbr_addr_head, &ei->eigrp->nbrs, &n)); 179 } 180 181 struct nbr * 182 nbr_find_peerid(uint32_t peerid) 183 { 184 struct nbr n; 185 n.peerid = peerid; 186 return (RB_FIND(nbr_pid_head, &nbrs_by_pid, &n)); 187 } 188 189 struct ctl_nbr * 190 nbr_to_ctl(struct nbr *nbr) 191 { 192 static struct ctl_nbr nctl; 193 struct timeval now; 194 195 nctl.af = nbr->ei->eigrp->af; 196 nctl.as = nbr->ei->eigrp->as; 197 memcpy(nctl.ifname, nbr->ei->iface->name, sizeof(nctl.ifname)); 198 nctl.addr = nbr->addr; 199 nctl.hello_holdtime = nbr->hello_holdtime; 200 gettimeofday(&now, NULL); 201 nctl.uptime = now.tv_sec - nbr->uptime; 202 203 return (&nctl); 204 } 205 206 void 207 nbr_clear_ctl(struct ctl_nbr *nctl) 208 { 209 struct eigrp *eigrp; 210 struct nbr *nbr, *safe; 211 212 TAILQ_FOREACH(eigrp, &econf->instances, entry) { 213 if (nctl->af && nctl->af != eigrp->af) 214 continue; 215 if (nctl->as && nctl->as != eigrp->as) 216 continue; 217 218 RB_FOREACH_SAFE(nbr, nbr_addr_head, &eigrp->nbrs, safe) { 219 if (nbr->flags & (F_EIGRP_NBR_PENDING|F_EIGRP_NBR_SELF)) 220 continue; 221 if (eigrp_addrisset(nctl->af, &nctl->addr) && 222 eigrp_addrcmp(nctl->af, &nctl->addr, &nbr->addr)) 223 continue; 224 225 log_debug("%s: neighbor %s manually cleared", __func__, 226 log_addr(nbr->ei->eigrp->af, &nbr->addr)); 227 send_peerterm(nbr); 228 nbr_del(nbr); 229 } 230 } 231 } 232 233 /* timers */ 234 235 /* ARGSUSED */ 236 static void 237 nbr_timeout(int fd, short event, void *arg) 238 { 239 struct nbr *nbr = arg; 240 struct eigrp *eigrp = nbr->ei->eigrp; 241 242 log_debug("%s: neighbor %s", __func__, log_addr(eigrp->af, &nbr->addr)); 243 244 nbr_del(nbr); 245 } 246 247 void 248 nbr_start_timeout(struct nbr *nbr) 249 { 250 struct timeval tv; 251 252 timerclear(&tv); 253 tv.tv_sec = nbr->hello_holdtime; 254 255 if (evtimer_add(&nbr->ev_hello_timeout, &tv) == -1) 256 fatal("nbr_start_timeout"); 257 } 258 259 static void 260 nbr_stop_timeout(struct nbr *nbr) 261 { 262 if (evtimer_pending(&nbr->ev_hello_timeout, NULL) && 263 evtimer_del(&nbr->ev_hello_timeout) == -1) 264 fatal("nbr_stop_timeout"); 265 } 266