Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Kevin Petremann <k.petremann@criteo.com>
Florian Domain <f.domain@criteo.com>
Djothi Carpentier <d.carpentier@criteo.com>
114 changes: 100 additions & 14 deletions internal/convertor/device/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import (
"sync"

bgpconvertors "github.com/criteo/data-aggregation-api/internal/convertor/bgp"
ifconvertors "github.com/criteo/data-aggregation-api/internal/convertor/interfaces"
ntpconvertors "github.com/criteo/data-aggregation-api/internal/convertor/ntp"
rpconvertors "github.com/criteo/data-aggregation-api/internal/convertor/routingpolicy"
snmpconvertors "github.com/criteo/data-aggregation-api/internal/convertor/snmp"
syslogconvertors "github.com/criteo/data-aggregation-api/internal/convertor/syslog"
tacacsconvertors "github.com/criteo/data-aggregation-api/internal/convertor/tacacs"
"github.com/criteo/data-aggregation-api/internal/ingestor/repository"
"github.com/criteo/data-aggregation-api/internal/model/cmdb/bgp"
cmdbif "github.com/criteo/data-aggregation-api/internal/model/cmdb/interfaces"
"github.com/criteo/data-aggregation-api/internal/model/cmdb/ntp"
"github.com/criteo/data-aggregation-api/internal/model/cmdb/routingpolicy"
"github.com/criteo/data-aggregation-api/internal/model/cmdb/snmp"
Expand All @@ -38,20 +40,25 @@ type GeneratedConfig struct {
}

type Device struct {
mutex *sync.Mutex
Dcim *dcim.NetworkDevice
Config *GeneratedConfig
BGPGlobalConfig *bgp.BGPGlobal
SNMP *snmp.SNMP
NTP *ntp.NTP
Syslog *syslog.Syslog
Tacacs *tacacs.Tacacs
Sessions []*bgp.Session
PeerGroups []*bgp.PeerGroup
PrefixLists []*routingpolicy.PrefixList
CommunityLists []*routingpolicy.CommunityList
RoutePolicies []*routingpolicy.RoutePolicy
AFKEnabled bool
mutex *sync.Mutex
Dcim *dcim.NetworkDevice
Config *GeneratedConfig
BGPGlobalConfig *bgp.BGPGlobal
SNMP *snmp.SNMP
NTP *ntp.NTP
Syslog *syslog.Syslog
Tacacs *tacacs.Tacacs
Sessions []*bgp.Session
PeerGroups []*bgp.PeerGroup
PrefixLists []*routingpolicy.PrefixList
CommunityLists []*routingpolicy.CommunityList
RoutePolicies []*routingpolicy.RoutePolicy
DeviceInterfaces []*cmdbif.DeviceInterface
LogicalInterfaces []*cmdbif.LogicalInterface
ManagementRoutes []*cmdbif.ManagementRoute
PortLayout cmdbif.PortLayoutTable
Neighbors cmdbif.NeighborTable
AFKEnabled bool

// Hwsku and SONiCType are DEVICE_METADATA's hwsku and type, empty when
// the device's model or role is not mapped.
Expand Down Expand Up @@ -142,6 +149,33 @@ func NewDevice(dcimInfo *dcim.NetworkDevice, devicesData *repository.AssetsPerDe
log.Warn().Msgf("no SONiC type mapped to the device role %q of %s", dcimInfo.DeviceRole.Name, dcimInfo.Hostname)
}

device.DeviceInterfaces, ok = devicesData.DeviceInterfaces[dcimInfo.Hostname]
if !ok {
log.Warn().Msgf("no device interfaces found for %s", dcimInfo.Hostname)
}

device.LogicalInterfaces, ok = devicesData.LogicalInterfaces[dcimInfo.Hostname]
if !ok {
log.Warn().Msgf("no logical interfaces found for %s", dcimInfo.Hostname)
}

// Only the devices whose management routing table is generated have
// management routes: having none is normal.
device.ManagementRoutes = devicesData.ManagementRoutes[dcimInfo.Hostname]

// The port layout is shared by all the devices of the same hardware model
// and network role. Devices without one keep their CMDB interface names.
layoutKey := cmdbif.PortLayoutKey{DeviceTypeID: dcimInfo.DeviceTypeID(), RoleID: dcimInfo.RoleID()}
device.PortLayout, ok = devicesData.PortLayouts[layoutKey]
if !ok {
log.Warn().Msgf("no port layout found for %s (device type %d, role %d)", dcimInfo.Hostname, layoutKey.DeviceTypeID, layoutKey.RoleID)
}

device.Neighbors, ok = devicesData.Neighbors[dcimInfo.Hostname]
if !ok {
log.Warn().Msgf("no links found for %s", dcimInfo.Hostname)
}

return device, nil
}

Expand All @@ -167,6 +201,16 @@ func (d *Device) Generateconfigs() error {
return fmt.Errorf("convert from TACACS to OpenConfig failed: %w", err)
}

interfacesConfig, networkInstanceInterfaces, err := ifconvertors.InterfacesToOpenconfig(d.Dcim.Hostname, d.DeviceInterfaces, d.LogicalInterfaces, d.PortLayout, d.Neighbors, d.AFKEnabled)
if err != nil {
return fmt.Errorf("convert from Interfaces to OpenConfig failed: %w", err)
}

networkInstanceProtocols, err := ifconvertors.ManagementRoutesToOpenconfig(d.Dcim.Hostname, d.ManagementRoutes, d.DeviceInterfaces, d.PortLayout, interfacesConfig, networkInstanceInterfaces)
if err != nil {
return fmt.Errorf("convert from Management Routes to OpenConfig failed: %w", err)
}

// Assemble global configuration
bgpKey := openconfig.NetworkInstance_Protocol_Key{Identifier: openconfig.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, Name: "bgp"}

Expand Down Expand Up @@ -194,6 +238,48 @@ func (d *Device) Generateconfigs() error {
},
}

if len(interfacesConfig) > 0 {
config.Interface = interfacesConfig
}

// Bind interfaces to their network instance (VRF). Non-default network
// instances only exist through those bindings and are typed as L3VRF.
for networkInstanceName, interfaceBindings := range networkInstanceInterfaces {
networkInstance, ok := config.NetworkInstance[networkInstanceName]
if !ok {
name := networkInstanceName
networkInstance = &openconfig.NetworkInstance{
Name: &name,
Type: openconfig.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_L3VRF,
}
config.NetworkInstance[networkInstanceName] = networkInstance
}
networkInstance.Interface = interfaceBindings
}

// Add the routing protocol instances (static routes) to their network
// instance, which exists through the interface bindings above.
for networkInstanceName, protocols := range networkInstanceProtocols {
networkInstance, ok := config.NetworkInstance[networkInstanceName]
if !ok {
name := networkInstanceName
networkInstance = &openconfig.NetworkInstance{
Name: &name,
Type: openconfig.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_L3VRF,
}
config.NetworkInstance[networkInstanceName] = networkInstance
}
if networkInstance.Protocol == nil {
networkInstance.Protocol = make(map[openconfig.NetworkInstance_Protocol_Key]*openconfig.NetworkInstance_Protocol)
}
for key, protocol := range protocols {
if _, duplicate := networkInstance.Protocol[key]; duplicate {
return fmt.Errorf("duplicate protocol %s/%s in network instance %s of %s", key.Identifier, key.Name, networkInstanceName, d.Dcim.Hostname)
}
networkInstance.Protocol[key] = protocol
}
}

devJSON, err := ygot.EmitJSON(
&config,
&ygot.EmitJSONConfig{
Expand Down
Loading
Loading