Thoughts on DHCP Option definition design
Marcin Siodelski
marcin at isc.org
Fri Sep 21 11:24:50 UTC 2012
Hi All,
I have recently started working on tickets #2232 and #2233. Before I
write a document on bind10 wiki I am looking forward to comments about
the design. As a prework to the task I went through the functionality of
Bind10 Config Manager (assuming that we want it to be used as a basic
mechanism to configure options contents and possibly define the options
layout). I also went through the documentation of legacy DHCPv4 where I
found how Options are defined. I also spoke to Tomek who always have a
lot of "good points". Finnaly here is a collection of thoughts I have
with respect to DHCPv6 Option definition design. Sorry for making it a
little extensive.
-----------
How to read it. I separated the topics with keyword "Requirement" that
indicates brifely what I think should be achieved. Each following line
starts with "dash" which is a beginning of the explanation how it is
going to be achieved.
-----------
Requirement: Give the ability to define custom option formats to DHCP
administrators without a need to write the code
- One of the possible ways to go would be to use BIND10 Configuration
Manager data structure to hold options definition. Options format varies
from simple options: OPCODE, LENGTH, UINT8 VALUE to much more complex
that hold arrays of values, arrays of structures and having suboptions.
I personally like the way it is currently done in DHCPv4 (with some
exceptions where I think developers went too far trying to create new
programming language). The way you define the option with single UINT8
would be:
{{{
option OPTION_FOO code 1234 = uint8;
}}}
If you want to have array of uint8s you do
{{{
option OPTION_FOO2 code 5678 = array of uint8;
}}}
You may even have array of records:
{{{
option OPTION_FOO3 code 91011 = { boolean, text, uint8 }
}}}
I like the simplicity of this solution so I would like to preserve it in
the design being created.
Requirement: Limit the number of different configuration files for the
same thing.
- Possible way to go that I was considering initially was to have a
separate config file that would accept format well known from DHCP4 to
define new options and put the reference to it in Configuration Manager.
The DHCP server reads and parses this file on its own. This would give
the advantage that people who got used to this format would be happy
that they don't have to learn new things. However they will have to
anyway because Config Manager will be used for defining option contents.
For this reason I finally came to solution that we could store the same
data but in the .spec file:
{
"module_spec": {
"module_name": "DHCP6",
"module_description": "DHCPv6 server daemon",
"config_data": [
{ "item_name": "interface",
"item_type": "string",
"item_optional": false,
"item_default": "eth0"
},
{ "item_name": "option_formats",
"item_type": "list",
"item_optional": false,
"item_default" : [
{ "option_name": "OPTION_FOO",
"option_code": 1234,
"option_data_types": "uint8"
},
{ "option_name": "OPTION_FOO2",
"option_code": 5678,
"option_data_types": "array of uint8"
}
{ "option_name": "OPTION_FOO3",
"option_code": 9012,
"option_data_types": "{ boolean, text, uint8 }"
}
],
"list_item_spec": {
"item_name": "option_format",
"item_type": "map",
"item_optional": false,
"item_default": [ ],
"map_item_spec": [
{ "item_name": "option_name",
"item_type": "string",
"item_optional": false,
"item_default": ""
},
{ "item_name": "option_code",
"item_type": "integer",
"item_optional": false,
"item_default: ""
},
{ "item_name": "option_data_types",
"item_type": "string",
"item_optional": true,
"item_default: "",
}
]
}
],
....
Note that at this point I omit setting the options contents so as the
.spec file is cleaner.
The option_data_types (which I don't know if is a best name) holds the
free text and this text can't be validated until the server gets it and
parses. But functionally it is the same thing as in DHCP4 and allows for
extensions to support more keywords.
Requirement: User can't override the format of the standard option.
- I can't think of any motivation why somebody would want to change the
format of standard option. If he or she wants to carry more data it is
possible to define new option to carry this data. If somebody wants to
change the order of fields in the standard option this opens the door to
the number of support requests to ISC like: "my server does not accept
CLIENTID option, please help!" just because somebody changed the client
id type to uint8. Thus, standard options format should not be defined in
the .spec file and if somebody tries to define the new option format
whith the code of CLIENTID option server should reject it. This means
that server has to store the standard option codes and names and
validate new options being defined against it.
Requirement: Only some standard options may have their content set by
the user.
- Many standard options have their content set in flight (based on
information coming from DHCP client). CLIENTID value is based on "who
the client is" so setting the arbitrary value does not make sense.
Attempt to set CLIENTID through the spec file should result in failure.
Thus, server has to carry the information which of the standard options
can be overriden and which not. Hardcoding it in the function with
switch() statement or number of ifs should be sufficient.
Requirement: Custom options value should be always set.
- Data carried by custom options are somewhat transparent to the server
and server has no way to set them on his own discretion. For this
reason, if user defined the new option he MUST set its value too. If it
doesn't than server should report an error. In fact it should be
prohibited to add new option without setting its data. Once option is
added the data can be modified but not removed. We could extend the
option definition data format to do something like this maybe:
{{{
{ "option_name": "OPTION_FOO3",
"option_code": 9012,
"option_data_types": "{ boolean, text, uint8 }"
"option_data_values": "{ true, "xyz", 8 }"
}
}}}
Obviously, it would be up to the server to make sure that entered values
are consistent with their types.
Requirement: Some options must be always sent to the user, some not.
- In many cases, DHCP client asks for specific options (using ORO) in
some cases server should always send the specific options even if not
asked. We need to have a flag in the data structure that would inform
the server that option is to be always sent. By default this flag could
be set to false. Extending the spec file to this would work:
{{{
"list_item_spec": {
"item_name": "option_format",
"item_type": "map",
"item_optional": false,
"item_default": [ ],
"map_item_spec": [
{ "item_name": "option_name",
"item_type": "string",
"item_optional": false,
"item_default": ""
},
{ "item_name": "option_code",
"item_type": "integer",
"item_optional": false,
"item_default: ""
},
{ "item_name": "always_send",
"item_type": boolean,
"item_optional": true,
"item_default": false
},
{ "item_name": "option_data_types",
"item_type": "string",
"item_optional": true,
"item_default: "",
}
}}}
Requirement: Use the same data structure to create new options and
configure new and standard options.
- This may be a little tricky but I think it is good to have single data
structure to define option formats and set values of all options
(incouding new and standard). For example, if one wanted to set the
contents of SERVERID and always send it to the user he would do somthing
like this in the spec file:
{{{
{ "option_name": "OPTION_SERVERID",
"option_code": 2,
"always_send": true,
"option_data_values": "xyzabcdfg"
}
}}}
Note that SERVERID is a standard option so user is not allowed to change
its format but it is right thing to set the serverid and tell that it
should be always sent. The more problematic thing is that user can
actually override the option_data_types like this:
{{{
{ "option_name": "OPTION_SERVERID",
"option_code": 2,
"always_send": true,
"option_data_types": ""
"option_data_values": "xyzabcdfg"
}
}}}
which does not result in any effect because by default it is an empty
string but the fact is that user overriden this value and server has no
ability to check it unless it is overriden to anything else than empty
string. Is this really an issue?
I did not yet consider "Options encapsulation" yet but as far as I know
it doesn't yet work really well in DHCP4. Should this be discussed here?
Lastly, I haven't made any attempts to specify CfgMgr commands to modify
the data and in fact I don't thing there is any sense to do this until
we define the final data structure in CfgMgr.
Please share your thoughts on this.
Marcin
More information about the bind10-dhcp
mailing list