return (AttrIpv6Addr::fromText(def->type_, value));
case PW_TYPE_IPV6PREFIX:
return (AttrIpv6Prefix::fromText(def->type_, value));
+ case PW_TYPE_VSA:
+ return (AttrVSA::fromText(def->type_, value));
default:
// Impossible case.
isc_throw(OutOfRange, "unknown value type "
return (AttrIpv6Addr::fromBytes(def->type_, value));
case PW_TYPE_IPV6PREFIX:
return (AttrIpv6Prefix::fromBytes(def->type_, value));
+ case PW_TYPE_VSA:
+ return (AttrVSA::fromBytes(def->type_, value));
default:
// Impossible case.
isc_throw(OutOfRange, "unknown value type "
string
Attribute::toString() const {
- isc_throw(TypeError, "the attribute value type must be string, not "
+ isc_throw(TypeError, "the attribute value type must be string or vsa, not "
<< attrValueTypeToText(getValueType()));
}
vector<uint8_t>
Attribute::toBinary() const {
- isc_throw(TypeError, "the attribute value type must be string, not "
+ isc_throw(TypeError, "the attribute value type must be string or vsa, not "
<< attrValueTypeToText(getValueType()));
}
<< attrValueTypeToText(getValueType()));
}
+uint32_t
+Attribute::toVendorId() const {
+ isc_throw(TypeError, "the attribute value type must be vsa, not "
+ << attrValueTypeToText(getValueType()));
+}
+
+void
+Attribute::setVendorId(const uint32_t vendor) {
+ isc_throw(TypeError, "the attribute value type must be vsa, not "
+ << attrValueTypeToText(getValueType()));
+}
+
AttrString::AttrString(const uint8_t type, const vector<uint8_t>& value)
: Attribute(type), value_() {
if (value.empty()) {
return (output);
}
+AttrVSA::AttrVSA(const uint8_t type, const int32_t vendor,
+ const vector<uint8_t>& value)
+ : Attribute(type), vendor_(vendor), value_() {
+ if (value.empty()) {
+ isc_throw(BadValue, "value is empty");
+ }
+ if (value.size() > MAX_VSA_DATA_LEN) {
+ isc_throw(BadValue, "value is too large " << value.size()
+ << " > " << MAX_VSA_DATA_LEN);
+ }
+ value_.resize(value.size());
+ memmove(&value_[0], &value[0], value_.size());
+}
+
+AttributePtr
+AttrVSA::fromText(const uint8_t type, const string& repr) {
+ isc_throw(NotImplemented, "Can't decode VSA from text");
+}
+
+AttributePtr
+AttrVSA::fromBytes(const uint8_t type, const vector<uint8_t>& bytes) {
+ if (bytes.empty()) {
+ isc_throw(BadValue, "empty attribute value");
+ }
+ if (bytes.size() < 5) {
+ isc_throw(BadValue, "value is too small " << bytes.size() << " < 5");
+ } else if (bytes.size() > MAX_STRING_LEN) {
+ isc_throw(BadValue, "value is too large " << bytes.size()
+ << " > " << MAX_STRING_LEN);
+ }
+ uint32_t vendor = bytes[0] << 24;
+ vendor |= bytes[1] << 16;
+ vendor |= bytes[2] << 8;
+ vendor |= bytes[3];
+ vector<uint8_t> value;
+ value.resize(bytes.size() - 4);
+ if (value.size() > 0) {
+ memmove(&value[0], &bytes[4], value.size());
+ }
+ return (AttributePtr(new AttrVSA(type, vendor, value)));
+}
+
+string
+AttrVSA::toText(size_t indent) const {
+ isc_throw(NotImplemented, "Can't encode VSA into text");
+}
+
+std::vector<uint8_t>
+AttrVSA::toBytes() const {
+ vector<uint8_t> output;
+ output.resize(2 + getValueLen());
+ output[0] = getType();
+ output[1] = 2 + getValueLen();
+ output[2] = (vendor_ & 0xff000000U) >> 24;
+ output[3] = (vendor_ & 0xff0000U) >> 16;
+ output[4] = (vendor_ & 0xff00U) >> 8;
+ output[5] = vendor_ & 0xffU;
+ if (output.size() > 6) {
+ memmove(&output[6], &value_[0], output.size() - 6);
+ }
+ return (output);
+}
+
+std::vector<uint8_t>
+AttrVSA::toBinary() const {
+ vector<uint8_t> binary;
+ binary.resize(getValueLen() - 4);
+ if (binary.size() > 0) {
+ memmove(&binary[0], &value_[0], binary.size());
+ }
+ return (binary);
+}
+
+ElementPtr
+AttrVSA::toElement() const {
+ ElementPtr output = Element::createMap();
+ AttrDefPtr def = AttrDefs::instance().getByType(getType());
+ if (def) {
+ output->set("name", Element::create(def->name_));
+ }
+ output->set("type", Element::create(static_cast<int>(getType())));
+ ostringstream vendor;
+ vendor << vendor_;
+ output->set("vendor", Element::create(vendor.str()));
+ vector<uint8_t> binary;
+ binary.resize(value_.size());
+ if (binary.size() > 0) {
+ memmove(&binary[0], value_.c_str(), binary.size());
+ }
+ string raw = encode::encodeHex(binary);
+ output->set("vsa-raw", Element::create(raw));
+ return (output);
+}
+
void
Attributes::add(const ConstAttributePtr& attr) {
if (!attr) {
/// @brief Maximum string size.
static constexpr size_t MAX_STRING_LEN = 253;
+/// @brief Maximum vsa data size.
+static constexpr size_t MAX_VSA_DATA_LEN = MAX_STRING_LEN - 4;
+
/// @brief Type error.
using isc::data::TypeError;
const uint8_t len,
const asiolink::IOAddress& value);
+ /// @brief From Vendor ID and string data with type.
+ ///
+ /// @note Requires the type to be of the Vendor Specific attribute (26).
+ ///
+ /// @param type type of attribute.
+ /// @param vendor vendor id.
+ /// @param value vsa data.
+ static AttributePtr fromVSA(const uint8_t type,
+ const uint32_t vendor,
+ const std::string& value);
+
+ /// @brief From Vendor ID and binary data with type.
+ ///
+ /// @note Requires the type to be of the Vendor Specific attribute (26).
+ ///
+ /// @param type type of attribute.
+ /// @param vendor vendor id.
+ /// @param value vsa data.
+ static AttributePtr fromVSA(const uint8_t type,
+ const uint32_t vendor,
+ const std::vector<uint8_t>& value);
+
/// Generic get methods.
/// @brief Value length.
/// @brief To string.
///
/// @return the string value.
- /// @throw TypeError if the attribute is not a string one.
+ /// @throw TypeError if the attribute is not a string or vsa one.
virtual std::string toString() const;
/// @brief To binary.
///
/// @return the string value as a binary.
- /// @throw TypeError if the attribute is not a string one.
+ /// @throw TypeError if the attribute is not a string or vsa one.
virtual std::vector<uint8_t> toBinary() const;
/// @brief To integer.
/// @throw TypeError if the attribute is not an ipv6prefix one.
virtual uint8_t toIpv6PrefixLen() const;
+ /// @brief To vendor id.
+ ///
+ /// @return the vendor id.
+ /// @throw TypeError if the attribute is not a vsa one.
+ virtual uint32_t toVendorId() const;
+
+ /// Generic set methods.
+
+ /// @brief Set vendor id.
+ ///
+ /// @param vendor vendor id.
+ /// @throw TypeError if the attribute is not a vsa one.
+ virtual void setVendorId(const uint32_t vendor);
+
/// @brief Type.
const uint8_t type_;
};
/// @brief RADIUS attribute holding strings.
class AttrString : public Attribute {
protected:
+
/// @brief Constructor.
///
/// @param type attribute type.
asiolink::IOAddress value_;
};
+/// @brief RADIUS attribute holding vsa.
+class AttrVSA : public Attribute {
+protected:
+
+ /// @brief Constructor.
+ ///
+ /// @param type attribute type.
+ /// @param vendor vendor id.
+ /// @param value string vsa data.
+ AttrVSA(const uint8_t type, const int32_t vendor, const std::string& value)
+ : Attribute(type), vendor_(vendor), value_(value) {
+ if (value.empty()) {
+ isc_throw(BadValue, "value is empty");
+ }
+ if (value.size() > MAX_VSA_DATA_LEN) {
+ isc_throw(BadValue, "value is too large " << value.size()
+ << " > " << MAX_VSA_DATA_LEN);
+ }
+ }
+
+ /// @brief Constructor.
+ ///
+ /// @param type attribute type.
+ /// @param vendor vendor id.
+ /// @param value binary vsa data.
+ AttrVSA(const uint8_t type, const int32_t vendor,
+ const std::vector<uint8_t>& value);
+
+ /// @brief From text.
+ ///
+ /// @param type attribute type.
+ /// @param repr value representation.
+ /// @return pointer to the attribute or null.
+ static AttributePtr fromText(const uint8_t type, const std::string& repr);
+
+ /// @brief From bytes.
+ ///
+ /// @param type attribute type.
+ /// @param bytes binary value.
+ /// @return pointer to the attribute or null.
+ static AttributePtr fromBytes(const uint8_t type,
+ const std::vector<uint8_t>& bytes);
+
+ /// Make Attribute a friend class.
+ friend class Attribute;
+
+public:
+
+ /// @brief Get value type.
+ ///
+ /// @return the value type.
+ virtual AttrValueType getValueType() const override {
+ return (PW_TYPE_VSA);
+ }
+
+ /// @brief Value length.
+ ///
+ /// @return Value length.
+ virtual size_t getValueLen() const override {
+ return (4 + value_.size());
+ }
+
+ /// @brief Returns text representation of the attribute.
+ ///
+ /// @param indent number of spaces before printing text.
+ /// @return string with text representation.
+ virtual std::string toText(size_t indent = 0) const override;
+
+ /// @brief To bytes.
+ ///
+ /// @return binary representation.
+ virtual std::vector<uint8_t> toBytes() const override;
+
+ /// @brief To string.
+ ///
+ /// @return the string value.
+ virtual std::string toString() const override {
+ return (value_);
+ }
+
+ /// @brief To binary.
+ ///
+ /// @return the string value as a binary.
+ virtual std::vector<uint8_t> toBinary() const override;
+
+ /// @brief To vendor id.
+ ///
+ /// @return the vendor id.
+ virtual uint32_t toVendorId() const override {
+ return (vendor_);
+ }
+
+ /// @brief Set vendor id.
+ ///
+ /// @param vendor vendor id.
+ virtual void setVendorId(const uint32_t vendor) override {
+ vendor_ = vendor;
+ }
+
+ /// @brief Unparse attribute.
+ ///
+ /// @return a pointer to unparsed attribute.
+ virtual data::ElementPtr toElement() const override;
+
+private:
+ /// @brief Vendor id.
+ uint32_t vendor_;
+
+ /// @brief Value.
+ std::string value_;
+};
+
+
/// @brief Collection of attributes.
class Attributes : public data::CfgToElement {
public:
return ("ipv6addr");
case PW_TYPE_IPV6PREFIX:
return ("ipv6prefix");
+ case PW_TYPE_VSA:
+ return ("vsa");
default:
// Impossible case.
return ("unknown?");
return (PW_TYPE_IPV6ADDR);
} else if (name == "ipv6prefix") {
return (PW_TYPE_IPV6PREFIX);
+ } else if (name == "vsa") {
+ return (PW_TYPE_VSA);
} else {
isc_throw(OutOfRange, "unknown AttrValueType name " << name);
}
isc_throw(Unexpected, "can't parse attribute type " << type_str);
}
AttrValueType value_type = textToAttrValueType(tokens[3]);
+ if ((value_type == PW_TYPE_VSA) && (type != PW_VENDOR_SPECIFIC)) {
+ isc_throw(BadValue, "only Vendor-Specific (26) attribute can "
+ << "have the vsa data type");
+ }
AttrDefPtr def(new AttrDef(type, name, value_type));
add(def);
return;
PW_TYPE_INTEGER,
PW_TYPE_IPADDR,
PW_TYPE_IPV6ADDR,
- PW_TYPE_IPV6PREFIX
+ PW_TYPE_IPV6PREFIX,
+ PW_TYPE_VSA
};
/// @brief AttrValueType value -> name function.
"the attribute value type must be ipv6prefix, not string");
EXPECT_THROW_MSG(attr->toIpv6PrefixLen(), TypeError,
"the attribute value type must be ipv6prefix, not string");
+ EXPECT_THROW_MSG(attr->toVendorId(), TypeError,
+ "the attribute value type must be vsa, not string");
}
// Verifies raw string attribute.
<< def_bytes->toText() << " != " << attr->toText();
EXPECT_THROW_MSG(attr->toString(), TypeError,
- "the attribute value type must be string, not integer");
+ "the attribute value type must be string or vsa, not integer");
EXPECT_THROW_MSG(attr->toBinary(), TypeError,
- "the attribute value type must be string, not integer");
+ "the attribute value type must be string or vsa, not integer");
EXPECT_THROW_MSG(attr->toIpAddr(), TypeError,
"the attribute value type must be ipaddr, not integer");
EXPECT_THROW_MSG(attr->toIpv6Addr(), TypeError,
EXPECT_THROW_MSG(attr->toIpv6Prefix(), TypeError,
"the attribute value type must be ipv6prefix, not integer");
EXPECT_THROW_MSG(attr->toIpv6PrefixLen(), TypeError,
- "the attribute value type must be ipv6prefix, not integer");
+ "the attribute value type must be ipv6prefix, not integer"
+);
+ EXPECT_THROW_MSG(attr->toVendorId(), TypeError,
+ "the attribute value type must be vsa, not integer");
}
// Verifies IP address attribute.
<< def_bytes->toText() << " != " << attr->toText();
EXPECT_THROW_MSG(attr->toString(), TypeError,
- "the attribute value type must be string, not ipaddr");
+ "the attribute value type must be string or vsa, not ipaddr");
EXPECT_THROW_MSG(attr->toBinary(), TypeError,
- "the attribute value type must be string, not ipaddr");
+ "the attribute value type must be string or vsa, not ipaddr");
EXPECT_THROW_MSG(attr->toInt(), TypeError,
"the attribute value type must be integer, not ipaddr");
EXPECT_THROW_MSG(attr->toIpv6Addr(), TypeError,
"the attribute value type must be ipv6prefix, not ipaddr");
EXPECT_THROW_MSG(attr->toIpv6PrefixLen(), TypeError,
"the attribute value type must be ipv6prefix, not ipaddr");
+ EXPECT_THROW_MSG(attr->toVendorId(), TypeError,
+ "the attribute value type must be vsa, not ipaddr");
}
// Verifies IPv6 address attribute.
<< def_bytes->toText() << " != " << attr->toText();
EXPECT_THROW_MSG(attr->toString(), TypeError,
- "the attribute value type must be string, not ipv6addr");
+ "the attribute value type must be string or vsa, not ipv6addr");
EXPECT_THROW_MSG(attr->toBinary(), TypeError,
- "the attribute value type must be string, not ipv6addr");
+ "the attribute value type must be string or vsa, not ipv6addr");
EXPECT_THROW_MSG(attr->toInt(), TypeError,
"the attribute value type must be integer, not ipv6addr");
EXPECT_THROW_MSG(attr->toIpAddr(), TypeError,
"the attribute value type must be ipv6prefix, not ipv6addr");
EXPECT_THROW_MSG(attr->toIpv6PrefixLen(), TypeError,
"the attribute value type must be ipv6prefix, not ipv6addr");
+ EXPECT_THROW_MSG(attr->toVendorId(), TypeError,
+ "the attribute value type must be vsa, not ipv6addr");
}
// Verifies IPv6 prefix attribute.
<< def_bytes->toText() << " != " << attr->toText();
EXPECT_THROW_MSG(attr->toString(), TypeError,
- "the attribute value type must be string, not ipv6prefix");
+ "the attribute value type must be string or vsa, not ipv6prefix");
EXPECT_THROW_MSG(attr->toBinary(), TypeError,
- "the attribute value type must be string, not ipv6prefix");
+ "the attribute value type must be string or vsa, not ipv6prefix");
EXPECT_THROW_MSG(attr->toInt(), TypeError,
"the attribute value type must be integer, not ipv6prefix");
EXPECT_THROW_MSG(attr->toIpAddr(), TypeError,
"the attribute value type must be ipaddr, not ipv6prefix");
EXPECT_THROW_MSG(attr->toIpv6Addr(), TypeError,
"the attribute value type must be ipv6addr, not ipv6prefix");
+ EXPECT_THROW_MSG(attr->toVendorId(), TypeError,
+ "the attribute value type must be vsa, not ipv6prefix");
}
// Verifies basic methods for attribute collection.
expected = "Illegal attribute redefinition of 'Service-Type' ";
expected += "type 6 value type integer by 6 string at line 2";
EXPECT_THROW_MSG(parseLines(new_value_type), BadValue, expected);
+
+ // Only the attribute 26 (Vendor-Specific) can have the vsa data type.
+ list<string> bad_vsa = {
+ "ATTRIBUTE Attr126 126 vsa"
+ };
+ expected = "only Vendor-Specific (26) attribute can have ";
+ expected += "the vsa data type at line 1";
+ EXPECT_THROW_MSG(parseLines(bad_vsa), BadValue, expected);
+
+ list<string> vsa = {
+ "ATTRIBUTE Attr26 26 vsa"
+ };
+ EXPECT_NO_THROW_LOG(parseLines(vsa));
}
// Verifies integer constant definitions.