Before 1.0.3, Pieter Hollants kindly implemented the XML I had earlier
suggested to support configure-by-number dhcp options in libvirt networks.
https://www.redhat.com/archives/libvir-list/2013-February/msg01251.html
I also posted a followup patch for a "force" attribute to options:
https://www.redhat.com/archives/libvir-list/2013-February/msg01349.html
I actually pushed a slightly fixed version of Pieter's patch, and was
looking for an ACK to mine when Eric questioned whether it was all
really ready to push since we hadn't implemented *named* options
(although there is no official RFC standard for the names of options,
dnsmasq uses a pretty good set of lowercase-dash-separated names that
make sense, and would certainly make it easier to decode the config). At
the time I had just started trying to write such a patch, and was
realizing that the XML we'd come up with didn't have any provision to
easily deal with an option that took a list of values (multiple IP
addresses, multiple domain names, etc); for numbered options we could
just punt on this and say "put the multiple values in the single 'value'
attribute, separated by commas", but we all know that's a cop-out, so I
decided to temporarily pull Pieter's patch to avoid regrets over getting
something suboptimal in an official release.
That's all the history. Now on to discussing how we should modify these
patches to be exactly what we want.
I tried digging down into the data of the options to try and make an
exhaustive XML representation, with the results below (these would all
go directly inside the <dhcp> element of a libvirt network). But it's
starting to seem like the deeper I go, the deeper it gets (the
classless-static-route option is the current "deepest", and I haven't
even attempted to do anything about vendor-specific options), so I'm
starting to wonder where to draw the line - see the "STEPPING BACK"
section at the bottom.
1) numeric option, single value:
<option code='119'>
<value type='domain' data='a.example.com'/>
</option>
(Note that I changed "number" to "code" after seeing that suggestion
in
[1] because that's what it's called in the RFC).
(Also note that the actual encoding of option 119's data is more
complicated than described here [2], but it's complicated enough that I
think whatever dhcp server implementation is underneath libvirt will
need to know the details anyway and decided what we should go for with
the "type" attribute is enough for libvirt to validate the input, not
necessarily to encode it into a DHCP response packet; any translation
from the validated input will be handled internally to the backend
driver (currently bridge_driver.c which uses dnsmasq) (I'm actually
wondering if type is needed in the XML at all, since the type of any
piece of data is always either implicit, or unknown (in which case we
just accept any text and pass it through to the backend driver).)
2) numeric option, multiple values:
<option code='119' force='yes'>
<value type='domain' data='a.example.com'/>
<value type='domain' data='b.example.com'/>
<value type='domain' data='c.example.com'/>
</option>
3) named option, single simple value:
<option name='ip-forward-enable'>
<value type='boolean' data='yes'/>
</option>
4) named option, multiple simple values:
<option name='dns-server'>
<value type='ipv4Addr' data='10.1.1.1'/>
<value type='ipv4Addr' data='10.1.1.2'/>
</option>
<option
(for all named options and known numeric options, the "type" field would
be optional, as libvirt will already have an internal table associating
option names/code with the type of data, as well as whether or not
multiples are allowed)
5) named option, multiple compound values:
<option name='classless-static-route'>
<value type='compound'>
<value type='ipv4Addr' data='1.2.3.0'/>
<value type='ipv4Prefix' data='24'/>
<value type='ipv4Addr' data='192.168.122.5'/>
</value>
<value type='compound'>
<value type='ipv4Addr' data='1.2.4.0'/>
<value type='ipv4Prefix' data='24'/>
<value type='ipv4Addr' data='192,.168.122.6'/>
</value>
</option>
(I suppose this could also be done as a flat list, since every static
route needs all three)
The types I can see that we need (to describe everything in RFC2132
(except vendor-specific options) and the other options I know about) are:
ipv4Addr
ipv4Prefix
text
path
domain
boolean
number
ANOTHER POSSIBILITY
===================
Another way of dealing with options that permit lists of multiple values
- just specify the option multiple times, e.g.:
<option name='dnsServer' type='ipv4Addr'
data='10.1.1.1'/>
<option name='dnsServer' type='ipv4Addr'
data='10.1.1.2'/>
============================
BTW - another point; I had earlier said that we didn't need to worry
about an option number blacklist/whitelist. After looking through the
options in RFC 2132, I've changed my mind - many of the option codes
(particularly those in the 50's) aren't really general purpose options,
but are used by dhcp as integral parts of implementing the exchange
sequence between the server and client. So I think what we need to do is
have a whitelist that has an entry for every dhcp option we are willing
to accept. It would contain:
uint8 code;
const char *name; /* could be "", in which case we don't recognize a
name for it */
unsigned int flags; /* whether or not multiple values are allowed,
name recognized by dnsmasq */
/* some representation of type here - what to do about the "compound"
type? */
STEPPING BACK
-------------
So are we going too far with this? Or should we dial it back to the
original proposal in Pieter's patch and just say that
1) if <option> is used, the data is passed through unqualified to the
dhcp implementation
2) only "simple", known option types with a single no-repeating value
can be specified this
way (and data type is implied)(this would be enforced with the
"whitelist")
3) then implement separate elements for the complicated/repeating
options, e.g.:
<route destination='1.2.3.0' prefix='24'
nextHop='192.168.122.5'/>
<route destination='1.2.4.0' prefix='24'
nextHop='192.168.122.6'/>
...
<dnsServer address='10.1.1.1'/>
<dnsServer address='10.1.1.2'/>
Or maybe to simplify the parser this would work as:
<option name='classless-static-route' destination='1.2.3.0'
prefix='24' nextHop='192.168.122.5'/>
<option name='classless-static-route' destination='1.2.4.0'
prefix='24' nextHop='192.168.122.6'/>
...
<option name='dns-server address='10.1.1.1'/>
<option name='dns-server address='10.1.1.2'/>
Either of these definitely seems more compact and easy to understand
than all that ranting and raving at the top of this message...
Any other suggestions?
===
[1]
https://bugzilla.redhat.com/show_bug.cgi?id=666556
[2]
https://tools.ietf.org/rfc/rfc3397.txt