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