GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/eigrpd/neighbor.c Lines: 0 109 0.0 %
Date: 2017-11-13 Branches: 0 414 0.0 %

Line Branch Exec Source
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
}