blob: fe741aa3acdac50acbd3c6563fde5e7554b91f14 [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;
Denis Ovsienko42e6d742011-07-14 12:36:19 +040096 case SAFI_MPLS_LABELED_VPN:
97 vty_out (vty, "SAFI MPLS-labeled VPN");
paul718e3742002-12-13 20:15:29 +000098 break;
99 default:
Paul Jakma6d582722007-08-06 15:21:45 +0000100 vty_out (vty, "SAFI Unknown %d ", mpc.safi);
paul718e3742002-12-13 20:15:29 +0000101 break;
102 }
103 vty_out (vty, "%s", VTY_NEWLINE);
104 }
Paul Jakma6d582722007-08-06 15:21:45 +0000105 else if (hdr->code >= 128)
paul718e3742002-12-13 20:15:29 +0000106 vty_out (vty, " Capability error: vendor specific capability code %d",
Paul Jakma6d582722007-08-06 15:21:45 +0000107 hdr->code);
paul718e3742002-12-13 20:15:29 +0000108 else
109 vty_out (vty, " Capability error: unknown capability code %d",
Paul Jakma6d582722007-08-06 15:21:45 +0000110 hdr->code);
paul718e3742002-12-13 20:15:29 +0000111
Paul Jakma6d582722007-08-06 15:21:45 +0000112 pnt += hdr->length + 2;
paul718e3742002-12-13 20:15:29 +0000113 }
114}
115
Paul Jakma6d582722007-08-06 15:21:45 +0000116static void
117bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)
118{
119 mpc->afi = stream_getw (s);
120 mpc->reserved = stream_getc (s);
121 mpc->safi = stream_getc (s);
122}
123
124int
125bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
126{
Paul Jakma6d582722007-08-06 15:21:45 +0000127 switch (afi)
128 {
129 case AFI_IP:
130#ifdef HAVE_IPV6
131 case AFI_IP6:
132#endif
133 switch (*safi)
134 {
Denis Ovsienko42e6d742011-07-14 12:36:19 +0400135 /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */
136 case SAFI_MPLS_LABELED_VPN:
Paul Jakma6d582722007-08-06 15:21:45 +0000137 *safi = SAFI_MPLS_VPN;
138 case SAFI_UNICAST:
139 case SAFI_MULTICAST:
140 case SAFI_MPLS_VPN:
141 return 1;
142 }
143 }
144 zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi);
145
146 return 0;
147}
148
paul718e3742002-12-13 20:15:29 +0000149/* Set negotiated capability value. */
paul94f2b392005-06-28 12:44:16 +0000150static int
Paul Jakma6d582722007-08-06 15:21:45 +0000151bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
paul718e3742002-12-13 20:15:29 +0000152{
Paul Jakma6d582722007-08-06 15:21:45 +0000153 struct capability_mp_data mpc;
154 struct stream *s = BGP_INPUT (peer);
155
156 bgp_capability_mp_data (s, &mpc);
157
158 if (BGP_DEBUG (normal, NORMAL))
159 zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
160 peer->host, mpc.afi, mpc.safi);
161
162 if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi))
163 return -1;
164
165 /* Now safi remapped, and afi/safi are valid array indices */
166 peer->afc_recv[mpc.afi][mpc.safi] = 1;
167
168 if (peer->afc[mpc.afi][mpc.safi])
Paul Jakmae08286b2007-09-18 12:11:26 +0000169 peer->afc_nego[mpc.afi][mpc.safi] = 1;
Paul Jakma6d582722007-08-06 15:21:45 +0000170 else
171 return -1;
paul718e3742002-12-13 20:15:29 +0000172
173 return 0;
174}
175
paul94f2b392005-06-28 12:44:16 +0000176static void
paul718e3742002-12-13 20:15:29 +0000177bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
178 u_char type, u_char mode)
179{
180 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000181 zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported",
paul718e3742002-12-13 20:15:29 +0000182 peer->host, afi, safi, type, mode);
183}
184
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700185static const struct message orf_type_str[] =
paul718e3742002-12-13 20:15:29 +0000186{
Paul Jakma6d582722007-08-06 15:21:45 +0000187 { ORF_TYPE_PREFIX, "Prefixlist" },
188 { ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" },
189};
Balaji.G837d16c2012-09-26 14:09:10 +0530190static const int orf_type_str_max = array_size(orf_type_str);
Paul Jakma6d582722007-08-06 15:21:45 +0000191
Stephen Hemminger8f5abac2009-05-15 10:16:34 -0700192static const struct message orf_mode_str[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000193{
194 { ORF_MODE_RECEIVE, "Receive" },
195 { ORF_MODE_SEND, "Send" },
196 { ORF_MODE_BOTH, "Both" },
197};
Balaji.G837d16c2012-09-26 14:09:10 +0530198static const int orf_mode_str_max = array_size(orf_mode_str);
Paul Jakma6d582722007-08-06 15:21:45 +0000199
200static int
201bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
202{
203 struct stream *s = BGP_INPUT (peer);
204 struct capability_orf_entry entry;
205 afi_t afi;
206 safi_t safi;
paul718e3742002-12-13 20:15:29 +0000207 u_char type;
208 u_char mode;
209 u_int16_t sm_cap = 0; /* capability send-mode receive */
210 u_int16_t rm_cap = 0; /* capability receive-mode receive */
211 int i;
212
Paul Jakma6d582722007-08-06 15:21:45 +0000213 /* ORF Entry header */
214 bgp_capability_mp_data (s, &entry.mpc);
215 entry.num = stream_getc (s);
216 afi = entry.mpc.afi;
217 safi = entry.mpc.safi;
218
paul718e3742002-12-13 20:15:29 +0000219 if (BGP_DEBUG (normal, NORMAL))
Paul Jakma6d582722007-08-06 15:21:45 +0000220 zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
221 peer->host, entry.mpc.afi, entry.mpc.safi);
paul718e3742002-12-13 20:15:29 +0000222
223 /* Check AFI and SAFI. */
Paul Jakma6d582722007-08-06 15:21:45 +0000224 if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi))
paul718e3742002-12-13 20:15:29 +0000225 {
Paul Jakma6d582722007-08-06 15:21:45 +0000226 zlog_info ("%s Addr-family %d/%d not supported."
227 " Ignoring the ORF capability",
228 peer->host, entry.mpc.afi, entry.mpc.safi);
229 return 0;
230 }
231
232 /* validate number field */
David Lamparter5e728e92013-01-23 05:50:24 +0100233 if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length)
Paul Jakma6d582722007-08-06 15:21:45 +0000234 {
235 zlog_info ("%s ORF Capability entry length error,"
236 " Cap length %u, num %u",
237 peer->host, hdr->length, entry.num);
238 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
paul718e3742002-12-13 20:15:29 +0000239 return -1;
240 }
241
Paul Jakma6d582722007-08-06 15:21:45 +0000242 for (i = 0 ; i < entry.num ; i++)
paul718e3742002-12-13 20:15:29 +0000243 {
Paul Jakma6d582722007-08-06 15:21:45 +0000244 type = stream_getc(s);
245 mode = stream_getc(s);
246
paul718e3742002-12-13 20:15:29 +0000247 /* ORF Mode error check */
Paul Jakma6d582722007-08-06 15:21:45 +0000248 switch (mode)
249 {
250 case ORF_MODE_BOTH:
251 case ORF_MODE_SEND:
252 case ORF_MODE_RECEIVE:
253 break;
254 default:
255 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
256 continue;
paul718e3742002-12-13 20:15:29 +0000257 }
Paul Jakma6d582722007-08-06 15:21:45 +0000258 /* ORF Type and afi/safi error checks */
259 /* capcode versus type */
260 switch (hdr->code)
261 {
262 case CAPABILITY_CODE_ORF:
263 switch (type)
264 {
265 case ORF_TYPE_PREFIX:
266 break;
267 default:
268 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
269 continue;
270 }
271 break;
272 case CAPABILITY_CODE_ORF_OLD:
273 switch (type)
274 {
275 case ORF_TYPE_PREFIX_OLD:
276 break;
277 default:
278 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
279 continue;
280 }
281 break;
282 default:
283 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
284 continue;
285 }
286
287 /* AFI vs SAFI */
288 if (!((afi == AFI_IP && safi == SAFI_UNICAST)
289 || (afi == AFI_IP && safi == SAFI_MULTICAST)
290 || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
291 {
292 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
293 continue;
294 }
295
296 if (BGP_DEBUG (normal, NORMAL))
297 zlog_debug ("%s OPEN has %s ORF capability"
298 " as %s for afi/safi: %d/%d",
299 peer->host, LOOKUP (orf_type_str, type),
300 LOOKUP (orf_mode_str, mode),
301 entry.mpc.afi, safi);
paul718e3742002-12-13 20:15:29 +0000302
Paul Jakma6d582722007-08-06 15:21:45 +0000303 if (hdr->code == CAPABILITY_CODE_ORF)
paul718e3742002-12-13 20:15:29 +0000304 {
Paul Jakma6d582722007-08-06 15:21:45 +0000305 sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
306 rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
paul718e3742002-12-13 20:15:29 +0000307 }
Paul Jakma6d582722007-08-06 15:21:45 +0000308 else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
paul718e3742002-12-13 20:15:29 +0000309 {
Paul Jakma6d582722007-08-06 15:21:45 +0000310 sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
311 rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
paul718e3742002-12-13 20:15:29 +0000312 }
313 else
314 {
315 bgp_capability_orf_not_support (peer, afi, safi, type, mode);
316 continue;
317 }
318
319 switch (mode)
320 {
321 case ORF_MODE_BOTH:
322 SET_FLAG (peer->af_cap[afi][safi], sm_cap);
323 SET_FLAG (peer->af_cap[afi][safi], rm_cap);
324 break;
325 case ORF_MODE_SEND:
326 SET_FLAG (peer->af_cap[afi][safi], sm_cap);
327 break;
328 case ORF_MODE_RECEIVE:
329 SET_FLAG (peer->af_cap[afi][safi], rm_cap);
330 break;
331 }
332 }
333 return 0;
334}
335
paul94f2b392005-06-28 12:44:16 +0000336static int
Paul Jakma6d582722007-08-06 15:21:45 +0000337bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
338{
339 struct stream *s = BGP_INPUT (peer);
340 u_int16_t restart_flag_time;
341 int restart_bit = 0;
342 size_t end = stream_get_getp (s) + caphdr->length;
343
344 SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
345 restart_flag_time = stream_getw(s);
346 if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
Vipin Kumardd49eb12014-09-30 14:36:38 -0700347 {
348 SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV);
349 restart_bit = 1;
350 }
Paul Jakma6d582722007-08-06 15:21:45 +0000351 UNSET_FLAG (restart_flag_time, 0xF000);
352 peer->v_gr_restart = restart_flag_time;
353
354 if (BGP_DEBUG (normal, NORMAL))
355 {
356 zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
357 zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
358 peer->host, restart_bit ? " " : " not ",
359 peer->v_gr_restart);
360 }
361
Peter Pentchev21cc7692011-09-12 16:30:31 +0400362 while (stream_get_getp (s) + 4 <= end)
Paul Jakma6d582722007-08-06 15:21:45 +0000363 {
364 afi_t afi = stream_getw (s);
365 safi_t safi = stream_getc (s);
366 u_char flag = stream_getc (s);
367
368 if (!bgp_afi_safi_valid_indices (afi, &safi))
369 {
370 if (BGP_DEBUG (normal, NORMAL))
371 zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
372 " Ignore the Graceful Restart capability",
373 peer->host, afi, safi);
374 }
375 else if (!peer->afc[afi][safi])
376 {
377 if (BGP_DEBUG (normal, NORMAL))
378 zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
379 " Ignore the Graceful Restart capability",
380 peer->host, afi, safi);
381 }
382 else
383 {
384 if (BGP_DEBUG (normal, NORMAL))
385 zlog_debug ("%s Address family %s is%spreserved", peer->host,
386 afi_safi_print (afi, safi),
387 CHECK_FLAG (peer->af_cap[afi][safi],
388 PEER_CAP_RESTART_AF_PRESERVE_RCV)
389 ? " " : " not ");
390
391 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
392 if (CHECK_FLAG (flag, RESTART_F_BIT))
393 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
394
395 }
396 }
397 return 0;
398}
399
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000400static as_t
401bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)
402{
Paul Jakma58617392012-01-09 20:59:26 +0000403 SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
404
405 if (hdr->length != CAPABILITY_CODE_AS4_LEN)
406 {
407 zlog_err ("%s AS4 capability has incorrect data length %d",
408 peer->host, hdr->length);
409 return 0;
410 }
411
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000412 as_t as4 = stream_getl (BGP_INPUT(peer));
413
414 if (BGP_DEBUG (as4, AS4))
415 zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
416 peer->host, as4);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000417 return as4;
418}
419
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700420static const struct message capcode_str[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000421{
Paul Jakma6d582722007-08-06 15:21:45 +0000422 { CAPABILITY_CODE_MP, "MultiProtocol Extensions" },
423 { CAPABILITY_CODE_REFRESH, "Route Refresh" },
424 { CAPABILITY_CODE_ORF, "Cooperative Route Filtering" },
425 { CAPABILITY_CODE_RESTART, "Graceful Restart" },
426 { CAPABILITY_CODE_AS4, "4-octet AS number" },
427 { CAPABILITY_CODE_DYNAMIC, "Dynamic" },
428 { CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" },
429 { CAPABILITY_CODE_ORF_OLD, "ORF (Old)" },
430};
Balaji.G837d16c2012-09-26 14:09:10 +0530431static const int capcode_str_max = array_size(capcode_str);
Paul Jakma6d582722007-08-06 15:21:45 +0000432
433/* Minimum sizes for length field of each cap (so not inc. the header) */
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700434static const size_t cap_minsizes[] =
Paul Jakma6d582722007-08-06 15:21:45 +0000435{
436 [CAPABILITY_CODE_MP] = sizeof (struct capability_mp_data),
437 [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN,
438 [CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry),
Paul Jakma370b64a2007-12-22 16:49:52 +0000439 [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr),
Paul Jakma6d582722007-08-06 15:21:45 +0000440 [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN,
441 [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
442 [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
443 [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry),
444};
445
Avneesh Sachdev3b381c32012-02-19 10:19:52 -0800446/**
447 * Parse given capability.
Paul Jakma6d582722007-08-06 15:21:45 +0000448 * XXX: This is reading into a stream, but not using stream API
Avneesh Sachdev3b381c32012-02-19 10:19:52 -0800449 *
450 * @param[out] mp_capability Set to 1 on return iff one or more Multiprotocol
451 * capabilities were encountered.
Paul Jakma6d582722007-08-06 15:21:45 +0000452 */
453static int
Avneesh Sachdev3b381c32012-02-19 10:19:52 -0800454bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability,
455 u_char **error)
paul718e3742002-12-13 20:15:29 +0000456{
457 int ret;
Paul Jakma6d582722007-08-06 15:21:45 +0000458 struct stream *s = BGP_INPUT (peer);
459 size_t end = stream_get_getp (s) + length;
460
461 assert (STREAM_READABLE (s) >= length);
462
463 while (stream_get_getp (s) < end)
paul718e3742002-12-13 20:15:29 +0000464 {
Paul Jakma6d582722007-08-06 15:21:45 +0000465 size_t start;
466 u_char *sp = stream_pnt (s);
467 struct capability_header caphdr;
468
paul718e3742002-12-13 20:15:29 +0000469 /* We need at least capability code and capability length. */
Paul Jakma6d582722007-08-06 15:21:45 +0000470 if (stream_get_getp(s) + 2 > end)
paul718e3742002-12-13 20:15:29 +0000471 {
Paul Jakma6d582722007-08-06 15:21:45 +0000472 zlog_info ("%s Capability length error (< header)", peer->host);
paul718e3742002-12-13 20:15:29 +0000473 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
474 return -1;
475 }
Paul Jakma6d582722007-08-06 15:21:45 +0000476
477 caphdr.code = stream_getc (s);
478 caphdr.length = stream_getc (s);
479 start = stream_get_getp (s);
480
481 /* Capability length check sanity check. */
482 if (start + caphdr.length > end)
paul718e3742002-12-13 20:15:29 +0000483 {
Paul Jakma6d582722007-08-06 15:21:45 +0000484 zlog_info ("%s Capability length error (< length)", 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 if (BGP_DEBUG (normal, NORMAL))
490 zlog_debug ("%s OPEN has %s capability (%u), length %u",
491 peer->host,
492 LOOKUP (capcode_str, caphdr.code),
493 caphdr.code, caphdr.length);
494
495 /* Length sanity check, type-specific, for known capabilities */
496 switch (caphdr.code)
497 {
498 case CAPABILITY_CODE_MP:
499 case CAPABILITY_CODE_REFRESH:
500 case CAPABILITY_CODE_REFRESH_OLD:
501 case CAPABILITY_CODE_ORF:
502 case CAPABILITY_CODE_ORF_OLD:
503 case CAPABILITY_CODE_RESTART:
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000504 case CAPABILITY_CODE_AS4:
Paul Jakma6d582722007-08-06 15:21:45 +0000505 case CAPABILITY_CODE_DYNAMIC:
506 /* Check length. */
507 if (caphdr.length < cap_minsizes[caphdr.code])
508 {
509 zlog_info ("%s %s Capability length error: got %u,"
510 " expected at least %u",
511 peer->host,
512 LOOKUP (capcode_str, caphdr.code),
Stephen Hemmingerfc52f952009-05-15 09:48:55 -0700513 caphdr.length,
514 (unsigned) cap_minsizes[caphdr.code]);
Paul Jakma6d582722007-08-06 15:21:45 +0000515 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
516 return -1;
517 }
518 /* we deliberately ignore unknown codes, see below */
519 default:
520 break;
521 }
522
523 switch (caphdr.code)
524 {
525 case CAPABILITY_CODE_MP:
526 {
Avneesh Sachdev3b381c32012-02-19 10:19:52 -0800527 *mp_capability = 1;
528
Paul Jakma6d582722007-08-06 15:21:45 +0000529 /* Ignore capability when override-capability is set. */
530 if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
531 {
532 /* Set negotiated value. */
533 ret = bgp_capability_mp (peer, &caphdr);
paul718e3742002-12-13 20:15:29 +0000534
Paul Jakma6d582722007-08-06 15:21:45 +0000535 /* Unsupported Capability. */
536 if (ret < 0)
537 {
538 /* Store return data. */
539 memcpy (*error, sp, caphdr.length + 2);
540 *error += caphdr.length + 2;
541 }
542 }
543 }
544 break;
545 case CAPABILITY_CODE_REFRESH:
546 case CAPABILITY_CODE_REFRESH_OLD:
547 {
548 /* BGP refresh capability */
549 if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
550 SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
551 else
552 SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
553 }
554 break;
555 case CAPABILITY_CODE_ORF:
556 case CAPABILITY_CODE_ORF_OLD:
Denis Ovsienkofe9bb642012-04-19 20:34:13 +0400557 if (bgp_capability_orf_entry (peer, &caphdr))
Paul Jakma6d582722007-08-06 15:21:45 +0000558 return -1;
559 break;
560 case CAPABILITY_CODE_RESTART:
561 if (bgp_capability_restart (peer, &caphdr))
562 return -1;
563 break;
564 case CAPABILITY_CODE_DYNAMIC:
565 SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
566 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000567 case CAPABILITY_CODE_AS4:
568 /* Already handled as a special-case parsing of the capabilities
569 * at the beginning of OPEN processing. So we care not a jot
570 * for the value really, only error case.
571 */
572 if (!bgp_capability_as4 (peer, &caphdr))
573 return -1;
574 break;
Paul Jakma6d582722007-08-06 15:21:45 +0000575 default:
576 if (caphdr.code > 128)
577 {
578 /* We don't send Notification for unknown vendor specific
579 capabilities. It seems reasonable for now... */
580 zlog_warn ("%s Vendor specific capability %d",
581 peer->host, caphdr.code);
582 }
583 else
584 {
585 zlog_warn ("%s unrecognized capability code: %d - ignored",
586 peer->host, caphdr.code);
587 memcpy (*error, sp, caphdr.length + 2);
588 *error += caphdr.length + 2;
589 }
590 }
591 if (stream_get_getp(s) != (start + caphdr.length))
592 {
593 if (stream_get_getp(s) > (start + caphdr.length))
594 zlog_warn ("%s Cap-parser for %s read past cap-length, %u!",
595 peer->host, LOOKUP (capcode_str, caphdr.code),
596 caphdr.length);
597 stream_set_getp (s, start + caphdr.length);
598 }
paul718e3742002-12-13 20:15:29 +0000599 }
600 return 0;
601}
602
paul94f2b392005-06-28 12:44:16 +0000603static int
Paul Jakma6d582722007-08-06 15:21:45 +0000604bgp_auth_parse (struct peer *peer, size_t length)
paul718e3742002-12-13 20:15:29 +0000605{
606 bgp_notify_send (peer,
607 BGP_NOTIFY_OPEN_ERR,
608 BGP_NOTIFY_OPEN_AUTH_FAILURE);
609 return -1;
610}
611
paul94f2b392005-06-28 12:44:16 +0000612static int
paul718e3742002-12-13 20:15:29 +0000613strict_capability_same (struct peer *peer)
614{
615 int i, j;
616
617 for (i = AFI_IP; i < AFI_MAX; i++)
618 for (j = SAFI_UNICAST; j < SAFI_MAX; j++)
619 if (peer->afc[i][j] != peer->afc_nego[i][j])
620 return 0;
621 return 1;
622}
623
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000624/* peek into option, stores ASN to *as4 if the AS4 capability was found.
625 * Returns 0 if no as4 found, as4cap value otherwise.
626 */
627as_t
628peek_for_as4_capability (struct peer *peer, u_char length)
629{
630 struct stream *s = BGP_INPUT (peer);
631 size_t orig_getp = stream_get_getp (s);
632 size_t end = orig_getp + length;
633 as_t as4 = 0;
634
635 /* The full capability parser will better flag the error.. */
636 if (STREAM_READABLE(s) < length)
637 return 0;
638
639 if (BGP_DEBUG (as4, AS4))
640 zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u,"
641 " peeking for as4",
642 peer->host, length);
643 /* the error cases we DONT handle, we ONLY try to read as4 out of
644 * correctly formatted options.
645 */
646 while (stream_get_getp(s) < end)
647 {
648 u_char opt_type;
649 u_char opt_length;
650
651 /* Check the length. */
652 if (stream_get_getp (s) + 2 > end)
653 goto end;
654
655 /* Fetch option type and length. */
656 opt_type = stream_getc (s);
657 opt_length = stream_getc (s);
658
659 /* Option length check. */
660 if (stream_get_getp (s) + opt_length > end)
661 goto end;
662
663 if (opt_type == BGP_OPEN_OPT_CAP)
664 {
665 unsigned long capd_start = stream_get_getp (s);
666 unsigned long capd_end = capd_start + opt_length;
667
668 assert (capd_end <= end);
669
670 while (stream_get_getp (s) < capd_end)
671 {
672 struct capability_header hdr;
673
674 if (stream_get_getp (s) + 2 > capd_end)
675 goto end;
676
677 hdr.code = stream_getc (s);
678 hdr.length = stream_getc (s);
679
680 if ((stream_get_getp(s) + hdr.length) > capd_end)
681 goto end;
682
683 if (hdr.code == CAPABILITY_CODE_AS4)
684 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000685 if (BGP_DEBUG (as4, AS4))
686 zlog_info ("[AS4] found AS4 capability, about to parse");
687 as4 = bgp_capability_as4 (peer, &hdr);
688
689 goto end;
690 }
691 stream_forward_getp (s, hdr.length);
692 }
693 }
694 }
695
696end:
697 stream_set_getp (s, orig_getp);
698 return as4;
699}
700
Avneesh Sachdev3b381c32012-02-19 10:19:52 -0800701/**
702 * Parse open option.
703 *
704 * @param[out] mp_capability @see bgp_capability_parse() for semantics.
705 */
paul718e3742002-12-13 20:15:29 +0000706int
Avneesh Sachdev3b381c32012-02-19 10:19:52 -0800707bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability)
paul718e3742002-12-13 20:15:29 +0000708{
709 int ret;
paul718e3742002-12-13 20:15:29 +0000710 u_char *error;
711 u_char error_data[BGP_MAX_PACKET_SIZE];
Paul Jakma6d582722007-08-06 15:21:45 +0000712 struct stream *s = BGP_INPUT(peer);
713 size_t end = stream_get_getp (s) + length;
paul718e3742002-12-13 20:15:29 +0000714
715 ret = 0;
paul718e3742002-12-13 20:15:29 +0000716 error = error_data;
717
718 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000719 zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
paul718e3742002-12-13 20:15:29 +0000720 peer->host, length);
721
Paul Jakma6d582722007-08-06 15:21:45 +0000722 while (stream_get_getp(s) < end)
paul718e3742002-12-13 20:15:29 +0000723 {
Paul Jakma6d582722007-08-06 15:21:45 +0000724 u_char opt_type;
725 u_char opt_length;
726
727 /* Must have at least an OPEN option header */
728 if (STREAM_READABLE(s) < 2)
paul718e3742002-12-13 20:15:29 +0000729 {
730 zlog_info ("%s Option length error", peer->host);
731 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
732 return -1;
733 }
734
735 /* Fetch option type and length. */
Paul Jakma6d582722007-08-06 15:21:45 +0000736 opt_type = stream_getc (s);
737 opt_length = stream_getc (s);
paul718e3742002-12-13 20:15:29 +0000738
739 /* Option length check. */
Paul Jakma6d582722007-08-06 15:21:45 +0000740 if (STREAM_READABLE (s) < opt_length)
paul718e3742002-12-13 20:15:29 +0000741 {
742 zlog_info ("%s Option length error", peer->host);
743 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
744 return -1;
745 }
746
747 if (BGP_DEBUG (normal, NORMAL))
ajs8325cd72004-12-08 20:47:40 +0000748 zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
paul718e3742002-12-13 20:15:29 +0000749 peer->host, opt_type,
750 opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
751 opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown",
752 opt_length);
753
754 switch (opt_type)
755 {
756 case BGP_OPEN_OPT_AUTH:
Paul Jakma6d582722007-08-06 15:21:45 +0000757 ret = bgp_auth_parse (peer, opt_length);
paul718e3742002-12-13 20:15:29 +0000758 break;
759 case BGP_OPEN_OPT_CAP:
Avneesh Sachdev3b381c32012-02-19 10:19:52 -0800760 ret = bgp_capability_parse (peer, opt_length, mp_capability, &error);
paul718e3742002-12-13 20:15:29 +0000761 break;
762 default:
763 bgp_notify_send (peer,
764 BGP_NOTIFY_OPEN_ERR,
765 BGP_NOTIFY_OPEN_UNSUP_PARAM);
766 ret = -1;
767 break;
768 }
769
770 /* Parse error. To accumulate all unsupported capability codes,
771 bgp_capability_parse does not return -1 when encounter
772 unsupported capability code. To detect that, please check
773 error and erro_data pointer, like below. */
774 if (ret < 0)
775 return -1;
paul718e3742002-12-13 20:15:29 +0000776 }
777
778 /* All OPEN option is parsed. Check capability when strict compare
779 flag is enabled.*/
780 if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
781 {
782 /* If Unsupported Capability exists. */
783 if (error != error_data)
784 {
785 bgp_notify_send_with_data (peer,
786 BGP_NOTIFY_OPEN_ERR,
787 BGP_NOTIFY_OPEN_UNSUP_CAPBL,
788 error_data, error - error_data);
789 return -1;
790 }
791
792 /* Check local capability does not negotiated with remote
793 peer. */
794 if (! strict_capability_same (peer))
795 {
796 bgp_notify_send (peer,
797 BGP_NOTIFY_OPEN_ERR,
798 BGP_NOTIFY_OPEN_UNSUP_CAPBL);
799 return -1;
800 }
801 }
802
Avneesh Sachdev3b381c32012-02-19 10:19:52 -0800803 /* Check there are no common AFI/SAFIs and send Unsupported Capability
paul718e3742002-12-13 20:15:29 +0000804 error. */
Avneesh Sachdev3b381c32012-02-19 10:19:52 -0800805 if (*mp_capability &&
806 ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
paul718e3742002-12-13 20:15:29 +0000807 {
808 if (! peer->afc_nego[AFI_IP][SAFI_UNICAST]
809 && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
810 && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
811 && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
812 && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST])
813 {
Avneesh Sachdev3b381c32012-02-19 10:19:52 -0800814 plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not "
815 "overlap with received MP capabilities",
816 peer->host);
paul718e3742002-12-13 20:15:29 +0000817
818 if (error != error_data)
819
820 bgp_notify_send_with_data (peer,
821 BGP_NOTIFY_OPEN_ERR,
822 BGP_NOTIFY_OPEN_UNSUP_CAPBL,
823 error_data, error - error_data);
824 else
825 bgp_notify_send (peer,
826 BGP_NOTIFY_OPEN_ERR,
827 BGP_NOTIFY_OPEN_UNSUP_CAPBL);
828 return -1;
829 }
830 }
831 return 0;
832}
833
paul94f2b392005-06-28 12:44:16 +0000834static void
paul718e3742002-12-13 20:15:29 +0000835bgp_open_capability_orf (struct stream *s, struct peer *peer,
836 afi_t afi, safi_t safi, u_char code)
837{
838 u_char cap_len;
839 u_char orf_len;
840 unsigned long capp;
841 unsigned long orfp;
842 unsigned long numberp;
843 int number_of_orfs = 0;
844
845 if (safi == SAFI_MPLS_VPN)
Denis Ovsienko42e6d742011-07-14 12:36:19 +0400846 safi = SAFI_MPLS_LABELED_VPN;
paul718e3742002-12-13 20:15:29 +0000847
848 stream_putc (s, BGP_OPEN_OPT_CAP);
paul9985f832005-02-09 15:51:56 +0000849 capp = stream_get_endp (s); /* Set Capability Len Pointer */
paul718e3742002-12-13 20:15:29 +0000850 stream_putc (s, 0); /* Capability Length */
851 stream_putc (s, code); /* Capability Code */
paul9985f832005-02-09 15:51:56 +0000852 orfp = stream_get_endp (s); /* Set ORF Len Pointer */
paul718e3742002-12-13 20:15:29 +0000853 stream_putc (s, 0); /* ORF Length */
854 stream_putw (s, afi);
855 stream_putc (s, 0);
856 stream_putc (s, safi);
paul9985f832005-02-09 15:51:56 +0000857 numberp = stream_get_endp (s); /* Set Number Pointer */
paul718e3742002-12-13 20:15:29 +0000858 stream_putc (s, 0); /* Number of ORFs */
859
860 /* Address Prefix ORF */
861 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
862 || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
863 {
864 stream_putc (s, (code == CAPABILITY_CODE_ORF ?
865 ORF_TYPE_PREFIX : ORF_TYPE_PREFIX_OLD));
866
867 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
868 && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
869 {
870 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
871 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
872 stream_putc (s, ORF_MODE_BOTH);
873 }
874 else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM))
875 {
876 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
877 stream_putc (s, ORF_MODE_SEND);
878 }
879 else
880 {
881 SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
882 stream_putc (s, ORF_MODE_RECEIVE);
883 }
884 number_of_orfs++;
885 }
886
887 /* Total Number of ORFs. */
888 stream_putc_at (s, numberp, number_of_orfs);
889
890 /* Total ORF Len. */
paul9985f832005-02-09 15:51:56 +0000891 orf_len = stream_get_endp (s) - orfp - 1;
paul718e3742002-12-13 20:15:29 +0000892 stream_putc_at (s, orfp, orf_len);
893
894 /* Total Capability Len. */
paul9985f832005-02-09 15:51:56 +0000895 cap_len = stream_get_endp (s) - capp - 1;
paul718e3742002-12-13 20:15:29 +0000896 stream_putc_at (s, capp, cap_len);
897}
898
899/* Fill in capability open option to the packet. */
900void
901bgp_open_capability (struct stream *s, struct peer *peer)
902{
903 u_char len;
Vipin Kumardd49eb12014-09-30 14:36:38 -0700904 unsigned long cp, capp, rcapp;
paul718e3742002-12-13 20:15:29 +0000905 afi_t afi;
906 safi_t safi;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000907 as_t local_as;
Vipin Kumardd49eb12014-09-30 14:36:38 -0700908 u_int32_t restart_time;
paul718e3742002-12-13 20:15:29 +0000909
910 /* Remember current pointer for Opt Parm Len. */
paul9985f832005-02-09 15:51:56 +0000911 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +0000912
913 /* Opt Parm Len. */
914 stream_putc (s, 0);
915
916 /* Do not send capability. */
917 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN)
918 || CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
919 return;
920
paul718e3742002-12-13 20:15:29 +0000921 /* IPv4 unicast. */
922 if (peer->afc[AFI_IP][SAFI_UNICAST])
923 {
924 peer->afc_adv[AFI_IP][SAFI_UNICAST] = 1;
925 stream_putc (s, BGP_OPEN_OPT_CAP);
926 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
927 stream_putc (s, CAPABILITY_CODE_MP);
928 stream_putc (s, CAPABILITY_CODE_MP_LEN);
929 stream_putw (s, AFI_IP);
930 stream_putc (s, 0);
931 stream_putc (s, SAFI_UNICAST);
932 }
933 /* IPv4 multicast. */
934 if (peer->afc[AFI_IP][SAFI_MULTICAST])
935 {
936 peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 1;
937 stream_putc (s, BGP_OPEN_OPT_CAP);
938 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
939 stream_putc (s, CAPABILITY_CODE_MP);
940 stream_putc (s, CAPABILITY_CODE_MP_LEN);
941 stream_putw (s, AFI_IP);
942 stream_putc (s, 0);
943 stream_putc (s, SAFI_MULTICAST);
944 }
945 /* IPv4 VPN */
946 if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
947 {
948 peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 1;
949 stream_putc (s, BGP_OPEN_OPT_CAP);
950 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
951 stream_putc (s, CAPABILITY_CODE_MP);
952 stream_putc (s, CAPABILITY_CODE_MP_LEN);
953 stream_putw (s, AFI_IP);
954 stream_putc (s, 0);
Denis Ovsienko42e6d742011-07-14 12:36:19 +0400955 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +0000956 }
957#ifdef HAVE_IPV6
958 /* IPv6 unicast. */
959 if (peer->afc[AFI_IP6][SAFI_UNICAST])
960 {
961 peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 1;
962 stream_putc (s, BGP_OPEN_OPT_CAP);
963 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
964 stream_putc (s, CAPABILITY_CODE_MP);
965 stream_putc (s, CAPABILITY_CODE_MP_LEN);
966 stream_putw (s, AFI_IP6);
967 stream_putc (s, 0);
968 stream_putc (s, SAFI_UNICAST);
969 }
970 /* IPv6 multicast. */
971 if (peer->afc[AFI_IP6][SAFI_MULTICAST])
972 {
973 peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1;
974 stream_putc (s, BGP_OPEN_OPT_CAP);
975 stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
976 stream_putc (s, CAPABILITY_CODE_MP);
977 stream_putc (s, CAPABILITY_CODE_MP_LEN);
978 stream_putw (s, AFI_IP6);
979 stream_putc (s, 0);
980 stream_putc (s, SAFI_MULTICAST);
981 }
982#endif /* HAVE_IPV6 */
983
984 /* Route refresh. */
hassoc9502432005-02-01 22:01:48 +0000985 SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
986 stream_putc (s, BGP_OPEN_OPT_CAP);
987 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
988 stream_putc (s, CAPABILITY_CODE_REFRESH_OLD);
989 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
990 stream_putc (s, BGP_OPEN_OPT_CAP);
991 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
992 stream_putc (s, CAPABILITY_CODE_REFRESH);
993 stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
paul718e3742002-12-13 20:15:29 +0000994
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000995 /* AS4 */
996 SET_FLAG (peer->cap, PEER_CAP_AS4_ADV);
997 stream_putc (s, BGP_OPEN_OPT_CAP);
998 stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2);
999 stream_putc (s, CAPABILITY_CODE_AS4);
1000 stream_putc (s, CAPABILITY_CODE_AS4_LEN);
1001 if ( peer->change_local_as )
1002 local_as = peer->change_local_as;
1003 else
1004 local_as = peer->local_as;
1005 stream_putl (s, local_as );
1006
paul718e3742002-12-13 20:15:29 +00001007 /* ORF capability. */
1008 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
1009 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
1010 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
1011 || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
1012 {
1013 bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF_OLD);
1014 bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF);
1015 }
1016
1017 /* Dynamic capability. */
1018 if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
1019 {
1020 SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
1021 stream_putc (s, BGP_OPEN_OPT_CAP);
1022 stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
1023 stream_putc (s, CAPABILITY_CODE_DYNAMIC);
1024 stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN);
1025 }
1026
Vipin Kumardd49eb12014-09-30 14:36:38 -07001027 /* Sending base graceful-restart capability irrespective of the config */
1028 SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV);
1029 stream_putc (s, BGP_OPEN_OPT_CAP);
1030 capp = stream_get_endp (s); /* Set Capability Len Pointer */
1031 stream_putc (s, 0); /* Capability Length */
1032 stream_putc (s, CAPABILITY_CODE_RESTART);
1033 rcapp = stream_get_endp (s); /* Set Restart Capability Len Pointer */
1034 stream_putc (s, 0);
1035 restart_time = peer->bgp->restart_time;
1036 if (peer->bgp->t_startup)
1037 {
1038 SET_FLAG (restart_time, RESTART_R_BIT);
1039 SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_ADV);
1040 }
1041 stream_putw (s, restart_time);
1042
1043 /* Send address-family specific graceful-restart capability only when GR config
1044 is present */
hasso538621f2004-05-21 09:31:30 +00001045 if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART))
1046 {
Vipin Kumardd49eb12014-09-30 14:36:38 -07001047 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
1048 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
1049 if (peer->afc[afi][safi])
1050 {
1051 stream_putw (s, afi);
1052 stream_putc (s, safi);
1053 stream_putc (s, 0); //Forwarding is not retained as of now.
1054 }
1055 }
1056
1057 /* Total Graceful restart capability Len. */
1058 len = stream_get_endp (s) - rcapp - 1;
1059 stream_putc_at (s, rcapp, len);
1060
1061 /* Total Capability Len. */
1062 len = stream_get_endp (s) - capp - 1;
1063 stream_putc_at (s, capp, len);
hasso538621f2004-05-21 09:31:30 +00001064
paul718e3742002-12-13 20:15:29 +00001065 /* Total Opt Parm Len. */
paul9985f832005-02-09 15:51:56 +00001066 len = stream_get_endp (s) - cp - 1;
paul718e3742002-12-13 20:15:29 +00001067 stream_putc_at (s, cp, len);
1068}