Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* BGP open message handling |
3 | | * Copyright (C) 1998, 1999 Kunihiro Ishiguro |
4 | | */ |
5 | | |
6 | | #include <zebra.h> |
7 | | |
8 | | #include "linklist.h" |
9 | | #include "prefix.h" |
10 | | #include "stream.h" |
11 | | #include "frrevent.h" |
12 | | #include "log.h" |
13 | | #include "command.h" |
14 | | #include "memory.h" |
15 | | #include "queue.h" |
16 | | #include "filter.h" |
17 | | |
18 | | #include "lib/json.h" |
19 | | #include "bgpd/bgpd.h" |
20 | | #include "bgpd/bgp_attr.h" |
21 | | #include "bgpd/bgp_debug.h" |
22 | | #include "bgpd/bgp_errors.h" |
23 | | #include "bgpd/bgp_fsm.h" |
24 | | #include "bgpd/bgp_packet.h" |
25 | | #include "bgpd/bgp_open.h" |
26 | | #include "bgpd/bgp_aspath.h" |
27 | | #include "bgpd/bgp_vty.h" |
28 | | #include "bgpd/bgp_memory.h" |
29 | | |
30 | | static const struct message capcode_str[] = { |
31 | | {CAPABILITY_CODE_MP, "MultiProtocol Extensions"}, |
32 | | {CAPABILITY_CODE_REFRESH, "Route Refresh"}, |
33 | | {CAPABILITY_CODE_ORF, "Cooperative Route Filtering"}, |
34 | | {CAPABILITY_CODE_RESTART, "Graceful Restart"}, |
35 | | {CAPABILITY_CODE_AS4, "4-octet AS number"}, |
36 | | {CAPABILITY_CODE_ADDPATH, "AddPath"}, |
37 | | {CAPABILITY_CODE_DYNAMIC, "Dynamic"}, |
38 | | {CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding"}, |
39 | | {CAPABILITY_CODE_DYNAMIC_OLD, "Dynamic (Old)"}, |
40 | | {CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)"}, |
41 | | {CAPABILITY_CODE_ORF_OLD, "ORF (Old)"}, |
42 | | {CAPABILITY_CODE_FQDN, "FQDN"}, |
43 | | {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"}, |
44 | | {CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"}, |
45 | | {CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart"}, |
46 | | {CAPABILITY_CODE_ROLE, "Role"}, |
47 | | {CAPABILITY_CODE_SOFT_VERSION, "Software Version"}, |
48 | | {0}}; |
49 | | |
50 | | /* Minimum sizes for length field of each cap (so not inc. the header) */ |
51 | | static const size_t cap_minsizes[] = { |
52 | | [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, |
53 | | [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, |
54 | | [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, |
55 | | [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN, |
56 | | [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, |
57 | | [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN, |
58 | | [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, |
59 | | [CAPABILITY_CODE_DYNAMIC_OLD] = CAPABILITY_CODE_DYNAMIC_LEN, |
60 | | [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN, |
61 | | [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, |
62 | | [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN, |
63 | | [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN, |
64 | | [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN, |
65 | | [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN, |
66 | | [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN, |
67 | | [CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN, |
68 | | [CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN, |
69 | | }; |
70 | | |
71 | | /* value the capability must be a multiple of. |
72 | | * 0-data capabilities won't be checked against this. |
73 | | * Other capabilities whose data doesn't fall on convenient boundaries for this |
74 | | * table should be set to 1. |
75 | | */ |
76 | | static const size_t cap_modsizes[] = { |
77 | | [CAPABILITY_CODE_MP] = 4, |
78 | | [CAPABILITY_CODE_REFRESH] = 1, |
79 | | [CAPABILITY_CODE_ORF] = 1, |
80 | | [CAPABILITY_CODE_RESTART] = 1, |
81 | | [CAPABILITY_CODE_AS4] = 4, |
82 | | [CAPABILITY_CODE_ADDPATH] = 4, |
83 | | [CAPABILITY_CODE_DYNAMIC] = 1, |
84 | | [CAPABILITY_CODE_DYNAMIC_OLD] = 1, |
85 | | [CAPABILITY_CODE_ENHE] = 6, |
86 | | [CAPABILITY_CODE_REFRESH_OLD] = 1, |
87 | | [CAPABILITY_CODE_ORF_OLD] = 1, |
88 | | [CAPABILITY_CODE_FQDN] = 1, |
89 | | [CAPABILITY_CODE_ENHANCED_RR] = 1, |
90 | | [CAPABILITY_CODE_EXT_MESSAGE] = 1, |
91 | | [CAPABILITY_CODE_LLGR] = 1, |
92 | | [CAPABILITY_CODE_ROLE] = 1, |
93 | | [CAPABILITY_CODE_SOFT_VERSION] = 1, |
94 | | }; |
95 | | |
96 | | /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can |
97 | | negotiate remote peer supports extentions or not. But if |
98 | | remote-peer doesn't supports negotiation process itself. We would |
99 | | like to do manual configuration. |
100 | | |
101 | | So there is many configurable point. First of all we want set each |
102 | | peer whether we send capability negotiation to the peer or not. |
103 | | Next, if we send capability to the peer we want to set my capability |
104 | | inforation at each peer. */ |
105 | | |
106 | | void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, |
107 | | json_object *json_neigh) |
108 | 0 | { |
109 | 0 | char *pnt; |
110 | 0 | char *end; |
111 | 0 | struct capability_mp_data mpc; |
112 | 0 | struct capability_header *hdr; |
113 | 0 | json_object *json_cap = NULL; |
114 | |
|
115 | 0 | if (use_json) |
116 | 0 | json_cap = json_object_new_object(); |
117 | |
|
118 | 0 | pnt = peer->notify.data; |
119 | 0 | end = pnt + peer->notify.length; |
120 | |
|
121 | 0 | while (pnt < end) { |
122 | 0 | if (pnt + sizeof(struct capability_mp_data) + 2 > end) |
123 | 0 | return; |
124 | | |
125 | 0 | hdr = (struct capability_header *)pnt; |
126 | 0 | if (pnt + hdr->length + 2 > end) |
127 | 0 | return; |
128 | | |
129 | 0 | memcpy(&mpc, pnt + 2, sizeof(struct capability_mp_data)); |
130 | |
|
131 | 0 | if (hdr->code == CAPABILITY_CODE_MP) { |
132 | 0 | afi_t afi; |
133 | 0 | safi_t safi; |
134 | |
|
135 | 0 | (void)bgp_map_afi_safi_iana2int(ntohs(mpc.afi), |
136 | 0 | mpc.safi, &afi, &safi); |
137 | |
|
138 | 0 | if (use_json) { |
139 | 0 | switch (afi) { |
140 | 0 | case AFI_IP: |
141 | 0 | json_object_string_add( |
142 | 0 | json_cap, |
143 | 0 | "capabilityErrorMultiProtocolAfi", |
144 | 0 | "IPv4"); |
145 | 0 | break; |
146 | 0 | case AFI_IP6: |
147 | 0 | json_object_string_add( |
148 | 0 | json_cap, |
149 | 0 | "capabilityErrorMultiProtocolAfi", |
150 | 0 | "IPv6"); |
151 | 0 | break; |
152 | 0 | case AFI_L2VPN: |
153 | 0 | json_object_string_add( |
154 | 0 | json_cap, |
155 | 0 | "capabilityErrorMultiProtocolAfi", |
156 | 0 | "L2VPN"); |
157 | 0 | break; |
158 | 0 | case AFI_UNSPEC: |
159 | 0 | case AFI_MAX: |
160 | 0 | json_object_int_add( |
161 | 0 | json_cap, |
162 | 0 | "capabilityErrorMultiProtocolAfiUnknown", |
163 | 0 | ntohs(mpc.afi)); |
164 | 0 | break; |
165 | 0 | } |
166 | 0 | switch (safi) { |
167 | 0 | case SAFI_UNICAST: |
168 | 0 | json_object_string_add( |
169 | 0 | json_cap, |
170 | 0 | "capabilityErrorMultiProtocolSafi", |
171 | 0 | "unicast"); |
172 | 0 | break; |
173 | 0 | case SAFI_MULTICAST: |
174 | 0 | json_object_string_add( |
175 | 0 | json_cap, |
176 | 0 | "capabilityErrorMultiProtocolSafi", |
177 | 0 | "multicast"); |
178 | 0 | break; |
179 | 0 | case SAFI_LABELED_UNICAST: |
180 | 0 | json_object_string_add( |
181 | 0 | json_cap, |
182 | 0 | "capabilityErrorMultiProtocolSafi", |
183 | 0 | "labeled-unicast"); |
184 | 0 | break; |
185 | 0 | case SAFI_MPLS_VPN: |
186 | 0 | json_object_string_add( |
187 | 0 | json_cap, |
188 | 0 | "capabilityErrorMultiProtocolSafi", |
189 | 0 | "MPLS-labeled VPN"); |
190 | 0 | break; |
191 | 0 | case SAFI_ENCAP: |
192 | 0 | json_object_string_add( |
193 | 0 | json_cap, |
194 | 0 | "capabilityErrorMultiProtocolSafi", |
195 | 0 | "encap"); |
196 | 0 | break; |
197 | 0 | case SAFI_EVPN: |
198 | 0 | json_object_string_add( |
199 | 0 | json_cap, |
200 | 0 | "capabilityErrorMultiProtocolSafi", |
201 | 0 | "EVPN"); |
202 | 0 | break; |
203 | 0 | case SAFI_FLOWSPEC: |
204 | 0 | json_object_string_add( |
205 | 0 | json_cap, |
206 | 0 | "capabilityErrorMultiProtocolSafi", |
207 | 0 | "flowspec"); |
208 | 0 | break; |
209 | 0 | case SAFI_UNSPEC: |
210 | 0 | case SAFI_MAX: |
211 | 0 | json_object_int_add( |
212 | 0 | json_cap, |
213 | 0 | "capabilityErrorMultiProtocolSafiUnknown", |
214 | 0 | mpc.safi); |
215 | 0 | break; |
216 | 0 | } |
217 | 0 | } else { |
218 | 0 | vty_out(vty, |
219 | 0 | " Capability error for: Multi protocol "); |
220 | 0 | switch (afi) { |
221 | 0 | case AFI_IP: |
222 | 0 | vty_out(vty, "AFI IPv4, "); |
223 | 0 | break; |
224 | 0 | case AFI_IP6: |
225 | 0 | vty_out(vty, "AFI IPv6, "); |
226 | 0 | break; |
227 | 0 | case AFI_L2VPN: |
228 | 0 | vty_out(vty, "AFI L2VPN, "); |
229 | 0 | break; |
230 | 0 | case AFI_UNSPEC: |
231 | 0 | case AFI_MAX: |
232 | 0 | vty_out(vty, "AFI Unknown %d, ", |
233 | 0 | ntohs(mpc.afi)); |
234 | 0 | break; |
235 | 0 | } |
236 | 0 | switch (safi) { |
237 | 0 | case SAFI_UNICAST: |
238 | 0 | vty_out(vty, "SAFI Unicast"); |
239 | 0 | break; |
240 | 0 | case SAFI_MULTICAST: |
241 | 0 | vty_out(vty, "SAFI Multicast"); |
242 | 0 | break; |
243 | 0 | case SAFI_LABELED_UNICAST: |
244 | 0 | vty_out(vty, "SAFI Labeled-unicast"); |
245 | 0 | break; |
246 | 0 | case SAFI_MPLS_VPN: |
247 | 0 | vty_out(vty, "SAFI MPLS-labeled VPN"); |
248 | 0 | break; |
249 | 0 | case SAFI_ENCAP: |
250 | 0 | vty_out(vty, "SAFI ENCAP"); |
251 | 0 | break; |
252 | 0 | case SAFI_FLOWSPEC: |
253 | 0 | vty_out(vty, "SAFI FLOWSPEC"); |
254 | 0 | break; |
255 | 0 | case SAFI_EVPN: |
256 | 0 | vty_out(vty, "SAFI EVPN"); |
257 | 0 | break; |
258 | 0 | case SAFI_UNSPEC: |
259 | 0 | case SAFI_MAX: |
260 | 0 | vty_out(vty, "SAFI Unknown %d ", |
261 | 0 | mpc.safi); |
262 | 0 | break; |
263 | 0 | } |
264 | 0 | vty_out(vty, "\n"); |
265 | 0 | } |
266 | 0 | } else if (hdr->code >= 128) { |
267 | 0 | if (use_json) |
268 | 0 | json_object_int_add( |
269 | 0 | json_cap, |
270 | 0 | "capabilityErrorVendorSpecificCapabilityCode", |
271 | 0 | hdr->code); |
272 | 0 | else |
273 | 0 | vty_out(vty, |
274 | 0 | " Capability error: vendor specific capability code %d", |
275 | 0 | hdr->code); |
276 | 0 | } else { |
277 | 0 | if (use_json) |
278 | 0 | json_object_int_add( |
279 | 0 | json_cap, |
280 | 0 | "capabilityErrorUnknownCapabilityCode", |
281 | 0 | hdr->code); |
282 | 0 | else |
283 | 0 | vty_out(vty, |
284 | 0 | " Capability error: unknown capability code %d", |
285 | 0 | hdr->code); |
286 | 0 | } |
287 | 0 | pnt += hdr->length + 2; |
288 | 0 | } |
289 | 0 | if (use_json) |
290 | 0 | json_object_object_add(json_neigh, "capabilityErrors", |
291 | 0 | json_cap); |
292 | 0 | } |
293 | | |
294 | | static void bgp_capability_mp_data(struct stream *s, |
295 | | struct capability_mp_data *mpc) |
296 | 26 | { |
297 | 26 | mpc->afi = stream_getw(s); |
298 | 26 | mpc->reserved = stream_getc(s); |
299 | 26 | mpc->safi = stream_getc(s); |
300 | 26 | } |
301 | | |
302 | | /* Set negotiated capability value. */ |
303 | | static int bgp_capability_mp(struct peer *peer, struct capability_header *hdr) |
304 | 26 | { |
305 | 26 | struct capability_mp_data mpc; |
306 | 26 | struct stream *s = BGP_INPUT(peer); |
307 | 26 | afi_t afi; |
308 | 26 | safi_t safi; |
309 | | |
310 | | /* Verify length is 4 */ |
311 | 26 | if (hdr->length != 4) { |
312 | 3 | flog_warn( |
313 | 3 | EC_BGP_CAPABILITY_INVALID_LENGTH, |
314 | 3 | "MP Cap: Received invalid length %d, non-multiple of 4", |
315 | 3 | hdr->length); |
316 | 3 | return -1; |
317 | 3 | } |
318 | | |
319 | 23 | bgp_capability_mp_data(s, &mpc); |
320 | | |
321 | 23 | if (bgp_debug_neighbor_events(peer)) |
322 | 0 | zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s", |
323 | 23 | peer->host, lookup_msg(capcode_str, hdr->code, NULL), |
324 | 23 | iana_afi2str(mpc.afi), iana_safi2str(mpc.safi)); |
325 | | |
326 | | /* Convert AFI, SAFI to internal values, check. */ |
327 | 23 | if (bgp_map_afi_safi_iana2int(mpc.afi, mpc.safi, &afi, &safi)) |
328 | 4 | return -1; |
329 | | |
330 | | /* Now safi remapped, and afi/safi are valid array indices */ |
331 | 19 | peer->afc_recv[afi][safi] = 1; |
332 | | |
333 | 19 | if (peer->afc[afi][safi]) |
334 | 0 | peer->afc_nego[afi][safi] = 1; |
335 | 19 | else |
336 | 19 | return -1; |
337 | | |
338 | 0 | return 0; |
339 | 19 | } |
340 | | |
341 | | static void bgp_capability_orf_not_support(struct peer *peer, iana_afi_t afi, |
342 | | iana_safi_t safi, uint8_t type, |
343 | | uint8_t mode) |
344 | 0 | { |
345 | 0 | if (bgp_debug_neighbor_events(peer)) |
346 | 0 | zlog_debug( |
347 | 0 | "%s Addr-family %d/%d has ORF type/mode %d/%d not supported", |
348 | 0 | peer->host, afi, safi, type, mode); |
349 | 0 | } |
350 | | |
351 | | static const struct message orf_type_str[] = { |
352 | | {ORF_TYPE_RESERVED, "Reserved"}, |
353 | | {ORF_TYPE_PREFIX, "Prefixlist"}, |
354 | | {ORF_TYPE_PREFIX_OLD, "Prefixlist (old)"}, |
355 | | {0}}; |
356 | | |
357 | | static const struct message orf_mode_str[] = {{ORF_MODE_RECEIVE, "Receive"}, |
358 | | {ORF_MODE_SEND, "Send"}, |
359 | | {ORF_MODE_BOTH, "Both"}, |
360 | | {0}}; |
361 | | |
362 | | static int bgp_capability_orf_entry(struct peer *peer, |
363 | | struct capability_header *hdr) |
364 | 3 | { |
365 | 3 | struct stream *s = BGP_INPUT(peer); |
366 | 3 | struct capability_mp_data mpc; |
367 | 3 | uint8_t num; |
368 | 3 | iana_afi_t pkt_afi; |
369 | 3 | afi_t afi; |
370 | 3 | iana_safi_t pkt_safi; |
371 | 3 | safi_t safi; |
372 | 3 | uint8_t type; |
373 | 3 | uint8_t mode; |
374 | 3 | uint16_t sm_cap = 0; /* capability send-mode receive */ |
375 | 3 | uint16_t rm_cap = 0; /* capability receive-mode receive */ |
376 | 3 | int i; |
377 | | |
378 | | /* ORF Entry header */ |
379 | 3 | bgp_capability_mp_data(s, &mpc); |
380 | 3 | num = stream_getc(s); |
381 | 3 | pkt_afi = mpc.afi; |
382 | 3 | pkt_safi = mpc.safi; |
383 | | |
384 | 3 | if (bgp_debug_neighbor_events(peer)) |
385 | 0 | zlog_debug("%s ORF Cap entry for afi/safi: %s/%s", peer->host, |
386 | 3 | iana_afi2str(mpc.afi), iana_safi2str(mpc.safi)); |
387 | | |
388 | | /* Convert AFI, SAFI to internal values, check. */ |
389 | 3 | if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { |
390 | 3 | zlog_info( |
391 | 3 | "%s Addr-family %d/%d not supported. Ignoring the ORF capability", |
392 | 3 | peer->host, pkt_afi, pkt_safi); |
393 | 3 | return 0; |
394 | 3 | } |
395 | | |
396 | 0 | mpc.afi = pkt_afi; |
397 | 0 | mpc.safi = safi; |
398 | | |
399 | | /* validate number field */ |
400 | 0 | if (CAPABILITY_CODE_ORF_LEN + (num * 2) > hdr->length) { |
401 | 0 | zlog_info( |
402 | 0 | "%s ORF Capability entry length error, Cap length %u, num %u", |
403 | 0 | peer->host, hdr->length, num); |
404 | 0 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
405 | 0 | BGP_NOTIFY_OPEN_MALFORMED_ATTR); |
406 | 0 | return -1; |
407 | 0 | } |
408 | | |
409 | 0 | for (i = 0; i < num; i++) { |
410 | 0 | type = stream_getc(s); |
411 | 0 | mode = stream_getc(s); |
412 | | |
413 | | /* ORF Mode error check */ |
414 | 0 | switch (mode) { |
415 | 0 | case ORF_MODE_BOTH: |
416 | 0 | case ORF_MODE_SEND: |
417 | 0 | case ORF_MODE_RECEIVE: |
418 | 0 | break; |
419 | 0 | default: |
420 | 0 | bgp_capability_orf_not_support(peer, pkt_afi, pkt_safi, |
421 | 0 | type, mode); |
422 | 0 | continue; |
423 | 0 | } |
424 | | /* ORF Type and afi/safi error checks */ |
425 | | /* capcode versus type */ |
426 | 0 | switch (hdr->code) { |
427 | 0 | case CAPABILITY_CODE_ORF: |
428 | 0 | switch (type) { |
429 | 0 | case ORF_TYPE_RESERVED: |
430 | 0 | if (bgp_debug_neighbor_events(peer)) |
431 | 0 | zlog_debug( |
432 | 0 | "%s Addr-family %d/%d has reserved ORF type, ignoring", |
433 | 0 | peer->host, afi, safi); |
434 | 0 | break; |
435 | 0 | case ORF_TYPE_PREFIX: |
436 | 0 | break; |
437 | 0 | default: |
438 | 0 | bgp_capability_orf_not_support( |
439 | 0 | peer, pkt_afi, pkt_safi, type, mode); |
440 | 0 | continue; |
441 | 0 | } |
442 | 0 | break; |
443 | 0 | case CAPABILITY_CODE_ORF_OLD: |
444 | 0 | switch (type) { |
445 | 0 | case ORF_TYPE_RESERVED: |
446 | 0 | if (bgp_debug_neighbor_events(peer)) |
447 | 0 | zlog_debug( |
448 | 0 | "%s Addr-family %d/%d has reserved ORF type, ignoring", |
449 | 0 | peer->host, afi, safi); |
450 | 0 | break; |
451 | 0 | case ORF_TYPE_PREFIX_OLD: |
452 | 0 | break; |
453 | 0 | default: |
454 | 0 | bgp_capability_orf_not_support( |
455 | 0 | peer, pkt_afi, pkt_safi, type, mode); |
456 | 0 | continue; |
457 | 0 | } |
458 | 0 | break; |
459 | 0 | default: |
460 | 0 | bgp_capability_orf_not_support(peer, pkt_afi, pkt_safi, |
461 | 0 | type, mode); |
462 | 0 | continue; |
463 | 0 | } |
464 | | |
465 | | /* AFI vs SAFI */ |
466 | 0 | if (!((afi == AFI_IP && safi == SAFI_UNICAST) |
467 | 0 | || (afi == AFI_IP && safi == SAFI_MULTICAST) |
468 | 0 | || (afi == AFI_IP6 && safi == SAFI_UNICAST))) { |
469 | 0 | bgp_capability_orf_not_support(peer, pkt_afi, pkt_safi, |
470 | 0 | type, mode); |
471 | 0 | continue; |
472 | 0 | } |
473 | | |
474 | 0 | if (bgp_debug_neighbor_events(peer)) |
475 | 0 | zlog_debug( |
476 | 0 | "%s OPEN has %s ORF capability as %s for afi/safi: %s/%s", |
477 | 0 | peer->host, |
478 | 0 | lookup_msg(orf_type_str, type, NULL), |
479 | 0 | lookup_msg(orf_mode_str, mode, NULL), |
480 | 0 | iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); |
481 | |
|
482 | 0 | if (hdr->code == CAPABILITY_CODE_ORF) { |
483 | 0 | sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; |
484 | 0 | rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; |
485 | 0 | } else if (hdr->code == CAPABILITY_CODE_ORF_OLD) { |
486 | 0 | sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV; |
487 | 0 | rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV; |
488 | 0 | } else { |
489 | 0 | bgp_capability_orf_not_support(peer, pkt_afi, pkt_safi, |
490 | 0 | type, mode); |
491 | 0 | continue; |
492 | 0 | } |
493 | | |
494 | 0 | switch (mode) { |
495 | 0 | case ORF_MODE_BOTH: |
496 | 0 | SET_FLAG(peer->af_cap[afi][safi], sm_cap); |
497 | 0 | SET_FLAG(peer->af_cap[afi][safi], rm_cap); |
498 | 0 | break; |
499 | 0 | case ORF_MODE_SEND: |
500 | 0 | SET_FLAG(peer->af_cap[afi][safi], sm_cap); |
501 | 0 | break; |
502 | 0 | case ORF_MODE_RECEIVE: |
503 | 0 | SET_FLAG(peer->af_cap[afi][safi], rm_cap); |
504 | 0 | break; |
505 | 0 | } |
506 | 0 | } |
507 | 0 | return 0; |
508 | 0 | } |
509 | | |
510 | | static int bgp_capability_restart(struct peer *peer, |
511 | | struct capability_header *caphdr) |
512 | 15 | { |
513 | 15 | struct stream *s = BGP_INPUT(peer); |
514 | 15 | uint16_t restart_flag_time; |
515 | 15 | size_t end = stream_get_getp(s) + caphdr->length; |
516 | | |
517 | | /* Verify length is a multiple of 4 */ |
518 | 15 | if ((caphdr->length - 2) % 4) { |
519 | 0 | flog_warn( |
520 | 0 | EC_BGP_CAPABILITY_INVALID_LENGTH, |
521 | 0 | "Restart Cap: Received invalid length %d, non-multiple of 4", |
522 | 0 | caphdr->length); |
523 | 0 | return -1; |
524 | 0 | } |
525 | | |
526 | 15 | SET_FLAG(peer->cap, PEER_CAP_RESTART_RCV); |
527 | 15 | restart_flag_time = stream_getw(s); |
528 | | |
529 | | /* The most significant bit is defined in [RFC4724] as |
530 | | * the Restart State ("R") bit. |
531 | | */ |
532 | 15 | if (CHECK_FLAG(restart_flag_time, GRACEFUL_RESTART_R_BIT)) |
533 | 4 | SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); |
534 | 11 | else |
535 | 11 | UNSET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); |
536 | | |
537 | | /* The second most significant bit is defined in this |
538 | | * document as the Graceful Notification ("N") bit. |
539 | | */ |
540 | 15 | if (CHECK_FLAG(restart_flag_time, GRACEFUL_RESTART_N_BIT)) |
541 | 10 | SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV); |
542 | 5 | else |
543 | 5 | UNSET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV); |
544 | | |
545 | 15 | UNSET_FLAG(restart_flag_time, 0xF000); |
546 | 15 | peer->v_gr_restart = restart_flag_time; |
547 | | |
548 | 15 | if (bgp_debug_neighbor_events(peer)) { |
549 | 0 | zlog_debug( |
550 | 0 | "%s Peer has%srestarted. Restart Time: %d, N-bit set: %s", |
551 | 0 | peer->host, |
552 | 0 | CHECK_FLAG(peer->cap, |
553 | 0 | PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) |
554 | 0 | ? " " |
555 | 0 | : " not ", |
556 | 0 | peer->v_gr_restart, |
557 | 0 | CHECK_FLAG(peer->cap, |
558 | 0 | PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) |
559 | 0 | ? "yes" |
560 | 0 | : "no"); |
561 | 0 | } |
562 | | |
563 | 62 | while (stream_get_getp(s) + 4 <= end) { |
564 | 47 | afi_t afi; |
565 | 47 | safi_t safi; |
566 | 47 | iana_afi_t pkt_afi = stream_getw(s); |
567 | 47 | iana_safi_t pkt_safi = stream_getc(s); |
568 | 47 | uint8_t flag = stream_getc(s); |
569 | | |
570 | | /* Convert AFI, SAFI to internal values, check. */ |
571 | 47 | if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { |
572 | 47 | if (bgp_debug_neighbor_events(peer)) |
573 | 0 | zlog_debug( |
574 | 47 | "%s Addr-family %s/%s(afi/safi) not supported. Ignore the Graceful Restart capability for this AFI/SAFI", |
575 | 47 | peer->host, iana_afi2str(pkt_afi), |
576 | 47 | iana_safi2str(pkt_safi)); |
577 | 47 | } else if (!peer->afc[afi][safi]) { |
578 | 0 | if (bgp_debug_neighbor_events(peer)) |
579 | 0 | zlog_debug( |
580 | 0 | "%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Graceful Restart capability", |
581 | 0 | peer->host, iana_afi2str(pkt_afi), |
582 | 0 | iana_safi2str(pkt_safi)); |
583 | 0 | } else { |
584 | 0 | if (bgp_debug_neighbor_events(peer)) |
585 | 0 | zlog_debug( |
586 | 0 | "%s Address family %s is%spreserved", |
587 | 0 | peer->host, get_afi_safi_str(afi, safi, false), |
588 | 0 | CHECK_FLAG( |
589 | 0 | peer->af_cap[afi][safi], |
590 | 0 | PEER_CAP_RESTART_AF_PRESERVE_RCV) |
591 | 0 | ? " " |
592 | 0 | : " not "); |
593 | |
|
594 | 0 | SET_FLAG(peer->af_cap[afi][safi], |
595 | 0 | PEER_CAP_RESTART_AF_RCV); |
596 | 0 | if (CHECK_FLAG(flag, GRACEFUL_RESTART_F_BIT)) |
597 | 0 | SET_FLAG(peer->af_cap[afi][safi], |
598 | 0 | PEER_CAP_RESTART_AF_PRESERVE_RCV); |
599 | 0 | } |
600 | 47 | } |
601 | 15 | return 0; |
602 | 15 | } |
603 | | |
604 | | static int bgp_capability_llgr(struct peer *peer, |
605 | | struct capability_header *caphdr) |
606 | 4 | { |
607 | | /* |
608 | | * +--------------------------------------------------+ |
609 | | * | Address Family Identifier (16 bits) | |
610 | | * +--------------------------------------------------+ |
611 | | * | Subsequent Address Family Identifier (8 bits) | |
612 | | * +--------------------------------------------------+ |
613 | | * | Flags for Address Family (8 bits) | |
614 | | * +--------------------------------------------------+ |
615 | | * | Long-lived Stale Time (24 bits) | |
616 | | * +--------------------------------------------------+ |
617 | | */ |
618 | 64 | #define BGP_CAP_LLGR_MIN_PACKET_LEN 7 |
619 | 4 | struct stream *s = BGP_INPUT(peer); |
620 | 4 | size_t end = stream_get_getp(s) + caphdr->length; |
621 | | |
622 | 4 | SET_FLAG(peer->cap, PEER_CAP_LLGR_RCV); |
623 | | |
624 | 64 | while (stream_get_getp(s) + BGP_CAP_LLGR_MIN_PACKET_LEN <= end) { |
625 | 60 | afi_t afi; |
626 | 60 | safi_t safi; |
627 | 60 | iana_afi_t pkt_afi = stream_getw(s); |
628 | 60 | iana_safi_t pkt_safi = stream_getc(s); |
629 | 60 | uint8_t flags = stream_getc(s); |
630 | 60 | uint32_t stale_time = stream_get3(s); |
631 | | |
632 | 60 | if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { |
633 | 59 | if (bgp_debug_neighbor_events(peer)) |
634 | 0 | zlog_debug( |
635 | 59 | "%s Addr-family %s/%s(afi/safi) not supported. Ignore the Long-lived Graceful Restart capability for this AFI/SAFI", |
636 | 59 | peer->host, iana_afi2str(pkt_afi), |
637 | 59 | iana_safi2str(pkt_safi)); |
638 | 59 | } else if (!peer->afc[afi][safi] |
639 | 0 | || !CHECK_FLAG(peer->af_cap[afi][safi], |
640 | 1 | PEER_CAP_RESTART_AF_RCV)) { |
641 | 1 | if (bgp_debug_neighbor_events(peer)) |
642 | 0 | zlog_debug( |
643 | 1 | "%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Long-lived Graceful Restart capability", |
644 | 1 | peer->host, iana_afi2str(pkt_afi), |
645 | 1 | iana_safi2str(pkt_safi)); |
646 | 1 | } else { |
647 | 0 | if (bgp_debug_neighbor_events(peer)) |
648 | 0 | zlog_debug( |
649 | 0 | "%s Addr-family %s/%s(afi/safi) Long-lived Graceful Restart capability stale time %u sec", |
650 | 0 | peer->host, iana_afi2str(pkt_afi), |
651 | 0 | iana_safi2str(pkt_safi), stale_time); |
652 | |
|
653 | 0 | peer->llgr[afi][safi].flags = flags; |
654 | 0 | peer->llgr[afi][safi].stale_time = |
655 | 0 | MIN(stale_time, peer->bgp->llgr_stale_time); |
656 | 0 | SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_LLGR_AF_RCV); |
657 | 0 | } |
658 | 60 | } |
659 | | |
660 | 4 | return 0; |
661 | 4 | } |
662 | | |
663 | | /* Unlike other capability parsing routines, this one returns 0 on error */ |
664 | | static as_t bgp_capability_as4(struct peer *peer, struct capability_header *hdr) |
665 | 200 | { |
666 | 200 | SET_FLAG(peer->cap, PEER_CAP_AS4_RCV); |
667 | | |
668 | 200 | if (hdr->length != CAPABILITY_CODE_AS4_LEN) { |
669 | 2 | flog_err(EC_BGP_PKT_OPEN, |
670 | 2 | "%s AS4 capability has incorrect data length %d", |
671 | 2 | peer->host, hdr->length); |
672 | 2 | return 0; |
673 | 2 | } |
674 | | |
675 | 198 | as_t as4 = stream_getl(BGP_INPUT(peer)); |
676 | | |
677 | 198 | if (BGP_DEBUG(as4, AS4)) |
678 | 0 | zlog_debug( |
679 | 198 | "%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u", |
680 | 198 | peer->host, as4); |
681 | 198 | return as4; |
682 | 200 | } |
683 | | |
684 | | static int bgp_capability_ext_message(struct peer *peer, |
685 | | struct capability_header *hdr) |
686 | 2 | { |
687 | 2 | if (hdr->length != CAPABILITY_CODE_EXT_MESSAGE_LEN) { |
688 | 0 | flog_err( |
689 | 0 | EC_BGP_PKT_OPEN, |
690 | 0 | "%s: BGP Extended Message capability has incorrect data length %d", |
691 | 0 | peer->host, hdr->length); |
692 | 0 | return -1; |
693 | 0 | } |
694 | | |
695 | 2 | SET_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_RCV); |
696 | | |
697 | 2 | return 0; |
698 | 2 | } |
699 | | |
700 | | static int bgp_capability_addpath(struct peer *peer, |
701 | | struct capability_header *hdr) |
702 | 42 | { |
703 | 42 | struct stream *s = BGP_INPUT(peer); |
704 | 42 | size_t end = stream_get_getp(s) + hdr->length; |
705 | | |
706 | 42 | SET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV); |
707 | | |
708 | | /* Verify length is a multiple of 4 */ |
709 | 42 | if (hdr->length % 4) { |
710 | 0 | flog_warn( |
711 | 0 | EC_BGP_CAPABILITY_INVALID_LENGTH, |
712 | 0 | "Add Path: Received invalid length %d, non-multiple of 4", |
713 | 0 | hdr->length); |
714 | 0 | return -1; |
715 | 0 | } |
716 | | |
717 | 168 | while (stream_get_getp(s) + 4 <= end) { |
718 | 126 | afi_t afi; |
719 | 126 | safi_t safi; |
720 | 126 | iana_afi_t pkt_afi = stream_getw(s); |
721 | 126 | iana_safi_t pkt_safi = stream_getc(s); |
722 | 126 | uint8_t send_receive = stream_getc(s); |
723 | | |
724 | 126 | if (bgp_debug_neighbor_events(peer)) |
725 | 0 | zlog_debug( |
726 | 126 | "%s OPEN has %s capability for afi/safi: %s/%s%s%s", |
727 | 126 | peer->host, |
728 | 126 | lookup_msg(capcode_str, hdr->code, NULL), |
729 | 126 | iana_afi2str(pkt_afi), iana_safi2str(pkt_safi), |
730 | 126 | (send_receive & BGP_ADDPATH_RX) ? ", receive" |
731 | 126 | : "", |
732 | 126 | (send_receive & BGP_ADDPATH_TX) ? ", transmit" |
733 | 126 | : ""); |
734 | | |
735 | | /* Convert AFI, SAFI to internal values, check. */ |
736 | 126 | if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { |
737 | 50 | if (bgp_debug_neighbor_events(peer)) |
738 | 0 | zlog_debug( |
739 | 50 | "%s Addr-family %s/%s(afi/safi) not supported. Ignore the Addpath Attribute for this AFI/SAFI", |
740 | 50 | peer->host, iana_afi2str(pkt_afi), |
741 | 50 | iana_safi2str(pkt_safi)); |
742 | 50 | continue; |
743 | 76 | } else if (!peer->afc[afi][safi]) { |
744 | 0 | if (bgp_debug_neighbor_events(peer)) |
745 | 0 | zlog_debug( |
746 | 0 | "%s Addr-family %s/%s(afi/safi) not enabled. Ignore the AddPath capability for this AFI/SAFI", |
747 | 0 | peer->host, iana_afi2str(pkt_afi), |
748 | 0 | iana_safi2str(pkt_safi)); |
749 | 0 | continue; |
750 | 0 | } |
751 | | |
752 | 76 | if (send_receive & BGP_ADDPATH_RX) |
753 | 49 | SET_FLAG(peer->af_cap[afi][safi], |
754 | 76 | PEER_CAP_ADDPATH_AF_RX_RCV); |
755 | | |
756 | 76 | if (send_receive & BGP_ADDPATH_TX) |
757 | 23 | SET_FLAG(peer->af_cap[afi][safi], |
758 | 76 | PEER_CAP_ADDPATH_AF_TX_RCV); |
759 | 76 | } |
760 | | |
761 | 42 | return 0; |
762 | 42 | } |
763 | | |
764 | | static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr) |
765 | 2 | { |
766 | 2 | struct stream *s = BGP_INPUT(peer); |
767 | 2 | size_t end = stream_get_getp(s) + hdr->length; |
768 | | |
769 | | /* Verify length is a multiple of 4 */ |
770 | 2 | if (hdr->length % 6) { |
771 | 0 | flog_warn( |
772 | 0 | EC_BGP_CAPABILITY_INVALID_LENGTH, |
773 | 0 | "Extended NH: Received invalid length %d, non-multiple of 6", |
774 | 0 | hdr->length); |
775 | 0 | return -1; |
776 | 0 | } |
777 | | |
778 | 86 | while (stream_get_getp(s) + 6 <= end) { |
779 | 84 | iana_afi_t pkt_afi = stream_getw(s); |
780 | 84 | afi_t afi; |
781 | 84 | iana_safi_t pkt_safi = stream_getw(s); |
782 | 84 | safi_t safi; |
783 | 84 | iana_afi_t pkt_nh_afi = stream_getw(s); |
784 | 84 | afi_t nh_afi; |
785 | | |
786 | 84 | if (bgp_debug_neighbor_events(peer)) |
787 | 0 | zlog_debug( |
788 | 84 | "%s Received with afi/safi/next-hop afi: %s/%s/%u", |
789 | 84 | peer->host, iana_afi2str(pkt_afi), |
790 | 84 | iana_safi2str(pkt_safi), pkt_nh_afi); |
791 | | |
792 | | /* Convert AFI, SAFI to internal values, check. */ |
793 | 84 | if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { |
794 | 84 | if (bgp_debug_neighbor_events(peer)) |
795 | 0 | zlog_debug( |
796 | 84 | "%s Addr-family %s/%s(afi/safi) not supported. Ignore the ENHE Attribute for this AFI/SAFI", |
797 | 84 | peer->host, iana_afi2str(pkt_afi), |
798 | 84 | iana_safi2str(pkt_safi)); |
799 | 84 | continue; |
800 | 84 | } |
801 | | |
802 | | /* RFC 5549 specifies use of this capability only for IPv4 AFI, |
803 | | * with |
804 | | * the Nexthop AFI being IPv6. A future spec may introduce other |
805 | | * possibilities, so we ignore other values with a log. Also, |
806 | | * only |
807 | | * SAFI_UNICAST and SAFI_LABELED_UNICAST are currently supported |
808 | | * (and expected). |
809 | | */ |
810 | 0 | nh_afi = afi_iana2int(pkt_nh_afi); |
811 | |
|
812 | 0 | if (afi != AFI_IP || nh_afi != AFI_IP6 |
813 | 0 | || !(safi == SAFI_UNICAST || safi == SAFI_MPLS_VPN |
814 | 0 | || safi == SAFI_LABELED_UNICAST)) { |
815 | 0 | flog_warn( |
816 | 0 | EC_BGP_CAPABILITY_INVALID_DATA, |
817 | 0 | "%s Unexpected afi/safi/next-hop afi: %s/%s/%u in Extended Next-hop capability, ignoring", |
818 | 0 | peer->host, iana_afi2str(pkt_afi), |
819 | 0 | iana_safi2str(pkt_safi), pkt_nh_afi); |
820 | 0 | continue; |
821 | 0 | } |
822 | | |
823 | 0 | SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_RCV); |
824 | |
|
825 | 0 | if (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_ADV)) |
826 | 0 | SET_FLAG(peer->af_cap[afi][safi], |
827 | 0 | PEER_CAP_ENHE_AF_NEGO); |
828 | 0 | } |
829 | | |
830 | 2 | SET_FLAG(peer->cap, PEER_CAP_ENHE_RCV); |
831 | | |
832 | 2 | return 0; |
833 | 2 | } |
834 | | |
835 | | static int bgp_capability_hostname(struct peer *peer, |
836 | | struct capability_header *hdr) |
837 | 9 | { |
838 | 9 | struct stream *s = BGP_INPUT(peer); |
839 | 9 | char str[BGP_MAX_HOSTNAME + 1]; |
840 | 9 | size_t end = stream_get_getp(s) + hdr->length; |
841 | 9 | uint8_t len; |
842 | | |
843 | 9 | SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV); |
844 | | |
845 | 9 | len = stream_getc(s); |
846 | 9 | if (stream_get_getp(s) + len > end) { |
847 | 0 | flog_warn( |
848 | 0 | EC_BGP_CAPABILITY_INVALID_DATA, |
849 | 0 | "%s: Received malformed hostname capability from peer %s", |
850 | 0 | __func__, peer->host); |
851 | 0 | return -1; |
852 | 0 | } |
853 | | |
854 | 9 | if (len > BGP_MAX_HOSTNAME) { |
855 | 0 | stream_get(str, s, BGP_MAX_HOSTNAME); |
856 | 0 | stream_forward_getp(s, len - BGP_MAX_HOSTNAME); |
857 | 0 | len = BGP_MAX_HOSTNAME; /* to set the '\0' below */ |
858 | 9 | } else if (len) |
859 | 0 | stream_get(str, s, len); |
860 | | |
861 | 9 | if (len) { |
862 | 0 | str[len] = '\0'; |
863 | |
|
864 | 0 | XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); |
865 | 0 | XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); |
866 | |
|
867 | 0 | peer->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, str); |
868 | 0 | } |
869 | | |
870 | 9 | if (stream_get_getp(s) + 1 > end) { |
871 | 0 | flog_warn( |
872 | 0 | EC_BGP_CAPABILITY_INVALID_DATA, |
873 | 0 | "%s: Received invalid domain name len (hostname capability) from peer %s", |
874 | 0 | __func__, peer->host); |
875 | 0 | return -1; |
876 | 0 | } |
877 | | |
878 | 9 | len = stream_getc(s); |
879 | 9 | if (stream_get_getp(s) + len > end) { |
880 | 0 | flog_warn( |
881 | 0 | EC_BGP_CAPABILITY_INVALID_DATA, |
882 | 0 | "%s: Received runt domain name (hostname capability) from peer %s", |
883 | 0 | __func__, peer->host); |
884 | 0 | return -1; |
885 | 0 | } |
886 | | |
887 | 9 | if (len > BGP_MAX_HOSTNAME) { |
888 | 0 | stream_get(str, s, BGP_MAX_HOSTNAME); |
889 | 0 | stream_forward_getp(s, len - BGP_MAX_HOSTNAME); |
890 | 0 | len = BGP_MAX_HOSTNAME; /* to set the '\0' below */ |
891 | 9 | } else if (len) |
892 | 0 | stream_get(str, s, len); |
893 | | |
894 | 9 | if (len) { |
895 | 0 | str[len] = '\0'; |
896 | |
|
897 | 0 | XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); |
898 | |
|
899 | 0 | peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str); |
900 | 0 | } |
901 | | |
902 | 9 | if (bgp_debug_neighbor_events(peer)) { |
903 | 0 | zlog_debug("%s received hostname %s, domainname %s", peer->host, |
904 | 0 | peer->hostname, peer->domainname); |
905 | 0 | } |
906 | | |
907 | 9 | return 0; |
908 | 9 | } |
909 | | |
910 | | static int bgp_capability_role(struct peer *peer, struct capability_header *hdr) |
911 | 1 | { |
912 | 1 | SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); |
913 | 1 | if (hdr->length != CAPABILITY_CODE_ROLE_LEN) { |
914 | 1 | flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, |
915 | 1 | "Role: Received invalid length %d", hdr->length); |
916 | 1 | return -1; |
917 | 1 | } |
918 | 0 | uint8_t role = stream_getc(BGP_INPUT(peer)); |
919 | |
|
920 | 0 | peer->remote_role = role; |
921 | 0 | return 0; |
922 | 1 | } |
923 | | |
924 | | static int bgp_capability_software_version(struct peer *peer, |
925 | | struct capability_header *hdr) |
926 | 7 | { |
927 | 7 | struct stream *s = BGP_INPUT(peer); |
928 | 7 | char str[BGP_MAX_SOFT_VERSION + 1]; |
929 | 7 | size_t end = stream_get_getp(s) + hdr->length; |
930 | 7 | uint8_t len; |
931 | | |
932 | 7 | SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); |
933 | | |
934 | 7 | len = stream_getc(s); |
935 | 7 | if (stream_get_getp(s) + len > end) { |
936 | 0 | flog_warn( |
937 | 0 | EC_BGP_CAPABILITY_INVALID_DATA, |
938 | 0 | "%s: Received malformed Software Version capability from peer %s", |
939 | 0 | __func__, peer->host); |
940 | 0 | return -1; |
941 | 0 | } |
942 | | |
943 | 7 | if (len > BGP_MAX_SOFT_VERSION) { |
944 | 0 | flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, |
945 | 0 | "%s: Received Software Version, but the length is too big, truncating, from peer %s", |
946 | 0 | __func__, peer->host); |
947 | 0 | stream_get(str, s, BGP_MAX_SOFT_VERSION); |
948 | 0 | stream_forward_getp(s, len - BGP_MAX_SOFT_VERSION); |
949 | 0 | len = BGP_MAX_SOFT_VERSION; |
950 | 7 | } else if (len) { |
951 | 0 | stream_get(str, s, len); |
952 | 0 | } |
953 | | |
954 | 7 | if (len) { |
955 | 0 | str[len] = '\0'; |
956 | |
|
957 | 0 | XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); |
958 | |
|
959 | 0 | peer->soft_version = XSTRDUP(MTYPE_BGP_SOFT_VERSION, str); |
960 | |
|
961 | 0 | if (bgp_debug_neighbor_events(peer)) |
962 | 0 | zlog_debug("%s sent Software Version: %s", peer->host, |
963 | 0 | peer->soft_version); |
964 | 0 | } |
965 | | |
966 | 7 | return 0; |
967 | 7 | } |
968 | | |
969 | | /** |
970 | | * Parse given capability. |
971 | | * XXX: This is reading into a stream, but not using stream API |
972 | | * |
973 | | * @param[out] mp_capability Set to 1 on return iff one or more Multiprotocol |
974 | | * capabilities were encountered. |
975 | | */ |
976 | | static int bgp_capability_parse(struct peer *peer, size_t length, |
977 | | int *mp_capability, uint8_t **error) |
978 | 81 | { |
979 | 81 | int ret; |
980 | 81 | struct stream *s = BGP_INPUT(peer); |
981 | 81 | size_t end = stream_get_getp(s) + length; |
982 | 81 | uint16_t restart_flag_time = 0; |
983 | | |
984 | 81 | assert(STREAM_READABLE(s) >= length); |
985 | | |
986 | 2.02k | while (stream_get_getp(s) < end) { |
987 | 1.97k | size_t start; |
988 | 1.97k | uint8_t *sp = stream_pnt(s); |
989 | 1.97k | struct capability_header caphdr; |
990 | | |
991 | 1.97k | ret = 0; |
992 | | /* We need at least capability code and capability length. */ |
993 | 1.97k | if (stream_get_getp(s) + 2 > end) { |
994 | 3 | zlog_info("%s Capability length error (< header)", |
995 | 3 | peer->host); |
996 | 3 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
997 | 3 | BGP_NOTIFY_OPEN_MALFORMED_ATTR); |
998 | 3 | return -1; |
999 | 3 | } |
1000 | | |
1001 | 1.97k | caphdr.code = stream_getc(s); |
1002 | 1.97k | caphdr.length = stream_getc(s); |
1003 | 1.97k | start = stream_get_getp(s); |
1004 | | |
1005 | | /* Capability length check sanity check. */ |
1006 | 1.97k | if (start + caphdr.length > end) { |
1007 | 32 | zlog_info("%s Capability length error (< length)", |
1008 | 32 | peer->host); |
1009 | 32 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1010 | 32 | BGP_NOTIFY_OPEN_MALFORMED_ATTR); |
1011 | 32 | return -1; |
1012 | 32 | } |
1013 | | |
1014 | 1.94k | if (bgp_debug_neighbor_events(peer)) |
1015 | 0 | zlog_debug("%s OPEN has %s capability (%u), length %u", |
1016 | 1.94k | peer->host, |
1017 | 1.94k | lookup_msg(capcode_str, caphdr.code, NULL), |
1018 | 1.94k | caphdr.code, caphdr.length); |
1019 | | |
1020 | | /* Length sanity check, type-specific, for known capabilities */ |
1021 | 1.94k | switch (caphdr.code) { |
1022 | 27 | case CAPABILITY_CODE_MP: |
1023 | 116 | case CAPABILITY_CODE_REFRESH: |
1024 | 150 | case CAPABILITY_CODE_REFRESH_OLD: |
1025 | 150 | case CAPABILITY_CODE_ORF: |
1026 | 153 | case CAPABILITY_CODE_ORF_OLD: |
1027 | 168 | case CAPABILITY_CODE_RESTART: |
1028 | 322 | case CAPABILITY_CODE_AS4: |
1029 | 364 | case CAPABILITY_CODE_ADDPATH: |
1030 | 364 | case CAPABILITY_CODE_DYNAMIC: |
1031 | 370 | case CAPABILITY_CODE_DYNAMIC_OLD: |
1032 | 372 | case CAPABILITY_CODE_ENHE: |
1033 | 381 | case CAPABILITY_CODE_FQDN: |
1034 | 384 | case CAPABILITY_CODE_ENHANCED_RR: |
1035 | 386 | case CAPABILITY_CODE_EXT_MESSAGE: |
1036 | 387 | case CAPABILITY_CODE_ROLE: |
1037 | 394 | case CAPABILITY_CODE_SOFT_VERSION: |
1038 | | /* Check length. */ |
1039 | 394 | if (caphdr.length < cap_minsizes[caphdr.code]) { |
1040 | 2 | zlog_info( |
1041 | 2 | "%s %s Capability length error: got %u, expected at least %u", |
1042 | 2 | peer->host, |
1043 | 2 | lookup_msg(capcode_str, caphdr.code, |
1044 | 2 | NULL), |
1045 | 2 | caphdr.length, |
1046 | 2 | (unsigned)cap_minsizes[caphdr.code]); |
1047 | 2 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1048 | 2 | BGP_NOTIFY_OPEN_MALFORMED_ATTR); |
1049 | 2 | return -1; |
1050 | 2 | } |
1051 | 392 | if (caphdr.length |
1052 | 334 | && caphdr.length % cap_modsizes[caphdr.code] != 0) { |
1053 | 0 | zlog_info( |
1054 | 0 | "%s %s Capability length error: got %u, expected a multiple of %u", |
1055 | 0 | peer->host, |
1056 | 0 | lookup_msg(capcode_str, caphdr.code, |
1057 | 0 | NULL), |
1058 | 0 | caphdr.length, |
1059 | 0 | (unsigned)cap_modsizes[caphdr.code]); |
1060 | 0 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1061 | 0 | BGP_NOTIFY_OPEN_MALFORMED_ATTR); |
1062 | 0 | return -1; |
1063 | 0 | } |
1064 | | /* we deliberately ignore unknown codes, see below */ |
1065 | 1.94k | default: |
1066 | 1.94k | break; |
1067 | 1.94k | } |
1068 | | |
1069 | 1.94k | switch (caphdr.code) { |
1070 | 26 | case CAPABILITY_CODE_MP: { |
1071 | 26 | *mp_capability = 1; |
1072 | | |
1073 | | /* Ignore capability when override-capability is set. */ |
1074 | 26 | if (!CHECK_FLAG(peer->flags, |
1075 | 26 | PEER_FLAG_OVERRIDE_CAPABILITY)) { |
1076 | | /* Set negotiated value. */ |
1077 | 26 | ret = bgp_capability_mp(peer, &caphdr); |
1078 | | |
1079 | | /* Unsupported Capability. */ |
1080 | 26 | if (ret < 0) { |
1081 | | /* Store return data. */ |
1082 | 26 | memcpy(*error, sp, caphdr.length + 2); |
1083 | 26 | *error += caphdr.length + 2; |
1084 | 26 | } |
1085 | 26 | ret = 0; /* Don't return error for this */ |
1086 | 26 | } |
1087 | 26 | } break; |
1088 | 3 | case CAPABILITY_CODE_ENHANCED_RR: |
1089 | 92 | case CAPABILITY_CODE_REFRESH: |
1090 | 126 | case CAPABILITY_CODE_REFRESH_OLD: { |
1091 | | /* BGP refresh capability */ |
1092 | 126 | if (caphdr.code == CAPABILITY_CODE_ENHANCED_RR) |
1093 | 3 | SET_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_RCV); |
1094 | 123 | else if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD) |
1095 | 34 | SET_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV); |
1096 | 89 | else |
1097 | 89 | SET_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV); |
1098 | 126 | } break; |
1099 | 0 | case CAPABILITY_CODE_ORF: |
1100 | 3 | case CAPABILITY_CODE_ORF_OLD: |
1101 | 3 | ret = bgp_capability_orf_entry(peer, &caphdr); |
1102 | 3 | break; |
1103 | 15 | case CAPABILITY_CODE_RESTART: |
1104 | 15 | ret = bgp_capability_restart(peer, &caphdr); |
1105 | 15 | break; |
1106 | 4 | case CAPABILITY_CODE_LLGR: |
1107 | 4 | ret = bgp_capability_llgr(peer, &caphdr); |
1108 | 4 | break; |
1109 | 0 | case CAPABILITY_CODE_DYNAMIC: |
1110 | 6 | case CAPABILITY_CODE_DYNAMIC_OLD: |
1111 | 6 | SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV); |
1112 | 6 | break; |
1113 | 153 | case CAPABILITY_CODE_AS4: |
1114 | | /* Already handled as a special-case parsing of the |
1115 | | * capabilities |
1116 | | * at the beginning of OPEN processing. So we care not a |
1117 | | * jot |
1118 | | * for the value really, only error case. |
1119 | | */ |
1120 | 153 | if (!bgp_capability_as4(peer, &caphdr)) |
1121 | 2 | ret = -1; |
1122 | 153 | break; |
1123 | 42 | case CAPABILITY_CODE_ADDPATH: |
1124 | 42 | ret = bgp_capability_addpath(peer, &caphdr); |
1125 | 42 | break; |
1126 | 2 | case CAPABILITY_CODE_ENHE: |
1127 | 2 | ret = bgp_capability_enhe(peer, &caphdr); |
1128 | 2 | break; |
1129 | 2 | case CAPABILITY_CODE_EXT_MESSAGE: |
1130 | 2 | ret = bgp_capability_ext_message(peer, &caphdr); |
1131 | 2 | break; |
1132 | 9 | case CAPABILITY_CODE_FQDN: |
1133 | 9 | ret = bgp_capability_hostname(peer, &caphdr); |
1134 | 9 | break; |
1135 | 1 | case CAPABILITY_CODE_ROLE: |
1136 | 1 | ret = bgp_capability_role(peer, &caphdr); |
1137 | 1 | break; |
1138 | 7 | case CAPABILITY_CODE_SOFT_VERSION: |
1139 | 7 | ret = bgp_capability_software_version(peer, &caphdr); |
1140 | 7 | break; |
1141 | 1.54k | default: |
1142 | 1.54k | if (caphdr.code > 128) { |
1143 | | /* We don't send Notification for unknown vendor |
1144 | | specific |
1145 | | capabilities. It seems reasonable for now... |
1146 | | */ |
1147 | 130 | flog_warn(EC_BGP_CAPABILITY_VENDOR, |
1148 | 130 | "%s Vendor specific capability %d", |
1149 | 130 | peer->host, caphdr.code); |
1150 | 1.41k | } else { |
1151 | 1.41k | flog_warn( |
1152 | 1.41k | EC_BGP_CAPABILITY_UNKNOWN, |
1153 | 1.41k | "%s unrecognized capability code: %d - ignored", |
1154 | 1.41k | peer->host, caphdr.code); |
1155 | 1.41k | memcpy(*error, sp, caphdr.length + 2); |
1156 | 1.41k | *error += caphdr.length + 2; |
1157 | 1.41k | } |
1158 | 1.94k | } |
1159 | | |
1160 | 1.94k | if (ret < 0) { |
1161 | 3 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1162 | 3 | BGP_NOTIFY_OPEN_MALFORMED_ATTR); |
1163 | 3 | return -1; |
1164 | 3 | } |
1165 | 1.93k | if (stream_get_getp(s) != (start + caphdr.length)) { |
1166 | 443 | if (stream_get_getp(s) > (start + caphdr.length)) |
1167 | 0 | flog_warn( |
1168 | 443 | EC_BGP_CAPABILITY_INVALID_LENGTH, |
1169 | 443 | "%s Cap-parser for %s read past cap-length, %u!", |
1170 | 443 | peer->host, |
1171 | 443 | lookup_msg(capcode_str, caphdr.code, |
1172 | 443 | NULL), |
1173 | 443 | caphdr.length); |
1174 | 443 | stream_set_getp(s, start + caphdr.length); |
1175 | 443 | } |
1176 | | |
1177 | 1.93k | if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) { |
1178 | 1.74k | UNSET_FLAG(restart_flag_time, 0xF000); |
1179 | 1.74k | peer->v_gr_restart = restart_flag_time; |
1180 | 1.74k | } |
1181 | 1.93k | } |
1182 | 41 | return 0; |
1183 | 81 | } |
1184 | | |
1185 | | static bool strict_capability_same(struct peer *peer) |
1186 | 0 | { |
1187 | 0 | int i, j; |
1188 | |
|
1189 | 0 | for (i = AFI_IP; i < AFI_MAX; i++) |
1190 | 0 | for (j = SAFI_UNICAST; j < SAFI_MAX; j++) |
1191 | 0 | if (peer->afc[i][j] != peer->afc_nego[i][j]) |
1192 | 0 | return false; |
1193 | 0 | return true; |
1194 | 0 | } |
1195 | | |
1196 | | |
1197 | | static bool bgp_role_violation(struct peer *peer) |
1198 | 5 | { |
1199 | 5 | uint8_t local_role = peer->local_role; |
1200 | 5 | uint8_t remote_role = peer->remote_role; |
1201 | | |
1202 | 5 | if (local_role != ROLE_UNDEFINED && remote_role != ROLE_UNDEFINED && |
1203 | 0 | !((local_role == ROLE_PEER && remote_role == ROLE_PEER) || |
1204 | 0 | (local_role == ROLE_PROVIDER && remote_role == ROLE_CUSTOMER) || |
1205 | 0 | (local_role == ROLE_CUSTOMER && remote_role == ROLE_PROVIDER) || |
1206 | 0 | (local_role == ROLE_RS_SERVER && remote_role == ROLE_RS_CLIENT) || |
1207 | 0 | (local_role == ROLE_RS_CLIENT && |
1208 | 0 | remote_role == ROLE_RS_SERVER))) { |
1209 | 0 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1210 | 0 | BGP_NOTIFY_OPEN_ROLE_MISMATCH); |
1211 | 0 | return true; |
1212 | 0 | } |
1213 | 5 | if (remote_role == ROLE_UNDEFINED && |
1214 | 5 | CHECK_FLAG(peer->flags, PEER_FLAG_ROLE_STRICT_MODE)) { |
1215 | 0 | const char *err_msg = |
1216 | 0 | "Strict mode. Please set the role on your side."; |
1217 | 0 | bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, |
1218 | 0 | BGP_NOTIFY_OPEN_ROLE_MISMATCH, |
1219 | 0 | (uint8_t *)err_msg, strlen(err_msg)); |
1220 | 0 | return true; |
1221 | 0 | } |
1222 | 5 | return false; |
1223 | 5 | } |
1224 | | |
1225 | | |
1226 | | /* peek into option, stores ASN to *as4 if the AS4 capability was found. |
1227 | | * Returns 0 if no as4 found, as4cap value otherwise. |
1228 | | */ |
1229 | | as_t peek_for_as4_capability(struct peer *peer, uint16_t length) |
1230 | 64 | { |
1231 | 64 | struct stream *s = BGP_INPUT(peer); |
1232 | 64 | size_t orig_getp = stream_get_getp(s); |
1233 | 64 | size_t end = orig_getp + length; |
1234 | 64 | as_t as4 = 0; |
1235 | | |
1236 | 64 | if (BGP_DEBUG(as4, AS4)) |
1237 | 0 | zlog_debug( |
1238 | 64 | "%s [AS4] rcv OPEN w/ OPTION parameter len: %u, peeking for as4", |
1239 | 64 | peer->host, length); |
1240 | | /* the error cases we DONT handle, we ONLY try to read as4 out of |
1241 | | * correctly formatted options. |
1242 | | */ |
1243 | 250 | while (stream_get_getp(s) < end) { |
1244 | 250 | uint8_t opt_type; |
1245 | 250 | uint16_t opt_length; |
1246 | | |
1247 | | /* Ensure we can read the option type */ |
1248 | 250 | if (stream_get_getp(s) + 1 > end) |
1249 | 0 | goto end; |
1250 | | |
1251 | | /* Fetch the option type */ |
1252 | 250 | opt_type = stream_getc(s); |
1253 | | |
1254 | | /* |
1255 | | * Check the length and fetch the opt_length |
1256 | | * If the peer is BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer) |
1257 | | * then we do a getw which is 2 bytes. So we need to |
1258 | | * ensure that we can read that as well |
1259 | | */ |
1260 | 250 | if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)) { |
1261 | 250 | if (stream_get_getp(s) + 2 > end) |
1262 | 4 | goto end; |
1263 | | |
1264 | 246 | opt_length = stream_getw(s); |
1265 | 246 | } else { |
1266 | 0 | if (stream_get_getp(s) + 1 > end) |
1267 | 0 | goto end; |
1268 | | |
1269 | 0 | opt_length = stream_getc(s); |
1270 | 0 | } |
1271 | | |
1272 | | /* Option length check. */ |
1273 | 246 | if (stream_get_getp(s) + opt_length > end) |
1274 | 11 | goto end; |
1275 | | |
1276 | 235 | if (opt_type == BGP_OPEN_OPT_CAP) { |
1277 | 55 | unsigned long capd_start = stream_get_getp(s); |
1278 | 55 | unsigned long capd_end = capd_start + opt_length; |
1279 | | |
1280 | 55 | assert(capd_end <= end); |
1281 | | |
1282 | 164 | while (stream_get_getp(s) < capd_end) { |
1283 | 158 | struct capability_header hdr; |
1284 | | |
1285 | 158 | if (stream_get_getp(s) + 2 > capd_end) |
1286 | 2 | goto end; |
1287 | | |
1288 | 156 | hdr.code = stream_getc(s); |
1289 | 156 | hdr.length = stream_getc(s); |
1290 | | |
1291 | 156 | if ((stream_get_getp(s) + hdr.length) |
1292 | 156 | > capd_end) |
1293 | 0 | goto end; |
1294 | | |
1295 | 156 | if (hdr.code == CAPABILITY_CODE_AS4) { |
1296 | 47 | if (BGP_DEBUG(as4, AS4)) |
1297 | 0 | zlog_debug( |
1298 | 47 | "[AS4] found AS4 capability, about to parse"); |
1299 | 47 | as4 = bgp_capability_as4(peer, &hdr); |
1300 | | |
1301 | 47 | goto end; |
1302 | 47 | } |
1303 | 109 | stream_forward_getp(s, hdr.length); |
1304 | 109 | } |
1305 | 55 | } |
1306 | 235 | } |
1307 | | |
1308 | 64 | end: |
1309 | 64 | stream_set_getp(s, orig_getp); |
1310 | 64 | return as4; |
1311 | 64 | } |
1312 | | |
1313 | | /** |
1314 | | * Parse open option. |
1315 | | * |
1316 | | * @param[out] mp_capability @see bgp_capability_parse() for semantics. |
1317 | | */ |
1318 | | int bgp_open_option_parse(struct peer *peer, uint16_t length, |
1319 | | int *mp_capability) |
1320 | 46 | { |
1321 | 46 | int ret = 0; |
1322 | 46 | uint8_t *error; |
1323 | 46 | uint8_t error_data[BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE]; |
1324 | 46 | struct stream *s = BGP_INPUT(peer); |
1325 | 46 | size_t end = stream_get_getp(s) + length; |
1326 | | |
1327 | 46 | error = error_data; |
1328 | | |
1329 | 46 | if (bgp_debug_neighbor_events(peer)) |
1330 | 0 | zlog_debug("%s rcv OPEN w/ OPTION parameter len: %u", |
1331 | 46 | peer->host, length); |
1332 | | |
1333 | | /* Unset any previously received GR capability. */ |
1334 | 46 | UNSET_FLAG(peer->cap, PEER_CAP_RESTART_RCV); |
1335 | | |
1336 | 87 | while (stream_get_getp(s) < end) { |
1337 | 82 | uint8_t opt_type; |
1338 | 82 | uint16_t opt_length; |
1339 | | |
1340 | | /* |
1341 | | * Check that we can read the opt_type and fetch it |
1342 | | */ |
1343 | 82 | if (STREAM_READABLE(s) < 1) { |
1344 | 0 | zlog_info("%s Option length error", peer->host); |
1345 | 0 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1346 | 0 | BGP_NOTIFY_OPEN_MALFORMED_ATTR); |
1347 | 0 | return -1; |
1348 | 0 | } |
1349 | 82 | opt_type = stream_getc(s); |
1350 | | |
1351 | | /* |
1352 | | * Check the length of the stream to ensure that |
1353 | | * FRR can properly read the opt_length. Then read it |
1354 | | */ |
1355 | 82 | if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)) { |
1356 | 82 | if (STREAM_READABLE(s) < 2) { |
1357 | 0 | zlog_info("%s Option length error", peer->host); |
1358 | 0 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1359 | 0 | BGP_NOTIFY_OPEN_MALFORMED_ATTR); |
1360 | 0 | return -1; |
1361 | 0 | } |
1362 | | |
1363 | 82 | opt_length = stream_getw(s); |
1364 | 82 | } else { |
1365 | 0 | if (STREAM_READABLE(s) < 1) { |
1366 | 0 | zlog_info("%s Option length error", peer->host); |
1367 | 0 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1368 | 0 | BGP_NOTIFY_OPEN_MALFORMED_ATTR); |
1369 | 0 | return -1; |
1370 | 0 | } |
1371 | | |
1372 | 0 | opt_length = stream_getc(s); |
1373 | 0 | } |
1374 | | |
1375 | | /* Option length check. */ |
1376 | 82 | if (STREAM_READABLE(s) < opt_length) { |
1377 | 1 | zlog_info("%s Option length error (%d)", peer->host, |
1378 | 1 | opt_length); |
1379 | 1 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1380 | 1 | BGP_NOTIFY_OPEN_MALFORMED_ATTR); |
1381 | 1 | return -1; |
1382 | 1 | } |
1383 | | |
1384 | 81 | if (bgp_debug_neighbor_events(peer)) |
1385 | 0 | zlog_debug( |
1386 | 81 | "%s rcvd OPEN w/ optional parameter type %u (%s) len %u", |
1387 | 81 | peer->host, opt_type, |
1388 | 81 | opt_type == BGP_OPEN_OPT_CAP ? "Capability" |
1389 | 81 | : "Unknown", |
1390 | 81 | opt_length); |
1391 | | |
1392 | 81 | switch (opt_type) { |
1393 | 81 | case BGP_OPEN_OPT_CAP: |
1394 | 81 | ret = bgp_capability_parse(peer, opt_length, |
1395 | 81 | mp_capability, &error); |
1396 | 81 | break; |
1397 | 0 | default: |
1398 | 0 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1399 | 0 | BGP_NOTIFY_OPEN_UNSUP_PARAM); |
1400 | 0 | ret = -1; |
1401 | 0 | break; |
1402 | 81 | } |
1403 | | |
1404 | | /* Parse error. To accumulate all unsupported capability codes, |
1405 | | bgp_capability_parse does not return -1 when encounter |
1406 | | unsupported capability code. To detect that, please check |
1407 | | error and erro_data pointer, like below. */ |
1408 | 81 | if (ret < 0) |
1409 | 40 | return -1; |
1410 | 81 | } |
1411 | | |
1412 | | /* All OPEN option is parsed. Check capability when strict compare |
1413 | | flag is enabled.*/ |
1414 | 5 | if (CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) { |
1415 | | /* If Unsupported Capability exists. */ |
1416 | 0 | if (error != error_data) { |
1417 | 0 | bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, |
1418 | 0 | BGP_NOTIFY_OPEN_UNSUP_CAPBL, |
1419 | 0 | error_data, |
1420 | 0 | error - error_data); |
1421 | 0 | return -1; |
1422 | 0 | } |
1423 | | |
1424 | | /* Check local capability does not negotiated with remote |
1425 | | peer. */ |
1426 | 0 | if (!strict_capability_same(peer)) { |
1427 | 0 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1428 | 0 | BGP_NOTIFY_OPEN_UNSUP_CAPBL); |
1429 | 0 | return -1; |
1430 | 0 | } |
1431 | 0 | } |
1432 | | |
1433 | | /* Extended Message Support */ |
1434 | 5 | peer->max_packet_size = |
1435 | 5 | (CHECK_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_RCV) |
1436 | 1 | && CHECK_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_ADV)) |
1437 | 5 | ? BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE |
1438 | 5 | : BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE; |
1439 | | |
1440 | | /* Check that roles are corresponding to each other */ |
1441 | 5 | if (bgp_role_violation(peer)) |
1442 | 0 | return -1; |
1443 | | |
1444 | | /* Check there are no common AFI/SAFIs and send Unsupported Capability |
1445 | | error. */ |
1446 | 5 | if (*mp_capability |
1447 | 2 | && !CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { |
1448 | 2 | if (!peer->afc_nego[AFI_IP][SAFI_UNICAST] |
1449 | 2 | && !peer->afc_nego[AFI_IP][SAFI_MULTICAST] |
1450 | 2 | && !peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] |
1451 | 2 | && !peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] |
1452 | 1 | && !peer->afc_nego[AFI_IP][SAFI_ENCAP] |
1453 | 1 | && !peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] |
1454 | 1 | && !peer->afc_nego[AFI_IP6][SAFI_UNICAST] |
1455 | 1 | && !peer->afc_nego[AFI_IP6][SAFI_MULTICAST] |
1456 | 1 | && !peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] |
1457 | 1 | && !peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] |
1458 | 1 | && !peer->afc_nego[AFI_IP6][SAFI_ENCAP] |
1459 | 1 | && !peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] |
1460 | 1 | && !peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) { |
1461 | 1 | flog_err(EC_BGP_PKT_OPEN, |
1462 | 1 | "%s [Error] Configured AFI/SAFIs do not overlap with received MP capabilities", |
1463 | 1 | peer->host); |
1464 | | |
1465 | 1 | if (error != error_data) |
1466 | 1 | bgp_notify_send_with_data( |
1467 | 1 | peer, BGP_NOTIFY_OPEN_ERR, |
1468 | 1 | BGP_NOTIFY_OPEN_UNSUP_CAPBL, error_data, |
1469 | 1 | error - error_data); |
1470 | 0 | else |
1471 | 0 | bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, |
1472 | 0 | BGP_NOTIFY_OPEN_UNSUP_CAPBL); |
1473 | 1 | return -1; |
1474 | 1 | } |
1475 | 2 | } |
1476 | 4 | return 0; |
1477 | 5 | } |
1478 | | |
1479 | | static void bgp_open_capability_orf(struct stream *s, struct peer *peer, |
1480 | | afi_t afi, safi_t safi, uint8_t code, |
1481 | | bool ext_opt_params) |
1482 | 0 | { |
1483 | 0 | uint16_t cap_len; |
1484 | 0 | uint8_t orf_len; |
1485 | 0 | unsigned long capp; |
1486 | 0 | unsigned long orfp; |
1487 | 0 | unsigned long numberp; |
1488 | 0 | int number_of_orfs = 0; |
1489 | 0 | iana_afi_t pkt_afi = IANA_AFI_IPV4; |
1490 | 0 | iana_safi_t pkt_safi = IANA_SAFI_UNICAST; |
1491 | | |
1492 | | /* Convert AFI, SAFI to values for packet. */ |
1493 | 0 | bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); |
1494 | |
|
1495 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1496 | 0 | capp = stream_get_endp(s); /* Set Capability Len Pointer */ |
1497 | 0 | ext_opt_params ? stream_putw(s, 0) |
1498 | 0 | : stream_putc(s, 0); /* Capability Length */ |
1499 | 0 | stream_putc(s, code); /* Capability Code */ |
1500 | 0 | orfp = stream_get_endp(s); /* Set ORF Len Pointer */ |
1501 | 0 | stream_putc(s, 0); /* ORF Length */ |
1502 | 0 | stream_putw(s, pkt_afi); |
1503 | 0 | stream_putc(s, 0); |
1504 | 0 | stream_putc(s, pkt_safi); |
1505 | 0 | numberp = stream_get_endp(s); /* Set Number Pointer */ |
1506 | 0 | stream_putc(s, 0); /* Number of ORFs */ |
1507 | | |
1508 | | /* Address Prefix ORF */ |
1509 | 0 | if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) |
1510 | 0 | || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) { |
1511 | 0 | stream_putc(s, (code == CAPABILITY_CODE_ORF |
1512 | 0 | ? ORF_TYPE_PREFIX |
1513 | 0 | : ORF_TYPE_PREFIX_OLD)); |
1514 | |
|
1515 | 0 | if (CHECK_FLAG(peer->af_flags[afi][safi], |
1516 | 0 | PEER_FLAG_ORF_PREFIX_SM) |
1517 | 0 | && CHECK_FLAG(peer->af_flags[afi][safi], |
1518 | 0 | PEER_FLAG_ORF_PREFIX_RM)) { |
1519 | 0 | SET_FLAG(peer->af_cap[afi][safi], |
1520 | 0 | PEER_CAP_ORF_PREFIX_SM_ADV); |
1521 | 0 | SET_FLAG(peer->af_cap[afi][safi], |
1522 | 0 | PEER_CAP_ORF_PREFIX_RM_ADV); |
1523 | 0 | stream_putc(s, ORF_MODE_BOTH); |
1524 | 0 | } else if (CHECK_FLAG(peer->af_flags[afi][safi], |
1525 | 0 | PEER_FLAG_ORF_PREFIX_SM)) { |
1526 | 0 | SET_FLAG(peer->af_cap[afi][safi], |
1527 | 0 | PEER_CAP_ORF_PREFIX_SM_ADV); |
1528 | 0 | stream_putc(s, ORF_MODE_SEND); |
1529 | 0 | } else { |
1530 | 0 | SET_FLAG(peer->af_cap[afi][safi], |
1531 | 0 | PEER_CAP_ORF_PREFIX_RM_ADV); |
1532 | 0 | stream_putc(s, ORF_MODE_RECEIVE); |
1533 | 0 | } |
1534 | 0 | number_of_orfs++; |
1535 | 0 | } |
1536 | | |
1537 | | /* Total Number of ORFs. */ |
1538 | 0 | stream_putc_at(s, numberp, number_of_orfs); |
1539 | | |
1540 | | /* Total ORF Len. */ |
1541 | 0 | orf_len = stream_get_endp(s) - orfp - 1; |
1542 | 0 | stream_putc_at(s, orfp, orf_len); |
1543 | | |
1544 | | /* Total Capability Len. */ |
1545 | 0 | cap_len = stream_get_endp(s) - capp - 1; |
1546 | 0 | ext_opt_params ? stream_putw_at(s, capp, cap_len) |
1547 | 0 | : stream_putc_at(s, capp, cap_len); |
1548 | 0 | } |
1549 | | |
1550 | | static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, |
1551 | | bool ext_opt_params) |
1552 | 0 | { |
1553 | 0 | int len; |
1554 | 0 | iana_afi_t pkt_afi = IANA_AFI_IPV4; |
1555 | 0 | afi_t afi; |
1556 | 0 | safi_t safi; |
1557 | 0 | iana_safi_t pkt_safi = IANA_SAFI_UNICAST; |
1558 | 0 | uint32_t restart_time; |
1559 | 0 | unsigned long capp = 0; |
1560 | 0 | unsigned long rcapp = 0; |
1561 | |
|
1562 | 0 | if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) |
1563 | 0 | && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) |
1564 | 0 | return; |
1565 | | |
1566 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
1567 | 0 | zlog_debug("[BGP_GR] Sending helper Capability for Peer :%s :", |
1568 | 0 | peer->host); |
1569 | |
|
1570 | 0 | SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); |
1571 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1572 | 0 | capp = stream_get_endp(s); /* Set Capability Len Pointer */ |
1573 | 0 | ext_opt_params ? stream_putw(s, 0) |
1574 | 0 | : stream_putc(s, 0); /* Capability Length */ |
1575 | 0 | stream_putc(s, CAPABILITY_CODE_RESTART); |
1576 | | /* Set Restart Capability Len Pointer */ |
1577 | 0 | rcapp = stream_get_endp(s); |
1578 | 0 | stream_putc(s, 0); |
1579 | 0 | restart_time = peer->bgp->restart_time; |
1580 | 0 | if (peer->bgp->t_startup) { |
1581 | 0 | SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT); |
1582 | 0 | SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); |
1583 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
1584 | 0 | zlog_debug("[BGP_GR] Sending R-Bit for peer: %s", |
1585 | 0 | peer->host); |
1586 | 0 | } |
1587 | |
|
1588 | 0 | if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { |
1589 | 0 | SET_FLAG(restart_time, GRACEFUL_RESTART_N_BIT); |
1590 | 0 | SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV); |
1591 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
1592 | 0 | zlog_debug("[BGP_GR] Sending N-Bit for peer: %s", |
1593 | 0 | peer->host); |
1594 | 0 | } |
1595 | |
|
1596 | 0 | stream_putw(s, restart_time); |
1597 | | |
1598 | | /* Send address-family specific graceful-restart capability |
1599 | | * only when GR config is present |
1600 | | */ |
1601 | 0 | if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) { |
1602 | 0 | if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD) |
1603 | 0 | && BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
1604 | 0 | zlog_debug("[BGP_GR] F bit Set"); |
1605 | |
|
1606 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
1607 | 0 | if (!peer->afc[afi][safi]) |
1608 | 0 | continue; |
1609 | | |
1610 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
1611 | 0 | zlog_debug( |
1612 | 0 | "[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:", |
1613 | 0 | afi, safi); |
1614 | | |
1615 | | /* Convert AFI, SAFI to values for |
1616 | | * packet. |
1617 | | */ |
1618 | 0 | bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, |
1619 | 0 | &pkt_safi); |
1620 | 0 | stream_putw(s, pkt_afi); |
1621 | 0 | stream_putc(s, pkt_safi); |
1622 | 0 | if (CHECK_FLAG(peer->bgp->flags, |
1623 | 0 | BGP_FLAG_GR_PRESERVE_FWD)) |
1624 | 0 | stream_putc(s, GRACEFUL_RESTART_F_BIT); |
1625 | 0 | else |
1626 | 0 | stream_putc(s, 0); |
1627 | 0 | } |
1628 | 0 | } |
1629 | | |
1630 | | /* Total Graceful restart capability Len. */ |
1631 | 0 | len = stream_get_endp(s) - rcapp - 1; |
1632 | 0 | stream_putc_at(s, rcapp, len); |
1633 | | |
1634 | | /* Total Capability Len. */ |
1635 | 0 | len = stream_get_endp(s) - capp - 1; |
1636 | 0 | ext_opt_params ? stream_putw_at(s, capp, len - 1) |
1637 | 0 | : stream_putc_at(s, capp, len); |
1638 | 0 | } |
1639 | | |
1640 | | static void bgp_peer_send_llgr_capability(struct stream *s, struct peer *peer, |
1641 | | bool ext_opt_params) |
1642 | 0 | { |
1643 | 0 | int len; |
1644 | 0 | iana_afi_t pkt_afi = IANA_AFI_IPV4; |
1645 | 0 | afi_t afi; |
1646 | 0 | safi_t safi; |
1647 | 0 | iana_safi_t pkt_safi = IANA_SAFI_UNICAST; |
1648 | 0 | unsigned long capp = 0; |
1649 | 0 | unsigned long rcapp = 0; |
1650 | |
|
1651 | 0 | if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)) |
1652 | 0 | return; |
1653 | | |
1654 | 0 | SET_FLAG(peer->cap, PEER_CAP_LLGR_ADV); |
1655 | |
|
1656 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1657 | 0 | capp = stream_get_endp(s); /* Set Capability Len Pointer */ |
1658 | 0 | ext_opt_params ? stream_putw(s, 0) |
1659 | 0 | : stream_putc(s, 0); /* Capability Length */ |
1660 | 0 | stream_putc(s, CAPABILITY_CODE_LLGR); |
1661 | |
|
1662 | 0 | rcapp = stream_get_endp(s); |
1663 | 0 | stream_putc(s, 0); |
1664 | |
|
1665 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
1666 | 0 | if (!peer->afc[afi][safi]) |
1667 | 0 | continue; |
1668 | | |
1669 | 0 | bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); |
1670 | |
|
1671 | 0 | stream_putw(s, pkt_afi); |
1672 | 0 | stream_putc(s, pkt_safi); |
1673 | 0 | stream_putc(s, LLGR_F_BIT); |
1674 | 0 | stream_put3(s, peer->bgp->llgr_stale_time); |
1675 | |
|
1676 | 0 | SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_LLGR_AF_ADV); |
1677 | 0 | } |
1678 | | |
1679 | | /* Total Long-lived Graceful Restart capability Len. */ |
1680 | 0 | len = stream_get_endp(s) - rcapp - 1; |
1681 | 0 | stream_putc_at(s, rcapp, len); |
1682 | | |
1683 | | /* Total Capability Len. */ |
1684 | 0 | len = stream_get_endp(s) - capp - 1; |
1685 | 0 | ext_opt_params ? stream_putw_at(s, capp, len - 1) |
1686 | 0 | : stream_putc_at(s, capp, len); |
1687 | 0 | } |
1688 | | |
1689 | | /* Fill in capability open option to the packet. */ |
1690 | | uint16_t bgp_open_capability(struct stream *s, struct peer *peer, |
1691 | | bool ext_opt_params) |
1692 | 0 | { |
1693 | 0 | uint16_t len; |
1694 | 0 | unsigned long cp, capp, rcapp, eopl = 0; |
1695 | 0 | iana_afi_t pkt_afi = IANA_AFI_IPV4; |
1696 | 0 | afi_t afi; |
1697 | 0 | safi_t safi; |
1698 | 0 | iana_safi_t pkt_safi = IANA_SAFI_UNICAST; |
1699 | 0 | as_t local_as; |
1700 | 0 | uint8_t afi_safi_count = 0; |
1701 | 0 | bool adv_addpath_tx = false; |
1702 | | |
1703 | | /* Non-Ext OP Len. */ |
1704 | 0 | cp = stream_get_endp(s); |
1705 | 0 | stream_putc(s, 0); |
1706 | |
|
1707 | 0 | if (ext_opt_params) { |
1708 | | /* Non-Ext OP Len. */ |
1709 | 0 | stream_putc_at(s, cp, BGP_OPEN_NON_EXT_OPT_LEN); |
1710 | | |
1711 | | /* Non-Ext OP Type */ |
1712 | 0 | stream_putc(s, BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH); |
1713 | | |
1714 | | /* Extended Opt. Parm. Length */ |
1715 | 0 | eopl = stream_get_endp(s); |
1716 | 0 | stream_putw(s, 0); |
1717 | 0 | } |
1718 | | |
1719 | | /* Do not send capability. */ |
1720 | 0 | if (!CHECK_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN) |
1721 | 0 | || CHECK_FLAG(peer->flags, PEER_FLAG_DONT_CAPABILITY)) |
1722 | 0 | return 0; |
1723 | | |
1724 | | /* MP capability for configured AFI, SAFI */ |
1725 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
1726 | 0 | if (peer->afc[afi][safi]) { |
1727 | | /* Convert AFI, SAFI to values for packet. */ |
1728 | 0 | bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, |
1729 | 0 | &pkt_safi); |
1730 | |
|
1731 | 0 | peer->afc_adv[afi][safi] = 1; |
1732 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1733 | 0 | ext_opt_params |
1734 | 0 | ? stream_putw(s, CAPABILITY_CODE_MP_LEN + 2) |
1735 | 0 | : stream_putc(s, CAPABILITY_CODE_MP_LEN + 2); |
1736 | 0 | stream_putc(s, CAPABILITY_CODE_MP); |
1737 | 0 | stream_putc(s, CAPABILITY_CODE_MP_LEN); |
1738 | 0 | stream_putw(s, pkt_afi); |
1739 | 0 | stream_putc(s, 0); |
1740 | 0 | stream_putc(s, pkt_safi); |
1741 | | |
1742 | | /* Extended nexthop capability - currently |
1743 | | * supporting RFC-5549 for |
1744 | | * Link-Local peering only |
1745 | | */ |
1746 | 0 | if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE) |
1747 | 0 | && peer->su.sa.sa_family == AF_INET6 |
1748 | 0 | && afi == AFI_IP |
1749 | 0 | && (safi == SAFI_UNICAST || safi == SAFI_MPLS_VPN |
1750 | 0 | || safi == SAFI_LABELED_UNICAST)) { |
1751 | | /* RFC 5549 Extended Next Hop Encoding |
1752 | | */ |
1753 | 0 | SET_FLAG(peer->cap, PEER_CAP_ENHE_ADV); |
1754 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1755 | 0 | ext_opt_params |
1756 | 0 | ? stream_putw(s, |
1757 | 0 | CAPABILITY_CODE_ENHE_LEN |
1758 | 0 | + 2) |
1759 | 0 | : stream_putc(s, |
1760 | 0 | CAPABILITY_CODE_ENHE_LEN |
1761 | 0 | + 2); |
1762 | 0 | stream_putc(s, CAPABILITY_CODE_ENHE); |
1763 | 0 | stream_putc(s, CAPABILITY_CODE_ENHE_LEN); |
1764 | |
|
1765 | 0 | SET_FLAG(peer->af_cap[AFI_IP][safi], |
1766 | 0 | PEER_CAP_ENHE_AF_ADV); |
1767 | 0 | stream_putw(s, pkt_afi); |
1768 | 0 | stream_putw(s, pkt_safi); |
1769 | 0 | stream_putw(s, afi_int2iana(AFI_IP6)); |
1770 | |
|
1771 | 0 | if (CHECK_FLAG(peer->af_cap[afi][safi], |
1772 | 0 | PEER_CAP_ENHE_AF_RCV)) |
1773 | 0 | SET_FLAG(peer->af_cap[afi][safi], |
1774 | 0 | PEER_CAP_ENHE_AF_NEGO); |
1775 | 0 | } |
1776 | 0 | } |
1777 | 0 | } |
1778 | | |
1779 | | /* Route refresh. */ |
1780 | 0 | SET_FLAG(peer->cap, PEER_CAP_REFRESH_ADV); |
1781 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1782 | 0 | ext_opt_params ? stream_putw(s, CAPABILITY_CODE_REFRESH_LEN + 2) |
1783 | 0 | : stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2); |
1784 | 0 | stream_putc(s, CAPABILITY_CODE_REFRESH_OLD); |
1785 | 0 | stream_putc(s, CAPABILITY_CODE_REFRESH_LEN); |
1786 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1787 | 0 | ext_opt_params ? stream_putw(s, CAPABILITY_CODE_REFRESH_LEN + 2) |
1788 | 0 | : stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2); |
1789 | 0 | stream_putc(s, CAPABILITY_CODE_REFRESH); |
1790 | 0 | stream_putc(s, CAPABILITY_CODE_REFRESH_LEN); |
1791 | | |
1792 | | /* Enhanced Route Refresh. */ |
1793 | 0 | SET_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_ADV); |
1794 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1795 | 0 | ext_opt_params ? stream_putw(s, CAPABILITY_CODE_ENHANCED_LEN + 2) |
1796 | 0 | : stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN + 2); |
1797 | 0 | stream_putc(s, CAPABILITY_CODE_ENHANCED_RR); |
1798 | 0 | stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN); |
1799 | | |
1800 | | /* AS4 */ |
1801 | 0 | SET_FLAG(peer->cap, PEER_CAP_AS4_ADV); |
1802 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1803 | 0 | ext_opt_params ? stream_putw(s, CAPABILITY_CODE_AS4_LEN + 2) |
1804 | 0 | : stream_putc(s, CAPABILITY_CODE_AS4_LEN + 2); |
1805 | 0 | stream_putc(s, CAPABILITY_CODE_AS4); |
1806 | 0 | stream_putc(s, CAPABILITY_CODE_AS4_LEN); |
1807 | 0 | if (peer->change_local_as) |
1808 | 0 | local_as = peer->change_local_as; |
1809 | 0 | else |
1810 | 0 | local_as = peer->local_as; |
1811 | 0 | stream_putl(s, local_as); |
1812 | | |
1813 | | /* Extended Message Support */ |
1814 | 0 | SET_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_ADV); |
1815 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1816 | 0 | ext_opt_params ? stream_putw(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2) |
1817 | 0 | : stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2); |
1818 | 0 | stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE); |
1819 | 0 | stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN); |
1820 | | |
1821 | | /* Role*/ |
1822 | 0 | if (peer->local_role != ROLE_UNDEFINED) { |
1823 | 0 | SET_FLAG(peer->cap, PEER_CAP_ROLE_ADV); |
1824 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1825 | 0 | stream_putc(s, CAPABILITY_CODE_ROLE_LEN + 2); |
1826 | 0 | stream_putc(s, CAPABILITY_CODE_ROLE); |
1827 | 0 | stream_putc(s, CAPABILITY_CODE_ROLE_LEN); |
1828 | 0 | stream_putc(s, peer->local_role); |
1829 | 0 | } |
1830 | | |
1831 | | /* AddPath */ |
1832 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
1833 | 0 | if (peer->afc[afi][safi]) { |
1834 | 0 | afi_safi_count++; |
1835 | | |
1836 | | /* Only advertise addpath TX if a feature that |
1837 | | * will use it is |
1838 | | * configured */ |
1839 | 0 | if (peer->addpath_type[afi][safi] != BGP_ADDPATH_NONE) |
1840 | 0 | adv_addpath_tx = true; |
1841 | | |
1842 | | /* If we have enabled labeled unicast, we MUST check |
1843 | | * against unicast SAFI because addpath IDs are |
1844 | | * allocated under unicast SAFI, the same as the RIB |
1845 | | * is managed in unicast SAFI. |
1846 | | */ |
1847 | 0 | if (safi == SAFI_LABELED_UNICAST) |
1848 | 0 | if (peer->addpath_type[afi][SAFI_UNICAST] != |
1849 | 0 | BGP_ADDPATH_NONE) |
1850 | 0 | adv_addpath_tx = true; |
1851 | 0 | } |
1852 | 0 | } |
1853 | |
|
1854 | 0 | SET_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV); |
1855 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1856 | 0 | ext_opt_params |
1857 | 0 | ? stream_putw(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count) |
1858 | 0 | + 2) |
1859 | 0 | : stream_putc(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count) |
1860 | 0 | + 2); |
1861 | 0 | stream_putc(s, CAPABILITY_CODE_ADDPATH); |
1862 | 0 | stream_putc(s, CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count); |
1863 | |
|
1864 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
1865 | 0 | if (peer->afc[afi][safi]) { |
1866 | 0 | bool adv_addpath_rx = |
1867 | 0 | !CHECK_FLAG(peer->af_flags[afi][safi], |
1868 | 0 | PEER_FLAG_DISABLE_ADDPATH_RX); |
1869 | 0 | uint8_t flags = 0; |
1870 | | |
1871 | | /* Convert AFI, SAFI to values for packet. */ |
1872 | 0 | bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, |
1873 | 0 | &pkt_safi); |
1874 | |
|
1875 | 0 | stream_putw(s, pkt_afi); |
1876 | 0 | stream_putc(s, pkt_safi); |
1877 | |
|
1878 | 0 | if (adv_addpath_rx) { |
1879 | 0 | SET_FLAG(flags, BGP_ADDPATH_RX); |
1880 | 0 | SET_FLAG(peer->af_cap[afi][safi], |
1881 | 0 | PEER_CAP_ADDPATH_AF_RX_ADV); |
1882 | 0 | } else { |
1883 | 0 | UNSET_FLAG(peer->af_cap[afi][safi], |
1884 | 0 | PEER_CAP_ADDPATH_AF_RX_ADV); |
1885 | 0 | } |
1886 | |
|
1887 | 0 | if (adv_addpath_tx) { |
1888 | 0 | SET_FLAG(flags, BGP_ADDPATH_TX); |
1889 | 0 | SET_FLAG(peer->af_cap[afi][safi], |
1890 | 0 | PEER_CAP_ADDPATH_AF_TX_ADV); |
1891 | 0 | if (safi == SAFI_LABELED_UNICAST) |
1892 | 0 | SET_FLAG( |
1893 | 0 | peer->af_cap[afi][SAFI_UNICAST], |
1894 | 0 | PEER_CAP_ADDPATH_AF_TX_ADV); |
1895 | 0 | } else { |
1896 | 0 | UNSET_FLAG(peer->af_cap[afi][safi], |
1897 | 0 | PEER_CAP_ADDPATH_AF_TX_ADV); |
1898 | 0 | } |
1899 | |
|
1900 | 0 | stream_putc(s, flags); |
1901 | 0 | } |
1902 | 0 | } |
1903 | | |
1904 | | /* ORF capability. */ |
1905 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
1906 | 0 | if (CHECK_FLAG(peer->af_flags[afi][safi], |
1907 | 0 | PEER_FLAG_ORF_PREFIX_SM) |
1908 | 0 | || CHECK_FLAG(peer->af_flags[afi][safi], |
1909 | 0 | PEER_FLAG_ORF_PREFIX_RM)) { |
1910 | 0 | bgp_open_capability_orf(s, peer, afi, safi, |
1911 | 0 | CAPABILITY_CODE_ORF_OLD, |
1912 | 0 | ext_opt_params); |
1913 | 0 | bgp_open_capability_orf(s, peer, afi, safi, |
1914 | 0 | CAPABILITY_CODE_ORF, |
1915 | 0 | ext_opt_params); |
1916 | 0 | } |
1917 | 0 | } |
1918 | | |
1919 | | /* Dynamic capability. */ |
1920 | 0 | if (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) { |
1921 | 0 | SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV); |
1922 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1923 | 0 | ext_opt_params |
1924 | 0 | ? stream_putw(s, CAPABILITY_CODE_DYNAMIC_LEN + 2) |
1925 | 0 | : stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2); |
1926 | 0 | stream_putc(s, CAPABILITY_CODE_DYNAMIC_OLD); |
1927 | 0 | stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN); |
1928 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1929 | 0 | ext_opt_params |
1930 | 0 | ? stream_putw(s, CAPABILITY_CODE_DYNAMIC_LEN + 2) |
1931 | 0 | : stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2); |
1932 | 0 | stream_putc(s, CAPABILITY_CODE_DYNAMIC); |
1933 | 0 | stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN); |
1934 | 0 | } |
1935 | | |
1936 | | /* Hostname capability */ |
1937 | 0 | if (cmd_hostname_get()) { |
1938 | 0 | SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV); |
1939 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1940 | 0 | rcapp = stream_get_endp(s); /* Ptr to length placeholder */ |
1941 | 0 | ext_opt_params ? stream_putw(s, 0) |
1942 | 0 | : stream_putc(s, 0); /* Capability Length */ |
1943 | 0 | stream_putc(s, CAPABILITY_CODE_FQDN); |
1944 | 0 | capp = stream_get_endp(s); |
1945 | 0 | stream_putc(s, 0); /* dummy len for now */ |
1946 | 0 | len = strlen(cmd_hostname_get()); |
1947 | 0 | if (len > BGP_MAX_HOSTNAME) |
1948 | 0 | len = BGP_MAX_HOSTNAME; |
1949 | |
|
1950 | 0 | stream_putc(s, len); |
1951 | 0 | stream_put(s, cmd_hostname_get(), len); |
1952 | 0 | if (cmd_domainname_get()) { |
1953 | 0 | len = strlen(cmd_domainname_get()); |
1954 | 0 | if (len > BGP_MAX_HOSTNAME) |
1955 | 0 | len = BGP_MAX_HOSTNAME; |
1956 | |
|
1957 | 0 | stream_putc(s, len); |
1958 | 0 | stream_put(s, cmd_domainname_get(), len); |
1959 | 0 | } else |
1960 | 0 | stream_putc(s, 0); /* 0 length */ |
1961 | | |
1962 | | /* Set the lengths straight */ |
1963 | 0 | len = stream_get_endp(s) - rcapp - 1; |
1964 | 0 | ext_opt_params ? stream_putw_at(s, rcapp, len - 1) |
1965 | 0 | : stream_putc_at(s, rcapp, len); |
1966 | |
|
1967 | 0 | len = stream_get_endp(s) - capp - 1; |
1968 | 0 | stream_putc_at(s, capp, len); |
1969 | |
|
1970 | 0 | if (bgp_debug_neighbor_events(peer)) |
1971 | 0 | zlog_debug( |
1972 | 0 | "%s Sending hostname cap with hn = %s, dn = %s", |
1973 | 0 | peer->host, cmd_hostname_get(), |
1974 | 0 | cmd_domainname_get()); |
1975 | 0 | } |
1976 | |
|
1977 | 0 | bgp_peer_send_gr_capability(s, peer, ext_opt_params); |
1978 | 0 | bgp_peer_send_llgr_capability(s, peer, ext_opt_params); |
1979 | | |
1980 | | /* Software Version capability |
1981 | | * An implementation is REQUIRED Extended Optional Parameters |
1982 | | * Length for BGP OPEN Message support as defined in [RFC9072]. |
1983 | | * The inclusion of the Software Version Capability is OPTIONAL. |
1984 | | * If an implementation supports the inclusion of the capability, |
1985 | | * the implementation MUST include a configuration switch to enable |
1986 | | * or disable its use, and that switch MUST be off by default. |
1987 | | */ |
1988 | 0 | if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION) || |
1989 | 0 | peer->sort == BGP_PEER_IBGP) { |
1990 | 0 | SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV); |
1991 | 0 | stream_putc(s, BGP_OPEN_OPT_CAP); |
1992 | 0 | rcapp = stream_get_endp(s); |
1993 | 0 | ext_opt_params ? stream_putw(s, 0) |
1994 | 0 | : stream_putc(s, 0); /* Capability Length */ |
1995 | 0 | stream_putc(s, CAPABILITY_CODE_SOFT_VERSION); |
1996 | 0 | capp = stream_get_endp(s); |
1997 | 0 | stream_putc(s, 0); /* dummy placeholder len */ |
1998 | | |
1999 | | /* The Capability Length SHOULD be no greater than 64. |
2000 | | * This is the limit to allow other capabilities as much |
2001 | | * space as they require. |
2002 | | */ |
2003 | 0 | len = strlen(cmd_software_version_get()); |
2004 | 0 | if (len > BGP_MAX_SOFT_VERSION) |
2005 | 0 | len = BGP_MAX_SOFT_VERSION; |
2006 | |
|
2007 | 0 | stream_putc(s, len); |
2008 | 0 | stream_put(s, cmd_software_version_get(), len); |
2009 | | |
2010 | | /* Software Version capability Len. */ |
2011 | 0 | len = stream_get_endp(s) - rcapp - 1; |
2012 | 0 | ext_opt_params ? stream_putw_at(s, rcapp, len - 1) |
2013 | 0 | : stream_putc_at(s, rcapp, len); |
2014 | | |
2015 | | /* Total Capability Len. */ |
2016 | 0 | len = stream_get_endp(s) - capp - 1; |
2017 | 0 | stream_putc_at(s, capp, len); |
2018 | |
|
2019 | 0 | if (bgp_debug_neighbor_events(peer)) |
2020 | 0 | zlog_debug("%s Sending Software Version cap, value: %s", |
2021 | 0 | peer->host, cmd_software_version_get()); |
2022 | 0 | } |
2023 | | |
2024 | | /* Total Opt Parm Len. */ |
2025 | 0 | len = stream_get_endp(s) - cp - 1; |
2026 | |
|
2027 | 0 | if (ext_opt_params) { |
2028 | 0 | len = stream_get_endp(s) - eopl - 2; |
2029 | 0 | stream_putw_at(s, eopl, len); |
2030 | 0 | } else { |
2031 | 0 | stream_putc_at(s, cp, len); |
2032 | 0 | } |
2033 | |
|
2034 | 0 | return len; |
2035 | 0 | } |