xref: /openbsd-src/usr.sbin/ldpd/adjacency.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: adjacency.c,v 1.3 2013/10/15 20:21:24 renato Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
5  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6  * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <arpa/inet.h>
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "ldpd.h"
30 #include "ldpe.h"
31 #include "control.h"
32 #include "log.h"
33 
34 extern struct ldpd_conf        *leconf;
35 
36 void	 adj_itimer(int, short, void *);
37 char	*print_hello_src(struct hello_source *);
38 
39 void	 tnbr_hello_timer(int, short, void *);
40 void	 tnbr_start_hello_timer(struct tnbr *);
41 void	 tnbr_stop_hello_timer(struct tnbr *);
42 
43 struct adj *
44 adj_new(struct nbr *nbr, struct hello_source *source, u_int16_t holdtime,
45     struct in_addr addr)
46 {
47 	struct adj	*adj;
48 
49 	log_debug("adj_new: LSR ID %s, %s", inet_ntoa(nbr->id),
50 	    print_hello_src(source));
51 
52 	if ((adj = calloc(1, sizeof(*adj))) == NULL)
53 		fatal("adj_new");
54 
55 	adj->nbr = nbr;
56 	memcpy(&adj->source, source, sizeof(*source));
57 	adj->addr = addr;
58 
59 	evtimer_set(&adj->inactivity_timer, adj_itimer, adj);
60 
61 	LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry);
62 
63 	switch (source->type) {
64 	case HELLO_LINK:
65 		LIST_INSERT_HEAD(&source->link.iface->adj_list, adj,
66 		    iface_entry);
67 		break;
68 	case HELLO_TARGETED:
69 		source->target->adj = adj;
70 		break;
71 	}
72 
73 	return (adj);
74 }
75 
76 void
77 adj_del(struct adj *adj)
78 {
79 	log_debug("adj_del: LSR ID %s, %s", inet_ntoa(adj->nbr->id),
80 	    print_hello_src(&adj->source));
81 
82 	adj_stop_itimer(adj);
83 
84 	LIST_REMOVE(adj, nbr_entry);
85 
86 	/* last adjacency deleted */
87 	if (LIST_EMPTY(&adj->nbr->adj_list))
88 		nbr_del(adj->nbr);
89 
90 	free(adj);
91 }
92 
93 struct adj *
94 adj_find(struct nbr *nbr, struct hello_source *source)
95 {
96 	struct adj *adj;
97 
98 	LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) {
99 		if (adj->source.type != source->type)
100 			continue;
101 
102 		switch (source->type) {
103 		case HELLO_LINK:
104 			if (adj->source.link.src_addr.s_addr ==
105 			    source->link.src_addr.s_addr)
106 				return (adj);
107 			break;
108 		case HELLO_TARGETED:
109 			if (adj->source.target == source->target)
110 				return (adj);
111 			break;
112 		}
113 	}
114 
115 	return (NULL);
116 }
117 
118 char *
119 print_hello_src(struct hello_source *src)
120 {
121 	static char buffer[64];
122 
123 	switch (src->type) {
124 	case HELLO_LINK:
125 		snprintf(buffer, sizeof(buffer), "iface %s",
126 		    src->link.iface->name);
127 		break;
128 	case HELLO_TARGETED:
129 		snprintf(buffer, sizeof(buffer), "source %s",
130 		    inet_ntoa(src->target->addr));
131 		break;
132 	}
133 
134 	return (buffer);
135 }
136 
137 /* adjacency timers */
138 
139 /* ARGSUSED */
140 void
141 adj_itimer(int fd, short event, void *arg)
142 {
143 	struct adj *adj = arg;
144 
145 	log_debug("adj_itimer: LDP ID %s", inet_ntoa(adj->nbr->id));
146 
147 	switch (adj->source.type) {
148 	case HELLO_LINK:
149 		LIST_REMOVE(adj, iface_entry);
150 		break;
151 	case HELLO_TARGETED:
152 		adj->source.target->adj = NULL;
153 		if (!(adj->source.target->flags & F_TNBR_CONFIGURED)) {
154 			LIST_REMOVE(adj->source.target, entry);
155 			tnbr_del(adj->source.target);
156 		}
157 		break;
158 	}
159 
160 	adj_del(adj);
161 }
162 
163 void
164 adj_start_itimer(struct adj *adj)
165 {
166 	struct timeval	tv;
167 
168 	timerclear(&tv);
169 	tv.tv_sec = adj->holdtime;
170 
171 	if (evtimer_add(&adj->inactivity_timer, &tv) == -1)
172 		fatal("adj_start_itimer");
173 }
174 
175 void
176 adj_stop_itimer(struct adj *adj)
177 {
178 	if (evtimer_pending(&adj->inactivity_timer, NULL) &&
179 	    evtimer_del(&adj->inactivity_timer) == -1)
180 		fatal("adj_stop_itimer");
181 }
182 
183 /* targeted neighbors */
184 
185 struct tnbr *
186 tnbr_new(struct ldpd_conf *xconf, struct in_addr addr, int configured)
187 {
188 	struct tnbr		*tnbr;
189 
190 	if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL)
191 		fatal("tnbr_new");
192 
193 	tnbr->addr.s_addr = addr.s_addr;
194 	if (configured)
195 		tnbr->flags |= F_TNBR_CONFIGURED;
196 	else {
197 		tnbr->hello_holdtime = xconf->thello_holdtime;
198 		tnbr->hello_interval = xconf->thello_interval;
199 	}
200 
201 	return (tnbr);
202 }
203 
204 void
205 tnbr_del(struct tnbr *tnbr)
206 {
207 	tnbr_stop_hello_timer(tnbr);
208 	if (tnbr->adj)
209 		adj_del(tnbr->adj);
210 	free(tnbr);
211 }
212 
213 void
214 tnbr_init(struct ldpd_conf *xconf, struct tnbr *tnbr)
215 {
216 	/* set event handlers for targeted neighbor */
217 	evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr);
218 
219 	tnbr->discovery_fd = xconf->ldp_ediscovery_socket;
220 	tnbr_start_hello_timer(tnbr);
221 }
222 
223 struct tnbr *
224 tnbr_find(struct in_addr addr)
225 {
226 	struct tnbr *tnbr;
227 
228 	LIST_FOREACH(tnbr, &leconf->tnbr_list, entry)
229 		if (addr.s_addr == tnbr->addr.s_addr)
230 			return (tnbr);
231 
232 	return (NULL);
233 }
234 
235 /* target neighbors timers */
236 
237 /* ARGSUSED */
238 void
239 tnbr_hello_timer(int fd, short event, void *arg)
240 {
241 	struct tnbr *tnbr = arg;
242 	struct timeval tv;
243 
244 	send_hello(HELLO_TARGETED, NULL, tnbr);
245 
246 	/* reschedule hello_timer */
247 	timerclear(&tv);
248 	tv.tv_sec = tnbr->hello_interval;
249 	if (evtimer_add(&tnbr->hello_timer, &tv) == -1)
250 		fatal("tnbr_hello_timer");
251 }
252 
253 void
254 tnbr_start_hello_timer(struct tnbr *tnbr)
255 {
256 	struct timeval tv;
257 
258 	send_hello(HELLO_TARGETED, NULL, tnbr);
259 
260 	timerclear(&tv);
261 	tv.tv_sec = tnbr->hello_interval;
262 	if (evtimer_add(&tnbr->hello_timer, &tv) == -1)
263 		fatal("tnbr_start_hello_timer");
264 }
265 
266 void
267 tnbr_stop_hello_timer(struct tnbr *tnbr)
268 {
269 	if (evtimer_pending(&tnbr->hello_timer, NULL) &&
270 	    evtimer_del(&tnbr->hello_timer) == -1)
271 		fatal("tnbr_stop_hello_timer");
272 }
273 
274 struct ctl_adj *
275 adj_to_ctl(struct adj *adj)
276 {
277 	static struct ctl_adj	 actl;
278 
279 	actl.id.s_addr = adj->nbr->id.s_addr;
280 	actl.type = adj->source.type;
281 	switch (adj->source.type) {
282 	case HELLO_LINK:
283 		memcpy(actl.ifname, adj->source.link.iface->name,
284 		    sizeof(actl.ifname));
285 		break;
286 	case HELLO_TARGETED:
287 		actl.src_addr.s_addr = adj->source.target->addr.s_addr;
288 		break;
289 	}
290 	actl.holdtime = adj->holdtime;
291 
292 	return (&actl);
293 }
294 
295 void
296 ldpe_adj_ctl(struct ctl_conn *c)
297 {
298 	struct adj	*adj;
299 	struct iface	*iface;
300 	struct tnbr	*tnbr;
301 	struct ctl_adj	*actl;
302 
303 	/* basic discovery mechanism */
304 	LIST_FOREACH(iface, &leconf->iface_list, entry)
305 		LIST_FOREACH(adj, &iface->adj_list, iface_entry) {
306 			actl = adj_to_ctl(adj);
307 			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY,
308 			    0, 0, -1, actl, sizeof(struct ctl_adj));
309 		}
310 
311 	/* extended discovery mechanism */
312 	LIST_FOREACH(tnbr, &leconf->tnbr_list, entry)
313 		if (tnbr->adj) {
314 			actl = adj_to_ctl(tnbr->adj);
315 			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY,
316 			    0, 0, -1, actl, sizeof(struct ctl_adj));
317 		}
318 
319 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
320 }
321