LCOV - code coverage report
Current view: top level - vnsw/agent/oper - ecmp_load_balance.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 123 185 66.5 %
Date: 2026-11-09 02:10:49 Functions: 36 48 75.0 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.14