1 |
|
|
/* $OpenBSD: labelmapping.c,v 1.68 2017/03/04 00:15:35 renato Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2014, 2015 Renato Westphal <renato@openbsd.org> |
5 |
|
|
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> |
6 |
|
|
* |
7 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
8 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
9 |
|
|
* copyright notice and this permission notice appear in all copies. |
10 |
|
|
* |
11 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 |
|
|
*/ |
19 |
|
|
|
20 |
|
|
#include <sys/types.h> |
21 |
|
|
#include <sys/socket.h> |
22 |
|
|
#include <arpa/inet.h> |
23 |
|
|
#include <netmpls/mpls.h> |
24 |
|
|
#include <limits.h> |
25 |
|
|
#include <stdlib.h> |
26 |
|
|
#include <string.h> |
27 |
|
|
|
28 |
|
|
#include "ldpd.h" |
29 |
|
|
#include "ldpe.h" |
30 |
|
|
#include "log.h" |
31 |
|
|
|
32 |
|
|
static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t); |
33 |
|
|
static int gen_label_tlv(struct ibuf *, uint32_t); |
34 |
|
|
static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *, |
35 |
|
|
uint16_t, uint32_t *); |
36 |
|
|
static int gen_reqid_tlv(struct ibuf *, uint32_t); |
37 |
|
|
static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *); |
38 |
|
|
|
39 |
|
|
static void |
40 |
|
|
enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size) |
41 |
|
|
{ |
42 |
|
|
struct ldp_hdr *ldp_hdr; |
43 |
|
|
|
44 |
|
|
ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr)); |
45 |
|
|
ldp_hdr->length = htons(size); |
46 |
|
|
evbuf_enqueue(&nbr->tcp->wbuf, buf); |
47 |
|
|
} |
48 |
|
|
|
49 |
|
|
/* Generic function that handles all Label Message types */ |
50 |
|
|
void |
51 |
|
|
send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) |
52 |
|
|
{ |
53 |
|
|
struct ibuf *buf = NULL; |
54 |
|
|
struct mapping_entry *me; |
55 |
|
|
uint16_t msg_size, size = 0; |
56 |
|
|
int first = 1; |
57 |
|
|
int err = 0; |
58 |
|
|
|
59 |
|
|
/* nothing to send */ |
60 |
|
|
if (TAILQ_EMPTY(mh)) |
61 |
|
|
return; |
62 |
|
|
|
63 |
|
|
while ((me = TAILQ_FIRST(mh)) != NULL) { |
64 |
|
|
/* generate pdu */ |
65 |
|
|
if (first) { |
66 |
|
|
if ((buf = ibuf_open(nbr->max_pdu_len + |
67 |
|
|
LDP_HDR_DEAD_LEN)) == NULL) |
68 |
|
|
fatal(__func__); |
69 |
|
|
|
70 |
|
|
/* real size will be set up later */ |
71 |
|
|
err |= gen_ldp_hdr(buf, 0); |
72 |
|
|
|
73 |
|
|
size = LDP_HDR_PDU_LEN; |
74 |
|
|
first = 0; |
75 |
|
|
} |
76 |
|
|
|
77 |
|
|
/* calculate size */ |
78 |
|
|
msg_size = LDP_MSG_SIZE; |
79 |
|
|
msg_size += len_fec_tlv(&me->map); |
80 |
|
|
if (me->map.label != NO_LABEL) |
81 |
|
|
msg_size += LABEL_TLV_SIZE; |
82 |
|
|
if (me->map.flags & F_MAP_REQ_ID) |
83 |
|
|
msg_size += REQID_TLV_SIZE; |
84 |
|
|
if (me->map.flags & F_MAP_STATUS) |
85 |
|
|
msg_size += STATUS_SIZE; |
86 |
|
|
|
87 |
|
|
/* maximum pdu length exceeded, we need a new ldp pdu */ |
88 |
|
|
if (size + msg_size > nbr->max_pdu_len) { |
89 |
|
|
enqueue_pdu(nbr, buf, size); |
90 |
|
|
first = 1; |
91 |
|
|
continue; |
92 |
|
|
} |
93 |
|
|
|
94 |
|
|
size += msg_size; |
95 |
|
|
|
96 |
|
|
/* append message and tlvs */ |
97 |
|
|
err |= gen_msg_hdr(buf, type, msg_size); |
98 |
|
|
err |= gen_fec_tlv(buf, &me->map); |
99 |
|
|
if (me->map.label != NO_LABEL) |
100 |
|
|
err |= gen_label_tlv(buf, me->map.label); |
101 |
|
|
if (me->map.flags & F_MAP_REQ_ID) |
102 |
|
|
err |= gen_reqid_tlv(buf, me->map.requestid); |
103 |
|
|
if (me->map.flags & F_MAP_PW_STATUS) |
104 |
|
|
err |= gen_pw_status_tlv(buf, me->map.pw_status); |
105 |
|
|
if (me->map.flags & F_MAP_STATUS) |
106 |
|
|
err |= gen_status_tlv(buf, me->map.st.status_code, |
107 |
|
|
me->map.st.msg_id, me->map.st.msg_type); |
108 |
|
|
if (err) { |
109 |
|
|
ibuf_free(buf); |
110 |
|
|
mapping_list_clr(mh); |
111 |
|
|
return; |
112 |
|
|
} |
113 |
|
|
|
114 |
|
|
log_msg_mapping(1, type, nbr, &me->map); |
115 |
|
|
|
116 |
|
|
TAILQ_REMOVE(mh, me, entry); |
117 |
|
|
free(me); |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
enqueue_pdu(nbr, buf, size); |
121 |
|
|
|
122 |
|
|
nbr_fsm(nbr, NBR_EVT_PDU_SENT); |
123 |
|
|
} |
124 |
|
|
|
125 |
|
|
/* Generic function that handles all Label Message types */ |
126 |
|
|
int |
127 |
|
|
recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) |
128 |
|
|
{ |
129 |
|
|
struct ldp_msg msg; |
130 |
|
|
struct tlv ft; |
131 |
|
|
uint32_t label = NO_LABEL, reqid = 0; |
132 |
|
|
uint32_t pw_status = 0; |
133 |
|
|
uint8_t flags = 0; |
134 |
|
|
int feclen, lbllen, tlen; |
135 |
|
|
struct mapping_entry *me; |
136 |
|
|
struct mapping_head mh; |
137 |
|
|
struct map map; |
138 |
|
|
|
139 |
|
|
memcpy(&msg, buf, sizeof(msg)); |
140 |
|
|
buf += LDP_MSG_SIZE; |
141 |
|
|
len -= LDP_MSG_SIZE; |
142 |
|
|
|
143 |
|
|
/* FEC TLV */ |
144 |
|
|
if (len < sizeof(ft)) { |
145 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); |
146 |
|
|
return (-1); |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
memcpy(&ft, buf, sizeof(ft)); |
150 |
|
|
if (ntohs(ft.type) != TLV_TYPE_FEC) { |
151 |
|
|
send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); |
152 |
|
|
return (-1); |
153 |
|
|
} |
154 |
|
|
feclen = ntohs(ft.length); |
155 |
|
|
if (feclen > len - TLV_HDR_SIZE) { |
156 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); |
157 |
|
|
return (-1); |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
buf += TLV_HDR_SIZE; /* just advance to the end of the fec header */ |
161 |
|
|
len -= TLV_HDR_SIZE; |
162 |
|
|
|
163 |
|
|
TAILQ_INIT(&mh); |
164 |
|
|
do { |
165 |
|
|
memset(&map, 0, sizeof(map)); |
166 |
|
|
map.msg_id = msg.id; |
167 |
|
|
|
168 |
|
|
if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen, |
169 |
|
|
&map)) == -1) |
170 |
|
|
goto err; |
171 |
|
|
if (map.type == MAP_TYPE_PWID && |
172 |
|
|
!(map.flags & F_MAP_PW_ID) && |
173 |
|
|
type != MSG_TYPE_LABELWITHDRAW && |
174 |
|
|
type != MSG_TYPE_LABELRELEASE) { |
175 |
|
|
send_notification(nbr->tcp, S_MISS_MSG, msg.id, |
176 |
|
|
msg.type); |
177 |
|
|
return (-1); |
178 |
|
|
} |
179 |
|
|
|
180 |
|
|
/* |
181 |
|
|
* The Wildcard FEC Element can be used only in the |
182 |
|
|
* Label Withdraw and Label Release messages. |
183 |
|
|
*/ |
184 |
|
|
if (map.type == MAP_TYPE_WILDCARD) { |
185 |
|
|
switch (type) { |
186 |
|
|
case MSG_TYPE_LABELMAPPING: |
187 |
|
|
case MSG_TYPE_LABELREQUEST: |
188 |
|
|
case MSG_TYPE_LABELABORTREQ: |
189 |
|
|
session_shutdown(nbr, S_UNKNOWN_FEC, msg.id, |
190 |
|
|
msg.type); |
191 |
|
|
goto err; |
192 |
|
|
default: |
193 |
|
|
break; |
194 |
|
|
} |
195 |
|
|
} |
196 |
|
|
|
197 |
|
|
/* |
198 |
|
|
* RFC 5561 - Section 4: |
199 |
|
|
* "An LDP implementation that supports the Typed Wildcard |
200 |
|
|
* FEC Element MUST support its use in Label Request, Label |
201 |
|
|
* Withdraw, and Label Release messages". |
202 |
|
|
*/ |
203 |
|
|
if (map.type == MAP_TYPE_TYPED_WCARD) { |
204 |
|
|
switch (type) { |
205 |
|
|
case MSG_TYPE_LABELMAPPING: |
206 |
|
|
case MSG_TYPE_LABELABORTREQ: |
207 |
|
|
session_shutdown(nbr, S_UNKNOWN_FEC, msg.id, |
208 |
|
|
msg.type); |
209 |
|
|
goto err; |
210 |
|
|
default: |
211 |
|
|
break; |
212 |
|
|
} |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
/* |
216 |
|
|
* LDP supports the use of multiple FEC Elements per |
217 |
|
|
* FEC for the Label Mapping message only. |
218 |
|
|
*/ |
219 |
|
|
if (type != MSG_TYPE_LABELMAPPING && |
220 |
|
|
tlen != feclen) { |
221 |
|
|
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); |
222 |
|
|
goto err; |
223 |
|
|
} |
224 |
|
|
|
225 |
|
|
mapping_list_add(&mh, &map); |
226 |
|
|
|
227 |
|
|
buf += tlen; |
228 |
|
|
len -= tlen; |
229 |
|
|
feclen -= tlen; |
230 |
|
|
} while (feclen > 0); |
231 |
|
|
|
232 |
|
|
/* Mandatory Label TLV */ |
233 |
|
|
if (type == MSG_TYPE_LABELMAPPING) { |
234 |
|
|
lbllen = tlv_decode_label(nbr, &msg, buf, len, &label); |
235 |
|
|
if (lbllen == -1) |
236 |
|
|
goto err; |
237 |
|
|
|
238 |
|
|
buf += lbllen; |
239 |
|
|
len -= lbllen; |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
/* Optional Parameters */ |
243 |
|
|
while (len > 0) { |
244 |
|
|
struct tlv tlv; |
245 |
|
|
uint16_t tlv_type; |
246 |
|
|
uint16_t tlv_len; |
247 |
|
|
uint32_t reqbuf, labelbuf, statusbuf; |
248 |
|
|
|
249 |
|
|
if (len < sizeof(tlv)) { |
250 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); |
251 |
|
|
goto err; |
252 |
|
|
} |
253 |
|
|
|
254 |
|
|
memcpy(&tlv, buf, TLV_HDR_SIZE); |
255 |
|
|
tlv_type = ntohs(tlv.type); |
256 |
|
|
tlv_len = ntohs(tlv.length); |
257 |
|
|
if (tlv_len + TLV_HDR_SIZE > len) { |
258 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); |
259 |
|
|
goto err; |
260 |
|
|
} |
261 |
|
|
buf += TLV_HDR_SIZE; |
262 |
|
|
len -= TLV_HDR_SIZE; |
263 |
|
|
|
264 |
|
|
switch (tlv_type) { |
265 |
|
|
case TLV_TYPE_LABELREQUEST: |
266 |
|
|
switch (type) { |
267 |
|
|
case MSG_TYPE_LABELMAPPING: |
268 |
|
|
case MSG_TYPE_LABELREQUEST: |
269 |
|
|
if (tlv_len != REQID_TLV_LEN) { |
270 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, |
271 |
|
|
msg.id, msg.type); |
272 |
|
|
goto err; |
273 |
|
|
} |
274 |
|
|
|
275 |
|
|
flags |= F_MAP_REQ_ID; |
276 |
|
|
memcpy(&reqbuf, buf, sizeof(reqbuf)); |
277 |
|
|
reqid = ntohl(reqbuf); |
278 |
|
|
break; |
279 |
|
|
default: |
280 |
|
|
/* ignore */ |
281 |
|
|
break; |
282 |
|
|
} |
283 |
|
|
break; |
284 |
|
|
case TLV_TYPE_HOPCOUNT: |
285 |
|
|
case TLV_TYPE_PATHVECTOR: |
286 |
|
|
/* ignore */ |
287 |
|
|
break; |
288 |
|
|
case TLV_TYPE_GENERICLABEL: |
289 |
|
|
switch (type) { |
290 |
|
|
case MSG_TYPE_LABELWITHDRAW: |
291 |
|
|
case MSG_TYPE_LABELRELEASE: |
292 |
|
|
if (tlv_len != LABEL_TLV_LEN) { |
293 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, |
294 |
|
|
msg.id, msg.type); |
295 |
|
|
goto err; |
296 |
|
|
} |
297 |
|
|
|
298 |
|
|
memcpy(&labelbuf, buf, sizeof(labelbuf)); |
299 |
|
|
label = ntohl(labelbuf); |
300 |
|
|
break; |
301 |
|
|
default: |
302 |
|
|
/* ignore */ |
303 |
|
|
break; |
304 |
|
|
} |
305 |
|
|
break; |
306 |
|
|
case TLV_TYPE_ATMLABEL: |
307 |
|
|
case TLV_TYPE_FRLABEL: |
308 |
|
|
switch (type) { |
309 |
|
|
case MSG_TYPE_LABELWITHDRAW: |
310 |
|
|
case MSG_TYPE_LABELRELEASE: |
311 |
|
|
/* unsupported */ |
312 |
|
|
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, |
313 |
|
|
msg.type); |
314 |
|
|
goto err; |
315 |
|
|
break; |
316 |
|
|
default: |
317 |
|
|
/* ignore */ |
318 |
|
|
break; |
319 |
|
|
} |
320 |
|
|
break; |
321 |
|
|
case TLV_TYPE_STATUS: |
322 |
|
|
if (tlv_len != STATUS_TLV_LEN) { |
323 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, |
324 |
|
|
msg.type); |
325 |
|
|
goto err; |
326 |
|
|
} |
327 |
|
|
/* ignore */ |
328 |
|
|
break; |
329 |
|
|
case TLV_TYPE_PW_STATUS: |
330 |
|
|
switch (type) { |
331 |
|
|
case MSG_TYPE_LABELMAPPING: |
332 |
|
|
if (tlv_len != PW_STATUS_TLV_LEN) { |
333 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, |
334 |
|
|
msg.id, msg.type); |
335 |
|
|
goto err; |
336 |
|
|
} |
337 |
|
|
|
338 |
|
|
flags |= F_MAP_PW_STATUS; |
339 |
|
|
memcpy(&statusbuf, buf, sizeof(statusbuf)); |
340 |
|
|
pw_status = ntohl(statusbuf); |
341 |
|
|
break; |
342 |
|
|
default: |
343 |
|
|
/* ignore */ |
344 |
|
|
break; |
345 |
|
|
} |
346 |
|
|
break; |
347 |
|
|
default: |
348 |
|
|
if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) |
349 |
|
|
send_notification_rtlvs(nbr, S_UNKNOWN_TLV, |
350 |
|
|
msg.id, msg.type, tlv_type, tlv_len, buf); |
351 |
|
|
/* ignore unknown tlv */ |
352 |
|
|
break; |
353 |
|
|
} |
354 |
|
|
buf += tlv_len; |
355 |
|
|
len -= tlv_len; |
356 |
|
|
} |
357 |
|
|
|
358 |
|
|
/* notify lde about the received message. */ |
359 |
|
|
while ((me = TAILQ_FIRST(&mh)) != NULL) { |
360 |
|
|
int imsg_type = IMSG_NONE; |
361 |
|
|
|
362 |
|
|
me->map.flags |= flags; |
363 |
|
|
switch (me->map.type) { |
364 |
|
|
case MAP_TYPE_PREFIX: |
365 |
|
|
switch (me->map.fec.prefix.af) { |
366 |
|
|
case AF_INET: |
367 |
|
|
if (label == MPLS_LABEL_IPV6NULL) { |
368 |
|
|
session_shutdown(nbr, S_BAD_TLV_VAL, |
369 |
|
|
msg.id, msg.type); |
370 |
|
|
goto err; |
371 |
|
|
} |
372 |
|
|
if (!nbr->v4_enabled) |
373 |
|
|
goto next; |
374 |
|
|
break; |
375 |
|
|
case AF_INET6: |
376 |
|
|
if (label == MPLS_LABEL_IPV4NULL) { |
377 |
|
|
session_shutdown(nbr, S_BAD_TLV_VAL, |
378 |
|
|
msg.id, msg.type); |
379 |
|
|
goto err; |
380 |
|
|
} |
381 |
|
|
if (!nbr->v6_enabled) |
382 |
|
|
goto next; |
383 |
|
|
break; |
384 |
|
|
default: |
385 |
|
|
fatalx("recv_labelmessage: unknown af"); |
386 |
|
|
} |
387 |
|
|
break; |
388 |
|
|
case MAP_TYPE_PWID: |
389 |
|
|
if (label <= MPLS_LABEL_RESERVED_MAX) { |
390 |
|
|
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, |
391 |
|
|
msg.type); |
392 |
|
|
goto err; |
393 |
|
|
} |
394 |
|
|
if (me->map.flags & F_MAP_PW_STATUS) |
395 |
|
|
me->map.pw_status = pw_status; |
396 |
|
|
break; |
397 |
|
|
default: |
398 |
|
|
break; |
399 |
|
|
} |
400 |
|
|
me->map.label = label; |
401 |
|
|
if (me->map.flags & F_MAP_REQ_ID) |
402 |
|
|
me->map.requestid = reqid; |
403 |
|
|
|
404 |
|
|
log_msg_mapping(0, type, nbr, &me->map); |
405 |
|
|
|
406 |
|
|
switch (type) { |
407 |
|
|
case MSG_TYPE_LABELMAPPING: |
408 |
|
|
imsg_type = IMSG_LABEL_MAPPING; |
409 |
|
|
break; |
410 |
|
|
case MSG_TYPE_LABELREQUEST: |
411 |
|
|
imsg_type = IMSG_LABEL_REQUEST; |
412 |
|
|
break; |
413 |
|
|
case MSG_TYPE_LABELWITHDRAW: |
414 |
|
|
imsg_type = IMSG_LABEL_WITHDRAW; |
415 |
|
|
break; |
416 |
|
|
case MSG_TYPE_LABELRELEASE: |
417 |
|
|
imsg_type = IMSG_LABEL_RELEASE; |
418 |
|
|
break; |
419 |
|
|
case MSG_TYPE_LABELABORTREQ: |
420 |
|
|
imsg_type = IMSG_LABEL_ABORT; |
421 |
|
|
break; |
422 |
|
|
default: |
423 |
|
|
break; |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map, |
427 |
|
|
sizeof(struct map)); |
428 |
|
|
|
429 |
|
|
next: |
430 |
|
|
TAILQ_REMOVE(&mh, me, entry); |
431 |
|
|
free(me); |
432 |
|
|
} |
433 |
|
|
|
434 |
|
|
return (0); |
435 |
|
|
|
436 |
|
|
err: |
437 |
|
|
mapping_list_clr(&mh); |
438 |
|
|
|
439 |
|
|
return (-1); |
440 |
|
|
} |
441 |
|
|
|
442 |
|
|
/* Other TLV related functions */ |
443 |
|
|
static int |
444 |
|
|
gen_label_tlv(struct ibuf *buf, uint32_t label) |
445 |
|
|
{ |
446 |
|
|
struct label_tlv lt; |
447 |
|
|
|
448 |
|
|
lt.type = htons(TLV_TYPE_GENERICLABEL); |
449 |
|
|
lt.length = htons(LABEL_TLV_LEN); |
450 |
|
|
lt.label = htonl(label); |
451 |
|
|
|
452 |
|
|
return (ibuf_add(buf, <, sizeof(lt))); |
453 |
|
|
} |
454 |
|
|
|
455 |
|
|
static int |
456 |
|
|
tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf, |
457 |
|
|
uint16_t len, uint32_t *label) |
458 |
|
|
{ |
459 |
|
|
struct label_tlv lt; |
460 |
|
|
|
461 |
|
|
if (len < sizeof(lt)) { |
462 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type); |
463 |
|
|
return (-1); |
464 |
|
|
} |
465 |
|
|
memcpy(<, buf, sizeof(lt)); |
466 |
|
|
|
467 |
|
|
if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) { |
468 |
|
|
send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type); |
469 |
|
|
return (-1); |
470 |
|
|
} |
471 |
|
|
|
472 |
|
|
switch (htons(lt.type)) { |
473 |
|
|
case TLV_TYPE_GENERICLABEL: |
474 |
|
|
if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) { |
475 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
476 |
|
|
msg->type); |
477 |
|
|
return (-1); |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
*label = ntohl(lt.label); |
481 |
|
|
if (*label > MPLS_LABEL_MAX || |
482 |
|
|
(*label <= MPLS_LABEL_RESERVED_MAX && |
483 |
|
|
*label != MPLS_LABEL_IPV4NULL && |
484 |
|
|
*label != MPLS_LABEL_IPV6NULL && |
485 |
|
|
*label != MPLS_LABEL_IMPLNULL)) { |
486 |
|
|
session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, |
487 |
|
|
msg->type); |
488 |
|
|
return (-1); |
489 |
|
|
} |
490 |
|
|
break; |
491 |
|
|
case TLV_TYPE_ATMLABEL: |
492 |
|
|
case TLV_TYPE_FRLABEL: |
493 |
|
|
default: |
494 |
|
|
/* unsupported */ |
495 |
|
|
session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type); |
496 |
|
|
return (-1); |
497 |
|
|
} |
498 |
|
|
|
499 |
|
|
return (sizeof(lt)); |
500 |
|
|
} |
501 |
|
|
|
502 |
|
|
static int |
503 |
|
|
gen_reqid_tlv(struct ibuf *buf, uint32_t reqid) |
504 |
|
|
{ |
505 |
|
|
struct reqid_tlv rt; |
506 |
|
|
|
507 |
|
|
rt.type = htons(TLV_TYPE_LABELREQUEST); |
508 |
|
|
rt.length = htons(REQID_TLV_LEN); |
509 |
|
|
rt.reqid = htonl(reqid); |
510 |
|
|
|
511 |
|
|
return (ibuf_add(buf, &rt, sizeof(rt))); |
512 |
|
|
} |
513 |
|
|
|
514 |
|
|
int |
515 |
|
|
gen_pw_status_tlv(struct ibuf *buf, uint32_t status) |
516 |
|
|
{ |
517 |
|
|
struct pw_status_tlv st; |
518 |
|
|
|
519 |
|
|
st.type = htons(TLV_TYPE_PW_STATUS); |
520 |
|
|
st.length = htons(PW_STATUS_TLV_LEN); |
521 |
|
|
st.value = htonl(status); |
522 |
|
|
|
523 |
|
|
return (ibuf_add(buf, &st, sizeof(st))); |
524 |
|
|
} |
525 |
|
|
|
526 |
|
|
uint16_t |
527 |
|
|
len_fec_tlv(struct map *map) |
528 |
|
|
{ |
529 |
|
|
uint16_t len = TLV_HDR_SIZE; |
530 |
|
|
|
531 |
|
|
switch (map->type) { |
532 |
|
|
case MAP_TYPE_WILDCARD: |
533 |
|
|
len += FEC_ELM_WCARD_LEN; |
534 |
|
|
break; |
535 |
|
|
case MAP_TYPE_PREFIX: |
536 |
|
|
len += FEC_ELM_PREFIX_MIN_LEN + |
537 |
|
|
PREFIX_SIZE(map->fec.prefix.prefixlen); |
538 |
|
|
break; |
539 |
|
|
case MAP_TYPE_PWID: |
540 |
|
|
len += FEC_PWID_ELM_MIN_LEN; |
541 |
|
|
if (map->flags & F_MAP_PW_ID) |
542 |
|
|
len += PW_STATUS_TLV_LEN; |
543 |
|
|
if (map->flags & F_MAP_PW_IFMTU) |
544 |
|
|
len += FEC_SUBTLV_IFMTU_SIZE; |
545 |
|
|
if (map->flags & F_MAP_PW_STATUS) |
546 |
|
|
len += PW_STATUS_TLV_SIZE; |
547 |
|
|
break; |
548 |
|
|
case MAP_TYPE_TYPED_WCARD: |
549 |
|
|
len += FEC_ELM_TWCARD_MIN_LEN; |
550 |
|
|
switch (map->fec.twcard.type) { |
551 |
|
|
case MAP_TYPE_PREFIX: |
552 |
|
|
case MAP_TYPE_PWID: |
553 |
|
|
len += sizeof(uint16_t); |
554 |
|
|
break; |
555 |
|
|
default: |
556 |
|
|
fatalx("len_fec_tlv: unexpected fec type"); |
557 |
|
|
} |
558 |
|
|
break; |
559 |
|
|
default: |
560 |
|
|
fatalx("len_fec_tlv: unexpected fec type"); |
561 |
|
|
} |
562 |
|
|
|
563 |
|
|
return (len); |
564 |
|
|
} |
565 |
|
|
|
566 |
|
|
int |
567 |
|
|
gen_fec_tlv(struct ibuf *buf, struct map *map) |
568 |
|
|
{ |
569 |
|
|
struct tlv ft; |
570 |
|
|
uint16_t family, len, pw_type, ifmtu; |
571 |
|
|
uint8_t pw_len = 0, twcard_len; |
572 |
|
|
uint32_t group_id, pwid; |
573 |
|
|
int err = 0; |
574 |
|
|
|
575 |
|
|
ft.type = htons(TLV_TYPE_FEC); |
576 |
|
|
|
577 |
|
|
switch (map->type) { |
578 |
|
|
case MAP_TYPE_WILDCARD: |
579 |
|
|
ft.length = htons(sizeof(uint8_t)); |
580 |
|
|
err |= ibuf_add(buf, &ft, sizeof(ft)); |
581 |
|
|
err |= ibuf_add(buf, &map->type, sizeof(map->type)); |
582 |
|
|
break; |
583 |
|
|
case MAP_TYPE_PREFIX: |
584 |
|
|
len = PREFIX_SIZE(map->fec.prefix.prefixlen); |
585 |
|
|
ft.length = htons(sizeof(map->type) + sizeof(family) + |
586 |
|
|
sizeof(map->fec.prefix.prefixlen) + len); |
587 |
|
|
err |= ibuf_add(buf, &ft, sizeof(ft)); |
588 |
|
|
err |= ibuf_add(buf, &map->type, sizeof(map->type)); |
589 |
|
|
switch (map->fec.prefix.af) { |
590 |
|
|
case AF_INET: |
591 |
|
|
family = htons(AF_IPV4); |
592 |
|
|
break; |
593 |
|
|
case AF_INET6: |
594 |
|
|
family = htons(AF_IPV6); |
595 |
|
|
break; |
596 |
|
|
default: |
597 |
|
|
fatalx("gen_fec_tlv: unknown af"); |
598 |
|
|
break; |
599 |
|
|
} |
600 |
|
|
err |= ibuf_add(buf, &family, sizeof(family)); |
601 |
|
|
err |= ibuf_add(buf, &map->fec.prefix.prefixlen, |
602 |
|
|
sizeof(map->fec.prefix.prefixlen)); |
603 |
|
|
if (len) |
604 |
|
|
err |= ibuf_add(buf, &map->fec.prefix.prefix, len); |
605 |
|
|
break; |
606 |
|
|
case MAP_TYPE_PWID: |
607 |
|
|
if (map->flags & F_MAP_PW_ID) |
608 |
|
|
pw_len += FEC_PWID_SIZE; |
609 |
|
|
if (map->flags & F_MAP_PW_IFMTU) |
610 |
|
|
pw_len += FEC_SUBTLV_IFMTU_SIZE; |
611 |
|
|
|
612 |
|
|
len = FEC_PWID_ELM_MIN_LEN + pw_len; |
613 |
|
|
|
614 |
|
|
ft.length = htons(len); |
615 |
|
|
err |= ibuf_add(buf, &ft, sizeof(ft)); |
616 |
|
|
|
617 |
|
|
err |= ibuf_add(buf, &map->type, sizeof(uint8_t)); |
618 |
|
|
pw_type = map->fec.pwid.type; |
619 |
|
|
if (map->flags & F_MAP_PW_CWORD) |
620 |
|
|
pw_type |= CONTROL_WORD_FLAG; |
621 |
|
|
pw_type = htons(pw_type); |
622 |
|
|
err |= ibuf_add(buf, &pw_type, sizeof(uint16_t)); |
623 |
|
|
err |= ibuf_add(buf, &pw_len, sizeof(uint8_t)); |
624 |
|
|
group_id = htonl(map->fec.pwid.group_id); |
625 |
|
|
err |= ibuf_add(buf, &group_id, sizeof(uint32_t)); |
626 |
|
|
if (map->flags & F_MAP_PW_ID) { |
627 |
|
|
pwid = htonl(map->fec.pwid.pwid); |
628 |
|
|
err |= ibuf_add(buf, &pwid, sizeof(uint32_t)); |
629 |
|
|
} |
630 |
|
|
if (map->flags & F_MAP_PW_IFMTU) { |
631 |
|
|
struct subtlv stlv; |
632 |
|
|
|
633 |
|
|
stlv.type = SUBTLV_IFMTU; |
634 |
|
|
stlv.length = FEC_SUBTLV_IFMTU_SIZE; |
635 |
|
|
err |= ibuf_add(buf, &stlv, sizeof(uint16_t)); |
636 |
|
|
|
637 |
|
|
ifmtu = htons(map->fec.pwid.ifmtu); |
638 |
|
|
err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t)); |
639 |
|
|
} |
640 |
|
|
break; |
641 |
|
|
case MAP_TYPE_TYPED_WCARD: |
642 |
|
|
len = FEC_ELM_TWCARD_MIN_LEN; |
643 |
|
|
switch (map->fec.twcard.type) { |
644 |
|
|
case MAP_TYPE_PREFIX: |
645 |
|
|
case MAP_TYPE_PWID: |
646 |
|
|
len += sizeof(uint16_t); |
647 |
|
|
break; |
648 |
|
|
default: |
649 |
|
|
fatalx("gen_fec_tlv: unexpected fec type"); |
650 |
|
|
} |
651 |
|
|
ft.length = htons(len); |
652 |
|
|
err |= ibuf_add(buf, &ft, sizeof(ft)); |
653 |
|
|
err |= ibuf_add(buf, &map->type, sizeof(uint8_t)); |
654 |
|
|
err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t)); |
655 |
|
|
|
656 |
|
|
switch (map->fec.twcard.type) { |
657 |
|
|
case MAP_TYPE_PREFIX: |
658 |
|
|
twcard_len = sizeof(uint16_t); |
659 |
|
|
err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t)); |
660 |
|
|
|
661 |
|
|
switch (map->fec.twcard.u.prefix_af) { |
662 |
|
|
case AF_INET: |
663 |
|
|
family = htons(AF_IPV4); |
664 |
|
|
break; |
665 |
|
|
case AF_INET6: |
666 |
|
|
family = htons(AF_IPV6); |
667 |
|
|
break; |
668 |
|
|
default: |
669 |
|
|
fatalx("gen_fec_tlv: unknown af"); |
670 |
|
|
break; |
671 |
|
|
} |
672 |
|
|
|
673 |
|
|
err |= ibuf_add(buf, &family, sizeof(uint16_t)); |
674 |
|
|
break; |
675 |
|
|
case MAP_TYPE_PWID: |
676 |
|
|
twcard_len = sizeof(uint16_t); |
677 |
|
|
err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t)); |
678 |
|
|
pw_type = htons(map->fec.twcard.u.pw_type); |
679 |
|
|
err |= ibuf_add(buf, &pw_type, sizeof(uint16_t)); |
680 |
|
|
break; |
681 |
|
|
default: |
682 |
|
|
fatalx("gen_fec_tlv: unexpected fec type"); |
683 |
|
|
} |
684 |
|
|
break; |
685 |
|
|
default: |
686 |
|
|
break; |
687 |
|
|
} |
688 |
|
|
|
689 |
|
|
return (err); |
690 |
|
|
} |
691 |
|
|
|
692 |
|
|
int |
693 |
|
|
tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, |
694 |
|
|
uint16_t len, struct map *map) |
695 |
|
|
{ |
696 |
|
|
uint16_t off = 0; |
697 |
|
|
uint8_t pw_len, twcard_len; |
698 |
|
|
|
699 |
|
|
map->type = *buf; |
700 |
|
|
off += sizeof(uint8_t); |
701 |
|
|
|
702 |
|
|
switch (map->type) { |
703 |
|
|
case MAP_TYPE_WILDCARD: |
704 |
|
|
if (len == FEC_ELM_WCARD_LEN) |
705 |
|
|
return (off); |
706 |
|
|
else { |
707 |
|
|
session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, |
708 |
|
|
msg->type); |
709 |
|
|
return (-1); |
710 |
|
|
} |
711 |
|
|
break; |
712 |
|
|
case MAP_TYPE_PREFIX: |
713 |
|
|
if (len < FEC_ELM_PREFIX_MIN_LEN) { |
714 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
715 |
|
|
msg->type); |
716 |
|
|
return (-1); |
717 |
|
|
} |
718 |
|
|
|
719 |
|
|
/* Address Family */ |
720 |
|
|
memcpy(&map->fec.prefix.af, buf + off, |
721 |
|
|
sizeof(map->fec.prefix.af)); |
722 |
|
|
off += sizeof(map->fec.prefix.af); |
723 |
|
|
map->fec.prefix.af = ntohs(map->fec.prefix.af); |
724 |
|
|
switch (map->fec.prefix.af) { |
725 |
|
|
case AF_IPV4: |
726 |
|
|
map->fec.prefix.af = AF_INET; |
727 |
|
|
break; |
728 |
|
|
case AF_IPV6: |
729 |
|
|
map->fec.prefix.af = AF_INET6; |
730 |
|
|
break; |
731 |
|
|
default: |
732 |
|
|
send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id, |
733 |
|
|
msg->type); |
734 |
|
|
return (-1); |
735 |
|
|
} |
736 |
|
|
|
737 |
|
|
/* Prefix Length */ |
738 |
|
|
map->fec.prefix.prefixlen = buf[off]; |
739 |
|
|
off += sizeof(uint8_t); |
740 |
|
|
if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) { |
741 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
742 |
|
|
msg->type); |
743 |
|
|
return (-1); |
744 |
|
|
} |
745 |
|
|
|
746 |
|
|
/* Prefix */ |
747 |
|
|
memset(&map->fec.prefix.prefix, 0, |
748 |
|
|
sizeof(map->fec.prefix.prefix)); |
749 |
|
|
memcpy(&map->fec.prefix.prefix, buf + off, |
750 |
|
|
PREFIX_SIZE(map->fec.prefix.prefixlen)); |
751 |
|
|
|
752 |
|
|
/* Just in case... */ |
753 |
|
|
ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix, |
754 |
|
|
&map->fec.prefix.prefix, map->fec.prefix.prefixlen); |
755 |
|
|
|
756 |
|
|
return (off + PREFIX_SIZE(map->fec.prefix.prefixlen)); |
757 |
|
|
case MAP_TYPE_PWID: |
758 |
|
|
if (len < FEC_PWID_ELM_MIN_LEN) { |
759 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
760 |
|
|
msg->type); |
761 |
|
|
return (-1); |
762 |
|
|
} |
763 |
|
|
|
764 |
|
|
/* PW type */ |
765 |
|
|
memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t)); |
766 |
|
|
map->fec.pwid.type = ntohs(map->fec.pwid.type); |
767 |
|
|
if (map->fec.pwid.type & CONTROL_WORD_FLAG) { |
768 |
|
|
map->flags |= F_MAP_PW_CWORD; |
769 |
|
|
map->fec.pwid.type &= ~CONTROL_WORD_FLAG; |
770 |
|
|
} |
771 |
|
|
off += sizeof(uint16_t); |
772 |
|
|
|
773 |
|
|
/* PW info Length */ |
774 |
|
|
pw_len = buf[off]; |
775 |
|
|
off += sizeof(uint8_t); |
776 |
|
|
|
777 |
|
|
if (len != FEC_PWID_ELM_MIN_LEN + pw_len) { |
778 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
779 |
|
|
msg->type); |
780 |
|
|
return (-1); |
781 |
|
|
} |
782 |
|
|
|
783 |
|
|
/* Group ID */ |
784 |
|
|
memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t)); |
785 |
|
|
map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id); |
786 |
|
|
off += sizeof(uint32_t); |
787 |
|
|
|
788 |
|
|
/* PW ID */ |
789 |
|
|
if (pw_len == 0) |
790 |
|
|
return (off); |
791 |
|
|
|
792 |
|
|
if (pw_len < sizeof(uint32_t)) { |
793 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
794 |
|
|
msg->type); |
795 |
|
|
return (-1); |
796 |
|
|
} |
797 |
|
|
|
798 |
|
|
memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t)); |
799 |
|
|
map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid); |
800 |
|
|
map->flags |= F_MAP_PW_ID; |
801 |
|
|
off += sizeof(uint32_t); |
802 |
|
|
pw_len -= sizeof(uint32_t); |
803 |
|
|
|
804 |
|
|
/* Optional Interface Parameter Sub-TLVs */ |
805 |
|
|
while (pw_len > 0) { |
806 |
|
|
struct subtlv stlv; |
807 |
|
|
|
808 |
|
|
if (pw_len < sizeof(stlv)) { |
809 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
810 |
|
|
msg->type); |
811 |
|
|
return (-1); |
812 |
|
|
} |
813 |
|
|
|
814 |
|
|
memcpy(&stlv, buf + off, sizeof(stlv)); |
815 |
|
|
if (stlv.length > pw_len) { |
816 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
817 |
|
|
msg->type); |
818 |
|
|
return (-1); |
819 |
|
|
} |
820 |
|
|
|
821 |
|
|
switch (stlv.type) { |
822 |
|
|
case SUBTLV_IFMTU: |
823 |
|
|
if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) { |
824 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, |
825 |
|
|
msg->id, msg->type); |
826 |
|
|
return (-1); |
827 |
|
|
} |
828 |
|
|
memcpy(&map->fec.pwid.ifmtu, buf + off + |
829 |
|
|
SUBTLV_HDR_SIZE, sizeof(uint16_t)); |
830 |
|
|
map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu); |
831 |
|
|
map->flags |= F_MAP_PW_IFMTU; |
832 |
|
|
break; |
833 |
|
|
default: |
834 |
|
|
/* ignore */ |
835 |
|
|
break; |
836 |
|
|
} |
837 |
|
|
off += stlv.length; |
838 |
|
|
pw_len -= stlv.length; |
839 |
|
|
} |
840 |
|
|
|
841 |
|
|
return (off); |
842 |
|
|
case MAP_TYPE_TYPED_WCARD: |
843 |
|
|
if (len < FEC_ELM_TWCARD_MIN_LEN) { |
844 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
845 |
|
|
msg->type); |
846 |
|
|
return (-1); |
847 |
|
|
} |
848 |
|
|
|
849 |
|
|
memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t)); |
850 |
|
|
off += sizeof(uint8_t); |
851 |
|
|
memcpy(&twcard_len, buf + off, sizeof(uint8_t)); |
852 |
|
|
off += sizeof(uint8_t); |
853 |
|
|
if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) { |
854 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
855 |
|
|
msg->type); |
856 |
|
|
return (-1); |
857 |
|
|
} |
858 |
|
|
|
859 |
|
|
switch (map->fec.twcard.type) { |
860 |
|
|
case MAP_TYPE_PREFIX: |
861 |
|
|
if (twcard_len != sizeof(uint16_t)) { |
862 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
863 |
|
|
msg->type); |
864 |
|
|
return (-1); |
865 |
|
|
} |
866 |
|
|
|
867 |
|
|
memcpy(&map->fec.twcard.u.prefix_af, buf + off, |
868 |
|
|
sizeof(uint16_t)); |
869 |
|
|
map->fec.twcard.u.prefix_af = |
870 |
|
|
ntohs(map->fec.twcard.u.prefix_af); |
871 |
|
|
off += sizeof(uint16_t); |
872 |
|
|
|
873 |
|
|
switch (map->fec.twcard.u.prefix_af) { |
874 |
|
|
case AF_IPV4: |
875 |
|
|
map->fec.twcard.u.prefix_af = AF_INET; |
876 |
|
|
break; |
877 |
|
|
case AF_IPV6: |
878 |
|
|
map->fec.twcard.u.prefix_af = AF_INET6; |
879 |
|
|
break; |
880 |
|
|
default: |
881 |
|
|
session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, |
882 |
|
|
msg->type); |
883 |
|
|
return (-1); |
884 |
|
|
} |
885 |
|
|
break; |
886 |
|
|
case MAP_TYPE_PWID: |
887 |
|
|
if (twcard_len != sizeof(uint16_t)) { |
888 |
|
|
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, |
889 |
|
|
msg->type); |
890 |
|
|
return (-1); |
891 |
|
|
} |
892 |
|
|
|
893 |
|
|
memcpy(&map->fec.twcard.u.pw_type, buf + off, |
894 |
|
|
sizeof(uint16_t)); |
895 |
|
|
map->fec.twcard.u.pw_type = |
896 |
|
|
ntohs(map->fec.twcard.u.pw_type); |
897 |
|
|
/* ignore the reserved bit as per RFC 6667 */ |
898 |
|
|
map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT; |
899 |
|
|
off += sizeof(uint16_t); |
900 |
|
|
break; |
901 |
|
|
default: |
902 |
|
|
send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, |
903 |
|
|
msg->type); |
904 |
|
|
return (-1); |
905 |
|
|
} |
906 |
|
|
|
907 |
|
|
return (off); |
908 |
|
|
default: |
909 |
|
|
send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type); |
910 |
|
|
break; |
911 |
|
|
} |
912 |
|
|
|
913 |
|
|
return (-1); |
914 |
|
|
} |
915 |
|
|
|
916 |
|
|
static void |
917 |
|
|
log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map) |
918 |
|
|
{ |
919 |
|
|
log_debug("msg-%s: %s: lsr-id %s, fec %s, label %s", |
920 |
|
|
(out) ? "out" : "in", msg_name(msg_type), inet_ntoa(nbr->id), |
921 |
|
|
log_map(map), log_label(map->label)); |
922 |
|
|
} |