BIND 10 #1186: libdhcp implementation - DHCPv6 part

BIND 10 Development do-not-reply at isc.org
Tue Oct 11 14:47:55 UTC 2011


#1186: libdhcp implementation - DHCPv6 part
-------------------------------------+-------------------------------------
                   Reporter:  tomek  |                 Owner:  tomek
                       Type:         |                Status:  reviewing
  enhancement                        |             Milestone:  Sprint-
                   Priority:  major  |  DHCP-20111011
                  Component:  dhcp   |            Resolution:
                   Keywords:         |             Sensitive:  0
            Defect Severity:  N/A    |           Sub-Project:  DHCP
Feature Depending on Ticket:  878    |  Estimated Difficulty:  0
        Add Hours to Ticket:  0      |           Total Hours:  0
                  Internal?:  0      |
-------------------------------------+-------------------------------------

Comment (by tomek):

 Replying to [comment:3 stephen]:
 > '''src/bin/dhcp6/dhcp6_srv.cc'''[[BR]]
 > The #include of 'io_address.h' should be {{{#include
 "asiolink/io_address.h"}}}
 Done. In dhcp6_srv.cc and other files in src/bin/dhcp6 and src/lib/dhcp.

 > In Dhcpv6Srv::run(), there is the following construct:
 > {{{
 > if (rsp != boost::shared_ptr<Pkt6>()) {
 > }}}
 > To check whether rsp holds a valid pointer, the simpler {{{if (rsp) {}}}
 can be used.
 I think that is against BIND9 conding standards that is also used in DHCP.
 It seems that is ok in BIND10, though, so I changed it to use simpler
 form.

 > getServerID(): Presumably there is a getServerID() as a counterpart to
 setServerID()?  (If not, why not access serverid_ directly?) If so, it
 would make sense to have getServerID() return a reference to serverid_ to
 save on the copying of the shared pointer.  Also, getServerID() is
 sufficiently trivial that it can be coded inline in the header.
 Done.

 > In setServerID(), need to check that srvid[3] should really be 6.
 Certainly not. While 6 is the most common hardware type (Ethernet), we
 must not limit ourselves to this hardware type. In particular, Infiniband
 is represented by hardware type 32, which is a valid type. Anyway, there's
 explicit statement in RFC3315 that says that DUID content MUST be treated
 as opaque value. If user desires to have it composed with values other
 than 6, it is legal.

 > Does setServerID() need to return anything?  If the code fails to set
 the server ID, would an exception be a better way of signalling it?
 Changed as suggested. Once fully implemented, setServerID() will throw
 exception if it fails to load old DUID and there are no suitable
 interfaces for generation of new DUID.

 > in processSolicit(), the code contains two declarations of the form
 {{{Option * tmp}}}.  This should be {{{Option* tmp}}} (as the current
 layout looks at first glance like a multiplication).  Also, should be no
 space between the ">" and "(" in the dynamic_cast statement.
 Done.

 > Should include a 'TODO:' comment about changing them in the code for the
 hard-wired times and address.
 Added TODO explaining that this method should be rewritten once
 LeaseManager is implemented.

 > '''src/bin/dhcp6/dhcp6_srv.h'''[[BR]]
 > To avoid a copy of the input variable, the {{{solicit}}} argument to
 many of the methods should be passed by reference.
 No. In current state of implementation, packet is consumed immediately and
 is not stored anywhere. That is likely to change, however. Note that
 leasequery protocol may ask about details about relays, so it may be
 useful to keep at last some parts of message. Also, if we decide to
 implement distributed processing, we need separate instance of
 shared_pointer.

 > All methods in Dhcpv6Srv should have a Doxygen header.
 Done.

 > The class Dhcp6Srv should have a header explaining the purpose of the
 class.
 Done.
 > The convention in BIND 10 is to use nested namespaces rooted at "isc"
 for different components.  Suggest that the class be put into isc::dhcp.
 Done. Note that library, dhcp6 and upcoming dhcp4 components will all use
 a single (isc::dhcp) namespace.

 > Declaring the test class as a "friend" in the production code is unusual
 (in BIND 10) but valid.  This should be discussed on bind10-dev as to
 whether we want to make this a standard.  However, if the test class is a
 friend, why are methods protected?
 Use of a friend was a quick hack, rather than permanent solution.
 Implemented derived class that exposes Dhcpv6Srv and removed friend
 statement.

 > To prevent copying, the class should be derived from
 {{{boost::noncopyable}}}. (In fairness, although this was decided back in
 February, is has only today been included into the coding guidelines.)
 Done.

 > All member variables should include a Doxygen comment stating their
 purpose.
 Done.

 > '''src/bin/dhcp6/iface_mgr.cc'''
 > (A few things that may have been picked up in the review of #868 but
 caught my eye when reviewing these changes.)
 >
 > instance(): the {{{if}}} statement should contain braces, even if the
 contents are only one statement.
 Done.

 > Iface constructor.  For setting the mac_ array to zero, memset is OK
 (although some authorities prefer std::fill).  However the length should
 be {{{sizeof(mac_)}}} and not a hard-coded 20.
 Using std::fill is a overkill. modified memset should do the trick. Also
 added MAX_MAC_LEN const.

 > getFillName(): {{{return (name_ + "/");}}} is simpler than creating a
 temporary ostringstream object.
 No, it is not. It is not possible to add integer to strings. using
 stringstream is the preferred way of converting integers to strings in
 C++. Note that the format is eth0/2 (interface-name, a slash followed by
 integer representing interface index).

 > getPlainMac(): I think that setting the fill, width and radix once
 outside the {{{for}}} loop should be OK. (Also, if mac_ is declared as
 {{{uint8_t}}}, there should be no need for the cast to an {{{int}}} when
 output each element of it.)
 Note: As some manipulator affect only the next token (and I fail to
 remember which ones they are) I chose to set the before every token.

 To answer this comment: Yes and no. uint8_t is still printed as char, so
 cast to int is required, at least with g++ 4.5.2. Some stream manipulators
 apply to next token only. In particular that is true for width(). This
 page has nice table about applicability of stream manipulators:
 http://www.fredosaurus.com/notes-cpp/io/omanipulators.html

 Cast to (int) stays, fill() moved out of loop.

 > In !IfaceMgr constructor, {{{control_buf_}}} could be declared as a
 {{{boost::scoped_ptr<>}}} to provide automatic destruction in the case
 that anything else in the constructor throws an exception. (Would then
 remove the deallocation of {{{control_buf_}}} from the destructor.)
 scoped_ptr is not the proper type here as it will call delete to destroy
 pointer object. This is an array, so delete [] operator should be called.
 Note that deleting array type with delete results in undefined behavior.
 It just happens to work in g++.

 The better template would be shared_array<>. Do you want me to use it?

 > Header for openSocket.  The BIND 10 convention is to place the headers
 in the .h file.  Also, the first line of the header contains a typo "nad"
 instead of "and".
 >
 > receive(): without checking where this is called from, would not
 throwing an exception (instead of returning an empty packet) be a better
 way of signalling that the receive has failed?
 No. Once LeaseManager is implemented, this method will get a timeout timer
 ("try to receive something for 10 seconds. After that we need to expire a
 lease"). Not receiving anything will be a proper event.

 > '''src/bin/dhcp6/iface_mgr.h'''
 > See comment in dhcp6_srv.h about namespaces.
 Done.
 >
 > All methods - including those in the contained Iface struct - should
 have Doxygen headers.
 Done.

 > Remove the note that {{{struct Iface}}} could be a class as well - in
 this context, a {{{struct}}} is fine.
 Done.

 > {{{mac_}}} is best declared as {{{uint8_t}}}. (It is not being used as a
 {{{char}}}.)
 Done.

 > Should remove the final comment in {{{struct Iface}}} as there is no
 next field.
 This was an explanation why there is no such field. Removed as suggested.

 > Suggest grouping the variables and the method declarations in {{{struct
 Iface}}} instead of putting the latter in the middle of the former.
 Done.

 > {{{Iface * getIface(...)}}} should be {{{Iface* getIface(...)}}} (looks
 like a multiplication).  This appliease to other similar declarations in
 the file.
 Done.

 > send() should take a reference to a shared pointer as its argument.
 Also, if the argument is unchanged, it should be {{{const}}}.
 I prefer to keep it as separate copy of shared pointer. We may decide to
 use async send sometime later.

 > All member variables should include a Doxygen comment stating their
 purpose.
 Done.

 > '''src/bin/dhcp6/tests/dhcp6_srv_unittest.cc'''
 > Basic test.  The comment says that "an attempt to bind this socket will
 fail" yet the test is {{{EXPECT_NO_THROW}}} - which indicates that no
 exception will be thrown when the test succeeds.
 See IfaceMgr::IfaceMgr() comment. This exception is caught prematurely. It
 should stay that way until proper interface detection is implemented. I
 really don't want to engineer a work-around for a test that tests stub
 implementation that is going away in 2 months.

 > Should be a space after the comma in the {{{TEST_F}}} line for
 Solicit_basic.
 Added.

 > Inconsistency in declaration: both {{{sol}}} and {{{ia}}} are of the
 form {{{boost::shared_ptr<xyz>}}}, yet the former is initialized using the
 construct "ptr x = ptr(new Xyz(...))" and the latter "ptr x(new
 Xyz(...))".
 Done.

 > Would help to include a comment explaining what options are being set in
 the packet.
 Added a comment about content of "sent" message and expected content of
 "received" message.
 Also added several new checks.

 > See above for comments on the testing whether a shared pointer points to
 a null object.
 >
 > In the Solicit_basic test, the contents of the ASSERT_TRUE macros can
 simply be the shared_ptr in question - the implicit conversion to bool
 will return true if the pointed is non-null.
 Done.

 > '''src/bin/dhcp6/tests/iface_mgr_unittest.cc'''[[BR]]
 > In the test loDetect, can you guarantee that the default directory when
 running the test is writeable and that "interfaces.txt" will be created?
 In fact, removing "interfaces.txt" and instead using an environment
 variable might be safer.  (Which will require an update to the !IfaceMgr
 code.)
 I politely refuse to implement this. This is a temporary workaround that
 is expected to go away in less than 2 months. It is not perfect, I agree.
 However, at this stage of development, write access to current directory
 during running tests is required. Added comment that explain that.

 Let's not over-engineer a workaround. We risk making it a feature.

 > In the "sockets" test, the socket numbers are perhaps best put as
 constants at the head of the file (in case they need changing at some time
 in the future).
 These are just random numbers. Well, almost. DHCPv6 operates on 546 and
 547 ports. I used normal value+10000 to have the ability to run as non-
 root user. Defining constants would be confusing. Tests would use
 something like DEFAULT_DHCPV6_PORT_PLUS_10000 + 1. It would be more
 confusing than directly using numbers. They are not expected to be unified
 among different tests. On the contrary, using different values would
 increase test coverage.

 > In test sendReceive, the {{{ASSERT_TRUE}}} condition can be just
 {{{rcvPkt}}} (see above).
 Done.

 Commit-id: 8fdcf2aa39b5fdb224f5e57f9605090409abc4a1

-- 
Ticket URL: <http://bind10.isc.org/ticket/1186#comment:7>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list