xref: /openbsd/usr.sbin/eigrpd/neighbor.c (revision 274d7c50)
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