diff options
Diffstat (limited to 'dhcpv4/ztpv4/parse_circuitid.go')
-rw-r--r-- | dhcpv4/ztpv4/parse_circuitid.go | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/dhcpv4/ztpv4/parse_circuitid.go b/dhcpv4/ztpv4/parse_circuitid.go new file mode 100644 index 0000000..b9db358 --- /dev/null +++ b/dhcpv4/ztpv4/parse_circuitid.go @@ -0,0 +1,94 @@ +package ztpv4 + +import ( + "fmt" + "regexp" + + "github.com/insomniacslk/dhcp/dhcpv4" +) + +// CircuitID represents the structure of network vendor interface formats +type CircuitID struct { + Slot string + Module string + Port string + SubPort string + Vlan string +} + +var circuitRegexs = []*regexp.Regexp{ + // Juniper QFX et-0/0/0:0.0 + regexp.MustCompile("^et-(?P<slot>[0-9]+)/(?P<mod>[0-9]+)/(?P<port>[0-9]+):(?P<subport>[0-9]+).*$"), + // Juniper PTX et-0/0/0.0 + regexp.MustCompile("^et-(?P<slot>[0-9]+)/(?P<mod>[0-9]+)/(?P<port>[0-9]+).(?P<subport>[0-9]+)$"), + // Arista Ethernet3/17/1 + regexp.MustCompile("^Ethernet(?P<slot>[0-9]+)/(?P<mod>[0-9]+)/(?P<port>[0-9]+)$"), + // Juniper QFX et-1/0/61 + regexp.MustCompile("^et-(?P<slot>[0-9]+)/(?P<mod>[0-9]+)/(?P<port>[0-9]+)$"), + // Arista Ethernet14:Vlan2001 + // Arista Ethernet10:2020 + regexp.MustCompile("^Ethernet(?P<port>[0-9]+):(?P<vlan>.*)$"), + // Cisco Gi1/10:2020 + regexp.MustCompile("^Gi(?P<slot>[0-9]+)/(?P<port>[0-9]+):(?P<vlan>.*)$"), + // Nexus Ethernet1/3 + regexp.MustCompile("^Ethernet(?P<slot>[0-9]+)/(?P<port>[0-9]+)$"), + // Juniper bundle interface ae52.0 + regexp.MustCompile("^ae(?P<port>[0-9]+).(?P<subport>[0-9])$"), +} + +// ParseCircuitID will parse dhcpv4 packet and return CircuitID info +func ParseCircuitID(packet *dhcpv4.DHCPv4) (*CircuitID, error) { + // CircuitId info is stored as sub-option field in RelayAgentInformationOption + relayOptions := packet.RelayAgentInfo() + + if relayOptions == nil { + return nil, fmt.Errorf("No relay agent information option found in the dhcpv4 pkt") + } + + // As per RFC 3046 sub-Option 1 is circuit-id. Look at 2.0 section in that RFC + // https://tools.ietf.org/html/rfc3046 + circuitIdStr := string(relayOptions.Options.Get(dhcpv4.AgentCircuitIDSubOption)) + if circuitIdStr == "" { + return nil, fmt.Errorf("no circuit-id suboption found in dhcpv4 packet") + } + circuitId, err := matchCircuitID(circuitIdStr) + if err != nil { + return nil, err + } + return circuitId, nil +} + +func matchCircuitID(circuitIdStr string) (*CircuitID, error) { + + for _, re := range circuitRegexs { + + match := re.FindStringSubmatch(circuitIdStr) + if len(match) == 0 { + continue + } + + c := CircuitID{} + for i, k := range re.SubexpNames() { + switch k { + case "slot": + c.Slot = match[i] + case "mod": + c.Module = match[i] + case "port": + c.Port = match[i] + case "subport": + c.SubPort = match[i] + case "vlan": + c.Vlan = match[i] + } + } + + return &c, nil + } + return nil, fmt.Errorf("Unable to match circuit id : %s with listed regexes of interface types", circuitIdStr) +} + +// FormatCircuitID is the CircuitID format we send in our Bootfile URL for ZTP devices +func (c *CircuitID) FormatCircuitID() string { + return fmt.Sprintf("%v,%v,%v,%v,%v", c.Slot, c.Module, c.Port, c.SubPort, c.Vlan) +} |