[kea-dev] Some thoughts about client classification

Marcin Siodelski marcin at isc.org
Wed Sep 30 09:39:31 UTC 2015



On 25.09.2015 15:59, Tomek Mrugalski wrote:
> On 21.09.2015 21:08, Stephen Morris wrote:
>> Creation of client class
>> ---
>> Client classes are defined in a clause within the "Dhcp4" or "Dhcp6"
>> blocks, and contain the name of the class and a single "test" clause,
>> that defines the criteria for inclusion in that class, e.g.
>>
>> "client-classes": [
>>     {
>>         "name": "class-name",
>> 	"test": [ selector, op, value ]
>>     },
>>     {
>>         "name": "class-name",
>>         "test": [ selector, op, value ]
>>     }...
>> ]
>>
>> The "test" component is an array giving the name of the selector in the
>> packet, a comparison operation, and a comparison value.  To keep things
>> simple, everything is done as string comparisons. This means that for a
>> first pass:
>>
>> * The values of integers are converted to base 10 string format before
>> being checked.
>> * IP addresses are converted to presentation format.
>> * Boolean values are converted to "true" or "false".
>> * Binary data is converted to a hexadecimal string.
> This should be a generic mechanism for any class to text representation.
> 
>> "selector" is either the name of a field in the packet or the name of an
>> option carried by the packet.  If an option is an array, then the
>> elements of the array are concatenated together (possibly separated by a
>> separator such as "/" or ";") before being used in the comparison. If a
>> substring is required, that is included in the name of the selector by
>> suffixing it with "[start-offset:end-offset]".
>>
>> "op" is one of: "lt", "le", "eq", "ne", "ge", "gt" or "match".  The
>> first six are self-explanatory and compare the string derived from the
>> option with the value.  "match" checks if the option string matches the
>> regular expression.
>>
>> "value" is the value to compare against.
> This will work only for very basic case and is not extensible to more
> advanced cases. To be more specific let me give a very concrete example.
> 
> In cable networks, there's an essential need to distinguish if the
> device is a cable modem or something behind it. To test it, the DHCP
> server must compare hw address of the packet with value of subpoption
> 1023 in vendor information option with enterprise-id=4461, which itself
> it stored in RAI option put there by relay (CMTS). In logical terms,
> that looks more or less like this:
> 
> rai && rai.suboption(vivso) && (rai.suboption(vivso).enterprise-id ==
> 4461) && (rai.suboption(vivso).suboption(1023) == hwaddr)
> 
> Both the syntax and format proposed is inadequate. It has a number of
> other flaws. It does not cover unary operators (I want to assign clients
> to a class if option X exists or does not exist). It does not cover (and
> is not extensible for) any boolean operators.
> 
>> Kea searches the "client-classes" array testing the packet against each
>> element of the array in order.  The first clause that matches sets the
>> class of the packet to the name given. If no clause matches, the packet
>> is unclassified (i.e. its class name is the empty string "").
> That is incorrect as well. Packet can belong to zero or more classes.
> Sure, for now we assign only up to one class, but the structures and
> methods are prepared for handling multiple classes. In particular, cable
> networks are especially suitable for this. You can have cable_modems
> class, but also arris, arris_model123 etc. There's very good reason for
> such classes - each type of cable modem may require a different boot
> parameters. John said that sometimes even a different firmware version
> requires some tweaks.
> 
> -----------------------------------
> Here's my view on client classification:
> 
> 1. I agree with the "everything evaluates to string" approach
> All options need to be convertable to strings. We already have
> Option::toText(). Unfortunately, its format is intended for good
> readability. Therefore we'll need a replacement. Let's call it
> tentatively toString() (we can come up with a better name). We should
> implement a generic version in base Option class and also for selected
> few option types that we consider essential for 1.0. That will be
> extended in upcoming releases.
> 

It is going to be an overkill to always convert the whole option (or
whatever else) to a string in case you're just interested in checking a
value of a single option field.

Now you have to multiply it by the number of options you want to look
into for every single packet. I suggest that we design it in the way
that would allow for looking into individual option fields and don't
require conversion to string if native type (like integer) can be used.

This also has an advantage that 02 > 1.

> 2. Class definition. This is something that can start simple, but will
> eventually evolve to complex boolean expressions, including logical sum,
> alternative, parentheses and negations. For now, we can cover
> just simple operators, as Stephen had suggested, but the syntax must not
> be a limiting factor here. In my opinion, we should have an expression
> that is being evaluated. That's the most flexible and extensible approach.
> 
> For now, I think we should support the followign operations:
> == - matches when values are equal
> != - matches when values are different
>> , >=, <=, < - normal string comparisons (note: 02 < 1 )
> 

