LCOV - code coverage report
Current view: top level - src/extension - qos_profile.cc (source / functions) Hit Total Coverage
Test: vlink Lines: 25 219 11.4 %
Date: 2026-06-27 19:56:04 Functions: 3 22 13.6 %
Branches: 23 592 3.9 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2026 by Thun Lu. All rights reserved.
       3                 :            :  * Author: Thun Lu <thun.lu@zohomail.cn>
       4                 :            :  * Repo:   https://github.com/thun-res/vlink
       5                 :            :  *  _    __   __      _           __
       6                 :            :  * | |  / /  / /     (_) ____    / /__
       7                 :            :  * | | / /  / /     / / / __ \  / //_/
       8                 :            :  * | |/ /  / /___  / / / / / / / ,<
       9                 :            :  * |___/  /_____/ /_/ /_/ /_/ /_/|_|
      10                 :            :  *
      11                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
      12                 :            :  * you may not use this file except in compliance with the License.
      13                 :            :  * You may obtain a copy of the License at
      14                 :            :  *
      15                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
      16                 :            :  *
      17                 :            :  * Unless required by applicable law or agreed to in writing, software
      18                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      19                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      20                 :            :  * See the License for the specific language governing permissions and
      21                 :            :  * limitations under the License.
      22                 :            :  */
      23                 :            : 
      24                 :            : #include "./extension/qos_profile.h"
      25                 :            : 
      26                 :            : #include <fstream>
      27                 :            : #include <string>
      28                 :            : #include <unordered_map>
      29                 :            : 
      30                 :            : #include "./base/helpers.h"
      31                 :            : #include "./base/logger.h"
      32                 :            : #include "./base/utils.h"
      33                 :            : 
      34                 :            : // json
      35                 :            : #include <nlohmann/json.hpp>
      36                 :            : 
      37                 :            : namespace vlink {
      38                 :            : 
      39                 :            : // GlobalQosProfile
      40                 :            : struct GlobalQosProfile final {
      41                 :         22 :   GlobalQosProfile() {
      42         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kEvent.name, QosProfile::kEvent);
      43         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kMethod.name, QosProfile::kMethod);
      44         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kField.name, QosProfile::kField);
      45         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kSensor.name, QosProfile::kSensor);
      46         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kParameter.name, QosProfile::kParameter);
      47         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kService.name, QosProfile::kService);
      48         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kClock.name, QosProfile::kClock);
      49         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kStatic.name, QosProfile::kStatic);
      50         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kLight.name, QosProfile::kLight);
      51         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kPoor.name, QosProfile::kPoor);
      52         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kBetter.name, QosProfile::kBetter);
      53         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kBest.name, QosProfile::kBest);
      54         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kLarge.name, QosProfile::kLarge);
      55         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kAlarm.name, QosProfile::kAlarm);
      56         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kCommand.name, QosProfile::kCommand);
      57         [ +  - ]:         22 :     available_qos_map.emplace(QosProfile::kLog.name, QosProfile::kLog);
      58                 :            : 
      59   [ +  -  +  - ]:         44 :     const std::string qos_path = Utils::get_env("VLINK_QOS_CONFIG");
      60                 :            : 
      61         [ +  - ]:         22 :     if (qos_path.empty()) {
      62                 :         22 :       return;
      63                 :            :     }
      64                 :            : 
      65                 :          0 :     std::filesystem::path target_path;
      66                 :            : 
      67                 :            :     try {
      68                 :            : #ifdef _WIN32
      69                 :            :       target_path = std::filesystem::path(Helpers::string_to_wstring(qos_path));
      70                 :            : #else
      71         [ #  # ]:          0 :       target_path = std::filesystem::path(qos_path);
      72                 :            : #endif
      73                 :            : 
      74   [ #  #  #  # ]:          0 :       if VUNLIKELY (!std::filesystem::exists(target_path)) {
      75   [ #  #  #  # ]:          0 :         VLOG_E("QosProfile: Qos config file does not exist.");
      76                 :          0 :         return;
      77                 :            :       }
      78                 :            :     } catch (std::filesystem::filesystem_error&) {            // LCOV_EXCL_LINE GCOVR_EXCL_LINE
      79                 :            :       VLOG_E("QosProfile: Qos config file does not exist.");  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
      80                 :            :     }  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
      81                 :            : 
      82                 :            :     try {
      83                 :          0 :       nlohmann::json root_json;
      84                 :            : 
      85                 :            :       {
      86         [ #  # ]:          0 :         std::ifstream file(target_path);
      87                 :            : 
      88         [ #  # ]:          0 :         file >> root_json;
      89                 :            : 
      90         [ #  # ]:          0 :         file.close();
      91                 :          0 :       }
      92                 :            : 
      93   [ #  #  #  #  :          0 :       if VUNLIKELY (root_json.empty() || !root_json.is_array()) {
                   #  # ]
      94   [ #  #  #  # ]:          0 :         VLOG_E("QosProfile: Qos config file has wrong format.");
      95                 :          0 :         return;
      96                 :            :       }
      97                 :            : 
      98   [ #  #  #  #  :          0 :       for (const auto& obj : root_json) {
             #  #  #  # ]
      99         [ #  # ]:          0 :         if VUNLIKELY (!obj.is_object()) {
     100   [ #  #  #  # ]:          0 :           VLOG_E("QosProfile: Qos config file has wrong format.");
     101                 :          0 :           return;
     102                 :            :         }
     103                 :            : 
     104                 :          0 :         Qos qos;
     105                 :            : 
     106   [ #  #  #  #  :          0 :         if VUNLIKELY (!obj.contains("name") || !obj["name"].is_string()) {
          #  #  #  #  #  
                      # ]
     107   [ #  #  #  # ]:          0 :           VLOG_E("QosProfile: Qos config file qos name missing or invalid.");
     108                 :          0 :           return;
     109                 :            :         }
     110                 :            : 
     111   [ #  #  #  # ]:          0 :         std::string qos_name = obj["name"];
     112                 :            : 
     113         [ #  # ]:          0 :         if VUNLIKELY (qos_name.empty()) {
     114   [ #  #  #  # ]:          0 :           VLOG_E("QosProfile: Qos config file qos name is empty.");
     115                 :          0 :           return;
     116                 :            :         }
     117                 :            : 
     118         [ #  # ]:          0 :         if VUNLIKELY (qos_name.size() >= sizeof(qos.name)) {
     119   [ #  #  #  # ]:          0 :           VLOG_E("QosProfile: Qos config file qos name length error.");
     120                 :          0 :           return;
     121                 :            :         }
     122                 :            : 
     123                 :          0 :         std::memcpy(qos.name, qos_name.data(), qos_name.size());
     124                 :            : 
     125   [ #  #  #  # ]:          0 :         if (obj.contains("reliability")) {
     126   [ #  #  #  # ]:          0 :           auto tobj = obj["reliability"];
     127                 :            : 
     128         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     129   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     130                 :          0 :             return;
     131                 :            :           }
     132                 :            : 
     133   [ #  #  #  # ]:          0 :           if (tobj.contains("kind")) {
     134   [ #  #  #  # ]:          0 :             auto pkind = tobj["kind"];
     135                 :            : 
     136   [ #  #  #  #  :          0 :             if (pkind == "BestEffort" || pkind == "kBestEffort") {
                   #  # ]
     137                 :          0 :               qos.reliability.kind = Qos::Reliability::kBestEffort;
     138   [ #  #  #  #  :          0 :             } else if (pkind == "Reliable" || pkind == "kReliable") {
                   #  # ]
     139                 :          0 :               qos.reliability.kind = Qos::Reliability::kReliable;
     140                 :            :             } else {
     141         [ #  # ]:          0 :               qos.reliability.kind = pkind;
     142                 :            :             }
     143                 :          0 :           }
     144                 :            : 
     145   [ #  #  #  # ]:          0 :           if (tobj.contains("block_time")) {
     146   [ #  #  #  # ]:          0 :             qos.reliability.block_time = tobj["block_time"];
     147                 :            :           }
     148                 :            : 
     149   [ #  #  #  # ]:          0 :           if (tobj.contains("heartbeat_time")) {
     150   [ #  #  #  # ]:          0 :             qos.reliability.heartbeat_time = tobj["heartbeat_time"];
     151                 :            :           }
     152         [ #  # ]:          0 :         }
     153                 :            : 
     154   [ #  #  #  # ]:          0 :         if (obj.contains("history")) {
     155   [ #  #  #  # ]:          0 :           auto tobj = obj["history"];
     156                 :            : 
     157         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     158   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     159                 :          0 :             return;
     160                 :            :           }
     161                 :            : 
     162   [ #  #  #  # ]:          0 :           if (tobj.contains("kind")) {
     163   [ #  #  #  # ]:          0 :             auto pkind = tobj["kind"];
     164                 :            : 
     165   [ #  #  #  #  :          0 :             if (pkind == "KeepLast" || pkind == "kKeepLast") {
                   #  # ]
     166                 :          0 :               qos.history.kind = Qos::History::kKeepLast;
     167   [ #  #  #  #  :          0 :             } else if (pkind == "KeepAll" || pkind == "kKeepAll") {
                   #  # ]
     168                 :          0 :               qos.history.kind = Qos::History::kKeepAll;
     169                 :            :             } else {
     170         [ #  # ]:          0 :               qos.history.kind = pkind;
     171                 :            :             }
     172                 :          0 :           }
     173                 :            : 
     174   [ #  #  #  # ]:          0 :           if (tobj.contains("depth")) {
     175   [ #  #  #  # ]:          0 :             qos.history.depth = tobj["depth"];
     176                 :            :           }
     177         [ #  # ]:          0 :         }
     178                 :            : 
     179   [ #  #  #  # ]:          0 :         if (obj.contains("durability")) {
     180   [ #  #  #  # ]:          0 :           auto tobj = obj["durability"];
     181                 :            : 
     182         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     183   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     184                 :          0 :             return;
     185                 :            :           }
     186                 :            : 
     187   [ #  #  #  # ]:          0 :           if (tobj.contains("kind")) {
     188   [ #  #  #  # ]:          0 :             auto pkind = tobj["kind"];
     189                 :            : 
     190   [ #  #  #  #  :          0 :             if (pkind == "Volatile" || pkind == "kVolatile") {
                   #  # ]
     191                 :          0 :               qos.durability.kind = Qos::Durability::kVolatile;
     192   [ #  #  #  #  :          0 :             } else if (pkind == "TransientLocal" || pkind == "kTransientLocal") {
                   #  # ]
     193                 :          0 :               qos.durability.kind = Qos::Durability::kTransientLocal;
     194   [ #  #  #  #  :          0 :             } else if (pkind == "Transient" || pkind == "kTransient") {
                   #  # ]
     195                 :          0 :               qos.durability.kind = Qos::Durability::kTransient;
     196   [ #  #  #  #  :          0 :             } else if (pkind == "Persistent" || pkind == "kPersistent") {
                   #  # ]
     197                 :          0 :               qos.durability.kind = Qos::Durability::kPersistent;
     198                 :            :             } else {
     199         [ #  # ]:          0 :               qos.durability.kind = pkind;
     200                 :            :             }
     201                 :          0 :           }
     202         [ #  # ]:          0 :         }
     203                 :            : 
     204   [ #  #  #  # ]:          0 :         if (obj.contains("publish_mode")) {
     205   [ #  #  #  # ]:          0 :           auto tobj = obj["publish_mode"];
     206                 :            : 
     207         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     208   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     209                 :          0 :             return;
     210                 :            :           }
     211                 :            : 
     212   [ #  #  #  # ]:          0 :           if (tobj.contains("kind")) {
     213   [ #  #  #  # ]:          0 :             auto pkind = tobj["kind"];
     214                 :            : 
     215   [ #  #  #  #  :          0 :             if (pkind == "Sync" || pkind == "kSync") {
                   #  # ]
     216                 :          0 :               qos.publish_mode.kind = Qos::PublishMode::kSync;
     217   [ #  #  #  #  :          0 :             } else if (pkind == "ASync" || pkind == "kASync") {
                   #  # ]
     218                 :          0 :               qos.publish_mode.kind = Qos::PublishMode::kASync;
     219                 :            :             } else {
     220         [ #  # ]:          0 :               qos.publish_mode.kind = pkind;
     221                 :            :             }
     222                 :          0 :           }
     223         [ #  # ]:          0 :         }
     224                 :            : 
     225   [ #  #  #  # ]:          0 :         if (obj.contains("liveliness")) {
     226   [ #  #  #  # ]:          0 :           auto tobj = obj["liveliness"];
     227                 :            : 
     228         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     229   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     230                 :          0 :             return;
     231                 :            :           }
     232                 :            : 
     233   [ #  #  #  # ]:          0 :           if (tobj.contains("kind")) {
     234   [ #  #  #  # ]:          0 :             auto pkind = tobj["kind"];
     235                 :            : 
     236   [ #  #  #  #  :          0 :             if (pkind == "Automatic" || pkind == "kAutomatic") {
                   #  # ]
     237                 :          0 :               qos.liveliness.kind = Qos::Liveliness::kAutomatic;
     238   [ #  #  #  #  :          0 :             } else if (pkind == "ManualParticipant" || pkind == "kManualParticipant") {
                   #  # ]
     239                 :          0 :               qos.liveliness.kind = Qos::Liveliness::kManualParticipant;
     240   [ #  #  #  #  :          0 :             } else if (pkind == "ManualTopic" || pkind == "kManualTopic") {
                   #  # ]
     241                 :          0 :               qos.liveliness.kind = Qos::Liveliness::kManualTopic;
     242                 :            :             } else {
     243         [ #  # ]:          0 :               qos.liveliness.kind = pkind;
     244                 :            :             }
     245                 :          0 :           }
     246                 :            : 
     247   [ #  #  #  # ]:          0 :           if (tobj.contains("duration")) {
     248   [ #  #  #  # ]:          0 :             qos.liveliness.duration = tobj["duration"];
     249                 :            :           }
     250         [ #  # ]:          0 :         }
     251                 :            : 
     252   [ #  #  #  # ]:          0 :         if (obj.contains("destination_order")) {
     253   [ #  #  #  # ]:          0 :           auto tobj = obj["destination_order"];
     254                 :            : 
     255         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     256   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     257                 :          0 :             return;
     258                 :            :           }
     259                 :            : 
     260   [ #  #  #  # ]:          0 :           if (tobj.contains("kind")) {
     261   [ #  #  #  # ]:          0 :             auto pkind = tobj["kind"];
     262                 :            : 
     263   [ #  #  #  #  :          0 :             if (pkind == "ReceptionTimestamp" || pkind == "kReceptionTimestamp") {
                   #  # ]
     264                 :          0 :               qos.destination_order.kind = Qos::DestinationOrder::kReceptionTimestamp;
     265   [ #  #  #  #  :          0 :             } else if (pkind == "SourceTimestamp" || pkind == "kSourceTimestamp") {
                   #  # ]
     266                 :          0 :               qos.destination_order.kind = Qos::DestinationOrder::kSourceTimestamp;
     267                 :            :             } else {
     268         [ #  # ]:          0 :               qos.destination_order.kind = pkind;
     269                 :            :             }
     270                 :          0 :           }
     271         [ #  # ]:          0 :         }
     272                 :            : 
     273   [ #  #  #  # ]:          0 :         if (obj.contains("ownership")) {
     274   [ #  #  #  # ]:          0 :           auto tobj = obj["ownership"];
     275                 :            : 
     276         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     277   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     278                 :          0 :             return;
     279                 :            :           }
     280                 :            : 
     281   [ #  #  #  # ]:          0 :           if (tobj.contains("kind")) {
     282   [ #  #  #  # ]:          0 :             auto pkind = tobj["kind"];
     283                 :            : 
     284   [ #  #  #  #  :          0 :             if (pkind == "Shared" || pkind == "kShared") {
                   #  # ]
     285                 :          0 :               qos.ownership.kind = Qos::Ownership::kShared;
     286   [ #  #  #  #  :          0 :             } else if (pkind == "Exclusive" || pkind == "kExclusive" || pkind == "ExClusive") {
             #  #  #  # ]
     287                 :          0 :               qos.ownership.kind = Qos::Ownership::kExclusive;
     288                 :            :             } else {
     289         [ #  # ]:          0 :               qos.ownership.kind = pkind;
     290                 :            :             }
     291                 :          0 :           }
     292         [ #  # ]:          0 :         }
     293                 :            : 
     294   [ #  #  #  # ]:          0 :         if (obj.contains("deadline")) {
     295   [ #  #  #  # ]:          0 :           auto tobj = obj["deadline"];
     296                 :            : 
     297         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     298   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     299                 :          0 :             return;
     300                 :            :           }
     301                 :            : 
     302   [ #  #  #  # ]:          0 :           if (tobj.contains("period")) {
     303   [ #  #  #  # ]:          0 :             qos.deadline.period = tobj["period"];
     304                 :            :           }
     305         [ #  # ]:          0 :         }
     306                 :            : 
     307   [ #  #  #  # ]:          0 :         if (obj.contains("lifespan")) {
     308   [ #  #  #  # ]:          0 :           auto tobj = obj["lifespan"];
     309                 :            : 
     310         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     311   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     312                 :          0 :             return;
     313                 :            :           }
     314                 :            : 
     315   [ #  #  #  # ]:          0 :           if (tobj.contains("duration")) {
     316   [ #  #  #  # ]:          0 :             qos.lifespan.duration = tobj["duration"];
     317                 :            :           }
     318         [ #  # ]:          0 :         }
     319                 :            : 
     320   [ #  #  #  # ]:          0 :         if (obj.contains("latency_budget")) {
     321   [ #  #  #  # ]:          0 :           auto tobj = obj["latency_budget"];
     322                 :            : 
     323         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     324   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     325                 :          0 :             return;
     326                 :            :           }
     327                 :            : 
     328   [ #  #  #  # ]:          0 :           if (tobj.contains("duration")) {
     329   [ #  #  #  # ]:          0 :             qos.latency_budget.duration = tobj["duration"];
     330                 :            :           }
     331         [ #  # ]:          0 :         }
     332                 :            : 
     333   [ #  #  #  # ]:          0 :         if (obj.contains("resource_limits")) {
     334   [ #  #  #  # ]:          0 :           auto tobj = obj["resource_limits"];
     335                 :            : 
     336         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     337   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     338                 :          0 :             return;
     339                 :            :           }
     340                 :            : 
     341   [ #  #  #  # ]:          0 :           if (tobj.contains("max_samples")) {
     342   [ #  #  #  # ]:          0 :             qos.resource_limits.max_samples = tobj["max_samples"];
     343                 :            :           }
     344                 :            : 
     345   [ #  #  #  # ]:          0 :           if (tobj.contains("max_instances")) {
     346   [ #  #  #  # ]:          0 :             qos.resource_limits.max_instances = tobj["max_instances"];
     347                 :            :           }
     348                 :            : 
     349   [ #  #  #  # ]:          0 :           if (tobj.contains("max_samples_per_instance")) {
     350   [ #  #  #  # ]:          0 :             qos.resource_limits.max_samples_per_instance = tobj["max_samples_per_instance"];
     351                 :            :           }
     352         [ #  # ]:          0 :         }
     353                 :            : 
     354   [ #  #  #  # ]:          0 :         if (obj.contains("additions")) {
     355   [ #  #  #  # ]:          0 :           auto tobj = obj["additions"];
     356                 :            : 
     357         [ #  # ]:          0 :           if VUNLIKELY (!tobj.is_object()) {
     358   [ #  #  #  # ]:          0 :             VLOG_E("QosProfile: Qos config file has wrong format.");
     359                 :          0 :             return;
     360                 :            :           }
     361                 :            : 
     362   [ #  #  #  # ]:          0 :           if (tobj.contains("priority")) {
     363   [ #  #  #  # ]:          0 :             qos.additions.priority = static_cast<Qos::Additions::Priority>(tobj["priority"].get<uint8_t>());
     364                 :            :           }
     365                 :            : 
     366   [ #  #  #  # ]:          0 :           if (tobj.contains("is_express")) {
     367   [ #  #  #  # ]:          0 :             qos.additions.is_express = tobj["is_express"];
     368                 :            :           }
     369         [ #  # ]:          0 :         }
     370                 :            : 
     371                 :          0 :         qos.valid = true;
     372                 :            : 
     373   [ #  #  #  # ]:          0 :         available_qos_map[qos.name] = qos;
     374         [ #  # ]:          0 :       }
     375   [ #  #  #  # ]:          0 :     } catch (nlohmann::json::exception& e) {
     376   [ #  #  #  # ]:          0 :       VLOG_E("QosProfile: Qos config parse error: ", e.what(), ".");
     377                 :          0 :       return;
     378                 :          0 :     }
     379   [ -  -  -  + ]:         22 :   }
     380                 :            : 
     381                 :         22 :   ~GlobalQosProfile() = default;
     382                 :            : 
     383                 :            :   std::unordered_map<std::string, Qos> available_qos_map;
     384                 :            : };
     385                 :            : 
     386                 :            : namespace QosProfile {
     387                 :            : 
     388                 :         27 : const std::unordered_map<std::string, Qos>& get_available_qos_map() noexcept {
     389   [ +  +  +  - ]:         27 :   static GlobalQosProfile global_profile;
     390                 :            : 
     391                 :         27 :   return global_profile.available_qos_map;
     392                 :            : }
     393                 :            : 
     394                 :            : }  // namespace QosProfile
     395                 :            : 
     396                 :            : }  // namespace vlink

Generated by: LCOV version 1.14