diff options
author | Hariharakumar Narasimhakumar <hana8349@colorado.edu> | 2021-04-27 12:06:11 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-27 19:06:11 +0100 |
commit | f2616923e229eb3a760d676f77db5a1cd88d6f87 (patch) | |
tree | e3ffd9aa6a702c13625105aa7b7cb01e8ba30f1e /dhcpv4 | |
parent | 58efeba27ae80bda66d717542046e345105bc3d2 (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.go | 65 | ||||
-rw-r--r-- | dhcpv4/ztpv4/ztp_test.go | 48 |
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) + } + }) + } +} |