summaryrefslogtreecommitdiffhomepage
path: root/dhcpv4
diff options
context:
space:
mode:
authorHariharakumar Narasimhakumar <hana8349@colorado.edu>2021-04-27 12:06:11 -0600
committerGitHub <noreply@github.com>2021-04-27 19:06:11 +0100
commitf2616923e229eb3a760d676f77db5a1cd88d6f87 (patch)
treee3ffd9aa6a702c13625105aa7b7cb01e8ba30f1e /dhcpv4
parent58efeba27ae80bda66d717542046e345105bc3d2 (diff)
Add dhcp Opt 124(vivc) parsing to ztp (#425)
* Add dhcp Opt 124(vivc) parsing to ztp Signed-off-by: Hariharakumar Narasimhakumar <hhkumar@fb.com>
Diffstat (limited to 'dhcpv4')
-rw-r--r--dhcpv4/ztpv4/ztp.go65
-rw-r--r--dhcpv4/ztpv4/ztp_test.go48
2 files changed, 103 insertions, 10 deletions
diff --git a/dhcpv4/ztpv4/ztp.go b/dhcpv4/ztpv4/ztp.go
index 1bcb44f..43bc0e6 100644
--- a/dhcpv4/ztpv4/ztp.go
+++ b/dhcpv4/ztpv4/ztp.go
@@ -1,10 +1,12 @@
package ztpv4
import (
+ "bytes"
"errors"
"strings"
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/insomniacslk/dhcp/iana"
)
// VendorData is optional data a particular vendor may or may not include
@@ -15,16 +17,10 @@ type VendorData struct {
var errVendorOptionMalformed = errors.New("malformed vendor option")
-// ParseVendorData will try to parse dhcp4 options looking for more
-// specific vendor data (like model, serial number, etc).
-func ParseVendorData(packet *dhcpv4.DHCPv4) (*VendorData, error) {
- vc := packet.ClassIdentifier()
- if len(vc) == 0 {
- return nil, errors.New("vendor options not found")
- }
+func parseClassIdentifier(packet *dhcpv4.DHCPv4) (*VendorData, error) {
vd := &VendorData{}
- switch {
+ switch vc := packet.ClassIdentifier(); {
// Arista;DCS-7050S-64;01.23;JPE12221671
case strings.HasPrefix(vc, "Arista;"):
p := strings.Split(vc, ";")
@@ -71,6 +67,57 @@ func ParseVendorData(packet *dhcpv4.DHCPv4) (*VendorData, error) {
return vd, nil
}
- // We didn't match anything.
+ return nil, nil
+}
+
+func parseVIVC(packet *dhcpv4.DHCPv4) (*VendorData, error) {
+ vd := &VendorData{}
+
+ for _, id := range packet.VIVC() {
+ if id.EntID == uint32(iana.EntIDCiscoSystems) {
+ vd.VendorName = iana.EntIDCiscoSystems.String()
+ //SN:0;PID:R-IOSXRV9000-CC
+ for _, f := range bytes.Split(id.Data, []byte(";")) {
+ p := bytes.Split(f, []byte(":"))
+ if len(p) != 2 {
+ return nil, errVendorOptionMalformed
+ }
+
+ switch string(p[0]) {
+ case "SN":
+ vd.Serial = string(p[1])
+ case "PID":
+ vd.Model = string(p[1])
+ }
+ }
+ return vd, nil
+ }
+ }
+
+ return nil, nil
+}
+
+// ParseVendorData will try to parse dhcp4 options looking for more
+// specific vendor data (like model, serial number, etc).
+func ParseVendorData(packet *dhcpv4.DHCPv4) (*VendorData, error) {
+ vd, err := parseClassIdentifier(packet)
+ if err != nil {
+ return nil, err
+ }
+
+ // If VendorData is set, return early
+ if vd != nil {
+ return vd, nil
+ }
+
+ vd, err = parseVIVC(packet)
+ if err != nil {
+ return nil, err
+ }
+
+ if vd != nil {
+ return vd, nil
+ }
+
return nil, errors.New("no known ZTP vendor found")
}
diff --git a/dhcpv4/ztpv4/ztp_test.go b/dhcpv4/ztpv4/ztp_test.go
index 6e050d9..d0b002f 100644
--- a/dhcpv4/ztpv4/ztp_test.go
+++ b/dhcpv4/ztpv4/ztp_test.go
@@ -4,10 +4,11 @@ import (
"testing"
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/insomniacslk/dhcp/iana"
"github.com/stretchr/testify/require"
)
-func TestParseV4VendorClass(t *testing.T) {
+func TestParseClassIdentifier(t *testing.T) {
tt := []struct {
name string
vc, hostname string
@@ -70,3 +71,48 @@ func TestParseV4VendorClass(t *testing.T) {
})
}
}
+
+func TestParseVIVC(t *testing.T) {
+ tt := []struct {
+ name string
+ vivc string
+ entID iana.EntID
+ want *VendorData
+ fail bool
+ }{
+ {
+ name: "cisco",
+ entID: iana.EntIDCiscoSystems,
+ vivc: "SN:0;PID:R-IOSXRV9000-CC",
+ want: &VendorData{VendorName: "Cisco Systems", Model: "R-IOSXRV9000-CC", Serial: "0"},
+ },
+ {
+ name: "ciscoMultipleColonDelimiters",
+ entID: iana.EntIDCiscoSystems,
+ vivc: "SN:0:123;PID:R-IOSXRV9000-CC:456",
+ fail: true,
+ },
+ }
+
+ for _, tc := range tt {
+ t.Run(tc.name, func(t *testing.T) {
+ packet, err := dhcpv4.New()
+ if err != nil {
+ t.Fatalf("failed to creat dhcpv4 packet object: %v", err)
+ }
+
+ if tc.vivc != "" {
+ vivc := dhcpv4.VIVCIdentifier{EntID: uint32(tc.entID), Data: []byte(tc.vivc)}
+ packet.UpdateOption(dhcpv4.OptVIVC(vivc))
+ }
+
+ vd, err := ParseVendorData(packet)
+ if tc.fail {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tc.want, vd)
+ }
+ })
+ }
+}