blob: 21c7e36751a36fc17c62f6017c55f0e6d28a48b7 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP open message handling
2 Copyright (C) 1998, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "prefix.h"
25#include "stream.h"
26#include "thread.h"
27#include "log.h"
28#include "command.h"
Paul Jakma6d582722007-08-06 15:21:45 +000029#include "memory.h"
paul718e3742002-12-13 20:15:29 +000030
31#include "bgpd/bgpd.h"
32#include "bgpd/bgp_attr.h"
33#include "bgpd/bgp_debug.h"
34#include "bgpd/bgp_fsm.h"
35#include "bgpd/bgp_packet.h"
36#include "bgpd/bgp_open.h"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000037#include "bgpd/bgp_aspath.h"
hasso538621f2004-05-21 09:31:30 +000038#include "bgpd/bgp_vty.h"
39
paul718e3742002-12-13 20:15:29 +000040/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can
41 negotiate remote peer supports extentions or not. But if
42 remote-peer doesn't supports negotiation process itself. We would
43 like to do manual configuration.
44
45 So there is many configurable point. First of all we want set each
46 peer whether we send capability negotiation to the peer or not.
47 Next, if we send capability to the peer we want to set my capabilty
48 inforation at each peer. */
49
50void
51bgp_capability_vty_out (struct vty *vty, struct peer *peer)
52{
paul5228ad22004-06-04 17:58:18 +000053 char *pnt;
54 char *end;
Paul Jakma6d582722007-08-06 15:21:45 +000055 struct capability_mp_data mpc;
56 struct capability_header *hdr;
paul718e3742002-12-13 20:15:29 +000057
58 pnt = peer->notify.data;
59 end = pnt + peer->notify.length;
Paul Jakma6d582722007-08-06 15:21:45 +000060
paul718e3742002-12-13 20:15:29 +000061 while (pnt < end)
62 {
Paul Jakma6d582722007-08-06 15:21:45 +000063 if (pnt + sizeof (struct capability_mp_data) + 2 > end)
paul718e3742002-12-13 20:15:29 +000064 return;
Paul Jakma6d582722007-08-06 15:21:45 +000065
66 hdr = (struct capability_header *)pnt;
67 if (pnt + hdr->length + 2 > end)
paul718e3742002-12-13 20:15:29 +000068 return;
69
Paul Jakma6d582722007-08-06 15:21:45 +000070 memcpy (&mpc, pnt + 2, sizeof(struct capability_mp_data));
71
72 if (hdr->code == CAPABILITY_CODE_MP)
paul718e3742002-12-13 20:15:29 +000073 {
74 vty_out (vty, " Capability error for: Multi protocol ");
75
Paul Jakma6d582722007-08-06 15:21:45 +000076 switch (ntohs (mpc.afi))
paul718e3742002-12-13 20:15:29 +000077 {
78 case AFI_IP:
79 vty_out (vty, "AFI IPv4, ");
80 break;
81 case AFI_IP6:
82 vty_out (vty, "AFI IPv6, ");
83 break;
84 default:
Paul Jakma6d582722007-08-06 15:21:45 +000085 vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi));
paul718e3742002-12-13 20:15:29 +000086 break;
87 }
Paul Jakma6d582722007-08-06 15:21:45 +000088 switch (mpc.safi)
paul718e3742002-12-13 20:15:29 +000089 {
90 case SAFI_UNICAST:
91 vty_out (vty, "SAFI Unicast");
92 break;
93 case SAFI_MULTICAST:
94 vty_out (vty, "SAFI Multicast");
95 break;
96 case SAFI_UNICAST_MULTICAST:
97 vty_out (vty, "SAFI Unicast Multicast");
98 break;
Denis Ovsienko42e6d742011-07-14 12:36:19 +040099 case SAFI_MPLS_LABELED_VPN:
100 vty_out (vty, "SAFI MPLS-labeled VPN");
paul718e3742002-12-13 20:15:29 +0000101 break;
102 default:
Paul Jakma6d582722007-08-06 15:21:45 +0000103 vty_out (vty, "SAFI Unknown %d ", mpc.safi);
paul718e3742002-12-13 20:15:29 +0000104 break;
105 }
106 vty_out (vty, "%s", VTY_NEWLINE);
107 }
Paul Jakma6d582722007-08-06 15:21:45 +0000108 else if (hdr->code >= 128)
paul718e3742002-12-13 20:15:29 +0000109 vty_out (vty, " Capability error: vendor specific capability code %d",
Paul Jakma6d582722007-08-06 15:21:45 +0000110 hdr->code);
paul718e3742002-12-13 20:15:29 +0000111 else
112 vty_out (vty, " Capability error: unknown capability code %d",
Paul Jakma6d582722007-08-06 15:21:45 +0000113 hdr->code);
paul718e3742002-12-13 20:15:29 +0000114
Paul Jakma6d582722007-08-06 15:21:45 +0000115 pnt += hdr->length + 2;
paul718e3742002-12-13 20:15:29 +0000116 }
117}
118
Paul Jakma6d582722007-08-06 15:21:45 +0000119static void
120bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)
121{
122 mpc->afi = stream_getw (s);
123 mpc->reserved = stream_getc (s);
124 mpc->safi = stream_getc (s);
125}
126
127int
128bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
129{
Paul Jakma6d582722007-08-06 15:21:45 +0000130 switch (afi)
131 {
132 case AFI_IP:
133#ifdef HAVE_IPV6
134 case AFI_IP6:
135#endif
136 switch (*safi)
137 {
Denis Ovsienko42e6d742011-07-14 12:36:19 +0400138 /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */
139 case SAFI_MPLS_LABELED_VPN:
Paul Jakma6d582722007-08-06 15:21:45 +0000140 *safi = SAFI_MPLS_VPN;
141 case SAFI_UNICAST:
142 case SAFI_MULTICAST:
143 case SAFI_MPLS_VPN:
144 return 1;
145 }
146 }
147 zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi);
148
149 return 0;
150}
151
paul718e3742002-12-13 20:15:29 +0000152/* Set negotiated capability value. */
paul94f2b392005-06-28 12:44:16 +0000153static int
Paul Jakma6d582722007-08-06 15:21:45 +0000154bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
paul718e3742002-12-13 20:15:29 +0000155{
Paul Jakma6d582722007-08-06 15:21:45 +0000156 struct capability_mp_data mpc;
157 struct stream *s = BGP_INPUT (peer);
158
159 bgp_capability_mp_data (s, &mpc);
160
161 if (BGP_DEBUG (normal, NORMAL))
162 zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
163 peer->host, mpc.afi, mpc.safi);
164
165 if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi))
166 return -1;
167
168 /* Now safi remapped, and afi/safi are valid array indices */
169 peer->afc_recv[mpc.afi][mpc.safi] = 1;
170
171 if (peer->afc[mpc.afi][mpc.safi])
Paul Jakmae08286b2007-09-18 12:11:26 +0000172 peer->afc_nego[mpc.afi][mpc.safi] = 1;
Paul Jakma6d582722007-08-06 15:21:45 +0000173 else
174 return -1;
paul718e3742002-12-13 20:15:29 +0000175
176 return 0;
177}
178
paul94f2b392005-06-28 12:44:16 +0000179static void
paul718e3742002-12-13 20:15:29 +0000180bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
181 u_char type, u_char mode)
182{
183 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000184 zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported",
paul718e3742002-12-13 20:15:29 +0000185 peer->host, afi, safi, type, mode);
186}
187
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700188static const struct message orf_type_str[] =
paul718e3742002-12-13 20:15:29 +0000189{
Paul Jakma6d582722007-08-06 15:21:45 +0000190 { ORF_TYPE_PREFIX, "Prefixlist" },
191 { ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" },
192};
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700193static const int orf_type_str_max
194 = sizeof(orf_type_str)/sizeof(orf_type_str[0]);
Paul Jakma6d582722007-08-06 15:21:45 +0000195
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700196static const struct message orf_mode_str[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000197{
198 { ORF_MODE_RECEIVE, "Receive" },
199 { ORF_MODE_SEND, "Send" },
200 { ORF_MODE_BOTH, "Both" },
201};
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700202static const int orf_mode_str_max
203 = sizeof(orf_mode_str)/sizeof(orf_mode_str[0]);
Paul Jakma6d582722007-08-06 15:21:45 +0000204
205static int
206bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
207{
208 struct stream *s = BGP_INPUT (peer);
209 struct capability_orf_entry entry;
210 afi_t afi;
211 safi_t safi;
paul718e3742002-12-13 20:15:29 +0000212 u_char type;
213 u_char mode;
214 u_int16_t sm_cap = 0; /* capability send-mode receive */
215 u_int16_t rm_cap = 0; /* capability receive-mode receive */
216 int i;
217
Paul Jakma6d582722007-08-06 15:21:45 +0000218 /* ORF Entry header */
219 bgp_capability_mp_data (s, &entry.mpc);
220 entry.num = stream_getc (s);
221 afi = entry.mpc.afi;
222 safi = entry.mpc.safi;
223
paul718e3742002-12-13 20:15:29 +0000224 if (BGP_DEBUG (normal, NORMAL))
Paul Jakma6d582722007-08-06 15:21:45 +0000225 zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
226 peer->host, entry.mpc.afi, entry.mpc.safi);
paul718e3742002-12-13 20:15:29 +0000227
228 /* Check AFI and SAFI. */
Paul Jakma6d582722007-08-06 15:21:45 +0000229 if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi))
paul718e3742002-12-13 20:15:29 +0000230 {
Paul Jakma6d582722007-08-06 15:21:45 +0000231 zlog_info ("%s Addr-family %d/%d not supported."
232 " Ignoring the ORF capability",
233 peer->host, entry.mpc.afi, entry.mpc.safi);
234 return 0;
235 }
236
237 /* validate number field */
238 if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length)
239 {
240 zlog_info ("%s ORF Capability entry length error,"
241 " Cap length %u, num %u",
242 peer->host, hdr->length, entry.num);
243 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
paul718e3742002-12-13 20:15:29 +0000244 return -1;
245 }
246
Paul Jakma6d582722007-08-06 15:21:45 +0000247 for (i = 0 ; i < entry.num ; i++)
paul718e3742002-12-13 20:15:29 +0000248 {
Paul Jakma6d582722007-08-06 15:21:45 +0000249 type = stream_getc(s);
250 mode = stream_getc(s);
251
paul718e3742002-12-13 20:15:29 +0000252 /* ORF Mode error check */
Paul Jakma6d582722007-08-06 15:21:45 +0000253 switch (mode)
254 {
255 case ORF_MODE_BOTH:
256 case ORF_MODE_SEND:
257 case ORF_MODE_RECEIVE:
258 break;
259 default:
260 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
261 continue;
paul718e3742002-12-13 20:15:29 +0000262 }
Paul Jakma6d582722007-08-06 15:21:45 +0000263 /* ORF Type and afi/safi error checks */
264 /* capcode versus type */
265 switch (hdr->code)
266 {
267 case CAPABILITY_CODE_ORF:
268 switch (type)
269 {
270 case ORF_TYPE_PREFIX:
271 break;
272 default:
273 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
274 continue;
275 }
276 break;
277 case CAPABILITY_CODE_ORF_OLD:
278 switch (type)
279 {
280 case ORF_TYPE_PREFIX_OLD:
281 break;
282 default:
283 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
284 continue;
285 }
286 break;
287 default:
288 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
289 continue;
290 }
291
292 /* AFI vs SAFI */
293 if (!((afi == AFI_IP && safi == SAFI_UNICAST)
294 || (afi == AFI_IP && safi == SAFI_MULTICAST)
295 || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
296 {
297 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
298 continue;
299 }
300
301 if (BGP_DEBUG (normal, NORMAL))
302 zlog_debug ("%s OPEN has %s ORF capability"
303 " as %s for afi/safi: %d/%d",
304 peer->host, LOOKUP (orf_type_str, type),
305 LOOKUP (orf_mode_str, mode),
306 entry.mpc.afi, safi);
paul718e3742002-12-13 20:15:29 +0000307
Paul Jakma6d582722007-08-06 15:21:45 +0000308 if (hdr->code == CAPABILITY_CODE_ORF)
paul718e3742002-12-13 20:15:29 +0000309 {
Paul Jakma6d582722007-08-06 15:21:45 +0000310 sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
311 rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
paul718e3742002-12-13 20:15:29 +0000312 }
Paul Jakma6d582722007-08-06 15:21:45 +0000313 else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
paul718e3742002-12-13 20:15:29 +0000314 {
Paul Jakma6d582722007-08-06 15:21:45 +0000315 sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
316 rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
paul718e3742002-12-13 20:15:29 +0000317 }
318 else
319 {
320 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
321 continue;
322 }
323
324 switch (mode)
325 {
326 case ORF_MODE_BOTH:
327 SET_FLAG (peer->af_cap[afi][safi], sm_cap);
328 SET_FLAG (peer->af_cap[afi][safi], rm_cap);
329 break;
330 case ORF_MODE_SEND:
331 SET_FLAG (peer->af_cap[afi][safi], sm_cap);
332 break;
333 case ORF_MODE_RECEIVE:
334 SET_FLAG (peer->af_cap[afi][safi], rm_cap);
335 break;
336 }
337 }
338 return 0;
339}
340
paul94f2b392005-06-28 12:44:16 +0000341static int
Paul Jakma6d582722007-08-06 15:21:45 +0000342bgp_capability_orf (struct peer *peer, struct capability_header *hdr)
343{
344 struct stream *s = BGP_INPUT (peer);
345 size_t end = stream_get_getp (s) + hdr->length;
346
347 assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end);
348
349 /* We must have at least one ORF entry, as the caller has already done
350 * minimum length validation for the capability code - for ORF there must
351 * at least one ORF entry (header and unknown number of pairs of bytes).
352 */
353 do
354 {
355 if (bgp_capability_orf_entry (peer, hdr) == -1)
356 return -1;
357 }
358 while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end);
359
360 return 0;
361}
362
363static int
364bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
365{
366 struct stream *s = BGP_INPUT (peer);
367 u_int16_t restart_flag_time;
368 int restart_bit = 0;
369 size_t end = stream_get_getp (s) + caphdr->length;
370
371 SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
372 restart_flag_time = stream_getw(s);
373 if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
374 restart_bit = 1;
375 UNSET_FLAG (restart_flag_time, 0xF000);
376 peer->v_gr_restart = restart_flag_time;
377
378 if (BGP_DEBUG (normal, NORMAL))
379 {
380 zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
381 zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
382 peer->host, restart_bit ? " " : " not ",
383 peer->v_gr_restart);
384 }
385
386 while (stream_get_getp (s) + 4 < end)
387 {
388 afi_t afi = stream_getw (s);
389 safi_t safi = stream_getc (s);
390 u_char flag = stream_getc (s);
391
392 if (!bgp_afi_safi_valid_indices (afi, &safi))
393 {
394 if (BGP_DEBUG (normal, NORMAL))
395 zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
396 " Ignore the Graceful Restart capability",
397 peer->host, afi, safi);
398 }
399 else if (!peer->afc[afi][safi])
400 {
401 if (BGP_DEBUG (normal, NORMAL))
402 zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
403 " Ignore the Graceful Restart capability",
404 peer->host, afi, safi);
405 }
406 else
407 {
408 if (BGP_DEBUG (normal, NORMAL))
409 zlog_debug ("%s Address family %s is%spreserved", peer->host,
410 afi_safi_print (afi, safi),
411 CHECK_FLAG (peer->af_cap[afi][safi],
412 PEER_CAP_RESTART_AF_PRESERVE_RCV)
413 ? " " : " not ");
414
415 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
416 if (CHECK_FLAG (flag, RESTART_F_BIT))
417 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
418
419 }
420 }
421 return 0;
422}
423
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000424static as_t
425bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)
426{
427 as_t as4 = stream_getl (BGP_INPUT(peer));
428
429 if (BGP_DEBUG (as4, AS4))
430 zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
431 peer->host, as4);
432 SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
433
434 return as4;
435}
436
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700437static const struct message capcode_str[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000438{
Paul Jakma6d582722007-08-06 15:21:45 +0000439 { CAPABILITY_CODE_MP, "MultiProtocol Extensions" },
440 { CAPABILITY_CODE_REFRESH, "Route Refresh" },
441 { CAPABILITY_CODE_ORF, "Cooperative Route Filtering" },
442 { CAPABILITY_CODE_RESTART, "Graceful Restart" },
443 { CAPABILITY_CODE_AS4, "4-octet AS number" },
444 { CAPABILITY_CODE_DYNAMIC, "Dynamic" },
445 { CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" },
446 { CAPABILITY_CODE_ORF_OLD, "ORF (Old)" },
447};
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700448static const int capcode_str_max = sizeof(capcode_str)/sizeof(capcode_str[0]);
Paul Jakma6d582722007-08-06 15:21:45 +0000449
450/* Minimum sizes for length field of each cap (so not inc. the header) */
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700451static const size_t cap_minsizes[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000452{
453 [CAPABILITY_CODE_MP] = sizeof (struct capability_mp_data),
454 [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN,
455 [CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry),
Paul Jakma370b64a2007-12-22 16:49:52 +0000456 [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr),
Paul Jakma6d582722007-08-06 15:21:45 +0000457 [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN,
458 [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
459 [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
460 [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry),
461};
462
463/* Parse given capability.
464 * XXX: This is reading into a stream, but not using stream API
465 */
466static int
467bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
paul718e3742002-12-13 20:15:29 +0000468{
469 int ret;
Paul Jakma6d582722007-08-06 15:21:45 +0000470 struct stream *s = BGP_INPUT (peer);
471 size_t end = stream_get_getp (s) + length;
472
473 assert (STREAM_READABLE (s) >= length);
474
475 while (stream_get_getp (s) < end)
paul718e3742002-12-13 20:15:29 +0000476 {
Paul Jakma6d582722007-08-06 15:21:45 +0000477 size_t start;
478 u_char *sp = stream_pnt (s);
479 struct capability_header caphdr;
480
paul718e3742002-12-13 20:15:29 +0000481 /* We need at least capability code and capability length. */
Paul Jakma6d582722007-08-06 15:21:45 +0000482 if (stream_get_getp(s) + 2 > end)
paul718e3742002-12-13 20:15:29 +0000483 {
Paul Jakma6d582722007-08-06 15:21:45 +0000484 zlog_info ("%s Capability length error (< header)", peer->host);
paul718e3742002-12-13 20:15:29 +0000485 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
486 return -1;
487 }
Paul Jakma6d582722007-08-06 15:21:45 +0000488
489 caphdr.code = stream_getc (s);
490 caphdr.length = stream_getc (s);
491 start = stream_get_getp (s);
492
493 /* Capability length check sanity check. */
494 if (start + caphdr.length > end)
paul718e3742002-12-13 20:15:29 +0000495 {
Paul Jakma6d582722007-08-06 15:21:45 +0000496 zlog_info ("%s Capability length error (< length)", peer->host);
paul718e3742002-12-13 20:15:29 +0000497 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
498 return -1;
499 }
Paul Jakma6d582722007-08-06 15:21:45 +0000500
501 if (BGP_DEBUG (normal, NORMAL))
502 zlog_debug ("%s OPEN has %s capability (%u), length %u",
503 peer->host,
504 LOOKUP (capcode_str, caphdr.code),
505 caphdr.code, caphdr.length);
506
507 /* Length sanity check, type-specific, for known capabilities */
508 switch (caphdr.code)
509 {
510 case CAPABILITY_CODE_MP:
511 case CAPABILITY_CODE_REFRESH:
512 case CAPABILITY_CODE_REFRESH_OLD:
513 case CAPABILITY_CODE_ORF:
514 case CAPABILITY_CODE_ORF_OLD:
515 case CAPABILITY_CODE_RESTART:
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000516 case CAPABILITY_CODE_AS4:
Paul Jakma6d582722007-08-06 15:21:45 +0000517 case CAPABILITY_CODE_DYNAMIC:
518 /* Check length. */
519 if (caphdr.length < cap_minsizes[caphdr.code])
520 {
521 zlog_info ("%s %s Capability length error: got %u,"
522 " expected at least %u",
523 peer->host,
524 LOOKUP (capcode_str, caphdr.code),
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700525 caphdr.length,
526 (unsigned) cap_minsizes[caphdr.code]);
Paul Jakma6d582722007-08-06 15:21:45 +0000527 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
528 return -1;
529 }
530 /* we deliberately ignore unknown codes, see below */
531 default:
532 break;
533 }
534
535 switch (caphdr.code)
536 {
537 case CAPABILITY_CODE_MP:
538 {
539 /* Ignore capability when override-capability is set. */
540 if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
541 {
542 /* Set negotiated value. */
543 ret = bgp_capability_mp (peer, &caphdr);
paul718e3742002-12-13 20:15:29 +0000544
Paul Jakma6d582722007-08-06 15:21:45 +0000545 /* Unsupported Capability. */
546 if (ret < 0)
547 {
548 /* Store return data. */
549 memcpy (*error, sp, caphdr.length + 2);
550 *error += caphdr.length + 2;
551 }
552 }
553 }
554 break;
555 case CAPABILITY_CODE_REFRESH:
556 case CAPABILITY_CODE_REFRESH_OLD:
557 {
558 /* BGP refresh capability */
559 if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
560 SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
561 else
562 SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
563 }
564 break;
565 case CAPABILITY_CODE_ORF:
566 case CAPABILITY_CODE_ORF_OLD:
567 if (bgp_capability_orf (peer, &caphdr))
568 return -1;
569 break;
570 case CAPABILITY_CODE_RESTART:
571 if (bgp_capability_restart (peer, &caphdr))
572 return -1;
573 break;
574 case CAPABILITY_CODE_DYNAMIC:
575 SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
576 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000577 case CAPABILITY_CODE_AS4:
578 /* Already handled as a special-case parsing of the capabilities
579 * at the beginning of OPEN processing. So we care not a jot
580 * for the value really, only error case.
581 */
582 if (!bgp_capability_as4 (peer, &caphdr))
583 return -1;
584 break;
Paul Jakma6d582722007-08-06 15:21:45 +0000585 default:
586 if (caphdr.code > 128)
587 {
588 /* We don't send Notification for unknown vendor specific
589 capabilities. It seems reasonable for now... */
590 zlog_warn ("%s Vendor specific capability %d",
591 peer->host, caphdr.code);
592 }
593 else
594 {
595 zlog_warn ("%s unrecognized capability code: %d - ignored",
596 peer->host, caphdr.code);
597 memcpy (*error, sp, caphdr.length + 2);
598 *error += caphdr.length + 2;
599 }
600 }
601 if (stream_get_getp(s) != (start + caphdr.length))
602 {
603 if (stream_get_getp(s) > (start + caphdr.length))
604 zlog_warn ("%s Cap-parser for %s read past cap-length, %u!",
605 peer->host, LOOKUP (capcode_str, caphdr.code),
606 caphdr.length);
607 stream_set_getp (s, start + caphdr.length);
608 }
paul718e3742002-12-13 20:15:29 +0000609 }
610 return 0;
611}
612
paul94f2b392005-06-28 12:44:16 +0000613static int
Paul Jakma6d582722007-08-06 15:21:45 +0000614bgp_auth_parse (struct peer *peer, size_t length)
paul718e3742002-12-13 20:15:29 +0000615{
616 bgp_notify_send (peer,
617 BGP_NOTIFY_OPEN_ERR,
618 BGP_NOTIFY_OPEN_AUTH_FAILURE);
619 return -1;
620}
621
paul94f2b392005-06-28 12:44:16 +0000622static int
paul718e3742002-12-13 20:15:29 +0000623strict_capability_same (struct peer *peer)
624{
625 int i, j;
626
627 for (i = AFI_IP; i < AFI_MAX; i++)
628 for (j = SAFI_UNICAST; j < SAFI_MAX; j++)
629 if (peer->afc[i][j] != peer->afc_nego[i][j])
630 return 0;
631 return 1;
632}
633
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000634/* peek into option, stores ASN to *as4 if the AS4 capability was found.
635 * Returns 0 if no as4 found, as4cap value otherwise.
636 */
637as_t
638peek_for_as4_capability (struct peer *peer, u_char length)
639{
640 struct stream *s = BGP_INPUT (peer);
641 size_t orig_getp = stream_get_getp (s);
642 size_t end = orig_getp + length;
643 as_t as4 = 0;
644
645 /* The full capability parser will better flag the error.. */
646 if (STREAM_READABLE(s) < length)
647 return 0;
648
649 if (BGP_DEBUG (as4, AS4))
650 zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u,"
651 " peeking for as4",
652 peer->host, length);
653 /* the error cases we DONT handle, we ONLY try to read as4 out of
654 * correctly formatted options.
655 */
656 while (stream_get_getp(s) < end)
657 {
658 u_char opt_type;
659 u_char opt_length;
660
661 /* Check the length. */
662 if (stream_get_getp (s) + 2 > end)
663 goto end;
664
665 /* Fetch option type and length. */
666 opt_type = stream_getc (s);
667 opt_length = stream_getc (s);
668
669 /* Option length check. */
670 if (stream_get_getp (s) + opt_length > end)
671 goto end;
672
673 if (opt_type == BGP_OPEN_OPT_CAP)
674 {
675 unsigned long capd_start = stream_get_getp (s);
676 unsigned long capd_end = capd_start + opt_length;
677
678 assert (capd_end <= end);
679
680 while (stream_get_getp (s) < capd_end)
681 {
682 struct capability_header hdr;
683
684 if (stream_get_getp (s) + 2 > capd_end)
685 goto end;
686
687 hdr.code = stream_getc (s);
688 hdr.length = stream_getc (s);
689
690 if ((stream_get_getp(s) + hdr.length) > capd_end)
691 goto end;
692
693 if (hdr.code == CAPABILITY_CODE_AS4)
694 {
695 if (hdr.length != CAPABILITY_CODE_AS4_LEN)
696 goto end;
697
698 if (BGP_DEBUG (as4, AS4))
699 zlog_info ("[AS4] found AS4 capability, about to parse");
700 as4 = bgp_capability_as4 (peer, &hdr);
701
702 goto end;
703 }
704 stream_forward_getp (s, hdr.length);
705 }
706 }
707 }
708
709end:
710 stream_set_getp (s, orig_getp);
711 return as4;
712}
713
paul718e3742002-12-13 20:15:29 +0000714/* Parse open option */
715int
716bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
717{
718 int ret;
paul718e3742002-12-13 20:15:29 +0000719 u_char *error;
720 u_char error_data[BGP_MAX_PACKET_SIZE];
Paul Jakma6d582722007-08-06 15:21:45 +0000721 struct stream *s = BGP_INPUT(peer);
722 size_t end = stream_get_getp (s) + length;
paul718e3742002-12-13 20:15:29 +0000723
724 ret = 0;
paul718e3742002-12-13 20:15:29 +0000725 error = error_data;
726
727 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000728 zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
paul718e3742002-12-13 20:15:29 +0000729 peer->host, length);
730
Paul Jakma6d582722007-08-06 15:21:45 +0000731 while (stream_get_getp(s) < end)
paul718e3742002-12-13 20:15:29 +0000732 {
Paul Jakma6d582722007-08-06 15:21:45 +0000733 u_char opt_type;
734 u_char opt_length;
735
736 /* Must have at least an OPEN option header */
737 if (STREAM_READABLE(s) < 2)
paul718e3742002-12-13 20:15:29 +0000738 {
739 zlog_info ("%s Option length error", peer->host);
740 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
741 return -1;
742 }
743
744 /* Fetch option type and length. */
Paul Jakma6d582722007-08-06 15:21:45 +0000745 opt_type = stream_getc (s);
746 opt_length = stream_getc (s);
paul718e3742002-12-13 20:15:29 +0000747
748 /* Option length check. */
Paul Jakma6d582722007-08-06 15:21:45 +0000749 if (STREAM_READABLE (s) < opt_length)
paul718e3742002-12-13 20:15:29 +0000750 {
751 zlog_info ("%s Option length error", peer->host);
752 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
753 return -1;
754 }
755
756 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000757 zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
paul718e3742002-12-13 20:15:29 +0000758 peer->host, opt_type,
759 opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
760 opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown",
761 opt_length);
762
763 switch (opt_type)
764 {
765 case BGP_OPEN_OPT_AUTH:
Paul Jakma6d582722007-08-06 15:21:45 +0000766 ret = bgp_auth_parse (peer, opt_length);
paul718e3742002-12-13 20:15:29 +0000767 break;
768 case BGP_OPEN_OPT_CAP:
Paul Jakma6d582722007-08-06 15:21:45 +0000769 ret = bgp_capability_parse (peer, opt_length, &error);
paul718e3742002-12-13 20:15:29 +0000770 *capability = 1;
771 break;
772 default:
773 bgp_notify_send (peer,
774 BGP_NOTIFY_OPEN_ERR,
775 BGP_NOTIFY_OPEN_UNSUP_PARAM);
776 ret = -1;
777 break;
778 }
779
780 /* Parse error. To accumulate all unsupported capability codes,
781 bgp_capability_parse does not return -1 when encounter
782 unsupported capability code. To detect that, please check
783 error and erro_data pointer, like below. */
784 if (ret < 0)
785 return -1;
paul718e3742002-12-13 20:15:29 +0000786 }
787
788 /* All OPEN option is parsed. Check capability when strict compare
789 flag is enabled.*/
790 if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
791 {
792 /* If Unsupported Capability exists. */
793 if (error != error_data)
794 {
795 bgp_notify_send_with_data (peer,
796 BGP_NOTIFY_OPEN_ERR,
797 BGP_NOTIFY_OPEN_UNSUP_CAPBL,
798 error_data, error - error_data);
799 return -1;
800 }
801
802 /* Check local capability does not negotiated with remote
803 peer. */
804 if (! strict_capability_same (peer))
805 {
806 bgp_notify_send (peer,
807 BGP_NOTIFY_OPEN_ERR,
808 BGP_NOTIFY_OPEN_UNSUP_CAPBL);
809 return -1;
810 }
811 }
812
813 /* Check there is no common capability send Unsupported Capability
814 error. */
815 if (*capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
816 {
817 if (! peer->afc_nego[AFI_IP][SAFI_UNICAST]
818 && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
819 && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
820 && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
821 && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST])
822 {
823 plog_err (peer->log, "%s [Error] No common capability", peer->host);
824
825 if (error != error_data)
826
827 bgp_notify_send_with_data (peer,
828 BGP_NOTIFY_OPEN_ERR,
829 BGP_NOTIFY_OPEN_UNSUP_CAPBL,
830 error_data, error - error_data);
831 else
832 bgp_notify_send (peer,
833 BGP_NOTIFY_OPEN_ERR,
834 BGP_NOTIFY_OPEN_UNSUP_CAPBL);
835 return -1;
836 }
837 }
838 return 0;
839}
840
paul94f2b392005-06-28 12:44:16 +0000841static void
paul718e3742002-12-13 20:15:29 +0000842bgp_open_capability_orf (struct stream *s, struct peer *peer,
843 afi_t afi, safi_t safi, u_char code)
844{
845 u_char cap_len;
846 u_char orf_len;
847 unsigned long capp;
848 unsigned long orfp;
849 unsigned long numberp;
850 int number_of_orfs = 0;
851
852 if (safi == SAFI_MPLS_VPN)
Denis Ovsienko42e6d742011-07-14 12:36:19 +0400853 safi = SAFI_MPLS_LABELED_VPN;
paul718e3742002-12-13 20:15:29 +0000854
855 stream_putc (s, BGP_OPEN_OPT_CAP);
paul9985f832005-02-09 15:51:56 +0000856 capp = stream_get_endp (s); /* Set Capability Len Pointer */
paul718e3742002-12-13 20:15:29 +0000857 stream_putc (s, 0); /* Capability Length */
858 stream_putc (s, code); /* Capability Code */
paul9985f832005-02-09 15:51:56 +0000859 orfp = stream_get_endp (s); /* Set ORF Len Pointer */
paul718e3742002-12-13 20:15:29 +0000860 stream_putc (s, 0); /* ORF Length */
861 stream_putw (s, afi);
862 stream_putc (s, 0);
863 stream_putc (s, safi);
paul9985f832005-02-09 15:51:56 +0000864 numberp = stream_get_endp (s); /* Set Number Pointer */
paul718e3742002-12-13 20:15:29 +0000865 stream_putc (s, 0); /* Number of ORFs */
866
867 /* Address Prefix ORF */
868 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
869 || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
870 {
871 stream_putc (s, (code == CAPABILITY_CODE_ORF ?
872 ORF_TYPE_PREFIX : ORF_TYPE_PREFIX_OLD));
873
874 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
875 && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
876 {
877 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
878 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
879 stream_putc (s, ORF_MODE_BOTH);
880 }
881 else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM))
882 {
883 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
884 stream_putc (s, ORF_MODE_SEND);
885 }
886 else
887 {
888 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
889 stream_putc (s, ORF_MODE_RECEIVE);
890 }
891 number_of_orfs++;
892 }
893
894 /* Total Number of ORFs. */
895 stream_putc_at (s, numberp, number_of_orfs);
896
897 /* Total ORF Len. */
paul9985f832005-02-09 15:51:56 +0000898 orf_len = stream_get_endp (s) - orfp - 1;
paul718e3742002-12-13 20:15:29 +0000899 stream_putc_at (s, orfp, orf_len);
900
901 /* Total Capability Len. */
paul9985f832005-02-09 15:51:56 +0000902 cap_len = stream_get_endp (s) - capp - 1;
paul718e3742002-12-13 20:15:29 +0000903 stream_putc_at (s, capp, cap_len);
904}
905
906/* Fill in capability open option to the packet. */
907void
908bgp_open_capability (struct stream *s, struct peer *peer)
909{
910 u_char len;
911 unsigned long cp;
912 afi_t afi;
913 safi_t safi;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000914 as_t local_as;
paul718e3742002-12-13 20:15:29 +0000915
916 /* Remember current pointer for Opt Parm Len. */
paul9985f832005-02-09 15:51:56 +0000917 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +0000918
919 /* Opt Parm Len. */
920 stream_putc (s, 0);
921
922 /* Do not send capability. */
923 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN)
924 || CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
925 return;
926
paul718e3742002-12-13 20:15:29 +0000927 /* IPv4 unicast. */
928 if (peer->afc[AFI_IP][SAFI_UNICAST])
929 {
930 peer->afc_adv[AFI_IP][SAFI_UNICAST] = 1;
931 stream_putc (s, BGP_OPEN_OPT_CAP);
932 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
933 stream_putc (s, CAPABILITY_CODE_MP);
934 stream_putc (s, CAPABILITY_CODE_MP_LEN);
935 stream_putw (s, AFI_IP);
936 stream_putc (s, 0);
937 stream_putc (s, SAFI_UNICAST);
938 }
939 /* IPv4 multicast. */
940 if (peer->afc[AFI_IP][SAFI_MULTICAST])
941 {
942 peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 1;
943 stream_putc (s, BGP_OPEN_OPT_CAP);
944 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
945 stream_putc (s, CAPABILITY_CODE_MP);
946 stream_putc (s, CAPABILITY_CODE_MP_LEN);
947 stream_putw (s, AFI_IP);
948 stream_putc (s, 0);
949 stream_putc (s, SAFI_MULTICAST);
950 }
951 /* IPv4 VPN */
952 if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
953 {
954 peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 1;
955 stream_putc (s, BGP_OPEN_OPT_CAP);
956 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
957 stream_putc (s, CAPABILITY_CODE_MP);
958 stream_putc (s, CAPABILITY_CODE_MP_LEN);
959 stream_putw (s, AFI_IP);
960 stream_putc (s, 0);
Denis Ovsienko42e6d742011-07-14 12:36:19 +0400961 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +0000962 }
963#ifdef HAVE_IPV6
964 /* IPv6 unicast. */
965 if (peer->afc[AFI_IP6][SAFI_UNICAST])
966 {
967 peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 1;
968 stream_putc (s, BGP_OPEN_OPT_CAP);
969 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
970 stream_putc (s, CAPABILITY_CODE_MP);
971 stream_putc (s, CAPABILITY_CODE_MP_LEN);
972 stream_putw (s, AFI_IP6);
973 stream_putc (s, 0);
974 stream_putc (s, SAFI_UNICAST);
975 }
976 /* IPv6 multicast. */
977 if (peer->afc[AFI_IP6][SAFI_MULTICAST])
978 {
979 peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1;
980 stream_putc (s, BGP_OPEN_OPT_CAP);
981 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
982 stream_putc (s, CAPABILITY_CODE_MP);
983 stream_putc (s, CAPABILITY_CODE_MP_LEN);
984 stream_putw (s, AFI_IP6);
985 stream_putc (s, 0);
986 stream_putc (s, SAFI_MULTICAST);
987 }
988#endif /* HAVE_IPV6 */
989
990 /* Route refresh. */
hassoc9502432005-02-01 22:01:48 +0000991 SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
992 stream_putc (s, BGP_OPEN_OPT_CAP);
993 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
994 stream_putc (s, CAPABILITY_CODE_REFRESH_OLD);
995 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
996 stream_putc (s, BGP_OPEN_OPT_CAP);
997 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
998 stream_putc (s, CAPABILITY_CODE_REFRESH);
999 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
paul718e3742002-12-13 20:15:29 +00001000
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001001 /* AS4 */
1002 SET_FLAG (peer->cap, PEER_CAP_AS4_ADV);
1003 stream_putc (s, BGP_OPEN_OPT_CAP);
1004 stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2);
1005 stream_putc (s, CAPABILITY_CODE_AS4);
1006 stream_putc (s, CAPABILITY_CODE_AS4_LEN);
1007 if ( peer->change_local_as )
1008 local_as = peer->change_local_as;
1009 else
1010 local_as = peer->local_as;
1011 stream_putl (s, local_as );
1012
paul718e3742002-12-13 20:15:29 +00001013 /* ORF capability. */
1014 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
1015 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
1016 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
1017 || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
1018 {
1019 bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF_OLD);
1020 bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF);
1021 }
1022
1023 /* Dynamic capability. */
1024 if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
1025 {
1026 SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
1027 stream_putc (s, BGP_OPEN_OPT_CAP);
1028 stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
1029 stream_putc (s, CAPABILITY_CODE_DYNAMIC);
1030 stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN);
1031 }
1032
hasso538621f2004-05-21 09:31:30 +00001033 /* Graceful restart capability */
1034 if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART))
1035 {
1036 SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV);
1037 stream_putc (s, BGP_OPEN_OPT_CAP);
1038 stream_putc (s, CAPABILITY_CODE_RESTART_LEN + 2);
1039 stream_putc (s, CAPABILITY_CODE_RESTART);
1040 stream_putc (s, CAPABILITY_CODE_RESTART_LEN);
1041 stream_putw (s, peer->bgp->restart_time);
1042 }
1043
paul718e3742002-12-13 20:15:29 +00001044 /* Total Opt Parm Len. */
paul9985f832005-02-09 15:51:56 +00001045 len = stream_get_endp (s) - cp - 1;
paul718e3742002-12-13 20:15:29 +00001046 stream_putc_at (s, cp, len);
1047}