Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include "bgp/extended-community/site_of_origin.h"
7 :
8 : #include <algorithm>
9 :
10 : #include "base/address.h"
11 : #include "bgp/bgp_common.h"
12 :
13 : using std::copy;
14 : using std::string;
15 :
16 : SiteOfOrigin SiteOfOrigin::null_soo;
17 :
18 37688 : SiteOfOrigin::SiteOfOrigin() {
19 37688 : data_.fill(0);
20 37688 : }
21 :
22 352 : SiteOfOrigin::SiteOfOrigin(const bytes_type &data) {
23 352 : copy(data.begin(), data.end(), data_.begin());
24 352 : }
25 :
26 24 : string SiteOfOrigin::ToString() const {
27 : uint8_t data[SiteOfOrigin::kSize];
28 24 : copy(data_.begin(), data_.end(), &data[0]);
29 24 : if (data[0] == 0) {
30 8 : uint16_t asn = get_value(data + 2, 2);
31 8 : uint32_t num = get_value(data + 4, 4);
32 : char temp[50];
33 8 : snprintf(temp, sizeof(temp), "soo:%u:%u", asn, num);
34 8 : return string(temp);
35 16 : } else if (data[0] == 2) {
36 8 : uint32_t asn = get_value(data + 2, 4);
37 8 : uint16_t num = get_value(data + 6, 2);
38 : char temp[50];
39 8 : snprintf(temp, sizeof(temp), "soo:%u:%u", asn, num);
40 8 : return string(temp);
41 : } else {
42 8 : Ip4Address addr(get_value(data + 2, 4));
43 8 : uint16_t num = get_value(data + 6, 2);
44 : char temp[50];
45 8 : snprintf(temp, sizeof(temp), "soo:%s:%u",
46 16 : addr.to_string().c_str(), num);
47 8 : return string(temp);
48 : }
49 : }
50 :
51 73 : SiteOfOrigin SiteOfOrigin::FromString(const string &str,
52 : boost::system::error_code *errorp) {
53 73 : SiteOfOrigin soo;
54 : uint8_t data[SiteOfOrigin::kSize];
55 :
56 : // soo:1:2 OR soo:1.2.3.4:3
57 73 : size_t pos = str.find(':');
58 73 : if (pos == string::npos) {
59 1 : if (errorp != NULL) {
60 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
61 : }
62 1 : return SiteOfOrigin::null_soo;
63 : }
64 :
65 72 : string first(str.substr(0, pos));
66 72 : if (first != "soo") {
67 3 : if (errorp != NULL) {
68 3 : *errorp = make_error_code(boost::system::errc::invalid_argument);
69 : }
70 3 : return SiteOfOrigin::null_soo;
71 : }
72 :
73 69 : string rest(str.substr(pos+1));
74 :
75 69 : pos = rest.find(':');
76 69 : if (pos == string::npos) {
77 1 : if (errorp != NULL) {
78 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
79 : }
80 1 : return SiteOfOrigin::null_soo;
81 : }
82 :
83 68 : boost::system::error_code ec;
84 68 : string second(rest.substr(0, pos));
85 68 : Ip4Address addr = Ip4Address::from_string(second, ec);
86 : int offset;
87 : char *endptr;
88 68 : if (ec.failed()) {
89 : // Not an IP address. Try ASN
90 61 : int64_t asn = strtol(second.c_str(), &endptr, 10);
91 61 : if (asn == 0 || asn > 0xFFFFFFFF || *endptr != '\0') {
92 2 : if (errorp != NULL) {
93 : *errorp =
94 2 : make_error_code(boost::system::errc::invalid_argument);
95 : }
96 2 : return SiteOfOrigin::null_soo;
97 : }
98 :
99 59 : if (asn > AS2_MAX) {
100 4 : data[0] = BgpExtendedCommunityType::FourOctetAS;
101 4 : put_value(&data[2], 4, asn);
102 4 : offset = 6;
103 : } else {
104 55 : data[0] = BgpExtendedCommunityType::TwoOctetAS;
105 55 : put_value(&data[2], 2, asn);
106 55 : offset = 4;
107 : }
108 59 : data[1] = BgpExtendedCommunitySubType::RouteOrigin;
109 : } else {
110 7 : data[0] = BgpExtendedCommunityType::IPv4Address;
111 7 : data[1] = BgpExtendedCommunitySubType::RouteOrigin;
112 7 : uint32_t l_addr = addr.to_ulong();
113 7 : put_value(&data[2], 4, l_addr);
114 7 : offset = 6;
115 : }
116 :
117 66 : string third(rest.substr(pos+1));
118 66 : uint64_t value = strtol(third.c_str(), &endptr, 10);
119 66 : if (*endptr != '\0') {
120 4 : if (errorp != NULL) {
121 4 : *errorp = make_error_code(boost::system::errc::invalid_argument);
122 : }
123 4 : return SiteOfOrigin::null_soo;
124 : }
125 :
126 : // Check assigned number for type 0.
127 62 : if (offset == 4 && value > 0xFFFFFFFF) {
128 1 : if (errorp != NULL) {
129 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
130 : }
131 1 : return SiteOfOrigin::null_soo;
132 : }
133 :
134 : // Check assigned number for type 1.
135 61 : if (offset == 6 && value > 0xFFFF) {
136 1 : if (errorp != NULL) {
137 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
138 : }
139 1 : return SiteOfOrigin::null_soo;
140 : }
141 :
142 60 : put_value(&data[offset], SiteOfOrigin::kSize - offset, value);
143 60 : copy(&data[0], &data[SiteOfOrigin::kSize], soo.data_.begin());
144 60 : return soo;
145 72 : }
|