]>
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 ((if_addr
= 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
);
92 address_list_clr(addr_list
);
97 while ((if_addr
= LIST_FIRST(addr_list
)) != NULL
) {
98 log_msg_address(1, msg_type
, nbr
, af
, &if_addr
->addr
);
100 LIST_REMOVE(if_addr
, entry
);
102 if (--tlv_addr_count
== 0)
106 evbuf_enqueue(&nbr
->tcp
->wbuf
, buf
);
108 /* no errors - update per neighbor message counters */
111 nbr
->stats
.addr_sent
++;
113 case MSG_TYPE_ADDRWITHDRAW
:
114 nbr
->stats
.addrwdraw_sent
++;
121 nbr_fsm(nbr
, NBR_EVT_PDU_SENT
);
125 send_address_single(struct nbr
*nbr
, struct if_addr
*if_addr
, int withdraw
)
127 struct if_addr_head addr_list
;
129 LIST_INIT(&addr_list
);
130 address_list_add(&addr_list
, if_addr
);
131 send_address(nbr
, if_addr
->af
, &addr_list
, 1, withdraw
);
135 send_address_all(struct nbr
*nbr
, int af
)
137 struct if_addr_head addr_list
;
138 struct if_addr
*if_addr
;
139 unsigned int addr_count
= 0;
141 LIST_INIT(&addr_list
);
142 LIST_FOREACH(if_addr
, &global
.addr_list
, entry
) {
143 if (if_addr
->af
!= af
)
146 address_list_add(&addr_list
, if_addr
);
150 send_address(nbr
, af
, &addr_list
, addr_count
, 0);
154 send_mac_withdrawal(struct nbr
*nbr
, struct map
*fec
, uint8_t *mac
)
160 size
= LDP_HDR_SIZE
+ LDP_MSG_SIZE
+ ADDR_LIST_SIZE
+ len_fec_tlv(fec
) +
165 if ((buf
= ibuf_open(size
)) == NULL
)
168 err
= gen_ldp_hdr(buf
, size
);
169 size
-= LDP_HDR_SIZE
;
170 err
|= gen_msg_hdr(buf
, MSG_TYPE_ADDRWITHDRAW
, size
);
171 size
-= LDP_MSG_SIZE
;
172 err
|= gen_address_list_tlv(buf
, AF_INET
, NULL
, 0);
173 err
|= gen_fec_tlv(buf
, fec
);
174 err
|= gen_mac_list_tlv(buf
, mac
);
180 log_msg_mac_withdrawal(1, nbr
, mac
);
182 evbuf_enqueue(&nbr
->tcp
->wbuf
, buf
);
184 nbr_fsm(nbr
, NBR_EVT_PDU_SENT
);
188 recv_address(struct nbr
*nbr
, char *buf
, uint16_t len
)
193 struct address_list_tlv alt
;
196 struct lde_addr lde_addr
;
198 memcpy(&msg
, buf
, sizeof(msg
));
199 msg_type
= ntohs(msg
.type
);
202 type
= IMSG_ADDRESS_ADD
;
204 case MSG_TYPE_ADDRWITHDRAW
:
205 type
= IMSG_ADDRESS_DEL
;
208 fatalx("recv_address: unexpected msg type");
213 /* Address List TLV */
214 if (len
< ADDR_LIST_SIZE
) {
215 session_shutdown(nbr
, S_BAD_MSG_LEN
, msg
.id
, msg
.type
);
218 memcpy(&alt
, buf
, sizeof(alt
));
219 alt_len
= ntohs(alt
.length
);
220 alt_family
= ntohs(alt
.family
);
221 if (alt_len
> len
- TLV_HDR_SIZE
) {
222 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
225 if (ntohs(alt
.type
) != TLV_TYPE_ADDRLIST
) {
226 send_notification(nbr
->tcp
, S_MISS_MSG
, msg
.id
, msg
.type
);
229 switch (alt_family
) {
231 if (!nbr
->v4_enabled
)
232 /* just ignore the message */
236 if (!nbr
->v6_enabled
)
237 /* just ignore the message */
241 send_notification(nbr
->tcp
, S_UNSUP_ADDR
, msg
.id
, msg
.type
);
244 alt_len
-= sizeof(alt
.family
);
248 /* Process all received addresses */
249 while (alt_len
> 0) {
250 switch (alt_family
) {
252 if (alt_len
< sizeof(struct in_addr
)) {
253 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
,
258 memset(&lde_addr
, 0, sizeof(lde_addr
));
259 lde_addr
.af
= AF_INET
;
260 memcpy(&lde_addr
.addr
, buf
, sizeof(struct in_addr
));
262 buf
+= sizeof(struct in_addr
);
263 len
-= sizeof(struct in_addr
);
264 alt_len
-= sizeof(struct in_addr
);
267 if (alt_len
< sizeof(struct in6_addr
)) {
268 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
,
273 memset(&lde_addr
, 0, sizeof(lde_addr
));
274 lde_addr
.af
= AF_INET6
;
275 memcpy(&lde_addr
.addr
, buf
, sizeof(struct in6_addr
));
277 buf
+= sizeof(struct in6_addr
);
278 len
-= sizeof(struct in6_addr
);
279 alt_len
-= sizeof(struct in6_addr
);
282 fatalx("recv_address: unknown af");
285 log_msg_address(0, msg_type
, nbr
, lde_addr
.af
, &lde_addr
.addr
);
287 ldpe_imsg_compose_lde(type
, nbr
->peerid
, 0, &lde_addr
,
291 /* Optional Parameters */
297 if (len
< sizeof(tlv
)) {
298 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
302 memcpy(&tlv
, buf
, TLV_HDR_SIZE
);
303 tlv_type
= ntohs(tlv
.type
);
304 tlv_len
= ntohs(tlv
.length
);
305 if (tlv_len
+ TLV_HDR_SIZE
> len
) {
306 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
314 if (!(ntohs(tlv
.type
) & UNKNOWN_FLAG
))
315 send_notification_rtlvs(nbr
, S_UNKNOWN_TLV
,
316 msg
.id
, msg
.type
, tlv_type
, tlv_len
, buf
);
317 /* ignore unknown tlv */
328 gen_address_list_tlv(struct ibuf
*buf
, int af
, struct if_addr_head
*addr_list
,
329 unsigned int tlv_addr_count
)
331 struct address_list_tlv alt
;
333 struct if_addr
*if_addr
;
336 memset(&alt
, 0, sizeof(alt
));
337 alt
.type
= htons(TLV_TYPE_ADDRLIST
);
341 alt
.family
= htons(AF_IPV4
);
342 addr_size
= sizeof(struct in_addr
);
345 alt
.family
= htons(AF_IPV6
);
346 addr_size
= sizeof(struct in6_addr
);
349 fatalx("gen_address_list_tlv: unknown af");
351 alt
.length
= htons(sizeof(alt
.family
) + addr_size
* tlv_addr_count
);
353 err
|= ibuf_add(buf
, &alt
, sizeof(alt
));
354 if (addr_list
== NULL
)
357 LIST_FOREACH(if_addr
, addr_list
, entry
) {
358 err
|= ibuf_add(buf
, &if_addr
->addr
, addr_size
);
359 if (--tlv_addr_count
== 0)
367 gen_mac_list_tlv(struct ibuf
*buf
, uint8_t *mac
)
372 memset(&tlv
, 0, sizeof(tlv
));
373 tlv
.type
= htons(TLV_TYPE_MAC_LIST
);
375 tlv
.length
= htons(ETH_ALEN
);
376 err
= ibuf_add(buf
, &tlv
, sizeof(tlv
));
378 err
|= ibuf_add(buf
, mac
, ETH_ALEN
);
384 address_list_add(struct if_addr_head
*addr_list
, struct if_addr
*if_addr
)
388 new = malloc(sizeof(*new));
393 LIST_INSERT_HEAD(addr_list
, new, entry
);
397 address_list_clr(struct if_addr_head
*addr_list
)
399 struct if_addr
*if_addr
;
401 while ((if_addr
= LIST_FIRST(addr_list
)) != NULL
) {
402 LIST_REMOVE(if_addr
, entry
);
408 log_msg_address(int out
, uint16_t msg_type
, struct nbr
*nbr
, int af
,
409 union ldpd_addr
*addr
)
411 debug_msg(out
, "%s: lsr-id %s, address %s", msg_name(msg_type
),
412 inet_ntoa(nbr
->id
), log_addr(af
, addr
));
416 log_msg_mac_withdrawal(int out
, struct nbr
*nbr
, uint8_t *mac
)
418 char buf
[ETHER_ADDR_STRLEN
];
420 debug_msg(out
, "mac withdrawal: lsr-id %s, mac %s", inet_ntoa(nbr
->id
),
421 (mac
) ? prefix_mac2str((struct ethaddr
*)mac
, buf
, sizeof(buf
)) :