44package iosxr
55
66import (
7+ "errors"
78 "fmt"
89 "regexp"
10+ "strconv"
11+ "strings"
912
1013 "github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
1114)
1215
13- type PhysIf struct {
16+ type IFaceSpeed string
17+
18+ const (
19+ Speed10G IFaceSpeed = "TenGigE"
20+ Speed25G IFaceSpeed = "TwentyFiveGigE"
21+ Speed40G IFaceSpeed = "FortyGigE"
22+ Speed100G IFaceSpeed = "HundredGigE"
23+ EtherBundle IFaceSpeed = "etherbundle"
24+ )
25+
26+ type BunldePortActivity string
27+
28+ const (
29+ PortActivityOn BunldePortActivity = "on"
30+ PortActivityActive BunldePortActivity = "active"
31+ PortActivityPassive BunldePortActivity = "passive"
32+ PortActivityInherit BunldePortActivity = "inherit"
33+ )
34+
35+ type PhysIfStateType string
36+
37+ const (
38+ StateUp PhysIfStateType = "im-state-up"
39+ StateDown PhysIfStateType = "im-state-down"
40+ StateNotReady PhysIfStateType = "im-state-not-ready"
41+ StateAdminDown PhysIfStateType = "im-state-admin-down"
42+ StateShutDown PhysIfStateType = "im-state-shutdown"
43+ )
44+
45+ // Represent physical and bundle interfaces as part of the same struct as they share a lot of common configuration
46+ // and only differ in a few attributes like the interface name and the presence of bundle configuration or not.
47+ type Iface struct {
1448 Name string `json:"-"`
15- Description string `json:"description"`
16- Active string `json:"active"`
17- Vrf string `json:"Cisco-IOS-XR-infra-rsi-cfg:vrf,omitempty"`
18- Statistics Statistics `json:"Cisco-IOS-XR-infra-statsd-cfg:statistics,omitempty"`
19- IPv4Network IPv4Network `json:"Cisco-IOS-XR-ipv4-io-cfg:ipv4-network,omitempty"`
20- IPv6Network IPv6Network `json:"Cisco-IOS-XR-ipv6-ma-cfg:ipv6-network,omitempty"`
21- IPv6Neighbor IPv6Neighbor `json:"Cisco-IOS-XR-ipv6-nd-cfg:ipv6-neighbor,omitempty"`
22- MTUs MTUs `json:"mtus,omitempty"`
23- Shutdown gnmiext.Empty `json:"shutdown,omitempty"`
49+ Description string `json:"description,omitzero"`
50+ Statistics Statistics `json:"Cisco-IOS-XR-infra-statsd-cfg:statistics,omitzero"`
51+ MTUs MTUs `json:"mtus,omitzero"`
52+ Active string `json:"active,omitzero"`
53+ Vrf string `json:"Cisco-IOS-XR-infra-rsi-cfg:vrf,omitzero"`
54+ IPv4Network IPv4Network `json:"Cisco-IOS-XR-ipv4-io-cfg:ipv4-network,omitzero"`
55+ IPv6Network IPv6Network `json:"Cisco-IOS-XR-ipv6-ma-cfg:ipv6-network,omitzero"`
56+ IPv6Neighbor IPv6Neighbor `json:"Cisco-IOS-XR-ipv6-nd-cfg:ipv6-neighbor,omitzero"`
57+ Shutdown gnmiext.Empty `json:"shutdown,omitzero"`
58+
59+ // Existence of this object causes the creation of the software subinterface
60+ ModeNoPhysical string `json:"interface-mode-non-physical,omitzero"`
61+
62+ // BundleMember configuration for Physical interface as member of a Bundle-Ether
63+ BundleMember BundleMember `json:"Cisco-IOS-XR-bundlemgr-cfg:bundle-member,omitzero"`
64+
65+ // Mode in which an interface is running (e.g., virtual for subinterfaces)
66+ Mode gnmiext.Empty `json:"interface-virtual,omitzero"`
67+ Bundle Bundle `json:"Cisco-IOS-XR-bundlemgr-cfg:bundle,omitzero"`
68+ SubInterface VlanSubInterface `json:"Cisco-IOS-XR-l2-eth-infra-cfg:vlan-sub-configuration,omitzero"`
69+ }
70+
71+ type BundleMember struct {
72+ ID BundleID `json:"id"`
2473}
2574
2675type Statistics struct {
@@ -29,7 +78,7 @@ type Statistics struct {
2978
3079type IPv4Network struct {
3180 Addresses AddressesIPv4 `json:"addresses"`
32- Mtu uint16 `json:"mtu"`
81+ Mtu uint16 `json:"mtu,omitzero "`
3382}
3483
3584type AddressesIPv4 struct {
@@ -73,64 +122,157 @@ type MTU struct {
73122 Owner string `json:"owner"`
74123}
75124
76- func (i * PhysIf ) XPath () string {
125+ type BundleID struct {
126+ BundleID int32 `json:"bundle-id"`
127+ PortAcivity string `json:"port-activity"`
128+ }
129+
130+ type Bundle struct {
131+ MinAct MinimumActive `json:"minimum-active"`
132+ }
133+
134+ type MinimumActive struct {
135+ Links int32 `json:"links"`
136+ }
137+
138+ type VlanSubInterface struct {
139+ VlanIdentifier VlanIdentifier `json:"vlan-identifier"`
140+ }
141+
142+ type VlanIdentifier struct {
143+ FirstTag int32 `json:"first-tag"`
144+ SecondTag int32 `json:"second-tag,omitzero"`
145+ VlanType string `json:"vlan-type"`
146+ }
147+
148+ func (i * Iface ) XPath () string {
77149 return fmt .Sprintf ("Cisco-IOS-XR-ifmgr-cfg:interface-configurations/interface-configuration[active=act][interface-name=%s]" , i .Name )
78150}
79151
80- func (i * PhysIf ) String () string {
81- return fmt .Sprintf ("Name: %s, Description=%s, ShutDown=%t " , i .Name , i .Description , i . Shutdown )
152+ func (i * Iface ) String () string {
153+ return fmt .Sprintf ("Name: %s, Description=%s" , i .Name , i .Description )
82154}
83155
84- type IFaceSpeed string
156+ type PhysIfState struct {
157+ State string `json:"state"`
158+ Name string `json:"-"`
159+ }
85160
86- const (
87- Speed10G IFaceSpeed = "TenGigE"
88- Speed25G IFaceSpeed = "TwentyFiveGigE"
89- Speed40G IFaceSpeed = "FortyGigE"
90- Speed100G IFaceSpeed = "HundredGigE"
91- )
161+ func (phys * PhysIfState ) XPath () string {
162+ // (fixme): hardcoded route processor for the moment
163+ return fmt .Sprintf ("Cisco-IOS-XR-ifmgr-oper:interface-properties/data-nodes/data-node[data-node-name=0/RP0/CPU0]/system-view/interfaces/interface[interface-name=%s]" , phys .Name )
164+ }
165+
166+ func ExractInterfaceSpeedFromName (ifaceName string ) (IFaceSpeed , error ) {
167+ // Owner of bundle interfaces is 'etherbundle'
168+ bundleEtherRE := regexp .MustCompile (`^Bundle-Ether*` )
169+ if bundleEtherRE .MatchString (ifaceName ) {
170+ // For Bundle-Ether interfaces
171+ return EtherBundle , nil
172+ }
92173
93- func ExtractMTUOwnerFromIfaceName (ifaceName string ) (IFaceSpeed , error ) {
94174 // Match the port_type in an interface name <port_type>/<rack>/<slot/<module>/<port>
95175 // E.g. match TwentyFiveGigE of interface with name TwentyFiveGigE0/0/0/1
96176 re := regexp .MustCompile (`^\D*` )
97-
98- mtuOwner := string (re .Find ([]byte (ifaceName )))
99-
100- if mtuOwner == "" {
101- return "" , fmt .Errorf ("failed to extract MTU owner from interface name %s" , ifaceName )
177+ speed := string (re .Find ([]byte (ifaceName )))
178+ if speed == "" {
179+ return "" , fmt .Errorf ("failed to extract speed from interface name %s" , ifaceName )
102180 }
103181
104- switch mtuOwner {
182+ switch speed {
105183 case string (Speed10G ):
106184 return Speed10G , nil
107185 case string (Speed25G ):
108186 return Speed25G , nil
109187 case string (Speed40G ):
110- return Speed25G , nil
188+ return Speed40G , nil
111189 case string (Speed100G ):
112190 return Speed100G , nil
113191 default :
114- return "" , fmt .Errorf ("unsupported interface type %s for MTU owner extraction " , mtuOwner )
192+ return "" , fmt .Errorf ("unsupported interface type %s§§ " , speed )
115193 }
116194}
117195
118- type PhysIfStateType string
196+ func CheckInterfaceNameTypeAggregate (name string ) error {
197+ if name == "" {
198+ return errors .New ("interface name must not be empty" )
199+ }
200+ // Matches Bundle-Ether<VLAN>[.<VLAN>] or BE<VLAN>[.<VLAN>]
201+ re := regexp .MustCompile (`^(Bundle-Ether|BE)(\d+)(\.(\d+))?$` )
202+ matches := re .FindStringSubmatch (name )
119203
120- const (
121- StateUp PhysIfStateType = "im-state-up"
122- StateDown PhysIfStateType = "im-state-down"
123- StateNotReady PhysIfStateType = "im-state-not-ready"
124- StateAdminDown PhysIfStateType = "im-state-admin-down"
125- StateShutDown PhysIfStateType = "im-state-shutdown"
126- )
204+ if matches == nil {
205+ return fmt .Errorf ("unsupported interface format %q, expected one of: %q" , name , re .String ())
206+ }
127207
128- type PhysIfState struct {
129- State string `json:"state"`
130- Name string `json:"-"`
208+ // Vlan is part of the name
209+ if matches [2 ] == "" {
210+ return fmt .Errorf ("unsupported interface format %q, expected one of: %q" , name , re .String ())
211+ }
212+ // Check outer vlan
213+ // fixme: check range up to 65000
214+ // err := CheckVlanRange(matches[2])
215+
216+ // Check inner vlan if we have a subinterface
217+ if matches [4 ] != "" {
218+ return CheckVlanRange (matches [4 ])
219+ }
220+ return nil
131221}
132222
133- func (phys * PhysIfState ) XPath () string {
134- // (fixme): hardcoded route processor for the moment
135- return fmt .Sprintf ("Cisco-IOS-XR-ifmgr-oper:interface-properties/data-nodes/data-node[data-node-name=0/RP0/CPU0]/system-view/interfaces/interface[interface-name=%s]" , phys .Name )
223+ func ExtractVlanTagFromName (name string ) (vlanID int32 , err error ) {
224+ // TF0/0/0/3.2021 or Te0/0/0/3.2021 or Hun0/0/0/3.2021
225+ res := strings .Split (name , "." )
226+ switch len (res ) {
227+ case 1 :
228+ return 0 , nil
229+ case 2 :
230+ vlan , err := strconv .ParseInt (res [1 ], 10 , 32 )
231+ if err != nil {
232+ return 0 , fmt .Errorf ("failed to parse VLAN ID from interface name %q: %w" , name , err )
233+ }
234+ return int32 (vlan ), nil
235+ default :
236+ return 0 , fmt .Errorf ("unexpected interface name format %q, expected <interface> or <interface>.<vlan>" , name )
237+ }
238+ }
239+
240+ func ExtractBundleIdAndVlanTagsFromName (name string ) (bundleID , outerVlan int32 , err error ) {
241+ // Matches BE1.1 or Bundle-Ether1.1
242+ re := regexp .MustCompile (`^(Bundle-Ether|BE)(\d+)(?:\.(\d+))?$` )
243+ matches := re .FindStringSubmatch (name )
244+
245+ switch len (matches ) {
246+ case 3 :
247+ o , err := strconv .ParseInt (matches [2 ], 10 , 32 )
248+ if err != nil {
249+ return 0 , 0 , fmt .Errorf ("failed to parse bundle ID from interface name %q: %w" , name , err )
250+ }
251+ bundleID = int32 (o )
252+ case 4 :
253+ o , err := strconv .ParseInt (matches [2 ], 10 , 32 )
254+ if err != nil {
255+ return 0 , 0 , fmt .Errorf ("failed to parse bundle ID from interface name %q: %w" , name , err )
256+ }
257+ i , err := strconv .ParseInt (matches [3 ], 10 , 32 )
258+ if err != nil {
259+ return 0 , 0 , fmt .Errorf ("failed to parse outer VLAN from interface name %q: %w" , name , err )
260+ }
261+ bundleID = int32 (o )
262+ outerVlan = int32 (i )
263+ }
264+ return bundleID , outerVlan , nil
265+ }
266+
267+ func CheckVlanRange (vlan string ) error {
268+ v , err := strconv .Atoi (vlan )
269+
270+ if err != nil {
271+ return fmt .Errorf ("failed to parse VLAN %q: %w" , vlan , err )
272+ }
273+
274+ if v < 1 || v > 4095 {
275+ return fmt .Errorf ("VLAN %s is out of range, valid range is 1-4095" , vlan )
276+ }
277+ return nil
136278}
0 commit comments