The agent remote-id and circuit-id fields are left as vendor-specific and, of course, differ between switch platforms. Detecting the different formats is a little hit-and-miss, but seems to be possible between HP and Cisco, at least. When I get time later, I may look at Extreme XOS stuff as we use that too (although only in our data centres, where we don't have DHCP in use, except to set up servers initially).
HP DHCP Snooping and Option 82
HP has three modes for the remote-id, set with the dhcp-snooping option 82 remote-id global command: mac (the default) - just 6 bytes of the base MAC address of the switch, subnet-ip - the switch's IP address on the VLAN with the client (I have no idea what happens if there isn't one set), and mgmt-ip - the management IP address (the IP address set on the management VLAN). The latter looks the most useful. There is no leading byte to indicate which of these options has been selected.
There seems to be no way to control what the format of the circuit-id takes: on the switches I've tested it on - a 2610-24-PWR and a 5412), it's two bytes - the first is zero and I assume would increase with slot numbers on a chassis-based switch (the AP I have on the 5412 is in slot A and it's still 0); the second is the port number.
Cisco and HP Option 82 information compared
The remote-id is as follows:
Format | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7- | |
---|---|---|---|---|---|---|---|---|---|
Cisco | (default) | 0 | Switch base MAC address | ||||||
Hostname | 1 | Len | Hostname or explicit string | ||||||
HP | mac | Switch base MAC address | |||||||
subnet-ip | Client VLAN IP address? | ||||||||
mgmt-ip | Management VLAN IP address |
The logic to parse this field seems best as:
- If byte 0 is 1, it's probably a Cisco hostname (it's unlikely to be an IP address "1.q.r.s" or a multicast MAC address), so print the string starting at byte 2
- If it's 4 bytes long, assume it's an HP IP address, so print it as an IPv4 address
- Else assume it's an HP MAC address so print as colon-separate hex string (which, if it's not a MAC address, we can still translate)
The circuit-id is one of:
Format | 0 | 1 | 2 | 3 | 4 | 5 | 6- | |
---|---|---|---|---|---|---|---|---|
Cisco | vlan-mod-port | 0 | 4 (= Length) | VLAN ID (big endian) | Module (slot) | Port | ||
string | 1 | Length | Port and VLAN string | |||||
HP | - | Slot | Port |
- Cisco - parse the 2-byte VLAN ID and print the port as "module/port" in decimal
- HP - print the data as hyphen-separated decimals (it could be separated by slashes, but this is just to differentiate)
Cisco configuration
The following is what I've used on the Cisco switches; the lines with a leading "!" are defaults:
ip dhcp snooping vlan ...
!ip dhcp snooping information option
ip dhcp snooping information option format remote-id hostname
!no ip dhcp snooping information option allow-untrusted
ip dhcp snooping database ...
ip dhcp snooping database write-delay 900
ip dhcp snooping
!
interface <uplink>
ip dhcp snooping trust
On the Cisco routers, I've issued the following, to allow Option 82 to be set by a downstream switch:
ip dhcp relay information trust-all
HP configuration
The following is what I've used on HP switches; the lines with a leading "!" are defaults:
dhcp-snooping vlan ...
dhcp-snooping option 82 remote-id mgmt-ip
!dhcp-snooping option 82 untrusted-policy drop
!dhcp-snooping option 82
dhcp-snooping database file ...
dhcp-snooping
!
interface <uplink>
dhcp-snooping trust
Printing the agent details in ISC DHCP
Adapting the code posted before to cope with these variations:
# if the agent (Option 82) details are present, attempt to read information
# from them; this is tricky because different vendors and configurations can
# return information in conflicting formats and it's difficult to work out
# what format the information is in, so we make some assumptions
if exists agent.remote-id {
if substring(option agent.remote-id, 0, 1) = 1 {
# the first byte of the remote ID is 1 - that's unlikely to be an IP addr-
# ess and, if it were a MAC address it would be multicast, so it is
# probably a hostname from a Cisco switch
log(
info,
concat(
"agent information ",
binary-to-ascii(10, 8, ".", leased-address),
" to ",
binary-to-ascii(16, 8, ":", substring(hardware, 1, 6)),
" on ",
substring(option agent.remote-id, 2, extract-int(substring(option agent.remote-id, 1, 1), 8)),
" port ",
binary-to-ascii(10, 8, "", substring(option agent.circuit-id, 4, 1)),
"/",
binary-to-ascii(10, 8, "", substring(option agent.circuit-id, 5, 1)),
" VLAN ",
binary-to-ascii(10, 16, "", substring(option agent.circuit-id, 2, 2))));
} elsif substring(option agent.remote-id, 4, 2) = "" {
# if the length of the remote ID is less than 6, we probably have an IP
# address from an HP
log(
info,
concat(
"agent information ",
binary-to-ascii(10, 8, ".", leased-address),
" to ",
binary-to-ascii(16, 8, ":", substring(hardware, 1, 6)),
" on ",
binary-to-ascii(10, 8, ".", option agent.remote-id),
" port ",
binary-to-ascii(10, 8, "-", option agent.circuit-id)));
} else {
# otherwise, we probably have an HP MAC address, so just print the rem-
# ID as comma-separated hex; this doesn't hurt for anything else, anyway,
# as we can always translate it
log(
info,
concat(
"agent information ",
binary-to-ascii(10, 8, ".", leased-address),
" to ",
binary-to-ascii(16, 8, ":", substring(hardware, 1, 6)),
" on ",
binary-to-ascii(16, 8, ":", option agent.remote-id),
" port ",
binary-to-ascii(10, 8, "-", option agent.circuit-id)));
}
}
This gives log output for an HP:
Sep 16 22:56:52 janganmun dhcpd: agent information 172.30.162.130 to 6c:f3:7f:c0:54:cf on 172.30.64.114 port 0-23
... the switch has management IP address 172.30.64.114 and the port is A23 (on a 5412).
Or, for a Cisco:
Sep 16 23:08:23 janganmun dhcpd: agent information 172.30.140.9 to 24:de:c6:c6:51:40 on sw-ucs-rnb-n3 port 2/37 VLAN 3008
... switch sw-ucs-rnb-n3, port Gi2/0/37 on VLAN 3008.