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