Skip to content

Commit

Permalink
added adva channel matrix & 100G rx/tx power
Browse files Browse the repository at this point in the history
  • Loading branch information
TheFireMike committed Mar 18, 2021
1 parent 2f25225 commit 089152f
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 90 deletions.
25 changes: 1 addition & 24 deletions config/device-classes/generic/adva_fsp3kr7.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,4 @@ identify:
format: "$property$ ($read_value$)"
os_version:
- detection: snmpget
oid: .1.3.6.1.4.1.2544.1.11.2.2.1.5.0

components:
interfaces:
types:
dwdm:
detection: 1.3.6.1.4.1.2544.1.11.2.4.3.5.1.3
specific_values:
rx_level:
oid: 1.3.6.1.4.1.2544.1.11.2.4.3.5.1.3
operators:
- type: modify
modify_method: multiply
value:
detection: constant
value: 0.1
tx_level:
oid: 1.3.6.1.4.1.2544.1.11.2.4.3.5.1.4
operators:
- type: modify
modify_method: multiply
value:
detection: constant
value: 0.1
oid: .1.3.6.1.4.1.2544.1.11.2.2.1.5.0
238 changes: 238 additions & 0 deletions core/communicator/adva.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
package communicator

import (
"context"
"fmt"
"github.com/inexio/thola/core/device"
"github.com/inexio/thola/core/network"
"github.com/inexio/thola/core/value"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/shopspring/decimal"
"regexp"
"strconv"
"strings"
)

type advaCommunicator struct {
baseCommunicator
}

// GetInterfaces returns the interfaces of adva devices.
func (c *advaCommunicator) GetInterfaces(ctx context.Context) ([]device.Interface, error) {
interfaces, err := c.sub.GetInterfaces(ctx)
if err != nil {
return nil, err
}

if advaGetDWDMInterfaces(ctx, interfaces) != nil {
return nil, err
}

if advaGetChannelMatrix(ctx, interfaces) != nil {
return nil, err
}

return interfaces, nil
}

func advaGetDWDMInterfaces(ctx context.Context, interfaces []device.Interface) error {
con, ok := network.DeviceConnectionFromContext(ctx)
if !ok || con.SNMP == nil {
return errors.New("no device connection available")
}

specialInterfacesRaw, err := getValuesBySNMPWalk(ctx, deviceClassOIDs{
"rx_power": deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "1.3.6.1.4.1.2544.1.11.2.4.3.5.1.3",
},
operators: propertyOperators{
&modifyOperatorAdapter{
&multiplyNumberModifier{
value: &constantPropertyReader{
Value: value.New("0.1"),
},
},
},
},
},
"tx_power": deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "1.3.6.1.4.1.2544.1.11.2.4.3.5.1.4",
},
operators: propertyOperators{
&modifyOperatorAdapter{
&multiplyNumberModifier{
value: &constantPropertyReader{
Value: value.New("0.1"),
},
},
},
},
},
})

if err != nil {
return errors.Wrap(err, "failed to read rx/tx power of ports")
}

for i, networkInterface := range interfaces {
if specialValues, ok := specialInterfacesRaw[fmt.Sprint(*networkInterface.IfIndex)]; ok {
err := addSpecialInterfacesValuesToInterface("dwdm", &interfaces[i], specialValues)
if err != nil {
log.Ctx(ctx).Trace().Err(err).Msg("can't parse oid values into Interface struct")
return errors.Wrap(err, "can't parse oid values into Interface struct")
}
}
}

rx100Values, err := advaGetPowerValues(ctx, ".1.3.6.1.4.1.2544.1.11.11.7.2.1.1.1.21")
if err != nil {
return errors.Wrap(err, "failed to get rx 100 values")
}

tx100Values, err := advaGetPowerValues(ctx, ".1.3.6.1.4.1.2544.1.11.11.7.2.1.1.1.22")
if err != nil {
return errors.Wrap(err, "failed to get tx 100 values")
}

for i, interf := range interfaces {
if interf.IfDescr != nil {
rxVal, rxOK := rx100Values[*interf.IfDescr]
txVal, txOK := tx100Values[*interf.IfDescr]
if (rxOK || txOK) && interf.DWDM == nil {
interfaces[i].DWDM = &device.DWDMInterface{}
}
if rxOK {
interfaces[i].DWDM.RXPower100G = &rxVal
}
if txOK {
interfaces[i].DWDM.TXPower100G = &txVal
}
}
}

