Skip to content
Snippets Groups Projects
Commit b235148c authored by Manuel Kieweg's avatar Manuel Kieweg
Browse files

merge develop into branch

parents 497671b4 18cd0a67
No related branches found
No related tags found
2 merge requests!113increased test coverage,!90Develop
Pipeline #66659 passed with warnings
# goSDN Architecture
This document describes the the high-level architecture of the goSDN project. All contributors should familiarize themselves with it. To avoid too much divergence from the changing code this document does focus on high-level concepts instead of implementation details.
## Bird's Eye View
[<img src="documentation/architecture.png" style="height:50%; width:50%" > ](documentation/architecture.png)
On the highest level goSDn provides a gRPC northbound-interface and two types of southbound-interfaces: RESTCONF and gRPC-based. The northbound interface allows the interaction with a running goSDN daemon and may allow the stacking of multiple controllers in the future. The southbound interface (SBI) capabilities are split in `nucleus` models and plugins. The supported `nucleus` models are OpenConfig yang [openconfig-yang](https://github.com/openconfig/yang) and TAPI. Third party models and more SBI-transports can be attached using the go plugin architecture.
The internal data representation uses [ygot](https://github.com/openconfig/ygot) generated go-structs.
It is important to note that these go-structs are generated from yang models and thus are not generic data structures. This means that the `nucleus` code is organized in silos, i.e., one particular southbound-interface is visible in the `nucleus`, as the internal data representation depend on the used yang modes in the southbound-interface.
## Code Map
This section briefly describes important directories and data structures. It also introduces important API calls to relevant libraries.
It also mentions **architecture invariants** and **API boundaries**
### `api`
API specification for gRPC and protobuf definitions.
**Architecture invariant:** To import gRPC related protobuf definitions use `pb` as an import prefix. For gNMI related protobuf definitions use `gpb`
### `forks`
Forks of `google/gnxi/gnmi` and `arista/goarista/gnmi` for gNMI server and client respectively. Subject of change once we converge to own clients and servers.
### `nucleus/principalNetworkDomain`
`nucleus` is the core package of goSDN. The main data structure is the `principalNetworkDomain` (PND). It reflects one administrative entity, i.e., as set of connected network devices, and is the source of truth for network state and configuration. A PND is SBI agnostic and supports multiple SBI implementations simultaneously.
**API boundary:** The PND' is the only way to interact with an `orchestratedNetworkingDevice`
### `nucleus/device`
This is the representation of an `orchestratedNetworkingDevice` (OND). An `orchestratedNetworkingDevice` is the network device that is directly managed by goSDN. It holds a reference to the device's `transport` and `southboundInterface` implementation. It contains a fakeroot device based on its attached SBI.
**Architecture invariant:** The device is does not provide any functionality to upper API layers.
### `nucleus/southbound`
Implementation of SBI specifics. Provides SBI models to other callers and SBI specific function deviations.
**Architecture invariant:** Only SBIs defined by a YANG model will be supported by goSDN.
### `nucleus/transport` `nucleus/gnmi_transport` `nucleus/restconf_transport`
Transport between goSDN and ONDs. Current core implementations are gNMI and RESTCONF. Additionally to implementing the transports the packages also provide a mapping from general purpose goSDN API calls to diverging SBI API calls.
For example `gNMI::Subscribe` and `RESTCONF::Push` are mapped to `gosdn::Subscribe`.
The `gnmi_transport` implementation uses `ytypes.SetNode` to write to a device struct.
documentation/architecture.png

162 KiB

...@@ -166,8 +166,10 @@ func (g *Gnmi) subscribe(ctx context.Context) error { ...@@ -166,8 +166,10 @@ func (g *Gnmi) subscribe(ctx context.Context) error {
go func() { go func() {
for { for {
resp := <-g.RespChan resp := <-g.RespChan
if err := gnmi.LogSubscribeResponse(resp); err != nil { if resp != nil {
log.Fatal(err) if err := gnmi.LogSubscribeResponse(resp); err != nil {
log.Fatal(err)
}
} }
} }
}() }()
......
...@@ -114,7 +114,8 @@ func TestOpenConfig_Schema(t *testing.T) { ...@@ -114,7 +114,8 @@ func TestOpenConfig_Schema(t *testing.T) {
schema: tt.fields.schema, schema: tt.fields.schema,
id: tt.fields.id, id: tt.fields.id,
} }
if got := oc.Schema(); !reflect.DeepEqual(got, tt.want) { got := oc.Schema().SchemaTree
if !reflect.DeepEqual(got, tt.want.SchemaTree) {
t.Errorf("Schema() = %v, want %v", got, tt.want) t.Errorf("Schema() = %v, want %v", got, tt.want)
} }
}) })
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"reflect" "reflect"
"sort"
"testing" "testing"
) )
...@@ -221,7 +222,14 @@ func Test_store_UUIDs(t *testing.T) { ...@@ -221,7 +222,14 @@ func Test_store_UUIDs(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if got := tt.s.UUIDs(); !reflect.DeepEqual(got, tt.want) { sort.Slice(tt.want, func(i, j int) bool {
return tt.want[i].String() < tt.want[j].String()
})
got := tt.s.UUIDs()
sort.Slice(got, func(i, j int) bool {
return got[i].String() < got[j].String()
})
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("UUIDs() = %v, want %v", got, tt.want) t.Errorf("UUIDs() = %v, want %v", got, tt.want)
} }
}) })
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment