summaryrefslogtreecommitdiffhomepage
path: root/dhcpv4/ztp
diff options
context:
space:
mode:
Diffstat (limited to 'dhcpv4/ztp')
-rw-r--r--dhcpv4/ztp/ztp.go75
-rw-r--r--dhcpv4/ztp/ztp_test.go74
2 files changed, 28 insertions, 121 deletions
diff --git a/dhcpv4/ztp/ztp.go b/dhcpv4/ztp/ztp.go
index 7e1009f..a7e5d2f 100644
--- a/dhcpv4/ztp/ztp.go
+++ b/dhcpv4/ztp/ztp.go
@@ -1,11 +1,9 @@
package ztpv4
import (
- "bytes"
"errors"
"strings"
- "github.com/golang/glog"
"github.com/insomniacslk/dhcp/dhcpv4"
)
@@ -20,30 +18,22 @@ type VendorData struct {
var errVendorOptionMalformed = errors.New("malformed vendor option")
-// VendorDataV4 will try to parse dhcp4 options data looking for more specific
-// vendor data (like model, serial number, etc). If the options are missing
-func VendorDataV4(packet *dhcpv4.DHCPv4) VendorData {
- vd := VendorData{}
-
- if err := parseV4VendorClass(&vd, packet); err != nil {
- glog.Errorf("failed to parse vendor data from vendor class: %v", err)
- }
-
- if err := parseV4VIVC(&vd, packet); err != nil {
- glog.Errorf("failed to parse vendor data from vendor-idenitifying vendor class: %v", err)
- }
-
- return vd
+// 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) {
+ return parseV4VendorClass(packet);
}
// parseV4Opt60 will attempt to look at the Vendor Class option (Option 60) on
// DHCPv4. The option is formatted as a string with the content being specific
// for the vendor, usually using a deliminator to separate the values.
// See: https://tools.ietf.org/html/rfc1533#section-9.11
-func parseV4VendorClass(vd *VendorData, packet *dhcpv4.DHCPv4) error {
+func parseV4VendorClass(packet *dhcpv4.DHCPv4) (*VendorData, error) {
+ vd := &VendorData{}
+
opt := packet.GetOneOption(dhcpv4.OptionClassIdentifier)
if opt == nil {
- return nil
+ return vd, nil
}
vc := opt.(*dhcpv4.OptClassIdentifier).Identifier
@@ -52,25 +42,25 @@ func parseV4VendorClass(vd *VendorData, packet *dhcpv4.DHCPv4) error {
case strings.HasPrefix(vc, "Arista;"):
p := strings.Split(vc, ";")
if len(p) < 4 {
- return errVendorOptionMalformed
+ return vd, errVendorOptionMalformed
}
vd.VendorName = p[0]
vd.Model = p[1]
vd.Serial = p[3]
- return nil
+ return vd, nil
// ZPESystems:NSC:002251623
case strings.HasPrefix(vc, "ZPESystems:"):
p := strings.Split(vc, ":")
if len(p) < 3 {
- return errVendorOptionMalformed
+ return vd, errVendorOptionMalformed
}
vd.VendorName = p[0]
vd.Model = p[1]
vd.Serial = p[2]
- return nil
+ return vd, nil
// Juniper option 60 parsing is a bit more nuanced. The following are all
// "valid" indetifing stings for Juniper:
@@ -94,46 +84,9 @@ func parseV4VendorClass(vd *VendorData, packet *dhcpv4.DHCPv4) error {
}
vd.Model = vc
- return nil
+ return vd, nil
}
// We didn't match anything, just return an empty vendor data.
- return nil
-}
-
-const entIDCiscoSystems = 0x9
-
-// parseV4Opt124 will attempt to read the Vendor-Identifying Vendor Class
-// (Option 124) on a DHCPv4 packet. The data is represented in a length/value
-// format with an indentifying enterprise number.
-//
-// See: https://tools.ietf.org/html/rfc3925
-func parseV4VIVC(vd *VendorData, packet *dhcpv4.DHCPv4) error {
- opt := packet.GetOneOption(dhcpv4.OptionVendorIdentifyingVendorClass)
- if opt == nil {
- return nil
- }
- ids := opt.(*dhcpv4.OptVIVC).Identifiers
-
- for _, id := range ids {
- if id.EntID == entIDCiscoSystems {
- vd.VendorName = "Cisco Systems"
-
- //SN:0;PID:R-IOSXRV9000-CC
- for _, f := range bytes.Split(id.Data, []byte(";")) {
- p := bytes.SplitN(f, []byte(":"), 2)
- if len(p) != 2 {
- return errVendorOptionMalformed
- }
-
- switch string(p[0]) {
- case "SN":
- vd.Serial = string(p[1])
- case "PID":
- vd.Model = string(p[1])
- }
- }
- }
- }
- return nil
+ return vd, nil
}
diff --git a/dhcpv4/ztp/ztp_test.go b/dhcpv4/ztp/ztp_test.go
index f46f9d8..ae715b2 100644
--- a/dhcpv4/ztp/ztp_test.go
+++ b/dhcpv4/ztp/ztp_test.go
@@ -3,15 +3,15 @@ package ztpv4
import (
"testing"
- "github.com/google/go-cmp/cmp"
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/stretchr/testify/require"
)
func TestParseV4VendorClass(t *testing.T) {
tt := []struct {
name string
vc, hostname string
- want VendorData
+ want *VendorData
fail bool
}{
{name: "empty", fail: true},
@@ -20,44 +20,44 @@ func TestParseV4VendorClass(t *testing.T) {
{
name: "arista",
vc: "Arista;DCS-7050S-64;01.23;JPE12345678",
- want: VendorData{
+ want: &VendorData{
VendorName: "Arista", Model: "DCS-7050S-64", Serial: "JPE12345678"},
},
{
name: "juniper",
vc: "Juniper-ptx1000-DD123",
- want: VendorData{VendorName: "Juniper", Model: "ptx1000", Serial: "DD123"},
+ want: &VendorData{VendorName: "Juniper", Model: "ptx1000", Serial: "DD123"},
},
{
name: "juniperModelDash",
vc: "Juniper-qfx10002-36q-DN817",
- want: VendorData{VendorName: "Juniper", Model: "qfx10002-36q", Serial: "DN817"},
+ want: &VendorData{VendorName: "Juniper", Model: "qfx10002-36q", Serial: "DN817"},
},
{
name: "juniperHostnameSerial",
vc: "Juniper-qfx10008",
hostname: "DE123",
- want: VendorData{VendorName: "Juniper", Model: "qfx10008", Serial: "DE123"},
+ want: &VendorData{VendorName: "Juniper", Model: "qfx10008", Serial: "DE123"},
},
{
name: "juniperNoSerial",
vc: "Juniper-qfx10008",
- want: VendorData{VendorName: "Juniper", Model: "qfx10008", Serial: ""},
+ want: &VendorData{VendorName: "Juniper", Model: "qfx10008", Serial: ""},
},
{
name: "juniperInvalid",
vc: "Juniper-",
- want: VendorData{VendorName: "Juniper", Model: "", Serial: ""},
+ want: &VendorData{VendorName: "Juniper", Model: "", Serial: ""},
},
{
name: "juniperInvalid2",
vc: "Juniper-qfx99999-",
- want: VendorData{VendorName: "Juniper", Model: "qfx99999", Serial: ""},
+ want: &VendorData{VendorName: "Juniper", Model: "qfx99999", Serial: ""},
},
{
name: "zpe",
vc: "ZPESystems:NSC:001234567",
- want: VendorData{VendorName: "ZPESystems", Model: "NSC", Serial: "001234567"},
+ want: &VendorData{VendorName: "ZPESystems", Model: "NSC", Serial: "001234567"},
},
}
@@ -78,56 +78,10 @@ func TestParseV4VendorClass(t *testing.T) {
})
}
- vd := VendorData{}
-
- if err := parseV4VendorClass(&vd, packet); err != nil && !tc.fail {
- t.Errorf("unexpected failure: %v", err)
- }
-
- if !cmp.Equal(tc.want, vd) {
- t.Errorf("unexpected VendorData:\n%s", cmp.Diff(tc.want, vd))
- }
- })
- }
-}
-
-func TestParseV4VIVC(t *testing.T) {
- tt := []struct {
- name string
- entID uint32
- input []byte
- want VendorData
- fail bool
- }{
- {name: "empty", fail: true},
- {
- name: "ciscoIOSXR",
- entID: 0x09,
- input: []byte("SN:0;PID:R-IOSXRV9000-CC"),
- want: VendorData{VendorName: "Cisco Systems", Model: "R-IOSXRV9000-CC", Serial: "0"},
- },
- }
-
- 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)
- }
- packet.AddOption(&dhcpv4.OptVIVC{
- Identifiers: []dhcpv4.VIVCIdentifier{
- {EntID: tc.entID, Data: tc.input},
- },
- })
-
- vd := VendorData{}
-
- if err := parseV4VIVC(&vd, packet); err != nil && !tc.fail {
- t.Errorf("unexpected failure: %v", err)
- }
-
- if !cmp.Equal(tc.want, vd) {
- t.Errorf("unexpected VendorData:\n%s", cmp.Diff(tc.want, vd))
+ vd, err := parseV4VendorClass(packet)
+ if !tc.fail {
+ require.NoError(t, err)
+ require.Equal(t, tc.want, vd)
}
})
}