diff options
Diffstat (limited to 'api/capability.go')
-rw-r--r-- | api/capability.go | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/api/capability.go b/api/capability.go new file mode 100644 index 00000000..80e16c6f --- /dev/null +++ b/api/capability.go @@ -0,0 +1,288 @@ +// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gobgpapi + +import ( + "fmt" + + proto "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes/any" + + "github.com/osrg/gobgp/packet/bgp" +) + +func NewMultiProtocolCapability(a *bgp.CapMultiProtocol) *MultiProtocolCapability { + return &MultiProtocolCapability{ + Family: Family(a.CapValue), + } +} + +func (a *MultiProtocolCapability) ToNative() (*bgp.CapMultiProtocol, error) { + return bgp.NewCapMultiProtocol(bgp.RouteFamily(a.Family)), nil +} + +func NewRouteRefreshCapability(a *bgp.CapRouteRefresh) *RouteRefreshCapability { + return &RouteRefreshCapability{} +} + +func (a *RouteRefreshCapability) ToNative() (*bgp.CapRouteRefresh, error) { + return bgp.NewCapRouteRefresh(), nil +} + +func NewCarryingLabelInfoCapability(a *bgp.CapCarryingLabelInfo) *CarryingLabelInfoCapability { + return &CarryingLabelInfoCapability{} +} + +func (a *CarryingLabelInfoCapability) ToNative() (*bgp.CapCarryingLabelInfo, error) { + return bgp.NewCapCarryingLabelInfo(), nil +} + +func NewExtendedNexthopCapability(a *bgp.CapExtendedNexthop) *ExtendedNexthopCapability { + tuples := make([]*ExtendedNexthopCapabilityTuple, 0, len(a.Tuples)) + for _, t := range a.Tuples { + tuples = append(tuples, &ExtendedNexthopCapabilityTuple{ + NlriFamily: Family(bgp.AfiSafiToRouteFamily(t.NLRIAFI, uint8(t.NLRISAFI))), + NexthopFamily: Family(bgp.AfiSafiToRouteFamily(t.NexthopAFI, bgp.SAFI_UNICAST)), + }) + } + return &ExtendedNexthopCapability{ + Tuples: tuples, + } +} + +func (a *ExtendedNexthopCapability) ToNative() (*bgp.CapExtendedNexthop, error) { + tuples := make([]*bgp.CapExtendedNexthopTuple, 0, len(a.Tuples)) + for _, t := range a.Tuples { + var nhAfi uint16 + switch t.NexthopFamily { + case Family_IPv4: + nhAfi = bgp.AFI_IP + case Family_IPv6: + nhAfi = bgp.AFI_IP6 + default: + return nil, fmt.Errorf("invalid address family for nexthop afi in extended nexthop capability: %s", t.NexthopFamily) + } + tuples = append(tuples, bgp.NewCapExtendedNexthopTuple(bgp.RouteFamily(t.NlriFamily), nhAfi)) + } + return bgp.NewCapExtendedNexthop(tuples), nil +} + +func NewGracefulRestartCapability(a *bgp.CapGracefulRestart) *GracefulRestartCapability { + tuples := make([]*GracefulRestartCapabilityTuple, 0, len(a.Tuples)) + for _, t := range a.Tuples { + tuples = append(tuples, &GracefulRestartCapabilityTuple{ + Family: Family(bgp.AfiSafiToRouteFamily(t.AFI, uint8(t.SAFI))), + Flags: uint32(t.Flags), + }) + } + return &GracefulRestartCapability{ + Flags: uint32(a.Flags), + Time: uint32(a.Time), + Tuples: tuples, + } +} + +func (a *GracefulRestartCapability) ToNative() (*bgp.CapGracefulRestart, error) { + tuples := make([]*bgp.CapGracefulRestartTuple, 0, len(a.Tuples)) + for _, t := range a.Tuples { + var forward bool + if t.Flags&0x80 > 0 { + forward = true + } + tuples = append(tuples, bgp.NewCapGracefulRestartTuple(bgp.RouteFamily(t.Family), forward)) + } + var restarting bool + if a.Flags&0x08 > 0 { + restarting = true + } + var notification bool + if a.Flags&0x04 > 0 { + notification = true + } + return bgp.NewCapGracefulRestart(restarting, notification, uint16(a.Time), tuples), nil +} + +func NewFourOctetASNumberCapability(a *bgp.CapFourOctetASNumber) *FourOctetASNumberCapability { + return &FourOctetASNumberCapability{ + As: a.CapValue, + } +} + +func (a *FourOctetASNumberCapability) ToNative() (*bgp.CapFourOctetASNumber, error) { + return bgp.NewCapFourOctetASNumber(a.As), nil +} + +func NewAddPathCapability(a *bgp.CapAddPath) *AddPathCapability { + tuples := make([]*AddPathCapabilityTuple, 0, len(a.Tuples)) + for _, t := range a.Tuples { + tuples = append(tuples, &AddPathCapabilityTuple{ + Family: Family(t.RouteFamily), + Mode: AddPathMode(t.Mode), + }) + } + return &AddPathCapability{ + Tuples: tuples, + } +} + +func (a *AddPathCapability) ToNative() (*bgp.CapAddPath, error) { + tuples := make([]*bgp.CapAddPathTuple, 0, len(a.Tuples)) + for _, t := range a.Tuples { + tuples = append(tuples, bgp.NewCapAddPathTuple(bgp.RouteFamily(t.Family), bgp.BGPAddPathMode(t.Mode))) + } + return bgp.NewCapAddPath(tuples), nil +} + +func NewEnhancedRouteRefreshCapability(a *bgp.CapEnhancedRouteRefresh) *EnhancedRouteRefreshCapability { + return &EnhancedRouteRefreshCapability{} +} + +func (a *EnhancedRouteRefreshCapability) ToNative() (*bgp.CapEnhancedRouteRefresh, error) { + return bgp.NewCapEnhancedRouteRefresh(), nil +} + +func NewLongLivedGracefulRestartCapability(a *bgp.CapLongLivedGracefulRestart) *LongLivedGracefulRestartCapability { + tuples := make([]*LongLivedGracefulRestartCapabilityTuple, 0, len(a.Tuples)) + for _, t := range a.Tuples { + tuples = append(tuples, &LongLivedGracefulRestartCapabilityTuple{ + Family: Family(bgp.AfiSafiToRouteFamily(t.AFI, uint8(t.SAFI))), + Flags: uint32(t.Flags), + Time: t.RestartTime, + }) + } + return &LongLivedGracefulRestartCapability{ + Tuples: tuples, + } +} + +func (a *LongLivedGracefulRestartCapability) ToNative() (*bgp.CapLongLivedGracefulRestart, error) { + tuples := make([]*bgp.CapLongLivedGracefulRestartTuple, 0, len(a.Tuples)) + for _, t := range a.Tuples { + var forward bool + if t.Flags&0x80 > 0 { + forward = true + } + tuples = append(tuples, bgp.NewCapLongLivedGracefulRestartTuple(bgp.RouteFamily(t.Family), forward, t.Time)) + } + return bgp.NewCapLongLivedGracefulRestart(tuples), nil +} + +func NewRouteRefreshCiscoCapability(a *bgp.CapRouteRefreshCisco) *RouteRefreshCiscoCapability { + return &RouteRefreshCiscoCapability{} +} + +func (a *RouteRefreshCiscoCapability) ToNative() (*bgp.CapRouteRefreshCisco, error) { + return bgp.NewCapRouteRefreshCisco(), nil +} + +func NewUnknownCapability(a *bgp.CapUnknown) *UnknownCapability { + return &UnknownCapability{ + Code: uint32(a.CapCode), + Value: a.CapValue, + } +} + +func (a *UnknownCapability) ToNative() (*bgp.CapUnknown, error) { + return bgp.NewCapUnknown(bgp.BGPCapabilityCode(a.Code), a.Value), nil +} + +func MarshalCapability(value bgp.ParameterCapabilityInterface) (*any.Any, error) { + var m proto.Message + switch n := value.(type) { + case *bgp.CapMultiProtocol: + m = NewMultiProtocolCapability(n) + case *bgp.CapRouteRefresh: + m = NewRouteRefreshCapability(n) + case *bgp.CapCarryingLabelInfo: + m = NewCarryingLabelInfoCapability(n) + case *bgp.CapExtendedNexthop: + m = NewExtendedNexthopCapability(n) + case *bgp.CapGracefulRestart: + m = NewGracefulRestartCapability(n) + case *bgp.CapFourOctetASNumber: + m = NewFourOctetASNumberCapability(n) + case *bgp.CapAddPath: + m = NewAddPathCapability(n) + case *bgp.CapEnhancedRouteRefresh: + m = NewEnhancedRouteRefreshCapability(n) + case *bgp.CapLongLivedGracefulRestart: + m = NewLongLivedGracefulRestartCapability(n) + case *bgp.CapRouteRefreshCisco: + m = NewRouteRefreshCiscoCapability(n) + case *bgp.CapUnknown: + m = NewUnknownCapability(n) + default: + return nil, fmt.Errorf("invalid capability type to marshal: %+v", value) + } + return ptypes.MarshalAny(m) +} + +func MarshalCapabilities(values []bgp.ParameterCapabilityInterface) ([]*any.Any, error) { + caps := make([]*any.Any, 0, len(values)) + for _, value := range values { + a, err := MarshalCapability(value) + if err != nil { + return nil, err + } + caps = append(caps, a) + } + return caps, nil +} + +func UnmarshalCapability(a *any.Any) (bgp.ParameterCapabilityInterface, error) { + var value ptypes.DynamicAny + if err := ptypes.UnmarshalAny(a, &value); err != nil { + return nil, fmt.Errorf("failed to unmarshal capability: %s", err) + } + switch v := value.Message.(type) { + case *MultiProtocolCapability: + return v.ToNative() + case *RouteRefreshCapability: + return v.ToNative() + case *CarryingLabelInfoCapability: + return v.ToNative() + case *ExtendedNexthopCapability: + return v.ToNative() + case *GracefulRestartCapability: + return v.ToNative() + case *FourOctetASNumberCapability: + return v.ToNative() + case *AddPathCapability: + return v.ToNative() + case *EnhancedRouteRefreshCapability: + return v.ToNative() + case *LongLivedGracefulRestartCapability: + return v.ToNative() + case *RouteRefreshCiscoCapability: + return v.ToNative() + case *UnknownCapability: + return v.ToNative() + } + return nil, fmt.Errorf("invalid capability type to unmarshal: %s", a.TypeUrl) +} + +func UnmarshalCapabilities(values []*any.Any) ([]bgp.ParameterCapabilityInterface, error) { + caps := make([]bgp.ParameterCapabilityInterface, 0, len(values)) + for _, value := range values { + c, err := UnmarshalCapability(value) + if err != nil { + return nil, err + } + caps = append(caps, c) + } + return caps, nil +} |