Line data Source code
1 : /* 2 : * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #ifndef vnsw_agent_ecmp_load_balance_hpp 6 : #define vnsw_agent_ecmp_load_balance_hpp 7 : 8 : #include <atomic> 9 : #include <boost/intrusive_ptr.hpp> 10 : #include <vnc_cfg_types.h> 11 : 12 : namespace autogen { 13 : struct EcmpHashingIncludeFields; 14 : } 15 : 16 : static const std::string HashingFieldsStr[] = { 17 : "l3-source-address", 18 : "l3-destination-address", 19 : "l4-protocol", 20 : "l4-source-port", 21 : "l4-destination-port" 22 : }; 23 : static const std::string LoadBalanceDecision = "field-hash"; 24 : 25 : class EcmpLoadBalance { 26 : public: 27 : enum kHashingFields { 28 : SOURCE_IP, 29 : DESTINATION_IP, 30 : IP_PROTOCOL, 31 : SOURCE_PORT, 32 : DESTINATION_PORT, 33 : NUM_HASH_FIELDS 34 : }; 35 : 36 1806 : EcmpLoadBalance() { 37 1806 : SetAll(); 38 1806 : } 39 2203 : virtual ~EcmpLoadBalance() { } 40 : 41 0 : const std::string &source_ip_str() const { 42 0 : return HashingFieldsStr[(uint8_t)EcmpLoadBalance::SOURCE_IP]; 43 : } 44 0 : const std::string &destination_ip_str() const { 45 0 : return HashingFieldsStr[(uint8_t)EcmpLoadBalance::DESTINATION_IP]; 46 : } 47 0 : const std::string &source_port_str() const { 48 0 : return HashingFieldsStr[(uint8_t)EcmpLoadBalance::SOURCE_PORT]; 49 : } 50 0 : const std::string &destination_port_str() const { 51 0 : return HashingFieldsStr[(uint8_t)EcmpLoadBalance::DESTINATION_PORT]; 52 : } 53 0 : const std::string &ip_protocol_str() const { 54 0 : return HashingFieldsStr[(uint8_t)EcmpLoadBalance::IP_PROTOCOL]; 55 : } 56 : 57 0 : void GetStringVector (std::vector<std::string> &string_vector) const { 58 0 : for (uint8_t field_type = ((uint8_t) EcmpLoadBalance::SOURCE_IP); 59 0 : field_type < ((uint8_t) EcmpLoadBalance::NUM_HASH_FIELDS); 60 : field_type++) { 61 0 : if (hash_fields_to_use_[field_type]) 62 0 : string_vector.push_back(HashingFieldsStr[field_type]); 63 : } 64 0 : } 65 : 66 613 : bool operator!=(const EcmpLoadBalance &rhs) const { 67 3538 : for (uint8_t field_type = ((uint8_t) EcmpLoadBalance::SOURCE_IP); 68 3538 : field_type < ((uint8_t) EcmpLoadBalance::NUM_HASH_FIELDS); 69 : field_type++) { 70 2953 : if (hash_fields_to_use_[field_type] != 71 2953 : rhs.hash_fields_to_use_[field_type]) 72 28 : return true; 73 : } 74 585 : return false; 75 : } 76 : 77 57 : virtual void Copy(const EcmpLoadBalance &rhs) { 78 57 : for (uint8_t field_type = ((uint8_t) EcmpLoadBalance::SOURCE_IP); 79 342 : field_type < ((uint8_t) EcmpLoadBalance::NUM_HASH_FIELDS); 80 : field_type++) { 81 285 : hash_fields_to_use_[field_type] = 82 285 : rhs.hash_fields_to_use_[field_type]; 83 : } 84 57 : } 85 : 86 1806 : void SetAll() { 87 1806 : for (uint8_t field_type = ((uint8_t) EcmpLoadBalance::SOURCE_IP); 88 10836 : field_type < ((uint8_t) EcmpLoadBalance::NUM_HASH_FIELDS); 89 : field_type++) { 90 9030 : hash_fields_to_use_[field_type] = true; 91 : } 92 1806 : } 93 : 94 8 : void ResetAll() { 95 8 : for (uint8_t field_type = ((uint8_t) EcmpLoadBalance::SOURCE_IP); 96 48 : field_type < ((uint8_t) EcmpLoadBalance::NUM_HASH_FIELDS); 97 : field_type++) { 98 40 : hash_fields_to_use_[field_type] = false; 99 : } 100 8 : } 101 : 102 34 : bool AllSet() const { 103 204 : for (uint8_t field_type = ((uint8_t) EcmpLoadBalance::SOURCE_IP); 104 204 : field_type < ((uint8_t) EcmpLoadBalance::NUM_HASH_FIELDS); 105 : field_type++) { 106 170 : if (hash_fields_to_use_[field_type] == false) 107 0 : return false; 108 : } 109 34 : return true; 110 : } 111 5 : void set_source_ip() { 112 5 : hash_fields_to_use_[SOURCE_IP] = true; 113 5 : } 114 : void reset_source_ip() { 115 : hash_fields_to_use_[SOURCE_IP] = false; 116 : } 117 4 : void set_destination_ip() { 118 4 : hash_fields_to_use_[DESTINATION_IP] = true; 119 4 : } 120 : void reset_destination_ip() { 121 : hash_fields_to_use_[DESTINATION_IP] = false; 122 : } 123 2 : void set_ip_protocol() { 124 2 : hash_fields_to_use_[IP_PROTOCOL] = true; 125 2 : } 126 : void reset_ip_protocol() { 127 : hash_fields_to_use_[IP_PROTOCOL] = false; 128 : } 129 1 : void set_source_port() { 130 1 : hash_fields_to_use_[SOURCE_PORT] = true; 131 1 : } 132 : void reset_source_port() { 133 : hash_fields_to_use_[SOURCE_PORT] = false; 134 : } 135 0 : void set_destination_port() { 136 0 : hash_fields_to_use_[DESTINATION_PORT] = true; 137 0 : } 138 : void reset_destination_port() { 139 : hash_fields_to_use_[DESTINATION_PORT] = false; 140 : } 141 : 142 0 : bool is_source_ip_set() const { 143 0 : return (hash_fields_to_use_[SOURCE_IP]); 144 : } 145 0 : bool is_destination_ip_set() const { 146 0 : return (hash_fields_to_use_[DESTINATION_IP]); 147 : } 148 0 : bool is_source_port_set() const { 149 0 : return (hash_fields_to_use_[SOURCE_PORT]); 150 : } 151 0 : bool is_destination_port_set() const { 152 0 : return (hash_fields_to_use_[DESTINATION_PORT]); 153 : } 154 0 : bool is_ip_protocol_set() const { 155 0 : return (hash_fields_to_use_[IP_PROTOCOL]); 156 : } 157 : 158 70 : void reset() { 159 70 : for (uint8_t field_type = ((uint8_t) EcmpLoadBalance::SOURCE_IP); 160 420 : field_type < ((uint8_t) EcmpLoadBalance::NUM_HASH_FIELDS); 161 : field_type++) { 162 350 : hash_fields_to_use_[field_type] = false; 163 : } 164 70 : } 165 : 166 0 : bool UpdateFields 167 : (const autogen::EcmpHashingIncludeFields &ecmp_hashing_fields) { 168 0 : bool ret = false; 169 : 170 0 : if (hash_fields_to_use_[SOURCE_IP] != ecmp_hashing_fields.source_ip) { 171 0 : hash_fields_to_use_[SOURCE_IP] = ecmp_hashing_fields.source_ip; 172 0 : ret = true; 173 : } 174 0 : if (hash_fields_to_use_[DESTINATION_IP] != 175 0 : ecmp_hashing_fields.destination_ip) { 176 0 : hash_fields_to_use_[DESTINATION_IP] = 177 0 : ecmp_hashing_fields.destination_ip; 178 0 : ret = true; 179 : } 180 0 : if (hash_fields_to_use_[SOURCE_PORT] != 181 0 : ecmp_hashing_fields.source_port) { 182 0 : hash_fields_to_use_[SOURCE_PORT] = ecmp_hashing_fields.source_port; 183 0 : ret = true; 184 : } 185 0 : if (hash_fields_to_use_[DESTINATION_PORT] != 186 0 : ecmp_hashing_fields.destination_port) { 187 0 : hash_fields_to_use_[DESTINATION_PORT] = 188 0 : ecmp_hashing_fields.destination_port; 189 0 : ret = true; 190 : } 191 0 : if (hash_fields_to_use_[IP_PROTOCOL] != 192 0 : ecmp_hashing_fields.ip_protocol) { 193 0 : hash_fields_to_use_[IP_PROTOCOL] = ecmp_hashing_fields.ip_protocol; 194 0 : ret = true; 195 : } 196 0 : return ret; 197 : } 198 : 199 : private: 200 : bool hash_fields_to_use_[NUM_HASH_FIELDS]; 201 : }; 202 : 203 : class VmiEcmpLoadBalance : public EcmpLoadBalance { 204 : public: 205 1204 : VmiEcmpLoadBalance() : EcmpLoadBalance(), use_global_vrouter_(true) { } 206 1204 : virtual ~VmiEcmpLoadBalance() { } 207 : 208 29 : bool use_global_vrouter() const {return use_global_vrouter_;} 209 140 : void set_use_global_vrouter(bool use_global_vrouter) { 210 140 : use_global_vrouter_ = use_global_vrouter; 211 140 : } 212 28 : virtual void Copy(const VmiEcmpLoadBalance &rhs) { 213 28 : use_global_vrouter_ = rhs.use_global_vrouter_; 214 28 : EcmpLoadBalance::Copy(rhs); 215 28 : } 216 : 217 : private: 218 : bool use_global_vrouter_; 219 : }; 220 : 221 : class EcmpField { 222 : public: 223 1675 : EcmpField() { 224 1675 : ref_count_= 0; 225 1675 : } 226 : 227 485 : uint32_t RefCount() const { 228 485 : return ref_count_; 229 : } 230 : private: 231 : friend void intrusive_ptr_add_ref(EcmpField* ptr); 232 : friend void intrusive_ptr_release(EcmpField* ptr); 233 : mutable std::atomic<uint32_t> ref_count_; 234 : }; 235 : 236 1675 : inline void intrusive_ptr_add_ref(EcmpField* ptr) { 237 1675 : ptr->ref_count_++; 238 1675 : } 239 : 240 1675 : inline void intrusive_ptr_release(EcmpField* ptr) { 241 1675 : uint32_t prev = ptr->ref_count_.fetch_sub(1); 242 1675 : if (prev == 1) { 243 1675 : delete ptr; 244 : } 245 1675 : } 246 : 247 : class EcmpHashFields { 248 : public: 249 : typedef boost::intrusive_ptr<EcmpField> EcmpFieldPtr; 250 : 251 1653 : EcmpHashFields() { 252 1653 : } 253 : 254 160 : EcmpHashFields(const uint8_t hash_fields_to_use ) { 255 160 : hash_fields_to_use_ = hash_fields_to_use; 256 160 : } 257 205 : void operator = (const uint8_t hash_fields_to_use) { 258 205 : hash_fields_to_use_ = hash_fields_to_use; 259 205 : } 260 : 261 335 : void AllocateEcmpFields() { 262 335 : sip_ = new EcmpField; 263 335 : dip_ = new EcmpField; 264 335 : proto_ = new EcmpField; 265 335 : sport_ = new EcmpField; 266 335 : dport_ = new EcmpField; 267 335 : } 268 : 269 1604 : uint8_t HashFieldsToUse() const { 270 1604 : return hash_fields_to_use_; 271 : } 272 : 273 485 : void SetHashFieldtoUse(EcmpField *ptr, uint8_t key) { 274 485 : if (ptr && ptr->RefCount() == 1) { 275 485 : comp_hash_fields_to_use_ |= 1 << key; 276 : } 277 485 : } 278 : // If the field is not set create intrusive pointer 279 : // else release the pointer. 280 0 : void SetChangeInHashField(bool is_field_set, EcmpFieldPtr& fieldPtr, 281 : EcmpFieldPtr &objFieldPtr) { 282 0 : if (!is_field_set) { 283 0 : if (!objFieldPtr.get()) { 284 0 : objFieldPtr = fieldPtr; 285 : } 286 : } else { 287 0 : objFieldPtr.reset(); 288 : } 289 0 : } 290 : // This function will be called to ge intersection of ecmp fields 291 97 : uint8_t CalculateHashFieldsToUse() { 292 97 : comp_hash_fields_to_use_ = 0; 293 97 : SetHashFieldtoUse(sip_.get(), EcmpLoadBalance::SOURCE_IP); 294 97 : SetHashFieldtoUse(dip_.get(), EcmpLoadBalance::DESTINATION_IP); 295 97 : SetHashFieldtoUse(proto_.get(), EcmpLoadBalance::IP_PROTOCOL); 296 97 : SetHashFieldtoUse(sport_.get(), EcmpLoadBalance::SOURCE_PORT); 297 97 : SetHashFieldtoUse(dport_.get(), EcmpLoadBalance::DESTINATION_PORT); 298 97 : return comp_hash_fields_to_use_; 299 : } 300 : //This function used to calculate the Change in ecmp fields 301 0 : void CalculateChangeInEcmpFields(const EcmpLoadBalance &ecmp_load_balance, 302 : EcmpHashFields& ecmp_hash_fields) { 303 0 : SetChangeInHashField(ecmp_load_balance.is_source_ip_set(), 304 0 : ecmp_hash_fields.sip_, sip_); 305 0 : SetChangeInHashField(ecmp_load_balance.is_destination_ip_set(), 306 0 : ecmp_hash_fields.dip_, dip_); 307 0 : SetChangeInHashField(ecmp_load_balance.is_ip_protocol_set(), 308 0 : ecmp_hash_fields.proto_, proto_); 309 0 : SetChangeInHashField(ecmp_load_balance.is_source_port_set(), 310 0 : ecmp_hash_fields.sport_, sport_); 311 0 : SetChangeInHashField(ecmp_load_balance.is_destination_port_set(), 312 0 : ecmp_hash_fields.dport_, dport_); 313 0 : } 314 : 315 97 : bool IsFieldsInUseChanged() { 316 97 : return hash_fields_to_use_ != CalculateHashFieldsToUse(); 317 : } 318 : 319 40 : void SetHashFieldstoUse() { 320 40 : hash_fields_to_use_ = comp_hash_fields_to_use_; 321 40 : } 322 : 323 9 : void Reset() { 324 9 : sip_ = NULL; 325 9 : dip_ = NULL; 326 9 : proto_ = NULL; 327 9 : sport_ = NULL; 328 9 : dport_ = NULL; 329 9 : } 330 : 331 : private: 332 : // This will have latest computed value 333 : uint8_t comp_hash_fields_to_use_; 334 : uint8_t hash_fields_to_use_; 335 : EcmpFieldPtr sip_; 336 : EcmpFieldPtr dip_; 337 : EcmpFieldPtr proto_; 338 : EcmpFieldPtr sport_; 339 : EcmpFieldPtr dport_; 340 : DISALLOW_COPY_AND_ASSIGN(EcmpHashFields); 341 : }; 342 : #endif