qosd: добавлены базовые дисциплины Complex QoS ESR

А именно:

+ [B|P]FIFO;
+ HTB;
+ RED;
+ WRED (a.k.a. `gred` в Linux/TC и нашем CLI);
+ SFQ.

Два замечания:

1. Вместо GRED и RED теперь WRED и RED: RED — как был, так и есть, а
   WRED — специальный узел, который несёт глобальные настройки GRED, но
   параметры RED на VQ задаются через подключение дочерних узлов RED.
2. Параметры RED для SFQ также были оптимизированы: в узле SFQ их не
   будет, но зато к SFQ можно подключить один дочерний узел. Если
   подключить туда RED, то настройки RED будут применяться для per-flow
   RED дисциплины SFQ.
This commit is contained in:
Сергей Маринкевич
2025-09-02 19:56:58 +07:00
parent 4846a7fa53
commit ffa45f060a
19 changed files with 481 additions and 138 deletions
-1
View File
@@ -1,7 +1,6 @@
#pragma once
#include <memory>
#include <vector>
#include "ifaces/ILinkMixin.h"
/// \brief Интерфейс для классов-связей между элементами.
/// \tparam TElem Тип элемента, между которыми устанавливается связь.
+3 -2
View File
@@ -3,9 +3,10 @@
#include <stdexcept>
/// \brief Связь для листового узла, не допускающая дочерних элементов.
class LeafLink : public BaseLink {
template <class TElem>
class LeafLink : public BaseLink<TElem> {
public:
using BaseLink::BaseLink;
using BaseLink<TElem>::BaseLink;
void addChild(const NodePtr&) override {
throw std::logic_error("LeafLink cannot have children");
}
+2 -12
View File
@@ -1,17 +1,7 @@
#pragma once
#include "links/BaseLink.h"
/// \brief Связь "один-ко-многим" между элементами одного типа.
/// Каждый дочерний элемент должен быть того же типа, что и родитель.
/// \brief Связь "один-ко-многим" между элементами любого типа.
/// \tparam TElem Тип элемента.
template <class TElem>
class OneToManyLink : public BaseLink<TElem> {
public:
OneToManyLink(std::shared_ptr<TElem> e) : BaseLink<TElem>(e) {}
void addChild(const std::shared_ptr<TElem>& child) override {
/* Each child must be exactly the same type as parent */
if (typeid(*child) != typeid(*this->owner_node_.lock()))
throw std::logic_error("Foundling child");
BaseLink<TElem>::addChild(child);
}
};
using OneToManyLink = BaseLink<TElem>;
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <stdexcept>
/// \brief Обёртка для связей, чтобы сделать их типизированными.
/// Типизированная связь позволяет подключать только узлы заданного типа.
/// \tparam TElem Тип элемента.
/// \tparam TBase Базовый Link. После проверки типа, управление передаётся этому классу.
/// \tparam TExpected Опциональный ожидаемый конкретный тип детей.
/// Если не задан, сравниваем с родителем.
template <class TElem, class TBase, class TExpected = void>
class TypedLink : public TBase {
public:
using ElemPtr = std::shared_ptr<TElem>;
TypedLink(ElemPtr e) : TBase(e) {}
void addChild(const ElemPtr& child) override {
/* Validate type according to policy */
if constexpr (std::is_void_v<TExpected>) {
/* Default behavior: child must be exactly the same type as parent */
if (typeid(*child) != typeid(*this->owner_node_.lock()))
throw std::logic_error("Foundling child");
} else {
/* Explicit expected child type */
if (typeid(*child) != typeid(TExpected))
throw std::logic_error("Unexpected child type");
}
TBase::addChild(child);
}
};
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include "links/TypedLink.h"
#include "links/OneToManyLink.h"
#include <type_traits>
#include <typeinfo>
/// \brief Связь "один-ко-многим" между элементами одного типа.
/// Каждый дочерний элемент должен быть того же типа, что и родитель.
/// \tparam TElem Тип элемента.
/// \tparam TExpected Опциональный ожидаемый конкретный тип детей.
template <class TElem, class TExpected = void>
using TypedOneToManyLink = TypedLink<TElem, OneToManyLink<TElem>, TExpected>;
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include "links/BaseLink.h"
#include <stdexcept>
/// \brief Связь "один-к-одному" между элементами заданного типа.
/// Позволяет добавить только одного дочернего элемента.
/// \tparam TElem Тип элемента.
/// \tparam TExpected Опциональный ожидаемый конкретный тип детей.
/// Если не задан, сравниваем с родителем.
template <class TElem, class TExpected = void>
using TypedOneToOneLink = TypedLink<TElem, OneToOneLink<TElem>, TExpected>;
+2 -2
View File
@@ -2,7 +2,7 @@
#include <iostream>
#include "mixins/LazyLinkMixin.h"
#include <memory>
#include "links/OneToManyLink.h"
#include "links/TypedOneToManyLink.h"
#include "links/OneToOneLink.h"
#include "Logger.h"
@@ -34,7 +34,7 @@ protected:
if (typeid(*child) == typeid(*this)) {
Logger::get("Mixin").dbg("--- Mutate to OneToMany");
newLink = std::make_shared<OneToManyLink<TElem>>(*this);
newLink = std::make_shared<TypedOneToManyLink<TElem>>(*this);
} else {
Logger::get("Mixin").dbg("--- Mutate to OneToOne");
newLink = std::make_shared<OneToOneLink<TElem>>(*this);
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "nodes/LeafNode.h"
#include "mixins/FabricMixin.h"
#include "Logger.h"
/// \brief Узел дисциплины BFIFO. Лист.
class BFIFONode : public LeafNode,
public FabricMixin<BFIFONode> {
public:
~BFIFONode() {
Logger::get("ConDes").dbg(std::string("--- BFIFO destructor called for: ") + name_);
}
private:
friend class FabricMixin<BFIFONode>;
BFIFONode(std::string name) : LeafNode(std::move(name), "BFIFO") {
Logger::get("ConDes").dbg(std::string("--- BFIFO constructor called for: ") + name_);
}
};
+5 -1
View File
@@ -7,9 +7,13 @@
/// Содержит имя и тип узла, реализует интерфейс INode.
class BaseNode : public virtual INode {
public:
BaseNode(std::string name) : name_(std::move(name)) {
/// \brief Конструктор узла.
/// \param name Неуникальное имя узла.
BaseNode(std::string&& name, std::string kind) :
name_(std::move(name)), kind_(std::move(kind)) {
Logger::get("ConDes").dbg(std::string("--- Base constructor called for: ") + name_);
}
/// \brief Неуникальное имя узла.
const std::string& name() const override { return name_; }
const std::string& kind() const override { return kind_; }
~BaseNode() {
+4 -5
View File
@@ -9,15 +9,14 @@
/// Может содержать несколько дочерних узлов такого же типа или один узел
/// отличного типа.
class ComplexNode : public BaseNode,
virtual public HierarchicalLinkMixin<INode>,
public FabricMixin<ComplexNode> {
virtual public HierarchicalLinkMixin<INode> {
public:
~ComplexNode() {
Logger::get("ConDes").dbg(std::string("--- Complex destructor called for: ") + name_);
}
private:
friend class FabricMixin<ComplexNode>;
ComplexNode(std::string name) : BaseNode(std::move(name)) {
protected:
ComplexNode(std::string&& name, std::string kind) :
BaseNode(std::move(name), std::move(kind)) {
Logger::get("ConDes").dbg(std::string("--- Complex constructor called for: ") + name_);
}
};
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "nodes/ComplexNode.h"
#include "mixins/FabricMixin.h"
#include "Logger.h"
/// \brief Узел дисциплины HTB. Составной, допускает нескольких детей.
class HTBNode : public ComplexNode,
public FabricMixin<HTBNode> {
public:
~HTBNode() {
Logger::get("ConDes").dbg(std::string("--- HTB destructor called for: ") + name_);
}
private:
friend class FabricMixin<HTBNode>;
HTBNode(std::string&& name) : ComplexNode(std::move(name), "HTB") {
Logger::get("ConDes").dbg(std::string("--- HTB constructor called for: ") + name_);
}
};
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "nodes/BaseNode.h"
#include "mixins/LazyLinkMixin.h"
#include "mixins/FabricMixin.h"
#include "links/LeafLink.h"
#include "Logger.h"
/// \brief Базовый класс для краевых (листовых) узлов дисциплин.
/// Не допускает дочерних элементов.
class LeafNode : public BaseNode,
virtual public LazyLinkMixin<LeafLink<INode>> {
public:
~LeafNode() {
Logger::get("ConDes").dbg(
std::string("--- Leaf destructor called for: ") + name_
);
}
protected:
LeafNode(std::string&& name, std::string kind) :
BaseNode(std::move(name), std::move(kind)) {
Logger::get("ConDes").dbg(
std::string("--- Leaf constructor called for: ") +
name_ + ", kind=" + kind_
);
}
};
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "nodes/LeafNode.h"
#include "mixins/FabricMixin.h"
#include "Logger.h"
/// \brief Узел дисциплины PFIFO. Лист.
class PFIFONode : public LeafNode,
public FabricMixin<PFIFONode> {
public:
~PFIFONode() {
Logger::get("ConDes").dbg(std::string("--- PFIFO destructor called for: ") + name_);
}
private:
friend class FabricMixin<PFIFONode>;
PFIFONode(std::string name) : LeafNode(std::move(name), "PFIFO") {
Logger::get("ConDes").dbg(std::string("--- PFIFO constructor called for: ") + name_);
}
};
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "nodes/LeafNode.h"
#include "mixins/FabricMixin.h"
#include "Logger.h"
/// \brief Узел дисциплины RED. Лист; не допускает дочерних элементов.
class REDNode : public LeafNode,
public FabricMixin<REDNode> {
public:
~REDNode() {
Logger::get("ConDes").dbg(std::string("--- RED destructor called for: ") + name_);
}
private:
friend class FabricMixin<REDNode>;
REDNode(std::string name) : LeafNode(std::move(name), "RED") {
Logger::get("ConDes").dbg(std::string("--- RED constructor called for: ") + name_);
}
};
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include "nodes/BaseNode.h"
#include "mixins/LazyLinkMixin.h"
#include "mixins/FabricMixin.h"
#include "links/TypedOneToOneLink.h"
#include "nodes/REDNode.h"
#include "Logger.h"
/// \brief Узел дисциплины SFQ. Допускает одного ребёнка типа REDNode для настройки per-flow RED.
class SFQNode : public BaseNode,
virtual public LazyLinkMixin<TypedOneToOneLink<INode, REDNode>>,
public FabricMixin<SFQNode> {
public:
~SFQNode() {
Logger::get("ConDes").dbg(std::string("--- SFQ destructor called for: ") + name_);
}
private:
friend class FabricMixin<SFQNode>;
SFQNode(std::string&& name) : BaseNode(std::move(name), "SFQ") {
Logger::get("ConDes").dbg(std::string("--- SFQ constructor called for: ") + name_);
}
};
+3 -5
View File
@@ -9,15 +9,13 @@
/// \brief Класс простого (листового) узла дерева.
/// Может содержать только одного дочернего ComplexNode.
class SimpleNode : public BaseNode,
virtual public LazyLinkMixin<OneToOneLink<INode>>,
public FabricMixin<SimpleNode> {
virtual public LazyLinkMixin<OneToOneLink<INode>>{
public:
~SimpleNode() {
Logger::get("ConDes").dbg(std::string("--- Simple destructor called for: ") + name_);
}
private:
friend class FabricMixin<SimpleNode>;
SimpleNode(std::string name) : BaseNode(std::move(name)) {
protected:
SimpleNode(std::string&& name) : BaseNode(std::move(name)) {
Logger::get("ConDes").dbg(std::string("--- Simple constructor called for: ") + name_);
}
};
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include "nodes/BaseNode.h"
#include "mixins/LazyLinkMixin.h"
#include "mixins/FabricMixin.h"
#include "links/TypedOneToManyLink.h"
#include "nodes/REDNode.h"
#include "Logger.h"
class WREDNode : public BaseNode,
virtual public LazyLinkMixin<TypedOneToManyLink<INode, REDNode>>,
public FabricMixin<WREDNode> {
public:
~WREDNode() {
Logger::get("ConDes").dbg(std::string("--- WRED destructor called for: ") + name_);
}
private:
friend class FabricMixin<WREDNode>;
WREDNode(std::string&& name) : BaseNode(std::move(name), "WRED") {
Logger::get("ConDes").dbg(std::string("--- WRED constructor called for: ") + name_);
}
};