]>
git.proxmox.com Git - mirror_frr.git/blob - ldpd/address.c
4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
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.
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.
25 #include "ldp_debug.h"
27 static void send_address(struct nbr
*, int, struct if_addr_head
*,
29 static int gen_address_list_tlv(struct ibuf
*, int, struct if_addr_head
*,
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,
36 static void log_msg_mac_withdrawal(int, struct nbr
*, uint8_t *);
39 send_address(struct nbr
*nbr
, int af
, struct if_addr_head
*addr_list
,
40 unsigned int addr_count
, int withdraw
)
45 struct if_addr
*if_addr
;
47 unsigned int tlv_addr_count
= 0;
51 if (LIST_EMPTY(addr_list
))
55 msg_type
= MSG_TYPE_ADDR
;
57 msg_type
= MSG_TYPE_ADDRWITHDRAW
;
61 addr_size
= sizeof(struct in_addr
);
64 addr_size
= sizeof(struct in6_addr
);
67 fatalx("send_address: unknown af");
70 while (LIST_FIRST(addr_list
) != NULL
) {
72 * Send as many addresses as possible - respect the session's
73 * negotiated maximum pdu length.
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
;
79 tlv_addr_count
= (nbr
->max_pdu_len
- size
) / addr_size
;
80 size
+= tlv_addr_count
* addr_size
;
81 addr_count
-= tlv_addr_count
;
83 if ((buf
= ibuf_open(size
)) == NULL
)
86 err
|= gen_ldp_hdr(buf
, size
);
88 err
|= gen_msg_hdr(buf
, msg_type
, size
);
90 err
|= gen_address_list_tlv(buf
, af
, addr_list
, tlv_addr_count
);
93 address_list_clr(addr_list
);
98 while ((if_addr
= LIST_FIRST(addr_list
)) != NULL
) {
99 log_msg_address(1, msg_type
, nbr
, af
, &if_addr
->addr
);
101 LIST_REMOVE(if_addr
, entry
);
102 assert(if_addr
!= LIST_FIRST(addr_list
));
104 if (--tlv_addr_count
== 0)
108 evbuf_enqueue(&nbr
->tcp
->wbuf
, buf
);
110 /* no errors - update per neighbor message counters */
113 nbr
->stats
.addr_sent
++;
115 case MSG_TYPE_ADDRWITHDRAW
:
116 nbr
->stats
.addrwdraw_sent
++;
123 nbr_fsm(nbr
, NBR_EVT_PDU_SENT
);
127 send_address_single(struct nbr
*nbr
, struct if_addr
*if_addr
, int withdraw
)
129 struct if_addr_head addr_list
;
131 LIST_INIT(&addr_list
);
132 address_list_add(&addr_list
, if_addr
);
133 send_address(nbr
, if_addr
->af
, &addr_list
, 1, withdraw
);
137 send_address_all(struct nbr
*nbr
, int af
)
139 struct if_addr_head addr_list
;
140 struct if_addr
*if_addr
;
141 unsigned int addr_count
= 0;
143 LIST_INIT(&addr_list
);
144 LIST_FOREACH(if_addr
, &global
.addr_list
, entry
) {
145 if (if_addr
->af
!= af
)
148 address_list_add(&addr_list
, if_addr
);
152 send_address(nbr
, af
, &addr_list
, addr_count
, 0);
156 send_mac_withdrawal(struct nbr
*nbr
, struct map
*fec
, uint8_t *mac
)
162 size
= LDP_HDR_SIZE
+ LDP_MSG_SIZE
+ ADDR_LIST_SIZE
+ len_fec_tlv(fec
) +
167 if ((buf
= ibuf_open(size
)) == NULL
)
170 err
= gen_ldp_hdr(buf
, size
);
171 size
-= LDP_HDR_SIZE
;
172 err
|= gen_msg_hdr(buf
, MSG_TYPE_ADDRWITHDRAW
, size
);
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
);
181 log_msg_mac_withdrawal(1, nbr
, mac
);
183 evbuf_enqueue(&nbr
->tcp
->wbuf
, buf
);
185 nbr_fsm(nbr
, NBR_EVT_PDU_SENT
);
189 recv_address(struct nbr
*nbr
, char *buf
, uint16_t len
)
194 struct address_list_tlv alt
;
197 struct lde_addr lde_addr
;
199 memcpy(&msg
, buf
, sizeof(msg
));
200 msg_type
= ntohs(msg
.type
);
203 type
= IMSG_ADDRESS_ADD
;
205 case MSG_TYPE_ADDRWITHDRAW
:
206 type
= IMSG_ADDRESS_DEL
;
209 fatalx("recv_address: unexpected msg type");
214 /* Address List TLV */
215 if (len
< ADDR_LIST_SIZE
) {
216 session_shutdown(nbr
, S_BAD_MSG_LEN
, msg
.id
, msg
.type
);
219 memcpy(&alt
, buf
, sizeof(alt
));
220 alt_len
= ntohs(alt
.length
);
221 alt_family
= ntohs(alt
.family
);
222 if (alt_len
> len
- TLV_HDR_SIZE
) {
223 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
226 if (ntohs(alt
.type
) != TLV_TYPE_ADDRLIST
) {
227 send_notification(nbr
->tcp
, S_MISS_MSG
, msg
.id
, msg
.type
);
230 switch (alt_family
) {
232 if (!nbr
->v4_enabled
)
233 /* just ignore the message */
237 if (!nbr
->v6_enabled
)
238 /* just ignore the message */
242 send_notification(nbr
->tcp
, S_UNSUP_ADDR
, msg
.id
, msg
.type
);
245 alt_len
-= sizeof(alt
.family
);
249 /* Process all received addresses */
250 while (alt_len
> 0) {
251 switch (alt_family
) {
253 if (alt_len
< sizeof(struct in_addr
)) {
254 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
,
259 memset(&lde_addr
, 0, sizeof(lde_addr
));
260 lde_addr
.af
= AF_INET
;
261 memcpy(&lde_addr
.addr
, buf
, sizeof(struct in_addr
));
263 buf
+= sizeof(struct in_addr
);
264 len
-= sizeof(struct in_addr
);
265 alt_len
-= sizeof(struct in_addr
);
268 if (alt_len
< sizeof(struct in6_addr
)) {
269 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
,
274 memset(&lde_addr
, 0, sizeof(lde_addr
));
275 lde_addr
.af
= AF_INET6
;
276 memcpy(&lde_addr
.addr
, buf
, sizeof(struct in6_addr
));
278 buf
+= sizeof(struct in6_addr
);
279 len
-= sizeof(struct in6_addr
);
280 alt_len
-= sizeof(struct in6_addr
);
283 fatalx("recv_address: unknown af");
286 log_msg_address(0, msg_type
, nbr
, lde_addr
.af
, &lde_addr
.addr
);
288 ldpe_imsg_compose_lde(type
, nbr
->peerid
, 0, &lde_addr
,
292 /* Optional Parameters */
298 if (len
< sizeof(tlv
)) {
299 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
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
);
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 */
329 gen_address_list_tlv(struct ibuf
*buf
, int af
, struct if_addr_head
*addr_list
,
330 unsigned int tlv_addr_count
)
332 struct address_list_tlv alt
;
334 struct if_addr
*if_addr
;
337 memset(&alt
, 0, sizeof(alt
));
338 alt
.type
= htons(TLV_TYPE_ADDRLIST
);
342 alt
.family
= htons(AF_IPV4
);
343 addr_size
= sizeof(struct in_addr
);
346 alt
.family
= htons(AF_IPV6
);
347 addr_size
= sizeof(struct in6_addr
);
350 fatalx("gen_address_list_tlv: unknown af");
352 alt
.length
= htons(sizeof(alt
.family
) + addr_size
* tlv_addr_count
);
354 err
|= ibuf_add(buf
, &alt
, sizeof(alt
));
355 if (addr_list
== NULL
)
358 LIST_FOREACH(if_addr
, addr_list
, entry
) {
359 err
|= ibuf_add(buf
, &if_addr
->addr
, addr_size
);
360 if (--tlv_addr_count
== 0)
368 gen_mac_list_tlv(struct ibuf
*buf
, uint8_t *mac
)
373 memset(&tlv
, 0, sizeof(tlv
));
374 tlv
.type
= htons(TLV_TYPE_MAC_LIST
);
376 tlv
.length
= htons(ETH_ALEN
);
377 err
= ibuf_add(buf
, &tlv
, sizeof(tlv
));
379 err
|= ibuf_add(buf
, mac
, ETH_ALEN
);
385 address_list_add(struct if_addr_head
*addr_list
, struct if_addr
*if_addr
)
389 new = malloc(sizeof(*new));
394 LIST_INSERT_HEAD(addr_list
, new, entry
);
398 address_list_clr(struct if_addr_head
*addr_list
)
400 struct if_addr
*if_addr
;
402 while ((if_addr
= LIST_FIRST(addr_list
)) != NULL
) {
403 LIST_REMOVE(if_addr
, entry
);
404 assert(if_addr
!= LIST_FIRST(addr_list
));
410 log_msg_address(int out
, uint16_t msg_type
, struct nbr
*nbr
, int af
,
411 union ldpd_addr
*addr
)
413 debug_msg(out
, "%s: lsr-id %s, address %s", msg_name(msg_type
),
414 inet_ntoa(nbr
->id
), log_addr(af
, addr
));
418 log_msg_mac_withdrawal(int out
, struct nbr
*nbr
, uint8_t *mac
)
420 char buf
[ETHER_ADDR_STRLEN
];
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
)) :