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: 113 185 61.1 %
Date: 2026-08-03 02:19:58 Functions: 31 48 64.6 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.14