return nil
}

func advaGetChannelMatrix(ctx context.Context, interfaces []device.Interface) error {
con, ok := network.DeviceConnectionFromContext(ctx)
if !ok || con.SNMP == nil {
return errors.New("no device connection available")
}

facilityPhysInstValueInputPower := ".1.3.6.1.4.1.2544.1.11.11.7.2.1.1.1.2"
facilityPhysInstValueInputPowerValues, err := con.SNMP.SnmpClient.SNMPWalk(ctx, facilityPhysInstValueInputPower)
if err != nil {
return errors.Wrap(err, "failed to walk facilityPhysInstValueInputPower")
}

var subtrees []string
var channels []device.OpticalChannel

for _, res := range facilityPhysInstValueInputPowerValues {
subtree := strings.TrimPrefix(res.GetOID(), facilityPhysInstValueInputPower)
if s := strings.Split(strings.Trim(subtree, "."), "."); len(s) > 2 && s[len(s)-2] != "0" {
val, err := res.GetValueString()
if err != nil {
return errors.Wrap(err, "failed to get rx value of channel "+subtree)
}
a, err := decimal.NewFromString(val)
if err != nil {
return errors.Wrap(err, "failed to parse rx value of channel "+subtree)
}
b := decimal.NewFromFloat(0.1)
valFin, _ := a.Mul(b).Float64()

subtrees = append(subtrees, subtree)
channels = append(channels, device.OpticalChannel{
Channel: s[len(s)-2],
RXPower: &valFin,
})
}
}

for i, subtree := range subtrees {
res, err := con.SNMP.SnmpClient.SNMPGet(ctx, ".1.3.6.1.4.1.2544.1.11.11.7.2.1.1.1.1"+subtree)
if err != nil {
return errors.Wrap(err, "failed to get facilityPhysInstValueOutputPower for subtree "+subtree)
}

if len(res) != 1 {
return errors.New("failed to get tx value of channel " + subtree)
}

val, err := res[0].GetValueString()
if err != nil {
return errors.Wrap(err, "failed to get tx value of channel "+subtree)
}
a, err := decimal.NewFromString(val)
if err != nil {
return errors.Wrap(err, "failed to parse tx value of channel "+subtree)
}
b := decimal.NewFromFloat(0.1)
valFin, _ := a.Mul(b).Float64()

channels[i].TXPower = &valFin

p := strings.Split(strings.ReplaceAll(strings.Trim(subtree, "."), "33152", "N"), ".")
regex, err := regexp.Compile("-" + p[0] + "-" + p[1] + "-" + p[2])
if err != nil {
return errors.Wrap(err, "failed to build regex")
}

for j, interf := range interfaces {
if interf.IfDescr != nil && regex.MatchString(*interf.IfDescr) {
if interf.DWDM == nil {
interfaces[j].DWDM = &device.DWDMInterface{}
}
interfaces[j].DWDM.Channels = append(interfaces[j].DWDM.Channels, channels[i])
break
}
}
}

return nil
}

func advaGetPowerValues(ctx context.Context, oid string) (map[string]float64, error) {
con, ok := network.DeviceConnectionFromContext(ctx)
if !ok || con.SNMP == nil {
return nil, errors.New("no device connection available")
}

values, err := con.SNMP.SnmpClient.SNMPWalk(ctx, oid)
if err != nil {
return nil, errors.Wrap(err, "failed to walk facilityPhysInstValueCalculatedTotalPower")
}

descrToValues := make(map[string]float64)

for _, val := range values {
subtree := strings.TrimPrefix(val.GetOID(), oid)
subtreeSplit := strings.Split(strings.Trim(subtree, "."), ".")
if len(subtreeSplit) < 3 {
return nil, errors.New("invalid facilityPhysInstValueCalculatedTotalPower value")
}

valueString, err := val.GetValueString()
if err != nil {
return nil, errors.Wrap(err, "failed to get rx value")
}
valueDecimal, err := decimal.NewFromString(valueString)
if err != nil {
return nil, errors.Wrap(err, "failed to parse rx value")
}
multiplier := decimal.NewFromFloat(0.1)

portInt, err := strconv.Atoi(subtreeSplit[2])
if err != nil {
return nil, errors.Wrap(err, "failed to parse oid to int")
}

descrToValues["CH-"+subtreeSplit[0]+"-"+subtreeSplit[1]+"-C"+strconv.Itoa(portInt/256)], _ = valueDecimal.Mul(multiplier).Float64()
}

return descrToValues, nil
}
100 changes: 50 additions & 50 deletions core/communicator/device_class_communicator.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (o *deviceClassCommunicator) GetInterfaces(ctx context.Context) ([]device.I
}

