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