Skip to content

Commit

Permalink
router: add interfaces endpoint to service management API - implement…
Browse files Browse the repository at this point in the history
…ation

Added implementation for the `/interfaces` endpoint on the router.

GitOrigin-RevId: a0e227614140c980279efae17965ff0842eda942
  • Loading branch information
kmavromati authored and lukedirtwalker committed Nov 30, 2021
1 parent 3c204ca commit d36fd92
Show file tree
Hide file tree
Showing 18 changed files with 853 additions and 111 deletions.
23 changes: 21 additions & 2 deletions go/pkg/router/api/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("//lint:go.bzl", "go_embed_data", "go_library")
load("//lint:go.bzl", "go_embed_data", "go_library", "go_test")
load("@com_github_scionproto_scion//rules_openapi:defs.bzl", "openapi_generate_go")

genrule(
Expand Down Expand Up @@ -39,10 +39,29 @@ go_library(
importpath = "github.com/scionproto/scion/go/pkg/router/api",
visibility = ["//visibility:public"],
deps = [
"//go/lib/pathdb/query:go_default_library",
"//go/lib/addr:go_default_library",
"//go/pkg/api:go_default_library",
"//go/pkg/router/control:go_default_library",
"@com_github_deepmap_oapi_codegen//pkg/runtime:go_default_library", # keep
"@com_github_getkin_kin_openapi//openapi3:go_default_library", # keep
"@com_github_go_chi_chi_v5//:go_default_library", # keep
"@com_github_pkg_errors//:go_default_library", # keep
],
)

go_test(
name = "go_default_test",
srcs = ["api_test.go"],
data = glob(["testdata/**"]),
embed = [":go_default_library"],
deps = [
"//go/lib/serrors:go_default_library",
"//go/lib/topology:go_default_library",
"//go/lib/xtest:go_default_library",
"//go/pkg/router/control:go_default_library",
"//go/pkg/router/control/mock_api:go_default_library",
"@com_github_golang_mock//gomock:go_default_library",
"@com_github_stretchr_testify//assert:go_default_library",
"@com_github_stretchr_testify//require:go_default_library",
],
)
121 changes: 111 additions & 10 deletions go/pkg/router/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,20 @@
package api

import (
"context"
"encoding/json"
"net/http"

"github.com/scionproto/scion/go/lib/pathdb/query"
"github.com/scionproto/scion/go/lib/addr"
"github.com/scionproto/scion/go/pkg/api"
"github.com/scionproto/scion/go/pkg/router/control"
)

type SegmentsStore interface {
Get(context.Context, *query.Params) (query.Results, error)
}

// Server implements the Control Service API.
type Server struct {
Config http.HandlerFunc
Info http.HandlerFunc
LogLevel http.HandlerFunc
Config http.HandlerFunc
Info http.HandlerFunc
LogLevel http.HandlerFunc
Dataplane control.ObservableDataplane
}

// GetConfig is an indirection to the http handler.
Expand All @@ -52,7 +51,109 @@ func (s *Server) SetLogLevel(w http.ResponseWriter, r *http.Request) {
s.LogLevel(w, r)
}

// GetInterfaces TODO:
// GetInterfaces gets the interfaces and sibling interfaces of the router.
func (s *Server) GetInterfaces(w http.ResponseWriter, r *http.Request) {
internalInterfaces, err := s.Dataplane.ListInternalInterfaces()
if err != nil {
Error(w, Problem{
Detail: api.StringRef(err.Error()),
Status: http.StatusInternalServerError,
Title: "error getting internal interface",
Type: api.StringRef(api.InternalError),
})
return
}
externalInterfaces, err := s.Dataplane.ListExternalInterfaces()
if err != nil {
Error(w, Problem{
Detail: api.StringRef(err.Error()),
Status: http.StatusInternalServerError,
Title: "error getting external interfaces",
Type: api.StringRef(api.InternalError),
})
return
}
siblingInterfaces, err := s.Dataplane.ListSiblingInterfaces()
if err != nil {
Error(w, Problem{
Detail: api.StringRef(err.Error()),
Status: http.StatusInternalServerError,
Title: "error getting sibling interfaces",
Type: api.StringRef(api.InternalError),
})
return
}
intfs := make([]Interface, 0, len(externalInterfaces))
siblings := make([]SiblingInterface, 0, len(externalInterfaces))

findInternalInterface := func(ia addr.IA) string {
for _, intf := range internalInterfaces {
if intf.IA.Equal(ia) {
return intf.Addr.String()
}
}
return "undefined"
}
for _, intf := range externalInterfaces {
newInterface := Interface{
Bfd: BFD{
DesiredMinimumTxInterval: intf.Link.BFD.DesiredMinTxInterval.String(),
DetectionMultiplier: int(intf.Link.BFD.DetectMult),
Enabled: !intf.Link.BFD.Disable,
RequiredMinimumReceive: intf.Link.BFD.RequiredMinRxInterval.String(),
},
InterfaceId: int(intf.InterfaceID),
InternalInterface: findInternalInterface(intf.Link.Local.IA),
Neighbor: InterfaceNeighbor{
Address: intf.Link.Remote.Addr.String(),
IsdAs: IsdAs(intf.Link.Remote.IA.String()),
},
Relationship: LinkRelationship(intf.Link.LinkTo.String()),
ScionMtu: ScionMTU(intf.Link.MTU),
State: LinkState(intf.State),
}

intfs = append(intfs, newInterface)
}

for _, intf := range siblingInterfaces {
siblingInterface := SiblingInterface{
InterfaceId: int(intf.InterfaceID),
InternalInterface: intf.InternalInterface.String(),
Neighbor: SiblingNeighbor{
IsdAs: IsdAs(intf.NeighborIA.String()),
},
Relationship: LinkRelationship(intf.Relationship.String()),
ScionMtu: ScionMTU(intf.MTU),
State: LinkState(intf.State),
}

siblings = append(siblings, siblingInterface)
}

rep := InterfacesResponse{
Interfaces: &intfs,
SiblingInterfaces: &siblings,
}
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
if err := enc.Encode(rep); err != nil {
Error(w, Problem{
Detail: api.StringRef(err.Error()),
Status: http.StatusInternalServerError,
Title: "unable to marshal response",
Type: api.StringRef(api.InternalError),
})
return
}
}

// Error creates an detailed error response.
func Error(w http.ResponseWriter, p Problem) {
w.Header().Set("Content-Type", "application/problem+json")
w.WriteHeader(p.Status)
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
// no point in catching error here, there is nothing we can do about it anymore.
enc.Encode(p)
}
Loading

0 comments on commit d36fd92

Please sign in to comment.