for t, typeDef := range o.components.interfaces.Types {
specialInterfacesRaw, err := o.getValuesBySNMPWalk(ctx, typeDef.Values)
specialInterfacesRaw, err := getValuesBySNMPWalk(ctx, typeDef.Values)
if err != nil {
return nil, err
}
Expand All @@ -130,54 +130,6 @@ func (o *deviceClassCommunicator) GetInterfaces(ctx context.Context) ([]device.I
return networkInterfaces, nil
}

func addSpecialInterfacesValuesToInterface(interfaceType string, interf *device.Interface, specialValues interface{}) error {
switch interfaceType {
case "ether_like":
var specialValuesStruct device.EthernetLikeInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.EthernetLike = &specialValuesStruct
case "radio":
var specialValuesStruct device.RadioInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.Radio = &specialValuesStruct
case "dwdm":
var specialValuesStruct device.DWDMInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.DWDM = &specialValuesStruct
case "optical_transponder":
var specialValuesStruct device.OpticalTransponderInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.OpticalTransponder = &specialValuesStruct
case "optical_amplifier":
var specialValuesStruct device.OpticalAmplifierInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.OpticalAmplifier = &specialValuesStruct
case "optical_opm":
var specialValuesStruct device.OpticalOPMInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.OpticalOPM = &specialValuesStruct
}
return nil
}

func (o *deviceClassCommunicator) GetIfTable(ctx context.Context) ([]device.Interface, error) {
if o.components.interfaces == nil || o.components.interfaces.IfTable == nil {
log.Ctx(ctx).Trace().Str("property", "ifTable").Str("device_class", o.name).Msg("no interface information available")
Expand Down Expand Up @@ -805,7 +757,7 @@ func convertRawInterfaces(ctx context.Context, interfacesRaw []map[string]value.
return networkInterfaces, nil
}

func (o *deviceClassCommunicator) getValuesBySNMPWalk(ctx context.Context, oids deviceClassOIDs) (map[string]map[string]interface{}, error) {
func getValuesBySNMPWalk(ctx context.Context, oids deviceClassOIDs) (map[string]map[string]interface{}, error) {
networkInterfaces := make(map[string]map[string]interface{})

con, ok := network.DeviceConnectionFromContext(ctx)
Expand Down Expand Up @@ -849,3 +801,51 @@ func (o *deviceClassCommunicator) getValuesBySNMPWalk(ctx context.Context, oids

return networkInterfaces, nil
}

func addSpecialInterfacesValuesToInterface(interfaceType string, interf *device.Interface, specialValues map[string]interface{}) error {
switch interfaceType {
case "ether_like":
var specialValuesStruct device.EthernetLikeInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.EthernetLike = &specialValuesStruct
case "radio":
var specialValuesStruct device.RadioInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.Radio = &specialValuesStruct
case "dwdm":
var specialValuesStruct device.DWDMInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.DWDM = &specialValuesStruct
case "optical_transponder":
var specialValuesStruct device.OpticalTransponderInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.OpticalTransponder = &specialValuesStruct
case "optical_amplifier":
var specialValuesStruct device.OpticalAmplifierInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.OpticalAmplifier = &specialValuesStruct
case "optical_opm":
var specialValuesStruct device.OpticalOPMInterface
err := mapstructure.WeakDecode(specialValues, &specialValuesStruct)
if err != nil {
return errors.Wrap(err, "failed to decode special values")
}
interf.OpticalOPM = &specialValuesStruct
}
return nil
}
Loading

0 comments on commit 089152f

Please sign in to comment.