Skip to content
Prev Previous commit
Next Next commit
[#3860] More vendor
  • Loading branch information
fxdupont committed Aug 21, 2025
commit de7139a94b45f399d91940656fb1323ce8f0b554
51 changes: 25 additions & 26 deletions src/hooks/dhcp/radius/cfg_attribute.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,12 @@ CfgAttributes::add(const AttrDefPtr& def,
if (!def) {
isc_throw(BadValue, "no attribute definition");
}
container_.insert(pair<const uint8_t, AttributeValue>
(def->type_, AttributeValue(def, attr, expr, test)));
container_.insert(AttributeValue(def, attr, expr, test));
}

bool
CfgAttributes::del(const uint8_t type) {
auto it = container_.find(type);
CfgAttributes::del(const uint8_t type, const uint32_t vendor) {
auto it = container_.find(boost::make_tuple(vendor, type));
if (it != container_.end()) {
container_.erase(it);
return (true);
Expand All @@ -43,46 +42,46 @@ CfgAttributes::del(const uint8_t type) {
}

AttrDefPtr
CfgAttributes::getDef(const uint8_t type) const {
auto it = container_.find(type);
CfgAttributes::getDef(const uint8_t type, const uint32_t vendor) const {
auto it = container_.find(boost::make_tuple(vendor, type));
if (it == container_.end()) {
return (AttrDefPtr());
}
return (it->second.def_);
return (it->def_);
}

ConstAttributePtr
CfgAttributes::get(const uint8_t type) const {
auto it = container_.find(type);
CfgAttributes::get(const uint8_t type, const uint32_t vendor) const {
auto it = container_.find(boost::make_tuple(vendor, type));
if (it == container_.end()) {
return (AttributePtr());
}
return (it->second.attr_);
return (it->attr_);
}

ExpressionPtr
CfgAttributes::getExpr(const uint8_t type) const {
auto it = container_.find(type);
CfgAttributes::getExpr(const uint8_t type, const uint32_t vendor) const {
auto it = container_.find(boost::make_tuple(vendor, type));
if (it == container_.end()) {
return (ExpressionPtr());
}
return (it->second.expr_);
return (it->expr_);
}

string
CfgAttributes::getTest(const uint8_t type) const {
auto it = container_.find(type);
CfgAttributes::getTest(const uint8_t type, const uint32_t vendor) const {
auto it = container_.find(boost::make_tuple(vendor, type));
if (it == container_.end()) {
return ("");
}
return (it->second.test_);
return (it->test_);
}

Attributes
CfgAttributes::getAll() const {
Attributes attrs;
for (auto const& it : container_) {
attrs.add(it.second.attr_);
attrs.add(it.attr_);
}
return (attrs);
}
Expand All @@ -91,16 +90,16 @@ Attributes
CfgAttributes::getEvalAll(Pkt& pkt) {
Attributes attrs;
for (auto const& it : container_) {
const ExpressionPtr& match_expr = it.second.expr_;
const ExpressionPtr& match_expr = it.expr_;
if (!match_expr) {
attrs.add(it.second.attr_);
attrs.add(it.attr_);
continue;
}
string value = evaluateString(*match_expr, pkt);
if (value.empty()) {
continue;
}
AttrDefPtr def = it.second.def_;
AttrDefPtr def = it.def_;
if (!def) {
continue;
}
Expand All @@ -117,18 +116,18 @@ ElementPtr
CfgAttributes::toElement() const {
ElementPtr result = Element::createList();
for (auto const& it : container_) {
AttrDefPtr def = it.second.def_;
AttrDefPtr def = it.def_;
if (!def) {
continue;
}
ElementPtr map;
if (!it.second.test_.empty()) {
if (!it.test_.empty()) {
map = Element::createMap();
map->set("type", Element::create(static_cast<int>(it.first)));
map->set("expr", Element::create(it.second.test_));
map->set("type", Element::create(static_cast<int>(def->type_)));
map->set("expr", Element::create(it.test_));
map->set("name", Element::create(def->name_));
} else if (it.second.attr_) {
map = it.second.attr_->toElement();
} else if (it.attr_) {
map = it.attr_->toElement();
}
result->add(map);
}
Expand Down
64 changes: 55 additions & 9 deletions src/hooks/dhcp/radius/cfg_attribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
#include <dhcp/pkt.h>
#include <eval/token.h>
#include <util/buffer.h>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
#include <map>
Expand Down Expand Up @@ -81,8 +85,9 @@ class CfgAttributes : public data::CfgToElement {
/// Deletes only the first occurrence.
///
/// @param type type of the attribute to delete.
/// @param vendor vendor id (default 0).
/// @return true if found.
bool del(const uint8_t type);
bool del(const uint8_t type, const uint32_t vendor = 0);

/// @brief Clear the container.
void clear() {
Expand All @@ -92,34 +97,41 @@ class CfgAttributes : public data::CfgToElement {
/// @brief Counts instance of the attribute in the configuration.
///
/// @param type type of the attribute to count.
/// @return count of attributes with the given type in the configuration.
size_t count(const uint8_t type) const {
return (container_.count(type));
/// @param vendor vendor id (default 0).
/// @return count of attributes with the given type and vendor
/// in the configuration.
size_t count(const uint8_t type, const uint32_t vendor = 0) const {
return (container_.count(boost::make_tuple(vendor, type)));
}

/// @brief Returns the definition of an attribute.
///
/// @param type type of the attribute.
/// @param vendor vendor id (default 0).
/// @return the definition of the attribute.
AttrDefPtr getDef(const uint8_t type) const;
AttrDefPtr getDef(const uint8_t type, const uint32_t vendor = 0) const;

/// @brief Get instance of the attribute in the configuration.
///
/// @param type type of the attribute to retrieve.
/// @param vendor vendor id (default 0).
/// @return the first instance if exists.
ConstAttributePtr get(const uint8_t type) const;
ConstAttributePtr get(const uint8_t type, const uint32_t vendor = 0) const;

/// @brief Returns the expression of an attribute.
///
/// @param type type of the attribute.
/// @param vendor vendor id (default 0).
/// @return the expression of the attribute.
dhcp::ExpressionPtr getExpr(const uint8_t type) const;
dhcp::ExpressionPtr getExpr(const uint8_t type,
const uint32_t vendor = 0) const;

/// @brief Returns the text expression of an attribute.
///
/// @param type type of the attribute.
/// @param vendor vendor id (default 0).
/// @return the text expression of the attribute.
std::string getTest(const uint8_t type) const;
std::string getTest(const uint8_t type, const uint32_t vendor = 0) const;

/// @brief Get all attributes in the configuration.
///
Expand Down Expand Up @@ -182,10 +194,44 @@ class CfgAttributes : public data::CfgToElement {

/// @brief Original expression.
std::string test_;

/// @brief Return the type.
uint8_t getType() const {
if (!def_) {
isc_throw(BadValue, "no attribute definition");
}
return (def_->type_);
}

/// @brief Return the vendor.
uint32_t getVendor() const {
if (!def_) {
isc_throw(BadValue, "no attribute definition");
}
return (def_->vendor_);
}
};

/// @brief The container.
std::multimap<uint8_t, AttributeValue> container_;
boost::multi_index_container<
// This container stores AttributeValue objects.
AttributeValue,
// Start specification of indexes here.
boost::multi_index::indexed_by<
// Hash index for by vendor and type.
boost::multi_index::hashed_non_unique<
boost::multi_index::composite_key<
AttributeValue,
boost::multi_index::const_mem_fun<
AttributeValue, uint32_t, &AttributeValue::getVendor
>,
boost::multi_index::const_mem_fun<
AttributeValue, uint8_t, &AttributeValue::getType
>
>
>
>
> container_;
};

} // end of namespace isc::radius
Expand Down
34 changes: 33 additions & 1 deletion src/hooks/dhcp/radius/client_attribute.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ Attribute::fromText(const AttrDefPtr& def, const string& value) {
if (value.empty()) {
isc_throw(BadValue, "empty attribute value");
}
AttributePtr attr = fromText0(def, value);
if (def->vendor_ == 0) {
return (attr);
}
// Encapsulate into a Vendor-Specific attribute.
const vector<uint8_t> vsa_data = attr->toBytes();
return (fromVsa(PW_VENDOR_SPECIFIC, def->vendor_, vsa_data));
}

AttributePtr
Attribute::fromText0(const AttrDefPtr& def, const string& value) {
switch (static_cast<uint8_t>(def->value_type_)) {
case PW_TYPE_STRING:
return (AttrString::fromText(def->type_, value));
Expand Down Expand Up @@ -92,6 +103,17 @@ Attribute::fromBytes(const AttrDefPtr& def, const vector<uint8_t>& value) {
if (value.empty()) {
isc_throw(BadValue, "empty attribute value");
}
AttributePtr attr = fromBytes0(def, value);
if (def->vendor_ == 0) {
return (attr);
}
// Encapsulate into a Vendor-Specific attribute.
const vector<uint8_t> vsa_data = attr->toBytes();
return (fromVsa(PW_VENDOR_SPECIFIC, def->vendor_, vsa_data));
}

AttributePtr
Attribute::fromBytes0(const AttrDefPtr& def, const vector<uint8_t>& value) {
switch (static_cast<uint8_t>(def->value_type_)) {
case PW_TYPE_STRING:
return (AttrString::fromBytes(def->type_, value));
Expand Down Expand Up @@ -209,7 +231,7 @@ Attribute::toVendorId() const {
<< attrValueTypeToText(getValueType()));
}

string
std::vector<uint8_t>
Attribute::toVsaData() const {
isc_throw(TypeError, "the attribute value type must be vsa, not "
<< attrValueTypeToText(getValueType()));
Expand Down Expand Up @@ -695,6 +717,16 @@ AttrVsa::toBytes() const {
return (output);
}

std::vector<uint8_t>
AttrVsa::toVsaData() const {
vector<uint8_t> binary;
binary.resize(value_.size());
if (binary.size() > 0) {
memmove(&binary[0], &value_[0], binary.size());
}
return (binary);
}

ElementPtr
AttrVsa::toElement() const {
ElementPtr output = Element::createMap();
Expand Down
34 changes: 28 additions & 6 deletions src/hooks/dhcp/radius/client_attribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ class Attribute : public data::CfgToElement {

/// From definition generic factories.

/// @brief From text with definition.
/// @brief From text with definition (handle vendor).
///
/// Handle Vendor-Specific encapsulation.
///
/// @param def pointer to attribute definition.
/// @param value textual value.
Expand All @@ -87,7 +89,9 @@ class Attribute : public data::CfgToElement {
static AttributePtr fromText(const AttrDefPtr& def,
const std::string& value);

/// @brief From bytes with definition.
/// @brief From bytes with definition (handle vendor).
///
/// Handle Vendor-Specific encapsulation.
///
/// @param def pointer to attribute definition.
/// @param value binary value.
Expand Down Expand Up @@ -251,10 +255,30 @@ class Attribute : public data::CfgToElement {
///
/// @return the vsa data.
/// @throw TypeError if the attribute is not a vsa one.
virtual std::string toVsaData() const;
virtual std::vector<uint8_t> toVsaData() const;

/// @brief Type.
const uint8_t type_;

private:

/// @brief From text with definition.
///
/// @param def pointer to attribute definition.
/// @param value textual value.
/// @return pointer to the attribute.
/// @throw BadValue on errors.
static AttributePtr fromText0(const AttrDefPtr& def,
const std::string& value);

/// @brief From bytes with definition.
///
/// @param def pointer to attribute definition.
/// @param value binary value.
/// @return pointer to the attribute.
/// @throw BadValue on errors.
static AttributePtr fromBytes0(const AttrDefPtr& def,
const std::vector<uint8_t>& value);
};

/// @brief RADIUS attribute derived classes: do not use them directly
Expand Down Expand Up @@ -764,9 +788,7 @@ class AttrVsa : public Attribute {
/// @brief To vsa data.
///
/// @return the vsa data.
virtual std::string toVsaData() const override {
return (value_);
}
virtual std::vector<uint8_t> toVsaData() const override;

/// @brief Unparse attribute.
///
Expand Down
Loading