summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSatoshi Fujimoto <satoshi.fujimoto7@gmail.com>2017-07-14 14:01:28 +0900
committerSatoshi Fujimoto <satoshi.fujimoto7@gmail.com>2017-07-19 09:44:20 +0900
commitc7ff8580f7cb0834680dc6a48a322c5545a22bfd (patch)
tree8243fcf926e757a5d0ff7afefe1381123dc76420
parent2678142d300aea2d803d500ced865c8c89bf186b (diff)
cli: get detailed RPKI information
This patch adds the feature in the neighbor subcommand to get detailed information about RPKI validation. The command receives a prefix in Adj-RIB-In, and gives the detailed RPKI information for the route. The informaton includes the validation status, the reason if it is invalid, and matched/unmatched VRPs. Example: $ gobgp neighbor 172.17.0.3 adj-in 2.1.0.0/16 validation Target Prefix: 2.1.0.0/16, AS: 65001 This route is invalid reason: as No VRP ASN matches the route origin ASN. Matched VRPs: No Entry Unmatched AS VRPs: Network AS MaxLen 2.0.0.0/12 3215 16 2.1.0.0/16 3215 16 Unmatched Length VRPs: No Entry Signed-off-by: Satoshi Fujimoto <satoshi.fujimoto7@gmail.com>
-rw-r--r--api/grpc_server.go34
-rw-r--r--client/client.go17
-rw-r--r--gobgp/cmd/common.go6
-rw-r--r--gobgp/cmd/neighbor.go100
4 files changed, 122 insertions, 35 deletions
diff --git a/api/grpc_server.go b/api/grpc_server.go
index 1d8cca6a..54fd01ec 100644
--- a/api/grpc_server.go
+++ b/api/grpc_server.go
@@ -874,21 +874,7 @@ func (s *Server) GetRoa(ctx context.Context, arg *GetRoaRequest) (*GetRoaRespons
if err != nil {
return nil, err
}
- l := make([]*Roa, 0, len(roas))
- for _, r := range roas {
- host, port, _ := net.SplitHostPort(r.Src)
- l = append(l, &Roa{
- As: r.AS,
- Maxlen: uint32(r.MaxLen),
- Prefixlen: uint32(r.Prefix.Length),
- Prefix: r.Prefix.Prefix.String(),
- Conf: &RPKIConf{
- Address: host,
- RemotePort: port,
- },
- })
- }
- return &GetRoaResponse{Roas: l}, nil
+ return &GetRoaResponse{Roas: NewRoaListFromTableStructList(roas)}, nil
}
func (s *Server) EnableZebra(ctx context.Context, arg *EnableZebraRequest) (*EnableZebraResponse, error) {
@@ -2077,6 +2063,24 @@ func NewPolicyFromApiStruct(a *Policy) (*table.Policy, error) {
}, nil
}
+func NewRoaListFromTableStructList(origin []*table.ROA) []*Roa {
+ l := make([]*Roa, 0)
+ for _, r := range origin {
+ host, port, _ := net.SplitHostPort(r.Src)
+ l = append(l, &Roa{
+ As: r.AS,
+ Maxlen: uint32(r.MaxLen),
+ Prefixlen: uint32(r.Prefix.Length),
+ Prefix: r.Prefix.Prefix.String(),
+ Conf: &RPKIConf{
+ Address: host,
+ RemotePort: port,
+ },
+ })
+ }
+ return l
+}
+
func (s *Server) GetPolicy(ctx context.Context, arg *GetPolicyRequest) (*GetPolicyResponse, error) {
l := make([]*Policy, 0)
for _, p := range s.bgpServer.GetPolicy() {
diff --git a/client/client.go b/client/client.go
index b9faf6ba..e8108c64 100644
--- a/client/client.go
+++ b/client/client.go
@@ -22,12 +22,13 @@ import (
"strconv"
"time"
+ "golang.org/x/net/context"
+ "google.golang.org/grpc"
+
api "github.com/osrg/gobgp/api"
"github.com/osrg/gobgp/config"
"github.com/osrg/gobgp/packet/bgp"
"github.com/osrg/gobgp/table"
- "golang.org/x/net/context"
- "google.golang.org/grpc"
)
type Client struct {
@@ -841,17 +842,7 @@ func (cli *Client) GetROA(family bgp.RouteFamily) ([]*table.ROA, error) {
if err != nil {
return nil, err
}
- roas := make([]*table.ROA, 0, len(rsp.Roas))
- for _, r := range rsp.Roas {
- ip := net.ParseIP(r.Prefix)
- if ip.To4() != nil {
- ip = ip.To4()
- }
- 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
+ return api.NewROAListFromApiStructList(rsp.Roas), nil
}
func (cli *Client) AddRPKIServer(address string, port, lifetime int) error {
diff --git a/gobgp/cmd/common.go b/gobgp/cmd/common.go
index 124c2b99..53c17604 100644
--- a/gobgp/cmd/common.go
+++ b/gobgp/cmd/common.go
@@ -26,12 +26,13 @@ import (
"strings"
"time"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials"
+
cli "github.com/osrg/gobgp/client"
"github.com/osrg/gobgp/config"
"github.com/osrg/gobgp/packet/bgp"
"github.com/osrg/gobgp/table"
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials"
)
const (
@@ -78,6 +79,7 @@ const (
CMD_BMP = "bmp"
CMD_LARGECOMMUNITY = "large-community"
CMD_SUMMARY = "summary"
+ CMD_VALIDATION = "validation"
)
var subOpts struct {
diff --git a/gobgp/cmd/neighbor.go b/gobgp/cmd/neighbor.go
index 3c6b5669..bd957097 100644
--- a/gobgp/cmd/neighbor.go
+++ b/gobgp/cmd/neighbor.go
@@ -549,6 +549,71 @@ func ShowRoute(pathList []*table.Path, showAge, showBest, showLabel, showIdentif
}
}
+func checkOriginAsWasNotShown(p *table.Path, shownAs map[uint32]struct{}) bool {
+ asPath := p.GetAsPath().Value
+ // the path was generated in internal
+ if len(asPath) == 0 {
+ return false
+ }
+ aslist := asPath[len(asPath)-1].(*bgp.As4PathParam).AS
+ origin := aslist[len(aslist)-1]
+
+ if _, ok := shownAs[origin]; ok {
+ return false
+ }
+ shownAs[origin] = struct{}{}
+ return true
+}
+
+func ShowValidationInfo(p *table.Path) {
+ status := p.Validation().Status
+ reason := p.Validation().Reason
+ asPath := p.GetAsPath().Value
+ aslist := asPath[len(asPath)-1].(*bgp.As4PathParam).AS
+ origin := aslist[len(aslist)-1]
+
+ fmt.Printf("Target Prefix: %s, AS: %d\n", p.GetNlri().String(), origin)
+ fmt.Printf(" This route is %s", status)
+ switch status {
+ case config.RPKI_VALIDATION_RESULT_TYPE_INVALID:
+ fmt.Printf(" reason: %s\n", reason)
+ switch reason {
+ case table.RPKI_VALIDATION_REASON_TYPE_AS:
+ fmt.Println(" No VRP ASN matches the route origin ASN.")
+ case table.RPKI_VALIDATION_REASON_TYPE_LENGTH:
+ fmt.Println(" Route Prefix length is greater than the maximum length allowed by VRP(s) matching this route origin ASN.")
+ }
+ case config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND:
+ fmt.Println("\n No VRP Covers the Route Prefix")
+ default:
+ fmt.Print("\n\n")
+ }
+
+ printVRPs := func(l []*table.ROA) {
+ if len(l) == 0 {
+ fmt.Println(" No Entry")
+ } else {
+ var format string
+ if ip, _, _ := net.ParseCIDR(p.GetNlri().String()); ip.To4() != nil {
+ format = " %-18s %-6s %-10s\n"
+ } else {
+ format = " %-42s %-6s %-10s\n"
+ }
+ fmt.Printf(format, "Network", "AS", "MaxLen")
+ for _, m := range l {
+ fmt.Printf(format, m.Prefix, fmt.Sprint(m.AS), fmt.Sprint(m.MaxLen))
+ }
+ }
+ }
+
+ fmt.Println(" Matched VRPs: ")
+ printVRPs(p.Validation().Matched)
+ fmt.Println(" Unmatched AS VRPs: ")
+ printVRPs(p.Validation().UnmatchedAs)
+ fmt.Println(" Unmatched Length VRPs: ")
+ printVRPs(p.Validation().UnmatchedLength)
+}
+
func showRibInfo(r, name string) error {
def := addr2AddressFamily(net.ParseIP(name))
if r == CMD_GLOBAL {
@@ -605,6 +670,8 @@ func showNeighborRib(r string, name string, args []string) error {
showAge := true
showLabel := false
showIdentifier := false
+ validationTarget := ""
+
def := addr2AddressFamily(net.ParseIP(name))
switch r {
case CMD_GLOBAL:
@@ -628,21 +695,29 @@ func showNeighborRib(r string, name string, args []string) error {
var filter []*table.LookupPrefix
if len(args) > 0 {
+ target := args[0]
if _, _, err = parseCIDRorIP(args[0]); err != nil {
return err
}
var option table.LookupOption
- if len(args) > 1 {
- if args[1] == "longer-prefixes" {
+ args = args[1:]
+ for len(args) != 0 {
+ if args[0] == "longer-prefixes" {
option = table.LOOKUP_LONGER
- } else if args[1] == "shorter-prefixes" {
+ } else if args[0] == "shorter-prefixes" {
option = table.LOOKUP_SHORTER
+ } else if args[0] == "validation" {
+ if r != CMD_ADJ_IN {
+ return fmt.Errorf("RPKI information is supported for only adj-in.")
+ }
+ validationTarget = target
} else {
return fmt.Errorf("invalid format for route filtering")
}
+ args = args[1:]
}
filter = []*table.LookupPrefix{&table.LookupPrefix{
- Prefix: args[0],
+ Prefix: target,
LookupOption: option,
},
}
@@ -687,8 +762,12 @@ func showNeighborRib(r string, name string, args []string) error {
return nil
}
+ shownAs := make(map[uint32]struct{})
counter := 0
for _, d := range rib.GetSortedDestinations() {
+ if validationTarget != "" && d.GetNlri().String() != validationTarget {
+ continue
+ }
var ps []*table.Path
if r == CMD_ACCEPTED || r == CMD_REJECTED {
for _, p := range d.GetAllKnownPathList() {
@@ -711,7 +790,18 @@ func showNeighborRib(r string, name string, args []string) error {
if counter == 0 {
showHeader = true
}
- ShowRoute(ps, showAge, showBest, showLabel, showIdentifier, false, showHeader)
+ if validationTarget != "" {
+ for _, p := range ps {
+ asPath := p.GetAsPath().Value
+ if len(asPath) == 0 {
+ fmt.Printf("The path to %s was locally generated.\n", p.GetNlri().String())
+ } else if checkOriginAsWasNotShown(p, shownAs) {
+ ShowValidationInfo(p)
+ }
+ }
+ } else {
+ ShowRoute(ps, showAge, showBest, showLabel, showIdentifier, false, showHeader)
+ }
counter++
}