Line data Source code
1 : /*
2 : * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include "bgp/inet6vpn/inet6vpn_route.h"
7 :
8 : #include <algorithm>
9 :
10 : #include "bgp/inet6vpn/inet6vpn_table.h"
11 : #include "bgp/inet6/inet6_route.h"
12 :
13 : using std::copy;
14 : using std::string;
15 : using std::vector;
16 :
17 65005 : Inet6VpnPrefix::Inet6VpnPrefix() : prefixlen_(0) {
18 65005 : }
19 :
20 49829 : int Inet6VpnPrefix::FromProtoPrefix(const BgpProtoPrefix &proto_prefix,
21 : Inet6VpnPrefix *prefix, uint32_t *label) {
22 49829 : size_t nlri_size = proto_prefix.prefix.size();
23 49829 : size_t expected_min_nlri_size =
24 49829 : BgpProtoPrefix::kLabelSize + RouteDistinguisher::kSize;
25 :
26 49829 : if (nlri_size < expected_min_nlri_size)
27 1 : return -1;
28 49828 : if (nlri_size > expected_min_nlri_size + Address::kMaxV6Bytes)
29 1 : return -1;
30 :
31 49827 : size_t label_offset = 0;
32 49827 : *label = proto_prefix.ReadLabel(label_offset);
33 49827 : size_t rd_offset = label_offset + BgpProtoPrefix::kLabelSize;
34 49827 : prefix->rd_ = RouteDistinguisher(&proto_prefix.prefix[rd_offset]);
35 :
36 49827 : size_t prefix_offset = rd_offset + RouteDistinguisher::kSize;
37 49827 : prefix->prefixlen_ = proto_prefix.prefixlen - prefix_offset * 8;
38 49827 : Ip6Address::bytes_type bt = { { 0 } };
39 49827 : copy(proto_prefix.prefix.begin() + prefix_offset,
40 : proto_prefix.prefix.end(), bt.begin());
41 49827 : prefix->addr_ = Ip6Address(bt);
42 :
43 49827 : return 0;
44 : }
45 :
46 49824 : int Inet6VpnPrefix::FromProtoPrefix(BgpServer *server,
47 : const BgpProtoPrefix &proto_prefix,
48 : const BgpAttr *attr,
49 : const Address::Family family,
50 : Inet6VpnPrefix *prefix,
51 : BgpAttrPtr *new_attr, uint32_t *label,
52 : uint32_t *l3_label) {
53 49824 : return FromProtoPrefix(proto_prefix, prefix, label);
54 : }
55 :
56 57195 : void Inet6VpnPrefix::BuildProtoPrefix(uint32_t label,
57 : BgpProtoPrefix *proto_prefix) const {
58 57195 : proto_prefix->prefix.clear();
59 57199 : size_t prefix_size = (prefixlen_ + 7) / 8;
60 57199 : size_t nlri_size =
61 57199 : BgpProtoPrefix::kLabelSize + RouteDistinguisher::kSize + prefix_size;
62 :
63 57199 : proto_prefix->prefix.resize(nlri_size, 0);
64 57202 : size_t label_offset = 0;
65 57202 : proto_prefix->WriteLabel(label_offset, label);
66 57202 : size_t rd_offset = label_offset + BgpProtoPrefix::kLabelSize;
67 57203 : copy(rd_.GetData(), rd_.GetData() + RouteDistinguisher::kSize,
68 57202 : proto_prefix->prefix.begin() + rd_offset);
69 :
70 57197 : size_t prefix_offset = rd_offset + RouteDistinguisher::kSize;
71 57197 : proto_prefix->prefixlen = prefix_offset * 8 + prefixlen_;
72 57197 : const Ip6Address::bytes_type &addr_bytes = addr_.to_bytes();
73 57198 : copy(addr_bytes.begin(), addr_bytes.begin() + prefix_size,
74 57199 : proto_prefix->prefix.begin() + prefix_offset);
75 57192 : }
76 :
77 : // RD:inet6-prefix
78 15174 : Inet6VpnPrefix Inet6VpnPrefix::FromString(const string &str,
79 : boost::system::error_code *errorp) {
80 15174 : Inet6VpnPrefix prefix;
81 :
82 15174 : size_t pos = str.find(':');
83 15174 : if (pos == string::npos) {
84 1 : if (errorp != NULL) {
85 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
86 : }
87 1 : return prefix;
88 : }
89 15173 : pos = str.find(':', (pos + 1));
90 15173 : if (pos == string::npos) {
91 1 : if (errorp != NULL) {
92 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
93 : }
94 1 : return prefix;
95 : }
96 15172 : string rdstr = str.substr(0, pos);
97 15172 : boost::system::error_code rderr;
98 15172 : prefix.rd_ = RouteDistinguisher::FromString(rdstr, &rderr);
99 15172 : if (rderr.failed()) {
100 7 : if (errorp != NULL) {
101 5 : *errorp = rderr;
102 : }
103 7 : return prefix;
104 : }
105 :
106 15165 : string ip6pstr(str, pos + 1);
107 15165 : boost::system::error_code pfxerr = Inet6SubnetParse(ip6pstr, &prefix.addr_,
108 : &prefix.prefixlen_);
109 15165 : if (errorp != NULL) {
110 1589 : *errorp = pfxerr;
111 : }
112 15165 : return prefix;
113 15172 : }
114 :
115 9 : string Inet6VpnPrefix::ToString() const {
116 9 : Inet6Prefix prefix(addr_, prefixlen_);
117 18 : return (rd_.ToString() + ":" + prefix.ToString());
118 : }
119 :
120 : // Check whether 'this' is more specific than rhs.
121 35 : bool Inet6VpnPrefix::IsMoreSpecific(const Inet6VpnPrefix &rhs) const {
122 35 : Inet6Prefix this_prefix(addr_, prefixlen_);
123 35 : Inet6Prefix match_prefix(rhs.addr(), rhs.prefixlen());
124 :
125 70 : return this_prefix.IsMoreSpecific(match_prefix);
126 : }
127 :
128 1499237 : int Inet6VpnPrefix::CompareTo(const Inet6VpnPrefix &other) const {
129 1499237 : int res = route_distinguisher().CompareTo(other.route_distinguisher());
130 1499433 : if (res != 0) {
131 887724 : return res;
132 : }
133 611709 : Ip6Address laddr = addr();
134 611665 : Ip6Address raddr = other.addr();
135 611605 : if (laddr < raddr) {
136 216261 : return -1;
137 : }
138 395917 : if (laddr > raddr) {
139 173005 : return 1;
140 : }
141 222894 : if (prefixlen() < other.prefixlen()) {
142 16 : return -1;
143 : }
144 222907 : if (prefixlen() > other.prefixlen()) {
145 8 : return 1;
146 : }
147 222883 : return 0;
148 : }
149 :
150 9 : bool Inet6VpnPrefix::operator==(const Inet6VpnPrefix &rhs) const {
151 18 : return (rd_ == rhs.rd_ && addr_ == rhs.addr_ &&
152 18 : prefixlen_ == rhs.prefixlen_);
153 : }
154 :
155 196398 : Inet6VpnRoute::Inet6VpnRoute(const Inet6VpnPrefix &prefix) : prefix_(prefix) {
156 196381 : }
157 :
158 1499348 : int Inet6VpnRoute::CompareTo(const Route &rhs) const {
159 1499348 : const Inet6VpnRoute &other = static_cast<const Inet6VpnRoute &>(rhs);
160 1499348 : return prefix_.CompareTo(other.GetPrefix());
161 : }
162 :
163 440765 : string Inet6VpnRoute::ToString() const {
164 440765 : string repr = prefix_.route_distinguisher().ToString() + ":";
165 440762 : repr += prefix_.addr().to_string();
166 : char strplen[5];
167 440765 : snprintf(strplen, sizeof(strplen), "/%d", prefix_.prefixlen());
168 440761 : repr.append(strplen);
169 :
170 881536 : return repr;
171 0 : }
172 :
173 2 : void Inet6VpnRoute::SetKey(const DBRequestKey *reqkey) {
174 2 : const Inet6VpnTable::RequestKey *key =
175 : static_cast<const Inet6VpnTable::RequestKey *>(reqkey);
176 2 : prefix_ = key->prefix;
177 2 : }
178 :
179 57195 : void Inet6VpnRoute::BuildProtoPrefix(BgpProtoPrefix *prefix,
180 : const BgpAttr*,
181 : uint32_t label,
182 : uint32_t l3_label) const {
183 57195 : prefix_.BuildProtoPrefix(label, prefix);
184 57192 : }
185 :
186 : // XXX dest_nh should have been pointer. See if can change
187 30254 : void Inet6VpnRoute::BuildBgpProtoNextHop(vector<uint8_t> &dest_nh,
188 : IpAddress src_nh) const {
189 30254 : dest_nh.resize(sizeof(Ip6Address::bytes_type) + RouteDistinguisher::kSize,
190 30254 : 0);
191 30253 : Ip6Address source_addr;
192 30251 : if (src_nh.is_v4()) {
193 30249 : source_addr = Ip6Address::v4_mapped(src_nh.to_v4());
194 0 : } else if (src_nh.is_v6()) {
195 0 : source_addr = src_nh.to_v6();
196 : } else {
197 0 : assert(0);
198 : }
199 :
200 30256 : Ip6Address::bytes_type addr_bytes = source_addr.to_bytes();
201 30255 : copy(addr_bytes.begin(), addr_bytes.end(),
202 30255 : dest_nh.begin() + RouteDistinguisher::kSize);
203 30248 : }
204 :
205 59305 : DBEntryBase::KeyPtr Inet6VpnRoute::GetDBRequestKey() const {
206 : Inet6VpnTable::RequestKey *key =
207 59305 : new Inet6VpnTable::RequestKey(GetPrefix(), NULL);
208 59291 : return KeyPtr(key);
209 : }
210 :
211 : // Check whether 'this' is more specific than rhs.
212 22 : bool Inet6VpnRoute::IsMoreSpecific(const string &other) const {
213 22 : boost::system::error_code ec;
214 :
215 22 : Inet6VpnPrefix other_prefix = Inet6VpnPrefix::FromString(other, &ec);
216 22 : if (!ec) {
217 22 : return GetPrefix().IsMoreSpecific(other_prefix);
218 : }
219 :
220 0 : return false;
221 : }
222 :
223 : // Check whether 'this' is less specific than rhs.
224 10 : bool Inet6VpnRoute::IsLessSpecific(const string &other) const {
225 10 : boost::system::error_code ec;
226 :
227 10 : Inet6VpnPrefix other_prefix = Inet6VpnPrefix::FromString(other, &ec);
228 10 : if (!ec) {
229 10 : return other_prefix.IsMoreSpecific(GetPrefix());
230 : }
231 :
232 0 : return false;
233 : }
|