diff --git a/cmd/magna/main.go b/cmd/magna/main.go index a8f0505..6d4e949 100644 --- a/cmd/magna/main.go +++ b/cmd/magna/main.go @@ -29,7 +29,7 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/reflection" - "k8s.io/klog" + "k8s.io/klog/v2" gpb "github.com/openconfig/gnmi/proto/gnmi" ) diff --git a/flows/common/common.go b/flows/common/common.go index c9bcde7..5effa2b 100644 --- a/flows/common/common.go +++ b/flows/common/common.go @@ -9,7 +9,7 @@ import ( "github.com/google/gopacket/pcap" "github.com/open-traffic-generator/snappi/gosnappi/otg" "github.com/openconfig/magna/lwotg" - "k8s.io/klog" + "k8s.io/klog/v2" ) var ( diff --git a/flows/common/counter.go b/flows/common/counter.go index 7ddb069..4985ce1 100644 --- a/flows/common/counter.go +++ b/flows/common/counter.go @@ -13,7 +13,7 @@ import ( "github.com/openconfig/magna/otgyang" tcommon "github.com/openconfig/magna/telemetry/common" "github.com/openconfig/ygot/ygot" - "k8s.io/klog" + "k8s.io/klog/v2" ) var ( diff --git a/flows/ip/ip.go b/flows/ip/ip.go index 0b778be..5c7193f 100644 --- a/flows/ip/ip.go +++ b/flows/ip/ip.go @@ -12,7 +12,7 @@ import ( "github.com/openconfig/magna/flows/common" "github.com/openconfig/magna/lwotg" "github.com/openconfig/magna/lwotgtelem/gnmit" - "k8s.io/klog" + "k8s.io/klog/v2" ) // New returns a new IP flow generator, consisting of: diff --git a/flows/mpls/mpls.go b/flows/mpls/mpls.go index c5e7c03..c0497ee 100644 --- a/flows/mpls/mpls.go +++ b/flows/mpls/mpls.go @@ -17,7 +17,7 @@ import ( "github.com/openconfig/magna/flows/common" "github.com/openconfig/magna/lwotg" "github.com/openconfig/magna/lwotgtelem/gnmit" - "k8s.io/klog" + "k8s.io/klog/v2" ) const ( diff --git a/go.mod b/go.mod index 8f0693e..a5184a8 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,6 @@ require ( github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 google.golang.org/grpc v1.58.3 google.golang.org/protobuf v1.31.0 - k8s.io/klog v1.0.0 k8s.io/klog/v2 v2.90.1 ) diff --git a/go.sum b/go.sum index 69eb5d5..614b3df 100644 --- a/go.sum +++ b/go.sum @@ -858,7 +858,6 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -2012,8 +2011,6 @@ k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k= k8s.io/apimachinery v0.26.3/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s= k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a h1:gmovKNur38vgoWfGtP5QOGNOA7ki4n6qNYoFAgMlNvg= diff --git a/integration/intf_test.go b/integration/intf_test.go index fb01244..1f33ae6 100644 --- a/integration/intf_test.go +++ b/integration/intf_test.go @@ -86,3 +86,44 @@ func TestInterfaces(t *testing.T) { t.Logf("Got interfaces: %v", ints) } + +func TestInterfaceState(t *testing.T) { + name := "dummy0" + dummy := &netlink.Dummy{ + LinkAttrs: netlink.LinkAttrs{ + Name: name, + }, + } + + if err := netlink.LinkAdd(dummy); err != nil { + t.Fatalf("cannot add dummy link, %v", err) + } + + dummyState := func() intf.IntState { + l, err := intf.InterfaceByName(name) + if err != nil { + t.Errorf("unable to get dummy link, %v", err) + } + return l.AdminState + } + + if err := intf.InterfaceState(name, intf.InterfaceDown); err != nil { + t.Errorf("cannot shut down dummy link, %v", err) + } + + if got, want := dummyState(), intf.InterfaceDown; got != want { + t.Errorf("interface was not operationally down, got: %v, want: %v", got, want) + } + + if err := intf.InterfaceState(name, intf.InterfaceUp); err != nil { + t.Errorf("cannot enable dummy link, %v", err) + } + + if got, want := dummyState(), intf.InterfaceUp; got != want { + t.Errorf("interface was not restored to its previous state, got: %v, want: %v", got, want) + } + + if err := netlink.LinkDel(dummy); err != nil { + t.Fatalf("cannot delete dummy link, %v", err) + } +} diff --git a/intf/accessor_linux.go b/intf/accessor_linux.go index 61940fa..da7b733 100644 --- a/intf/accessor_linux.go +++ b/intf/accessor_linux.go @@ -19,7 +19,7 @@ import ( "net" "github.com/vishvananda/netlink" - "k8s.io/klog" + "k8s.io/klog/v2" ) const ( @@ -44,6 +44,31 @@ func init() { // system. type netlinkAccessor struct{} +// intOperState maps a netlink operational link state to an intf internal +// representation. +func intOperState(n netlink.LinkOperState) IntState { + operStateMap := map[netlink.LinkOperState]IntState{ + netlink.OperUp: InterfaceUp, + netlink.OperDown: InterfaceDown, + } + + if _, ok := operStateMap[n]; !ok { + return InterfaceStateUnknown + } + + return operStateMap[n] +} + +// intAdminState maps an interface's flags to the administrative state of +// the interface. The flags are defined in the net package +// (see https://cs.opensource.google/go/go/+/refs/tags/go1.21.4:src/net/interface.go;l=39). +func intAdminState(n net.Flags) IntState { + if n&1 != 0 { + return InterfaceUp + } + return InterfaceDown +} + // Interface retrieves the interface named from the underlying system // through making a netlink call. func (n netlinkAccessor) Interface(name string) (*Interface, error) { @@ -54,9 +79,11 @@ func (n netlinkAccessor) Interface(name string) (*Interface, error) { attrs := link.Attrs() return &Interface{ - Index: attrs.Index, - Name: attrs.Name, - MAC: attrs.HardwareAddr, + Index: attrs.Index, + Name: attrs.Name, + MAC: attrs.HardwareAddr, + AdminState: intAdminState(attrs.Flags), + OperState: intOperState(attrs.OperState), }, nil } @@ -72,9 +99,11 @@ func (n netlinkAccessor) Interfaces() ([]*Interface, error) { for _, i := range ints { attrs := i.Attrs() intfs = append(intfs, &Interface{ - Index: attrs.Index, - Name: attrs.Name, - MAC: attrs.HardwareAddr, + Index: attrs.Index, + Name: attrs.Name, + MAC: attrs.HardwareAddr, + AdminState: intAdminState(attrs.Flags), + OperState: intOperState(attrs.OperState), }) } return intfs, nil @@ -87,9 +116,11 @@ func interfaceByIndex(idx int) (*Interface, error) { return nil, fmt.Errorf("cannot find link by index %d", idx) } return &Interface{ - Index: idx, - Name: link.Attrs().Name, - MAC: link.Attrs().HardwareAddr, + Index: idx, + Name: link.Attrs().Name, + MAC: link.Attrs().HardwareAddr, + AdminState: intAdminState(link.Attrs().Flags), + OperState: intOperState(link.Attrs().OperState), }, nil } @@ -190,3 +221,28 @@ func (n netlinkAccessor) ARPSubscribe(updates chan ARPUpdate, done chan struct{} return nil } + +// InterfaceState changes the state of an interface on the underlying system. +// The interface is looked up by the name specified, and is set to the state +// specified by state. It returns an error if the interface cannot be found or +// the system cannot complete the specified operation. +func (n netlinkAccessor) InterfaceState(name string, state IntState) error { + l, err := netlink.LinkByName(name) + if err != nil { + return fmt.Errorf("cannot get link, %w", err) + } + + switch state { + case InterfaceDown: + if err := netlink.LinkSetDown(l); err != nil { + return fmt.Errorf("cannot shut down link, %w", err) + } + case InterfaceUp: + if err := netlink.LinkSetUp(l); err != nil { + return fmt.Errorf("cannot enable link, %w", err) + } + default: + return fmt.Errorf("unknown operation: %d", state) + } + return nil +} diff --git a/intf/intf.go b/intf/intf.go index 553022c..087d1ae 100644 --- a/intf/intf.go +++ b/intf/intf.go @@ -34,6 +34,10 @@ type Interface struct { Name string // MAC is the MAC address of the interface. MAC net.HardwareAddr + // OperState is the operational status of the interface. + OperState IntState + // AdminState is the administrative state of the interface. + AdminState IntState } // String is the string representation of an interface that can be read by humans. @@ -92,6 +96,8 @@ type NetworkAccessor interface { // that writes updates to the updates channel, and can be cancelled by sending a // message to the done channel. ARPSubscribe(updates chan ARPUpdate, done chan struct{}) error + // InterfaceState manipulates the state of the interface specified by name. + InterfaceState(name string, state IntState) error } // unimplementedAccessor is an accessor interface that returns unimplemented @@ -128,6 +134,12 @@ func (u unimplementedAccessor) ARPSubscribe(_ chan ARPUpdate, _ chan struct{}) e return fmt.Errorf("unimplemented ARPSubscribe method") } +// InterfaceState returns unimplemented when asked to manipulate an interface +// state. +func (u unimplementedAccessor) InterfaceState(_ string, _ IntState) error { + return fmt.Errorf("unimplemented InterfaceState method") +} + // accessor is the implementation of the network accessor that should be used. It // should be set by init() [which may be a platform-specific initiation]. var accessor NetworkAccessor @@ -230,3 +242,23 @@ func ARPSubscribe(updates chan ARPUpdate, done chan struct{}) error { func Interfaces() ([]*Interface, error) { return accessor.Interfaces() } + +// IntState sets enumerated state values that an interface +// can use. +type IntState int64 + +const ( + InterfaceStateUnknown IntState = iota + // InterfaceUp sets a link to administratively and operationally + // up. + InterfaceUp + // InterfaceDown sets a link to administratively and operationally + // down. + InterfaceDown +) + +// InterfaceState changes the administrative state of an interface +// on the local system. +func InterfaceState(name string, state IntState) error { + return accessor.InterfaceState(name, state) +} diff --git a/lwotg/flows.go b/lwotg/flows.go index c5e6fe1..ed104e2 100644 --- a/lwotg/flows.go +++ b/lwotg/flows.go @@ -8,7 +8,7 @@ import ( "github.com/open-traffic-generator/snappi/gosnappi/otg" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "k8s.io/klog" + "k8s.io/klog/v2" ) type TXRXWrapper struct { diff --git a/lwotg/lwotg.go b/lwotg/lwotg.go index ec90ee2..57f1e01 100644 --- a/lwotg/lwotg.go +++ b/lwotg/lwotg.go @@ -13,7 +13,7 @@ import ( "github.com/openconfig/magna/intf" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "k8s.io/klog" + "k8s.io/klog/v2" ) // Hint is tuple that can be handed to modules of the diff --git a/lwotgtelem/lwotgtelem.go b/lwotgtelem/lwotgtelem.go index 9844aa7..ed5ce4c 100644 --- a/lwotgtelem/lwotgtelem.go +++ b/lwotgtelem/lwotgtelem.go @@ -8,7 +8,7 @@ import ( "github.com/openconfig/magna/lwotg" "github.com/openconfig/magna/lwotgtelem/gnmit" - "k8s.io/klog" + "k8s.io/klog/v2" ) // HintMap is a structured set of hints that are supplied by the server, it diff --git a/mirrorsrv/mirror.go b/mirrorsrv/mirror.go index a68d805..4af98ff 100644 --- a/mirrorsrv/mirror.go +++ b/mirrorsrv/mirror.go @@ -9,10 +9,12 @@ import ( "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" - mpb "github.com/openconfig/magna/proto/mirror" + "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "k8s.io/klog" + "k8s.io/klog/v2" + + mpb "github.com/openconfig/magna/proto/mirror" ) type Server struct { diff --git a/telemetry/arp/arp.go b/telemetry/arp/arp.go index a4abb7b..94bb781 100644 --- a/telemetry/arp/arp.go +++ b/telemetry/arp/arp.go @@ -11,7 +11,7 @@ import ( "github.com/openconfig/magna/otgyang" "github.com/openconfig/magna/telemetry/common" "github.com/openconfig/ygot/ygot" - "k8s.io/klog" + "k8s.io/klog/v2" gpb "github.com/openconfig/gnmi/proto/gnmi" )