Files
osrg-gobgp/api/util.go
T
FUJITA Tomonori ed3f7b711c api: fix rpki regression
the commit 8c453bc936 fixes
NewROAListFromApiStructList() to check an error strictly. However,
this breaks the rpki table command:

$ gobgp rpki table
invalid CIDR address: 1.0.16.0

NewROAListFromApiStructList() has a bug about getting the address
family from an IP address. The address family was not used (other
information are used though) so before the commit, the command worked.

This fixes the bug in NewROAListFromApiStructList().

Signed-off-by: FUJITA Tomonori <[email protected]>
2018-05-30 21:44:54 +09:00

184 lines
5.3 KiB
Go

// Copyright (C) 2016 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"
"net"
"time"
"github.com/osrg/gobgp/config"
"github.com/osrg/gobgp/packet/bgp"
"github.com/osrg/gobgp/table"
)
type ToNativeOption struct {
LocalAS uint32
LocalID net.IP
RouteReflectorClient bool
RouteReflectorClusterID net.IP
NLRI bgp.AddrPrefixInterface
}
func (t *Table) ToNativeTable(option ...ToNativeOption) (*table.Table, error) {
dsts := make([]*table.Destination, 0, len(t.Destinations))
for _, d := range t.Destinations {
dst, err := d.ToNativeDestination(option...)
if err != nil {
return nil, err
}
dsts = append(dsts, dst)
}
return table.NewTable(bgp.RouteFamily(t.Family), dsts...), nil
}
func getNLRI(family bgp.RouteFamily, buf []byte) (bgp.AddrPrefixInterface, error) {
afi, safi := bgp.RouteFamilyToAfiSafi(family)
nlri, err := bgp.NewPrefixFromRouteFamily(afi, safi)
if err != nil {
return nil, err
}
if err := nlri.DecodeFromBytes(buf); err != nil {
return nil, err
}
return nlri, nil
}
func (d *Destination) ToNativeDestination(option ...ToNativeOption) (*table.Destination, error) {
if len(d.Paths) == 0 {
return nil, fmt.Errorf("no path in destination")
}
nlri, err := getNLRI(bgp.RouteFamily(d.Paths[0].Family), d.Paths[0].Nlri)
if err != nil {
return nil, err
}
option = append(option, ToNativeOption{
NLRI: nlri,
})
paths := make([]*table.Path, 0, len(d.Paths))
for _, p := range d.Paths {
var path *table.Path
var err error
if p.Identifier > 0 {
path, err = p.ToNativePath()
} else {
path, err = p.ToNativePath(option...)
}
if err != nil {
return nil, err
}
paths = append(paths, path)
}
return table.NewDestination(nlri, 0, paths...), nil
}
func (p *Path) GetNativeNlri() (bgp.AddrPrefixInterface, error) {
return getNLRI(bgp.RouteFamily(p.Family), p.Nlri)
}
func (p *Path) ToNativePath(option ...ToNativeOption) (*table.Path, error) {
info := &table.PeerInfo{
AS: p.SourceAsn,
ID: net.ParseIP(p.SourceId),
Address: net.ParseIP(p.NeighborIp),
}
var nlri bgp.AddrPrefixInterface
for _, o := range option {
info.LocalAS = o.LocalAS
info.LocalID = o.LocalID
info.RouteReflectorClient = o.RouteReflectorClient
info.RouteReflectorClusterID = o.RouteReflectorClusterID
nlri = o.NLRI
}
if nlri == nil {
var err error
nlri, err = getNLRI(bgp.RouteFamily(p.Family), p.Nlri)
if err != nil {
return nil, err
}
}
pattr := make([]bgp.PathAttributeInterface, 0, len(p.Pattrs))
for _, attr := range p.Pattrs {
p, err := bgp.GetPathAttribute(attr)
if err != nil {
return nil, err
}
err = p.DecodeFromBytes(attr)
if err != nil {
return nil, err
}
pattr = append(pattr, p)
}
t := time.Unix(p.Age, 0)
nlri.SetPathIdentifier(p.Identifier)
nlri.SetPathLocalIdentifier(p.LocalIdentifier)
path := table.NewPath(info, nlri, p.IsWithdraw, pattr, t, false)
// p.ValidationDetail.* are already validated
matched, _ := NewROAListFromApiStructList(p.ValidationDetail.Matched)
unmatchedAs, _ := NewROAListFromApiStructList(p.ValidationDetail.UnmatchedAs)
unmatchedLength, _ := NewROAListFromApiStructList(p.ValidationDetail.UnmatchedLength)
path.SetValidation(&table.Validation{
Status: config.IntToRpkiValidationResultTypeMap[int(p.Validation)],
Reason: table.IntToRpkiValidationReasonTypeMap[int(p.ValidationDetail.Reason)],
Matched: matched,
UnmatchedAs: unmatchedAs,
UnmatchedLength: unmatchedLength,
})
path.MarkStale(p.Stale)
path.IsNexthopInvalid = p.IsNexthopInvalid
return path, nil
}
func NewROAListFromApiStructList(l []*Roa) ([]*table.ROA, error) {
roas := make([]*table.ROA, 0, len(l))
for _, r := range l {
ip := net.ParseIP(r.Prefix)
family := bgp.RF_IPv4_UC
if ip == nil {
return nil, fmt.Errorf("invalid prefix %s", r.Prefix)
} else {
if ip.To4() == nil {
family = bgp.RF_IPv6_UC
}
}
afi, _ := bgp.RouteFamilyToAfiSafi(family)
roa := table.NewROA(int(afi), []byte(ip), uint8(r.Prefixlen), uint8(r.Maxlen), r.As, net.JoinHostPort(r.Conf.Address, r.Conf.RemotePort))
roas = append(roas, roa)
}
return roas, nil
}
func extractFamilyFromConfigAfiSafi(c *config.AfiSafi) uint32 {
if c == nil {
return 0
}
// If address family value is already stored in AfiSafiState structure,
// we prefer to use this value.
if c.State.Family != 0 {
return uint32(c.State.Family)
}
// In case that Neighbor structure came from CLI or gRPC, address family
// value in AfiSafiState structure can be omitted.
// Here extracts value from AfiSafiName field in AfiSafiConfig structure.
if rf, err := bgp.GetRouteFamily(string(c.Config.AfiSafiName)); err == nil {
return uint32(rf)
}
// Ignores invalid address family name
return 0
}