-
-
Notifications
You must be signed in to change notification settings - Fork 587
Expand file tree
/
Copy pathbgp_protocol.hpp
More file actions
853 lines (647 loc) · 30.4 KB
/
Copy pathbgp_protocol.hpp
File metadata and controls
853 lines (647 loc) · 30.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
#pragma once
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "dynamic_binary_buffer.hpp"
#include "fast_endianless.hpp"
#include "fast_library.hpp"
#include "fastnetmon_networks.hpp"
#include <boost/serialization/nvp.hpp>
#include "iana/iana_ip_protocols.hpp"
class bgp_attribute_origin;
class bgp_attribute_next_hop_ipv4;
class IPv4UnicastAnnounce;
class IPv6UnicastAnnounce;
extern log4cpp::Category& logger;
bool decode_bgp_subnet_encoding_ipv4(int len, uint8_t* value, subnet_cidr_mask_t& extracted_prefix, uint32_t& parsed_nlri_length);
uint32_t how_much_bytes_we_need_for_storing_certain_subnet_mask(uint8_t prefix_bit_length);
std::string get_bgp_attribute_name_by_number(uint8_t bgp_attribute_type);
enum BGP_PROTOCOL_MESSAGE_TYPES_UNTYPED : uint8_t {
BGP_PROTOCOL_MESSAGE_OPEN = 1,
BGP_PROTOCOL_MESSAGE_UPDATE = 2,
BGP_PROTOCOL_MESSAGE_NOTIFICATION = 3,
BGP_PROTOCOL_MESSAGE_KEEPALIVE = 4,
};
// More details here https://tools.ietf.org/html/rfc4271#page-12
class __attribute__((__packed__)) bgp_message_header_t {
public:
uint8_t marker[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
uint16_t length = 0;
uint8_t type = 0;
void host_byte_order_to_network_byte_order() {
length = htons(length);
}
};
static_assert(sizeof(bgp_message_header_t) == 19, "Broken size for bgp_message_header_t");
// https://www.ietf.org/rfc/rfc4271.txt pages 15 and 16
// https://github.com/osrg/gobgp/blob/d6148c75a30d87c3f8c1d0f68725127e4c5f3a65/packet/bgp.go#L3012
struct __attribute__((__packed__)) bgp_attribute_flags {
uint8_t : 4, extended_length_bit : 1 = 0, partial_bit : 1 = 0, transitive_bit : 1 = 0, optional_bit : 1 = 0;
bgp_attribute_flags(uint8_t flag_as_integer) {
memcpy(this, &flag_as_integer, sizeof(flag_as_integer));
}
bgp_attribute_flags() {
memset(this, 0, sizeof(*this));
}
void set_optional_bit(bool bit_value) {
optional_bit = (int)bit_value;
}
void set_transitive_bit(bool bit_value) {
transitive_bit = (int)bit_value;
}
void set_partial_bit(bool bit_value) {
partial_bit = (int)bit_value;
}
void set_extended_length_bit(bool bit_value) {
extended_length_bit = (int)bit_value;
}
bool get_optional_bit() {
return optional_bit == 1 ? true : false;
}
bool get_transitive_bit() {
return transitive_bit == 1 ? true : false;
}
bool get_partial_bit() {
return partial_bit == 1 ? true : false;
}
bool get_extended_length_bit() {
return extended_length_bit == 1 ? true : false;
}
std::string print() const {
std::stringstream buf;
buf << "optional: " << int(optional_bit) << " transitive: " << int(transitive_bit)
<< " partial_bit: " << int(partial_bit) << " extended_length_bit: " << int(extended_length_bit);
return buf.str();
}
};
class bgp_attibute_common_header_t {
public:
uint8_t attribute_flags = 0;
uint8_t attribute_type = 0;
uint32_t length_of_length_field = 0;
uint32_t attribute_value_length = 0;
uint32_t attribute_body_shift = 0;
// Just const value
uint32_t attribute_flag_and_type_length = 2;
std::string print() const {
std::stringstream buffer;
buffer << "attribute_flags: " << uint32_t(attribute_flags)
<< " "
// << "attribute_pretty_flags: " <<
// bgp_attribute_flags(attribute_flags).print() << " "
<< "attribute_type: " << uint32_t(attribute_type) << " "
<< "attribute_name: " << get_bgp_attribute_name_by_number(attribute_type) << " "
<< "length_of_length_field: " << length_of_length_field << " "
<< "attribute_value_length: " << attribute_value_length;
return buffer.str();
}
// More user friendly form
bool parse_raw_bgp_attribute_binary_buffer(dynamic_binary_buffer_t dynamic_binary_buffer) {
return parse_raw_bgp_attribute((uint8_t*)dynamic_binary_buffer.get_pointer(), dynamic_binary_buffer.get_used_size());
}
bool parse_raw_bgp_attribute(uint8_t* value, size_t len) {
if (len < attribute_flag_and_type_length or value == NULL) {
logger << log4cpp::Priority::WARN << "Too short attribute. We need least two bytes here but get " << len << " bytes";
return false;
}
// https://www.ietf.org/rfc/rfc4271.txt page 15
attribute_flags = value[0];
attribute_type = value[1];
bgp_attribute_flags attr_flags(attribute_flags);
// attr_flags.print();
length_of_length_field = 1;
if (attr_flags.extended_length_bit == 1) {
// When we have extended_length_bit we have two bytes for length
// information
length_of_length_field = 2;
}
if (len < attribute_flag_and_type_length + length_of_length_field) {
logger << log4cpp::Priority::WARN << "Too short attribute because we need least "
<< attribute_flag_and_type_length + length_of_length_field << " bytes";
return false;
}
if (length_of_length_field == 1) {
// Read one byte
attribute_value_length = value[2];
} else if (length_of_length_field == 2) {
// Read two bytes
attribute_value_length = fast_ntoh(*(uint16_t*)(value + 2));
} else {
logger << log4cpp::Priority::ERROR << "Broken length of length field: " << length_of_length_field;
return false;
}
uint32_t total_attribute_length = attribute_flag_and_type_length + length_of_length_field + attribute_value_length;
if (len < total_attribute_length) {
logger << log4cpp::Priority::WARN << "Atrribute value length: " << total_attribute_length
<< " length exceed whole packet length " << len;
return false;
}
// Store shift to attribute payload
attribute_body_shift = attribute_flag_and_type_length + length_of_length_field;
return true;
}
};
bool decode_attributes_to_ipv4_announce(char* value, int len, IPv4UnicastAnnounce& unicast_ipv4_announce);
bool encode_bgp_subnet_encoding(const subnet_cidr_mask_t& prefix, dynamic_binary_buffer_t& buffer_result);
std::string get_origin_name_by_value(uint8_t origin_value);
const unsigned int AFI_IP = 1;
const unsigned int AFI_IP6 = 2;
const unsigned int SAFI_UNICAST = 1;
const unsigned int SAFI_FLOW_SPEC_UNICAST = 133;
const unsigned int ipv4_unicast_route_family = AFI_IP << 16 | SAFI_UNICAST;
const unsigned int ipv4_flow_spec_route_family = AFI_IP << 16 | SAFI_FLOW_SPEC_UNICAST;
const unsigned int ipv6_unicast_route_family = AFI_IP6 << 16 | SAFI_UNICAST;
const unsigned int ipv6_flow_spec_route_family = AFI_IP6 << 16 | SAFI_FLOW_SPEC_UNICAST;
// http://www.iana.org/assignments/bgp-extended-communities/bgp-extended-communities.xhtml
// https://www.iana.org/assignments/bgp-extended-communities/bgp-extended-communities.xhtml#transitive
enum EXTENDED_COMMUNITY_TYPES_HIGHT_UNTYPED : uint8_t {
// Transitive IPv4-Address-Specific Extended Community (Sub-Types are defined in the "Transitive IPv4-Address-Specific Extended Community Sub-Types" registry)
EXTENDED_COMMUNITY_TRANSITIVE_IPV4_ADDRESS_SPECIFIC = 1, // 0x01
// We are encoding attributes for BGP flow spec this way
// Generic Transitive Experimental Use Extended Community
EXTENDED_COMMUNITY_TRANSITIVE_EXPEREMENTAL = 128, // 0x80
};
// Subtypes for EXTENDED_COMMUNITY_TRANSITIVE_EXPEREMENTAL
// http://www.iana.org/assignments/bgp-extended-communities/bgp-extended-communities.xhtml
// https://www.iana.org/assignments/bgp-extended-communities/bgp-extended-communities.xhtml#transitive
enum EXTENDED_COMMUNITY_TYPES_LOW_FOR_COMMUNITY_TRANSITIVE_EXPEREMENTAL : uint8_t {
FLOW_SPEC_EXTENDED_COMMUNITY_SUBTYPE_TRAFFIC_RATE = 6,
FLOW_SPEC_EXTENDED_COMMUNITY_SUBTYPE_TRAFFIC_ACTION = 7,
FLOW_SPEC_EXTENDED_COMMUNITY_SUBTYPE_REDIRECT_AS_TWO_BYTE = 8,
FLOW_SPEC_EXTENDED_COMMUNITY_SUBTYPE_TRAFFIC_REMARKING = 9,
};
enum BGP_ATTRIBUTES_TYPES : uint8_t {
// https://www.ietf.org/rfc/rfc4271.txt from page 17
BGP_ATTRIBUTE_ORIGIN = 1,
BGP_ATTRIBUTE_AS_PATH = 2,
BGP_ATTRIBUTE_NEXT_HOP = 3,
BGP_ATTRIBUTE_MULTI_EXIT_DISC = 4,
BGP_ATTRIBUTE_LOCAL_PREF = 5,
BGP_ATTRIBUTE_ATOMIC_AGGREGATE = 6,
BGP_ATTRIBUTE_AGGREGATOR = 7,
// https://tools.ietf.org/html/rfc1997 from page 1
BGP_ATTRIBUTE_COMMUNITY = 8,
// https://datatracker.ietf.org/doc/html/rfc4456#page-6
BGP_ATTRIBUTE_ORIGINATOR_ID = 9,
// https://datatracker.ietf.org/doc/html/rfc4456#page-6
BGP_ATTRIBUTE_CLUSTER_LIST = 10,
// https://tools.ietf.org/html/rfc4760 from page 2
BGP_ATTRIBUTE_MP_REACH_NLRI = 14,
// https://tools.ietf.org/html/rfc4360 from page 1
BGP_ATTRIBUTE_EXTENDED_COMMUNITY = 16,
};
// https://www.ietf.org/rfc/rfc4271.txt from page 17
enum BGP_ORIGIN_TYPES : uint8_t { BGP_ORIGIN_IGP = 0, BGP_ORIGIN_EGP = 1, BGP_ORIGIN_INCOMPLETE = 2 };
// https://www.iana.org/assignments/bgp-extended-communities/bgp-extended-communities.xhtml#trans-ipv4
enum BGP_IPV4_EXTENDED_COMMUNITY_SUBTYPES_TRANSITIVE : uint8_t {
BGP_IPV4_EXTENDED_COMMUNITY_SUBTYPE_FLOW_SPEC_REDIRECT_IPv4 = 0x0c,
};
// It's short MP reach NLRI header. We use it in case when we have non zero length for length_of_next_hop
// I use it only to decode/encode IPv6 annnounces
class __attribute__((__packed__)) bgp_mp_reach_short_header_t {
public:
uint16_t afi_identifier = AFI_IP6;
uint8_t safi_identifier = SAFI_UNICAST;
// According to https://www.ietf.org/rfc/rfc2545.txt we should set it to 16 for global IP addresses
uint8_t length_of_next_hop = 16;
void network_to_host_byte_order() {
afi_identifier = fast_ntoh(afi_identifier);
}
void host_byte_order_to_network_byte_order() {
afi_identifier = fast_hton(afi_identifier);
}
std::string print() const {
std::stringstream buffer;
buffer << "afi_identifier: " << uint32_t(afi_identifier) << " "
<< "safi_identifier: " << uint32_t(safi_identifier) << " "
<< "length_of_next_hop: " << uint32_t(length_of_next_hop);
return buffer.str();
}
};
class __attribute__((__packed__)) bgp_attribute_community_t {
public:
bgp_attribute_community_t() {
attribute_type = BGP_ATTRIBUTE_COMMUNITY;
// Set attribute flags
attribute_flags.set_transitive_bit(true);
attribute_flags.set_partial_bit(false);
attribute_flags.set_optional_bit(true);
attribute_flags.set_extended_length_bit(false);
}
bgp_attribute_flags attribute_flags;
uint8_t attribute_type = 0;
// This variable store total size in bytes of all community elements (each
// element should has
// size 4 bytes)
uint8_t attribute_length = 0;
// Here we have multiple elements of type: bgp_community_attribute_element_t
};
// Format of AS_PATH element described here: https://www.rfc-editor.org/rfc/rfc4271.html#page-17
// And with 32 bit / 4 byte ASN corrections from here: https://www.rfc-editor.org/rfc/rfc6793 page 2
// The AS path information exchanged between NEW BGP speakers is carried in the existing AS_PATH attribute,
// except that each AS number in the attribute is encoded as a four-octet entity (instead of a two-octet entity).
class __attribute__((__packed__)) bgp_as_path_segment_element_t {
public:
// Path segment type declares on of two possible types of segments:
// 1 AS_SET: unordered set of ASes a route in the UPDATE message has traversed
// 2 AS_SEQUENCE: ordered set of ASes a route in the UPDATE message has traversed
// We use AS_SEQUENCE as default option
uint8_t path_segment_type = 2;
// The path segment length is a 1-octet length field, containing the number of ASes (not the number of octets) in
// the path segment value field.
uint8_t path_segment_length = 0;
// Here we store list of 4 byte ASNs encoded in 4 byte format each
};
// BGP attribute AS_PATH
// In RFC this encoding format is covered here: https://www.rfc-editor.org/rfc/rfc4271.html#page-18
class __attribute__((__packed__)) bgp_attribute_as_path_t {
public:
bgp_attribute_as_path_t() {
attribute_type = BGP_ATTRIBUTE_AS_PATH;
// Set attribute flags
attribute_flags.set_transitive_bit(true);
attribute_flags.set_partial_bit(false);
// It's mandatory: https://www.rfc-editor.org/rfc/rfc4271.html#section-5.1.2
attribute_flags.set_optional_bit(false);
// Means that we using single octet length field encoding:
// https://www.rfc-editor.org/rfc/rfc4271.html#page-17
attribute_flags.set_extended_length_bit(false);
}
bgp_attribute_flags attribute_flags;
uint8_t attribute_type = 0;
// This variable store total size in bytes of all AS_PATH elements
uint8_t attribute_length = 0;
// Here we have multiple elements of type: bgp_as_path_segment_element_t
};
// This is new extended communities:
// More details: https://tools.ietf.org/html/rfc4360
class __attribute__((__packed__)) bgp_extended_community_attribute_t {
public:
bgp_extended_community_attribute_t() {
// Set attribute flags
attribute_flags.set_transitive_bit(true);
attribute_flags.set_partial_bit(false);
attribute_flags.set_optional_bit(true);
attribute_flags.set_extended_length_bit(false);
}
bgp_attribute_flags attribute_flags;
uint8_t attribute_type = BGP_ATTRIBUTE_EXTENDED_COMMUNITY;
// This variable store total size in bytes of all community elements. Each
// community element has
// size 8 bytes
uint8_t attribute_length = 0;
// Here we have multiple elements of type: bgp_extended_community_element_t
};
// BGP extended community attribute
class __attribute__((__packed__)) bgp_extended_community_element_t {
public:
uint8_t type_hight = 0;
uint8_t type_low = 0;
// This data depends on implementation and values in type_* variables
uint8_t value[6] = { 0, 0, 0, 0, 0, 0 };
std::string print() const {
std::stringstream buffer;
buffer << "type hight: " << uint32_t(type_hight) << " "
<< "type low: " << uint32_t(type_low) << " "
<< "value raw: " << print_binary_string_as_hex_with_leading_0x(value, sizeof(value));
return buffer.str();
}
};
static_assert(sizeof(bgp_extended_community_element_t) == 8, "Bad size for bgp_extended_community_element_t");
// This is class for storing old style BGP communities which support only 16
// bit AS numbers
class __attribute__((__packed__)) bgp_community_attribute_element_t {
public:
uint16_t asn_number = 0;
uint16_t community_number = 0;
bool operator==(const bgp_community_attribute_element_t& other) const {
return asn_number == other.asn_number && community_number == other.community_number;
}
void host_byte_order_to_network_byte_order() {
asn_number = htons(asn_number);
community_number = htons(community_number);
}
};
bool encode_bgp_flow_spec_elements_into_bgp_mp_attributebgp_community_from_string(std::string community_as_string,
bgp_community_attribute_element_t& bgp_community_attribute_element);
static_assert(sizeof(bgp_community_attribute_element_t) == 4, "Broken size of bgp_community_attribute_element_t");
// With this attribute we are encoding different things (flow spec for example)
class __attribute__((__packed__)) bgp_attribute_multiprotocol_extensions_t {
public:
bgp_attribute_multiprotocol_extensions_t() {
attribute_flags.set_transitive_bit(false);
attribute_flags.set_optional_bit(true);
attribute_flags.set_partial_bit(false);
attribute_flags.set_extended_length_bit(false);
}
std::string print() const {
std::stringstream buf;
buf << attribute_flags.print() << "attribute type: " << int(attribute_type)
<< " attribute_length: " << int(attribute_length);
return buf.str();
}
bgp_attribute_flags attribute_flags;
uint8_t attribute_type = BGP_ATTRIBUTE_MP_REACH_NLRI;
uint8_t attribute_length = 0;
// value has very complex format and we are encoding it with external code
};
class __attribute__((__packed__)) bgp_attribute_origin {
public:
bgp_attribute_origin() {
// Set attribute flags
attribute_flags.set_transitive_bit(true);
attribute_flags.set_partial_bit(false);
attribute_flags.set_optional_bit(false);
attribute_flags.set_extended_length_bit(false);
}
std::string print() const {
std::stringstream buf;
buf << attribute_flags.print() << "attribute type: " << int(attribute_type)
<< " attribute_length: " << int(attribute_length) << " attribute_value: " << attribute_value;
return buf.str();
}
bgp_attribute_flags attribute_flags;
uint8_t attribute_type = BGP_ATTRIBUTE_ORIGIN;
uint8_t attribute_length = 1;
uint8_t attribute_value = (uint8_t)BGP_ORIGIN_INCOMPLETE;
};
class __attribute__((__packed__)) bgp_attribute_next_hop_ipv4 {
public:
bgp_attribute_next_hop_ipv4() {
// Set attribute flags
attribute_flags.set_transitive_bit(true);
attribute_flags.set_partial_bit(false);
attribute_flags.set_optional_bit(false);
attribute_flags.set_extended_length_bit(false);
}
bgp_attribute_next_hop_ipv4(uint32_t next_hop) : bgp_attribute_next_hop_ipv4() {
attribute_value = next_hop;
}
bgp_attribute_flags attribute_flags;
uint8_t attribute_type = BGP_ATTRIBUTE_NEXT_HOP;
uint8_t attribute_length = 4;
uint32_t attribute_value = 0;
std::string print() const {
std::stringstream buf;
buf << attribute_flags.print() << "attribute type: " << int(attribute_type)
<< " attribute_length: " << int(attribute_length) << " attribute_value: " << attribute_value;
return buf.str();
}
};
class IPv4UnicastAnnounce {
public:
void set_withdraw(bool withdraw) {
this->is_withdraw = withdraw;
}
bool get_withdraw() {
return this->is_withdraw;
}
void set_next_hop(uint32_t next_hop) {
this->next_hop = next_hop;
}
void set_prefix(subnet_cidr_mask_t prefix) {
this->prefix = prefix;
}
void set_origin(BGP_ORIGIN_TYPES origin) {
this->origin = origin;
}
uint32_t get_next_hop() {
return next_hop;
}
subnet_cidr_mask_t get_prefix() const {
return this->prefix;
}
BGP_ORIGIN_TYPES get_origin() {
return this->origin;
}
// Returns prefix in text form
std::string get_prefix_in_cidr_form() {
return convert_ip_as_uint_to_string(prefix.subnet_address) + "/" + std::to_string(prefix.cidr_prefix_length);
}
bool generate_nlri(dynamic_binary_buffer_t& buffer_result) const {
return encode_bgp_subnet_encoding(this->prefix, buffer_result);
}
bool get_attributes(std::vector<dynamic_binary_buffer_t>& attributes_list) const {
/*
* The sender of an UPDATE message SHOULD order path attributes within
* the UPDATE message in ascending order of attribute type. The
* receiver of an UPDATE message MUST be prepared to handle path
* attributes within UPDATE messages that are out of order.
*/
bgp_attribute_origin origin_attr;
origin_attr.attribute_value = static_cast<uint8_t>(this->origin);
// logger << log4cpp::Priority::WARN << "origin_attr: " <<
// origin_attr.print() <<
// std::endl;
dynamic_binary_buffer_t origin_as_binary_array;
origin_as_binary_array.set_buffer_size_in_bytes(sizeof(origin_attr));
origin_as_binary_array.append_data_as_object_ptr(&origin_attr);
bgp_attribute_next_hop_ipv4 next_hop_attr(next_hop);
// logger << log4cpp::Priority::WARN << "next_hop_attr: " <<
// next_hop_attr.print() <<
// std::endl;
dynamic_binary_buffer_t next_hop_as_binary_array;
next_hop_as_binary_array.set_buffer_size_in_bytes(sizeof(next_hop_attr));
next_hop_as_binary_array.append_data_as_object_ptr(&next_hop_attr);
// Vector should be ordered in ascending order of attribute types
// Check numbers in enum BGP_ATTRIBUTES_TYPES for information
// We expect that we receive empty vector here
attributes_list.clear();
// It has attribute #1 and will be first in all the cases
attributes_list.push_back(origin_as_binary_array);
// AS Path should be here and it's #2
if (this->as_path_asns.size() > 0) {
// We have ASNs for AS_PATH attribute
bgp_attribute_as_path_t bgp_attribute_as_path;
uint64_t long_attribute_length = sizeof(bgp_as_path_segment_element_t) + this->as_path_asns.size() * sizeof(uint32_t);
// TODO: We need to enable extended length encoding when we have more than 255 bytes for attribute value
if (long_attribute_length > 255) {
logger << log4cpp::Priority::ERROR << "Too big AS_PATH attribute length: " << long_attribute_length;
return false;
}
// Populate attribute length
bgp_attribute_as_path.attribute_length = (uint8_t)long_attribute_length;
logger << log4cpp::Priority::DEBUG << "AS_PATH attribute length: " << uint32_t(bgp_attribute_as_path.attribute_length);
uint32_t as_path_attribute_full_length = sizeof(bgp_attribute_as_path_t) + bgp_attribute_as_path.attribute_length;
logger << log4cpp::Priority::DEBUG << "AS_PATH attribute full length: " << as_path_attribute_full_length;
dynamic_binary_buffer_t as_path_as_binary_array;
as_path_as_binary_array.set_buffer_size_in_bytes(as_path_attribute_full_length);
// Append attribute header
as_path_as_binary_array.append_data_as_object_ptr(&bgp_attribute_as_path);
bgp_as_path_segment_element_t bgp_as_path_segment_element;
// Numbers of ASNs in list
bgp_as_path_segment_element.path_segment_length = this->as_path_asns.size();
logger << log4cpp::Priority::DEBUG
<< "AS_PATH segments number: " << uint32_t(bgp_as_path_segment_element.path_segment_length);
// Append segment header
as_path_as_binary_array.append_data_as_object_ptr(&bgp_as_path_segment_element);
logger << log4cpp::Priority::DEBUG << "AS_PATH ASN number: " << this->as_path_asns.size();
for (auto asn : this->as_path_asns) {
// Append all ASNs in big endian encoding
uint32_t asn_big_endian = fast_hton(asn);
as_path_as_binary_array.append_data_as_object_ptr(&asn_big_endian);
}
if (as_path_as_binary_array.is_failed()) {
logger << log4cpp::Priority::ERROR << "Issue with storing AS_PATH";
}
attributes_list.push_back(as_path_as_binary_array);
}
// Vector should be ordered in ascending order of attribute types
// Next hop attribute is #3
attributes_list.push_back(next_hop_as_binary_array);
if (community_list.empty()) {
return true;
}
// We have communities
bgp_attribute_community_t bgp_attribute_community;
// Each record has this of 4 bytes
bgp_attribute_community.attribute_length = community_list.size() * sizeof(bgp_community_attribute_element_t);
uint32_t community_attribute_full_length = sizeof(bgp_attribute_community_t) + bgp_attribute_community.attribute_length;
dynamic_binary_buffer_t communities_list_as_binary_array;
communities_list_as_binary_array.set_buffer_size_in_bytes(community_attribute_full_length);
communities_list_as_binary_array.append_data_as_object_ptr(&bgp_attribute_community);
for (auto bgp_community_element : community_list) {
// TODO: Encode they in network byte order
// That's HORRIBLE and very error prone approach
bgp_community_element.host_byte_order_to_network_byte_order();
communities_list_as_binary_array.append_data_as_object_ptr(&bgp_community_element);
}
// Community is attribute #8
attributes_list.push_back(communities_list_as_binary_array);
return true;
}
std::string print() const {
std::stringstream buf;
buf << "Prefix: " << convert_ip_as_uint_to_string(prefix.subnet_address) << "/" << prefix.cidr_prefix_length << " "
<< "Origin: " << get_origin_name_by_value(origin) << " "
<< "Next hop: " << convert_ip_as_uint_to_string(next_hop) + "/32";
// TODO: print pretty communities!!!
return buf.str();
}
// Add multiple communities in single step
bool add_multiple_communities(std::vector<bgp_community_attribute_element_t> bgp_communities) {
for (auto bgp_community : bgp_communities) {
community_list.push_back(bgp_community);
}
return true;
}
bool add_community(bgp_community_attribute_element_t bgp_community) {
community_list.push_back(bgp_community);
return true;
}
std::vector<bgp_community_attribute_element_t> get_communities() const {
return community_list;
}
// Add ASN to AS_PATH
void add_asn_as_path(uint32_t asn) {
as_path_asns.push_back(asn);
}
// Sets AS_PATH to specified vector of uint32_t
void set_as_path(std::vector<uint32_t>& as_path_asns_param) {
as_path_asns = as_path_asns_param;
}
private:
uint32_t next_hop = 0;
subnet_cidr_mask_t prefix;
BGP_ORIGIN_TYPES origin = BGP_ORIGIN_INCOMPLETE;
bool is_withdraw = false;
// TODO: it's horrible encoding idea
// We store data here in little endian and then convert it into network byte order when need to send it to GoBGP
std::vector<bgp_community_attribute_element_t> community_list;
// List of ASNs in 32 bit format. May be empty
std::vector<uint32_t> as_path_asns;
};
class IPv6UnicastAnnounce {
public:
void set_withdraw(bool withdraw) {
this->is_withdraw = withdraw;
}
bool get_withdraw() {
return this->is_withdraw;
}
void set_next_hop(subnet_ipv6_cidr_mask_t next_hop) {
this->next_hop = next_hop;
}
void set_prefix(subnet_ipv6_cidr_mask_t prefix) {
this->prefix = prefix;
}
void set_origin(BGP_ORIGIN_TYPES origin) {
this->origin = origin;
}
subnet_ipv6_cidr_mask_t get_next_hop() const {
return next_hop;
}
subnet_ipv6_cidr_mask_t get_prefix() const {
return this->prefix;
}
BGP_ORIGIN_TYPES get_origin() const {
return this->origin;
}
std::string print() const {
std::stringstream buf;
buf << "Prefix: " << convert_ipv6_subnet_to_string(prefix) << " "
<< "Origin: " << get_origin_name_by_value(origin) << " "
<< "Next hop: " << convert_ipv6_subnet_to_string(next_hop);
return buf.str();
}
// Returns prefix in text form
std::string get_prefix_in_cidr_form() const {
return convert_ipv6_subnet_to_string(prefix);
}
// Add multiple communities in single step
bool add_multiple_communities(std::vector<bgp_community_attribute_element_t> bgp_communities) {
for (auto bgp_community : bgp_communities) {
community_list.push_back(bgp_community);
}
return true;
}
bool add_community(bgp_community_attribute_element_t bgp_community) {
community_list.push_back(bgp_community);
return true;
}
std::vector<bgp_community_attribute_element_t> get_communities() const {
return community_list;
}
// Add ASN to AS_PATH
void add_asn_as_path(uint32_t asn) {
as_path_asns.push_back(asn);
}
// Sets AS_PATH to specified vector of uint32_t
void set_as_path(std::vector<uint32_t>& as_path_asns_param) {
as_path_asns = as_path_asns_param;
}
private:
subnet_ipv6_cidr_mask_t next_hop{};
subnet_ipv6_cidr_mask_t prefix{};
BGP_ORIGIN_TYPES origin = BGP_ORIGIN_INCOMPLETE;
bool is_withdraw = false;
// TODO: it's horrible encoding idea
// We store data here in little endian and then convert it into network byte order when need to send it to GoBGP
std::vector<bgp_community_attribute_element_t> community_list;
// TODO: we need to rework AnnounceUnicastPrefixLowLevelIPv6
// and pull all logic from it into get_attributes() right here
public:
// List of ASNs in 32 bit format. May be empty
std::vector<uint32_t> as_path_asns;
};
static_assert(sizeof(bgp_attribute_flags) == 1, "broken size for bgp_attribute_flags");
static_assert(sizeof(bgp_attribute_origin) == 4, "Bad size for bgp_attribute_origin");
static_assert(sizeof(bgp_attribute_next_hop_ipv4) == 7, "Bad size for bgp_attribute_next_hop_ipv4");
bool is_bgp_community_valid(std::string community_as_string);
bool decode_ipv6_announce_from_binary_encoded_atributes(std::vector<dynamic_binary_buffer_t> binary_attributes,
IPv6UnicastAnnounce& ipv6_announce);
bool decode_mp_reach_attribute_to_ipv6_announce(uint8_t* data,
int length,
bgp_attibute_common_header_t bgp_attibute_common_header,
IPv6UnicastAnnounce& ipv6_announce);
bool encode_ipv6_announces_into_bgp_mp_reach_attribute_internal(const IPv6UnicastAnnounce& ipv6_announce,
dynamic_binary_buffer_t& bgp_mp_reach_ipv6_attribute);
bool encode_ipv6_announces_into_bgp_mp_reach_attribute(const IPv6UnicastAnnounce& ipv6_announce,
dynamic_binary_buffer_t& bgp_mp_reach_ipv6_attribute);
bool encode_ipv6_prefix(const subnet_ipv6_cidr_mask_t& prefix, dynamic_binary_buffer_t& dynamic_buffer);
bool read_bgp_community_from_string(std::string community_as_string, bgp_community_attribute_element_t& bgp_community_attribute_element);