]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/address.c
Merge pull request #3069 from donaldsharp/bgp_nexthop_address
[mirror_frr.git] / ldpd / address.c
CommitLineData
8429abe0
RW
1/* $OpenBSD$ */
2
3/*
4 * Copyright (c) 2009 Michele Marchetto <michele@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
eac6e3f0 19#include <zebra.h>
8429abe0
RW
20
21#include "ldpd.h"
22#include "ldpe.h"
23#include "lde.h"
24#include "log.h"
eac6e3f0 25#include "ldp_debug.h"
8429abe0
RW
26
27static void send_address(struct nbr *, int, struct if_addr_head *,
28 unsigned int, int);
26519d8c
RW
29static int gen_address_list_tlv(struct ibuf *, int, struct if_addr_head *,
30 unsigned int);
31static int gen_mac_list_tlv(struct ibuf *, uint8_t *);
8429abe0
RW
32static void address_list_add(struct if_addr_head *, struct if_addr *);
33static void address_list_clr(struct if_addr_head *);
faf75793
RW
34static void log_msg_address(int, uint16_t, struct nbr *, int,
35 union ldpd_addr *);
26519d8c 36static void log_msg_mac_withdrawal(int, struct nbr *, uint8_t *);
8429abe0
RW
37
38static void
39send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
40 unsigned int addr_count, int withdraw)
41{
42 struct ibuf *buf;
43 uint16_t msg_type;
44 uint8_t addr_size;
45 struct if_addr *if_addr;
46 uint16_t size;
47 unsigned int tlv_addr_count = 0;
48 int err = 0;
49
50 /* nothing to send */
51 if (LIST_EMPTY(addr_list))
52 return;
53
54 if (!withdraw)
55 msg_type = MSG_TYPE_ADDR;
56 else
57 msg_type = MSG_TYPE_ADDRWITHDRAW;
58
59 switch (af) {
60 case AF_INET:
61 addr_size = sizeof(struct in_addr);
62 break;
63 case AF_INET6:
64 addr_size = sizeof(struct in6_addr);
65 break;
66 default:
67 fatalx("send_address: unknown af");
68 }
69
70 while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
71 /*
72 * Send as many addresses as possible - respect the session's
73 * negotiated maximum pdu length.
74 */
75 size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE;
76 if (size + addr_count * addr_size <= nbr->max_pdu_len)
77 tlv_addr_count = addr_count;
78 else
79 tlv_addr_count = (nbr->max_pdu_len - size) / addr_size;
80 size += tlv_addr_count * addr_size;
81 addr_count -= tlv_addr_count;
82
83 if ((buf = ibuf_open(size)) == NULL)
84 fatal(__func__);
85
86 err |= gen_ldp_hdr(buf, size);
87 size -= LDP_HDR_SIZE;
88 err |= gen_msg_hdr(buf, msg_type, size);
89 size -= LDP_MSG_SIZE;
26519d8c 90 err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count);
e3df3ba6 91 (void)size;
8429abe0
RW
92 if (err) {
93 address_list_clr(addr_list);
94 ibuf_free(buf);
95 return;
96 }
97
98 while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
faf75793 99 log_msg_address(1, msg_type, nbr, af, &if_addr->addr);
8429abe0
RW
100
101 LIST_REMOVE(if_addr, entry);
11bf8e13 102 assert(if_addr != LIST_FIRST(addr_list));
8429abe0
RW
103 free(if_addr);
104 if (--tlv_addr_count == 0)
105 break;
106 }
107
108 evbuf_enqueue(&nbr->tcp->wbuf, buf);
0f7b5df9
RW
109
110 /* no errors - update per neighbor message counters */
111 switch (msg_type) {
112 case MSG_TYPE_ADDR:
113 nbr->stats.addr_sent++;
114 break;
115 case MSG_TYPE_ADDRWITHDRAW:
116 nbr->stats.addrwdraw_sent++;
117 break;
118 default:
119 break;
120 }
8429abe0
RW
121 }
122
123 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
124}
125
126void
127send_address_single(struct nbr *nbr, struct if_addr *if_addr, int withdraw)
128{
129 struct if_addr_head addr_list;
130
131 LIST_INIT(&addr_list);
132 address_list_add(&addr_list, if_addr);
133 send_address(nbr, if_addr->af, &addr_list, 1, withdraw);
134}
135
136void
137send_address_all(struct nbr *nbr, int af)
138{
139 struct if_addr_head addr_list;
140 struct if_addr *if_addr;
141 unsigned int addr_count = 0;
142
143 LIST_INIT(&addr_list);
144 LIST_FOREACH(if_addr, &global.addr_list, entry) {
145 if (if_addr->af != af)
146 continue;
147
148 address_list_add(&addr_list, if_addr);
149 addr_count++;
150 }
151
152 send_address(nbr, af, &addr_list, addr_count, 0);
153}
154
26519d8c
RW
155void
156send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac)
157{
158 struct ibuf *buf;
159 uint16_t size;
160 int err;
161
162 size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) +
163 TLV_HDR_SIZE;
164 if (mac)
9bff8057 165 size += ETH_ALEN;
26519d8c
RW
166
167 if ((buf = ibuf_open(size)) == NULL)
168 fatal(__func__);
169
170 err = gen_ldp_hdr(buf, size);
171 size -= LDP_HDR_SIZE;
172 err |= gen_msg_hdr(buf, MSG_TYPE_ADDRWITHDRAW, size);
26519d8c
RW
173 err |= gen_address_list_tlv(buf, AF_INET, NULL, 0);
174 err |= gen_fec_tlv(buf, fec);
175 err |= gen_mac_list_tlv(buf, mac);
176 if (err) {
177 ibuf_free(buf);
178 return;
179 }
180
181 log_msg_mac_withdrawal(1, nbr, mac);
182
183 evbuf_enqueue(&nbr->tcp->wbuf, buf);
184
185 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
186}
187
8429abe0
RW
188int
189recv_address(struct nbr *nbr, char *buf, uint16_t len)
190{
191 struct ldp_msg msg;
192 uint16_t msg_type;
8429abe0 193 enum imsg_type type;
fd1cf443
RW
194 struct address_list_tlv alt;
195 uint16_t alt_len;
196 uint16_t alt_family;
8429abe0
RW
197 struct lde_addr lde_addr;
198
199 memcpy(&msg, buf, sizeof(msg));
fd1cf443
RW
200 msg_type = ntohs(msg.type);
201 switch (msg_type) {
202 case MSG_TYPE_ADDR:
203 type = IMSG_ADDRESS_ADD;
204 break;
205 case MSG_TYPE_ADDRWITHDRAW:
206 type = IMSG_ADDRESS_DEL;
207 break;
208 default:
209 fatalx("recv_address: unexpected msg type");
210 }
8429abe0
RW
211 buf += LDP_MSG_SIZE;
212 len -= LDP_MSG_SIZE;
213
214 /* Address List TLV */
215 if (len < ADDR_LIST_SIZE) {
216 session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
217 return (-1);
218 }
8429abe0 219 memcpy(&alt, buf, sizeof(alt));
fd1cf443
RW
220 alt_len = ntohs(alt.length);
221 alt_family = ntohs(alt.family);
222 if (alt_len > len - TLV_HDR_SIZE) {
8429abe0
RW
223 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
224 return (-1);
225 }
226 if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) {
a33df200 227 send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
8429abe0
RW
228 return (-1);
229 }
fd1cf443 230 switch (alt_family) {
8429abe0
RW
231 case AF_IPV4:
232 if (!nbr->v4_enabled)
233 /* just ignore the message */
234 return (0);
235 break;
236 case AF_IPV6:
237 if (!nbr->v6_enabled)
238 /* just ignore the message */
239 return (0);
240 break;
241 default:
adbdf465 242 send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type);
8429abe0
RW
243 return (-1);
244 }
fd1cf443 245 alt_len -= sizeof(alt.family);
8429abe0
RW
246 buf += sizeof(alt);
247 len -= sizeof(alt);
248
fd1cf443
RW
249 /* Process all received addresses */
250 while (alt_len > 0) {
251 switch (alt_family) {
8429abe0 252 case AF_IPV4:
fd1cf443 253 if (alt_len < sizeof(struct in_addr)) {
8429abe0
RW
254 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
255 msg.type);
256 return (-1);
257 }
258
259 memset(&lde_addr, 0, sizeof(lde_addr));
260 lde_addr.af = AF_INET;
261 memcpy(&lde_addr.addr, buf, sizeof(struct in_addr));
262
263 buf += sizeof(struct in_addr);
264 len -= sizeof(struct in_addr);
fd1cf443 265 alt_len -= sizeof(struct in_addr);
8429abe0
RW
266 break;
267 case AF_IPV6:
fd1cf443 268 if (alt_len < sizeof(struct in6_addr)) {
8429abe0
RW
269 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
270 msg.type);
271 return (-1);
272 }
273
274 memset(&lde_addr, 0, sizeof(lde_addr));
275 lde_addr.af = AF_INET6;
276 memcpy(&lde_addr.addr, buf, sizeof(struct in6_addr));
277
278 buf += sizeof(struct in6_addr);
279 len -= sizeof(struct in6_addr);
fd1cf443 280 alt_len -= sizeof(struct in6_addr);
8429abe0
RW
281 break;
282 default:
283 fatalx("recv_address: unknown af");
284 }
285
faf75793 286 log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr);
8429abe0
RW
287
288 ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
289 sizeof(lde_addr));
290 }
291
fd1cf443
RW
292 /* Optional Parameters */
293 while (len > 0) {
294 struct tlv tlv;
295 uint16_t tlv_type;
296 uint16_t tlv_len;
297
298 if (len < sizeof(tlv)) {
299 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
300 return (-1);
301 }
302
303 memcpy(&tlv, buf, TLV_HDR_SIZE);
304 tlv_type = ntohs(tlv.type);
305 tlv_len = ntohs(tlv.length);
306 if (tlv_len + TLV_HDR_SIZE > len) {
307 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
308 return (-1);
309 }
310 buf += TLV_HDR_SIZE;
311 len -= TLV_HDR_SIZE;
312
313 switch (tlv_type) {
314 default:
315 if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
316 send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
317 msg.id, msg.type, tlv_type, tlv_len, buf);
318 /* ignore unknown tlv */
319 break;
320 }
321 buf += tlv_len;
322 len -= tlv_len;
323 }
324
8429abe0
RW
325 return (0);
326}
327
328static int
26519d8c
RW
329gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list,
330 unsigned int tlv_addr_count)
8429abe0
RW
331{
332 struct address_list_tlv alt;
333 uint16_t addr_size;
334 struct if_addr *if_addr;
335 int err = 0;
336
337 memset(&alt, 0, sizeof(alt));
a33df200 338 alt.type = htons(TLV_TYPE_ADDRLIST);
8429abe0
RW
339
340 switch (af) {
341 case AF_INET:
342 alt.family = htons(AF_IPV4);
343 addr_size = sizeof(struct in_addr);
344 break;
345 case AF_INET6:
346 alt.family = htons(AF_IPV6);
347 addr_size = sizeof(struct in6_addr);
348 break;
349 default:
350 fatalx("gen_address_list_tlv: unknown af");
351 }
26519d8c 352 alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count);
8429abe0
RW
353
354 err |= ibuf_add(buf, &alt, sizeof(alt));
26519d8c
RW
355 if (addr_list == NULL)
356 return (err);
357
8429abe0
RW
358 LIST_FOREACH(if_addr, addr_list, entry) {
359 err |= ibuf_add(buf, &if_addr->addr, addr_size);
360 if (--tlv_addr_count == 0)
361 break;
362 }
363
364 return (err);
365}
366
26519d8c
RW
367static int
368gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac)
369{
370 struct tlv tlv;
371 int err;
372
373 memset(&tlv, 0, sizeof(tlv));
374 tlv.type = htons(TLV_TYPE_MAC_LIST);
375 if (mac)
9bff8057 376 tlv.length = htons(ETH_ALEN);
26519d8c
RW
377 err = ibuf_add(buf, &tlv, sizeof(tlv));
378 if (mac)
9bff8057 379 err |= ibuf_add(buf, mac, ETH_ALEN);
26519d8c
RW
380
381 return (err);
382}
383
8429abe0
RW
384static void
385address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr)
386{
387 struct if_addr *new;
388
389 new = malloc(sizeof(*new));
390 if (new == NULL)
391 fatal(__func__);
392 *new = *if_addr;
393
394 LIST_INSERT_HEAD(addr_list, new, entry);
395}
396
397static void
398address_list_clr(struct if_addr_head *addr_list)
399{
400 struct if_addr *if_addr;
401
402 while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
403 LIST_REMOVE(if_addr, entry);
11bf8e13 404 assert(if_addr != LIST_FIRST(addr_list));
8429abe0
RW
405 free(if_addr);
406 }
407}
faf75793
RW
408
409static void
410log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af,
411 union ldpd_addr *addr)
412{
413 debug_msg(out, "%s: lsr-id %s, address %s", msg_name(msg_type),
414 inet_ntoa(nbr->id), log_addr(af, addr));
415}
26519d8c
RW
416
417static void
418log_msg_mac_withdrawal(int out, struct nbr *nbr, uint8_t *mac)
419{
420 char buf[ETHER_ADDR_STRLEN];
421
422 debug_msg(out, "mac withdrawal: lsr-id %s, mac %s", inet_ntoa(nbr->id),
423 (mac) ? prefix_mac2str((struct ethaddr *)mac, buf, sizeof(buf)) :
424 "wildcard");
425}