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