What do you mean by for now? 1.0? For 1.0 we need to cover simple PXE
boot scenarios we know of. This is comparison of a single option field
for equality and substring in the option.

> The proposed way to refer to options by their name is also a poor
> choice. For now, we'll cover only options. But soon you'll want to cover
> additional information, like packet fields (e.g. chaddr), but also other
> meta-information (e.g. source IP address, network interface, relay IP
> address, number of relays, specific option X from relay Y etc.).
> Therefore options should be referred to as option[number] or
> option[option-name]. This is essential especially in DHCPv6, which is
> nested and each relay adds another encapsulation level. In cascade
> relays scenario, each relay may add a different instance of the same
> option. One day we must be able to distinguish between them.
> 
> For 1.0 we should have a generic way to extract option value that works
> well for few (integer, address, string, fqdn) option types. We also
> should add a couple fields. chaddr is the obvious one, but also likely
> giaddr (to classify based on relay addresses in v4 and maybe htype. We
> will add more support for other fields in upcoming releases.
> 

I don't think we need chaddr and giaddr and such for 1.0. Though, I
agree that it should be possible to extend the client classification to
also look into those.

> Two important aspects to consider here are regular expressions and
> binary/hex format. One day (after 1.0) we should implement an operator
> regexp(value, regexp) that would evaluate a regular expression. Another
> would be something like base converter in ISC DHCP. That's something
> that we'll add later.
> 

Some sort of regex is needed now - that is an ability to look into the
option for substring. We can't postpone it for later.

> Also, for more complex options, it would be very useful to extract
> specific fields. something like fqdn.name, fqdn.n_bit or similar. This
> is something I think can be done after 1.0.
> 

I actually think it should be done now in favor of various operators
like less than, greater than etc.

> For 1.0 we can probably live with a simple A operator B, but for the
> next release we should extend it to cover parentheses and more complex
> expressions. To handle arbitrary complex expressions, we'll need to
> implement reverse polish notation, but it's not difficult.
> 
> Finally, the design does not cover one important thing: an ability to
> use result of the expression as a class. Right now we extract content of
> vendor-class as use it as VENDOR_CLASS_[content]. There's C++ code that
> does that. Something similar should be doable by users, without a need
> to write C++ code.
> 
> To wrap it up, in my opinion the class definition would look like this:
> 
>  "client-classes": [
>      {
>          "name": "class-name1",
>  	 "test": "(any-expression-here)"
>      },
>      {
>          "name": "class-name",
>          "test": "(any-expression-here)"
>      }...
>  ]
> 
> Examples:
>  "test": "chaddr == 08002b02deadbeef"
> ... matches if the hardware address (in the "chaddr" field) is that
> specified.
> 
>   "test": ["option[vendor-class-identifier] contains "foo"]
> Matches if the vendor class identifier option contains the string "foo"
> somewhere in it. (Previous proposal was to use 'match' which may be
> easily mistunderstood as "match in its entirety".
> 
>> Use of class information
>> The current classification scheme requires that for a configuration
>> block to be used, it must either contain no class name or, if it does,
>> the name must match the class associated with the packet.
> There are several levels on which client classification can be used:
> 1. subnet - in subnet X allow only clients from class Y
> 2. pool - in pool X allow only clients from class Y
> 3. options - use options X,Y,Z for clients from class Y
> 4. host - for a given host reservation, automatically assign to class X
> 

I think that nothing but subnet-level classification is required for
1.0, because it would cover existing use cases.

> We already have support for #1. I think it's realistic to have #2.
> implemented in 1.0. #3 is also very useful, but it would require
> implementing parsers for options nested in class definitions. This is
> tedious work and I think we can't realistically shove it into 1.0. This
> is a complex topic for testing and we don't want to rush things just
> before 1.0. Hopefully lots of people will look at Kea once it reaches
> 1.0. We can't risk news like "kea 1.0 is broken, because classification
> doesn't work".
> 
> Tomek
> 
> p.s.
> We did spend a lot of time discussing client classification during last
> and previous all-hands. Anyone bothered to look at our notes?
> 
> _______________________________________________
> kea-dev mailing list
> kea-dev at lists.isc.org
> https://lists.isc.org/mailman/listinfo/kea-dev
> 


More information about the kea-dev mailing list