Line data Source code
1 : /*
2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/extended-community/load_balance.h"
6 :
7 : #include <boost/foreach.hpp>
8 :
9 : #include <algorithm>
10 : #include <string>
11 : #include <vector>
12 :
13 : using std::copy;
14 : using std::string;
15 :
16 : // Initialize default attribute statically.
17 : const LoadBalance::LoadBalanceAttribute
18 : LoadBalance::LoadBalanceAttribute::kDefaultLoadBalanceAttribute =
19 : LoadBalance::LoadBalanceAttribute();
20 :
21 1 : LoadBalance::LoadBalanceAttribute::LoadBalanceAttribute() {
22 1 : value1 = 0; // reset all fields
23 1 : value2 = 0; // reset all fields
24 1 : type = BgpExtendedCommunityType::Opaque;
25 1 : sub_type = BgpExtendedCommunityOpaqueSubType::LoadBalance;
26 :
27 1 : l3_source_address = true;
28 1 : l3_destination_address = true;
29 1 : l4_protocol = true;
30 1 : l4_source_port = true;
31 1 : l4_destination_port = true;
32 1 : reserved1 = false;
33 :
34 1 : reserved2 = 0;
35 :
36 1 : source_bias = false;
37 :
38 1 : reserved3 = 0;
39 1 : reserved4 = 0;
40 1 : reserved5 = 0;
41 1 : }
42 :
43 0 : LoadBalance::LoadBalanceAttribute::LoadBalanceAttribute(
44 0 : uint32_t value1, uint32_t value2) : value1(value1), value2(value2) {
45 0 : }
46 :
47 0 : void LoadBalance::LoadBalanceAttribute::Encode(
48 : autogen::LoadBalanceType *lb_type) const {
49 0 : lb_type->load_balance_fields.load_balance_field_list.clear();
50 0 : if (l3_source_address)
51 0 : lb_type->load_balance_fields.load_balance_field_list.push_back(
52 0 : string("l3-source-address"));
53 0 : if (l3_destination_address)
54 0 : lb_type->load_balance_fields.load_balance_field_list.push_back(
55 0 : string("l3-destination-address"));
56 0 : if (l4_protocol)
57 0 : lb_type->load_balance_fields.load_balance_field_list.push_back(
58 0 : string("l4-protocol"));
59 0 : if (l4_source_port)
60 0 : lb_type->load_balance_fields.load_balance_field_list.push_back(
61 0 : string("l4-source-port"));
62 0 : if (l4_destination_port)
63 0 : lb_type->load_balance_fields.load_balance_field_list.push_back(
64 0 : string("l4-destination-port"));
65 0 : lb_type->load_balance_decision = source_bias ? "source-bias" : "field-hash";
66 0 : }
67 :
68 0 : bool LoadBalance::LoadBalanceAttribute::operator==(
69 : const LoadBalance::LoadBalanceAttribute &other) const {
70 0 : return value1 == other.value1 && value2 == other.value2;
71 : }
72 :
73 0 : bool LoadBalance::LoadBalanceAttribute::operator!=(
74 : const LoadBalance::LoadBalanceAttribute &other) const {
75 0 : return value1 != other.value1 || value2 != other.value2;
76 : }
77 :
78 0 : const bool LoadBalance::LoadBalanceAttribute::IsDefault() const {
79 0 : return *this == kDefaultLoadBalanceAttribute;
80 : }
81 :
82 0 : LoadBalance::LoadBalance() {
83 0 : LoadBalanceAttribute attr;
84 0 : put_value(&data_[0], 4, attr.value1);
85 0 : put_value(&data_[4], 4, attr.value2);
86 0 : }
87 :
88 0 : LoadBalance::LoadBalance(const bytes_type &data) {
89 0 : copy(data.begin(), data.end(), data_.begin());
90 0 : }
91 :
92 0 : LoadBalance::LoadBalance(const BgpPath *path) {
93 0 : LoadBalance();
94 0 : if (!path)
95 0 : return;
96 0 : const BgpAttr *attr = path->GetAttr();
97 0 : if (!attr)
98 0 : return;
99 0 : const ExtCommunity *ext_community = attr->ext_community();
100 0 : if (!ext_community)
101 0 : return;
102 0 : for (const auto &comm : ext_community->communities()) {
103 0 : if (ExtCommunity::is_load_balance(comm)) {
104 0 : copy(comm.begin(), comm.end(), data_.begin());
105 0 : break;
106 : }
107 : }
108 : }
109 :
110 0 : LoadBalance::LoadBalance(const LoadBalanceAttribute &attr) {
111 0 : put_value(&data_[0], 4, attr.value1);
112 0 : put_value(&data_[4], 4, attr.value2);
113 0 : }
114 :
115 0 : LoadBalance::LoadBalance(const autogen::LoadBalanceType &lb_type) {
116 0 : LoadBalanceAttribute attr;
117 :
118 0 : attr.source_bias = lb_type.load_balance_decision == "source-bias";
119 :
120 : // autogen::LoadBalanceType fields list empty should imply as standard
121 : // 5-tuple fields set. xml schema does not let one specifify default values
122 : // for a complex type such as a list in this case.
123 : bool load_balance_default =
124 0 : !attr.source_bias && (lb_type.load_balance_fields.begin() ==
125 0 : lb_type.load_balance_fields.end());
126 0 : attr.l3_source_address = load_balance_default || false;
127 0 : attr.l3_destination_address = load_balance_default || false;
128 0 : attr.l4_protocol = load_balance_default || false;
129 0 : attr.l4_source_port = load_balance_default || false;
130 0 : attr.l4_destination_port = load_balance_default || false;
131 :
132 0 : for (autogen::LoadBalanceFieldListType::const_iterator it =
133 0 : lb_type.load_balance_fields.begin();
134 0 : it != lb_type.load_balance_fields.end(); ++it) {
135 0 : const string s = *it;
136 0 : if (s == "l3-source-address") {
137 0 : attr.l3_source_address = true;
138 0 : continue;
139 : }
140 0 : if (s == "l3-destination-address") {
141 0 : attr.l3_destination_address = true;
142 0 : continue;
143 : }
144 0 : if (s == "l4-protocol") {
145 0 : attr.l4_protocol = true;
146 0 : continue;
147 : }
148 0 : if (s == "l4-source-port") {
149 0 : attr.l4_source_port = true;
150 0 : continue;
151 : }
152 0 : if (s == "l4-destination-port") {
153 0 : attr.l4_destination_port = true;
154 0 : continue;
155 : }
156 0 : }
157 :
158 0 : put_value(&data_[0], 4, attr.value1);
159 0 : put_value(&data_[4], 4, attr.value2);
160 0 : }
161 :
162 0 : void LoadBalance::FillAttribute(LoadBalanceAttribute *attr) {
163 0 : attr->value1 = get_value(&data_[0], 4);
164 0 : attr->value2 = get_value(&data_[4], 4);
165 0 : }
166 :
167 0 : const LoadBalance::LoadBalanceAttribute LoadBalance::ToAttribute() const {
168 0 : return LoadBalanceAttribute(
169 0 : get_value_unaligned(&data_[0], 4),
170 0 : get_value_unaligned(&data_[4], 4));
171 : }
172 :
173 0 : void LoadBalance::SetL3SourceAddress(bool flag) {
174 0 : LoadBalanceAttribute attr = ToAttribute();
175 0 : attr.l3_source_address = flag;
176 :
177 0 : put_value(&data_[0], 4, attr.value1);
178 0 : put_value(&data_[4], 4, attr.value2);
179 0 : }
180 :
181 0 : void LoadBalance::SetL3DestinationAddress(bool flag) {
182 0 : LoadBalanceAttribute attr = ToAttribute();
183 0 : attr.l3_destination_address = flag;
184 :
185 0 : put_value(&data_[0], 4, attr.value1);
186 0 : put_value(&data_[4], 4, attr.value2);
187 0 : }
188 :
189 0 : void LoadBalance::SetL4Protocol(bool flag) {
190 0 : LoadBalanceAttribute attr = ToAttribute();
191 0 : attr.l4_protocol = flag;
192 :
193 0 : put_value(&data_[0], 4, attr.value1);
194 0 : put_value(&data_[4], 4, attr.value2);
195 0 : }
196 :
197 0 : void LoadBalance::SetL4SourcePort(bool flag) {
198 0 : LoadBalanceAttribute attr = ToAttribute();
199 0 : attr.l4_source_port = flag;
200 :
201 0 : put_value(&data_[0], 4, attr.value1);
202 0 : put_value(&data_[4], 4, attr.value2);
203 0 : }
204 :
205 0 : void LoadBalance::SetL4DestinationPort(bool flag) {
206 0 : LoadBalanceAttribute attr = ToAttribute();
207 0 : attr.l4_destination_port = flag;
208 :
209 0 : put_value(&data_[0], 4, attr.value1);
210 0 : put_value(&data_[4], 4, attr.value2);
211 0 : }
212 :
213 0 : void LoadBalance::SetSourceBias(bool flag) {
214 0 : LoadBalanceAttribute attr = ToAttribute();
215 0 : attr.source_bias = flag;
216 :
217 0 : put_value(&data_[0], 4, attr.value1);
218 0 : put_value(&data_[4], 4, attr.value2);
219 0 : }
220 :
221 0 : bool LoadBalance::IsPresent(const BgpPath *path) {
222 0 : if (!path)
223 0 : return false;
224 0 : const BgpAttr *attr = path->GetAttr();
225 0 : if (!attr)
226 0 : return false;
227 0 : const ExtCommunity *ext_community = attr->ext_community();
228 0 : if (!ext_community)
229 0 : return false;
230 0 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
231 : ext_community->communities()) {
232 0 : if (ExtCommunity::is_load_balance(comm)) {
233 0 : return true;
234 : }
235 : }
236 0 : return false;
237 : }
238 :
239 0 : const bool LoadBalance::IsDefault() const {
240 0 : return ToAttribute() == LoadBalanceAttribute::kDefaultLoadBalanceAttribute;
241 : }
242 :
243 0 : bool LoadBalance::operator==(const LoadBalance &other) const {
244 0 : return ToAttribute() == other.ToAttribute();
245 : }
246 :
247 0 : bool LoadBalance::operator!=(const LoadBalance &other) const {
248 0 : return ToAttribute() != other.ToAttribute();
249 : }
250 :
251 0 : void LoadBalance::ShowAttribute(ShowLoadBalance *show_load_balance) const {
252 0 : const LoadBalanceAttribute attr = ToAttribute();
253 0 : vector<string> fields = vector<string>();
254 0 : if (attr.source_bias) {
255 0 : show_load_balance->set_decision_type("source-bias");
256 0 : show_load_balance->set_fields(fields);
257 0 : return;
258 : }
259 :
260 0 : show_load_balance->set_decision_type("field-hash");
261 0 : if (attr.l3_source_address)
262 0 : fields.push_back("l3-source-address");
263 0 : if (attr.l3_destination_address)
264 0 : fields.push_back("l3-destination-address");
265 0 : if (attr.l4_protocol)
266 0 : fields.push_back("l4-protocol");
267 0 : if (attr.l4_source_port)
268 0 : fields.push_back("l4-source-port");
269 0 : if (attr.l4_destination_port)
270 0 : fields.push_back("l4-destination-port");
271 0 : show_load_balance->set_fields(fields);
272 0 : }
273 :
274 0 : string LoadBalance::ToString() const {
275 0 : const LoadBalanceAttribute attr = ToAttribute();
276 0 : string str("load-balance:");
277 0 : str += attr.source_bias ? "source-bias" : "field-hash";
278 0 : return str;
279 0 : }
|