diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-08-12 13:16:58 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-08-12 13:44:33 +0900 |
commit | 6180ffb7106e3673e4da5a2d2ce1f87612462721 (patch) | |
tree | 74646c52142ccda5b34231207cc741f8288f38ec | |
parent | c2f5b1a176a1b7f72658821d057e23414e839718 (diff) |
support rpki validation
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | api/gobgp.pb.go | 1 | ||||
-rw-r--r-- | api/gobgp.proto | 1 | ||||
-rw-r--r-- | gobgp/common.go | 2 | ||||
-rw-r--r-- | gobgp/neighbor.go | 17 | ||||
-rw-r--r-- | gobgp/rpki.go | 23 | ||||
-rw-r--r-- | server/rpki.go | 62 | ||||
-rw-r--r-- | server/server.go | 4 | ||||
-rw-r--r-- | table/path.go | 6 |
8 files changed, 88 insertions, 28 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go index 4d91e526..9eebd786 100644 --- a/api/gobgp.pb.go +++ b/api/gobgp.pb.go @@ -322,6 +322,7 @@ type Path struct { Age int64 `protobuf:"varint,3,opt,name=age" json:"age,omitempty"` Best bool `protobuf:"varint,4,opt,name=best" json:"best,omitempty"` IsWithdraw bool `protobuf:"varint,5,opt,name=is_withdraw" json:"is_withdraw,omitempty"` + Validation int32 `protobuf:"varint,6,opt,name=validation" json:"validation,omitempty"` } func (m *Path) Reset() { *m = Path{} } diff --git a/api/gobgp.proto b/api/gobgp.proto index 650e452b..5c5afbfe 100644 --- a/api/gobgp.proto +++ b/api/gobgp.proto @@ -144,6 +144,7 @@ message Path { int64 age = 3; bool best = 4; bool is_withdraw = 5; + int32 validation = 6; } message Destination { diff --git a/gobgp/common.go b/gobgp/common.go index 31e0802a..12c08256 100644 --- a/gobgp/common.go +++ b/gobgp/common.go @@ -152,6 +152,7 @@ type Path struct { Age int64 `json:"age"` Best bool `json:"best"` IsWithdraw bool `json:"isWithdraw"` + Validation int32 } func ApiStruct2Path(p *api.Path) (*Path, error) { @@ -192,6 +193,7 @@ func ApiStruct2Path(p *api.Path) (*Path, error) { Age: p.Age, Best: p.Best, IsWithdraw: p.IsWithdraw, + Validation: p.Validation, }, nil } diff --git a/gobgp/neighbor.go b/gobgp/neighbor.go index ad700311..4b3b8425 100644 --- a/gobgp/neighbor.go +++ b/gobgp/neighbor.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" "github.com/osrg/gobgp/api" + "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/packet" "github.com/osrg/gobgp/policy" "github.com/spf13/cobra" @@ -305,11 +306,19 @@ func showRoute(pathList []*Path, showAge bool, showBest bool, isMonitor bool) { } best := "" + switch config.RpkiValidationResultType(p.Validation) { + case config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND: + best += "N" + case config.RPKI_VALIDATION_RESULT_TYPE_VALID: + best += "V" + case config.RPKI_VALIDATION_RESULT_TYPE_INVALID: + best += "I" + } if showBest { if p.Best { - best = "*>" + best += "*>" } else { - best = "* " + best += "* " } } @@ -334,10 +343,10 @@ func showRoute(pathList []*Path, showAge bool, showBest bool, isMonitor bool) { if isMonitor { format = "[%s] %s via %s aspath [%s] attrs %s\n" } else if showAge { - format = fmt.Sprintf("%%-2s %%-%ds %%-%ds %%-%ds %%-10s %%-s\n", maxPrefixLen, maxNexthopLen, maxAsPathLen) + format = fmt.Sprintf("%%-3s %%-%ds %%-%ds %%-%ds %%-10s %%-s\n", maxPrefixLen, maxNexthopLen, maxAsPathLen) fmt.Printf(format, "", "Network", "Next Hop", "AS_PATH", "Age", "Attrs") } else { - format = fmt.Sprintf("%%-2s %%-%ds %%-%ds %%-%ds %%-s\n", maxPrefixLen, maxNexthopLen, maxAsPathLen) + format = fmt.Sprintf("%%-3s %%-%ds %%-%ds %%-%ds %%-s\n", maxPrefixLen, maxNexthopLen, maxAsPathLen) fmt.Printf(format, "", "Network", "Next Hop", "AS_PATH", "Attrs") } diff --git a/gobgp/rpki.go b/gobgp/rpki.go index 2d0a3577..89632eac 100644 --- a/gobgp/rpki.go +++ b/gobgp/rpki.go @@ -24,7 +24,6 @@ import ( "io" "net" "os" - "sort" ) func showRPKITable(args []string) error { @@ -41,17 +40,7 @@ func showRPKITable(args []string) error { fmt.Println(err) return err } - l := roas{} - for { - r, err := stream.Recv() - if err == io.EOF { - break - } else if err != nil { - return err - } - l = append(l, r) - } - sort.Sort(l) + var format string afi, _ := bgp.RouteFamilyToAfiSafi(rf) if afi == bgp.AFI_IP { @@ -60,8 +49,14 @@ func showRPKITable(args []string) error { format = "%-42s %-6s %s\n" } fmt.Printf(format, "Network", "Maxlen", "AS") - for _, r := range l { - fmt.Printf(format, fmt.Sprintf("%s/%d", r.Prefix, r.Prefixlen), fmt.Sprint(r.Maxlen), fmt.Sprint(r.Maxlen)) + for { + r, err := stream.Recv() + if err == io.EOF { + break + } else if err != nil { + return err + } + fmt.Printf(format, fmt.Sprintf("%s/%d", r.Prefix, r.Prefixlen), fmt.Sprint(r.Maxlen), fmt.Sprint(r.As)) } return nil } diff --git a/server/rpki.go b/server/rpki.go index 6ad6aa0a..1261b7c8 100644 --- a/server/rpki.go +++ b/server/rpki.go @@ -17,9 +17,13 @@ package server import ( "bufio" + "bytes" "fmt" + "github.com/armon/go-radix" "github.com/osrg/gobgp/api" + "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/packet" + "github.com/osrg/gobgp/table" "net" ) @@ -44,7 +48,8 @@ func (r *roa) toApiStruct() *api.ROA { } type roaClient struct { - roas map[bgp.RouteFamily]map[string]*roa + url string + roas map[bgp.RouteFamily]*radix.Tree outgoing chan *roa } @@ -52,31 +57,70 @@ func (c *roaClient) recieveROA() chan *roa { return c.outgoing } +func roa2key(r *roa) string { + var buffer bytes.Buffer + for i := 0; i < len(r.Prefix) && i < int(r.PrefixLen); i++ { + buffer.WriteString(fmt.Sprintf("%08b", r.Prefix[i])) + } + return buffer.String()[:r.PrefixLen] +} + func (c *roaClient) handleRTRMsg(r *roa) { if r.Prefix.To4() != nil { - c.roas[bgp.RF_IPv4_UC][r.key()] = r + c.roas[bgp.RF_IPv4_UC].Insert(roa2key(r), r) } else { - c.roas[bgp.RF_IPv6_UC][r.key()] = r + c.roas[bgp.RF_IPv6_UC].Insert(roa2key(r), r) } } func (c *roaClient) handleGRPC(grpcReq *GrpcRequest) { - if roas, ok := c.roas[grpcReq.RouteFamily]; ok { - for _, r := range roas { + if tree, ok := c.roas[grpcReq.RouteFamily]; ok { + tree.Walk(func(s string, v interface{}) bool { + r, _ := v.(*roa) result := &GrpcResponse{} result.Data = r.toApiStruct() grpcReq.ResponseCh <- result - } + return false + }) } close(grpcReq.ResponseCh) } +func (c *roaClient) validate(pathList []*table.Path) { + if c.url == "" { + return + } + + for _, path := range pathList { + if tree, ok := c.roas[path.GetRouteFamily()]; ok { + _, n, _ := net.ParseCIDR(path.GetNlri().String()) + ones, _ := n.Mask.Size() + var buffer bytes.Buffer + for i := 0; i < len(n.IP) && i < ones; i++ { + buffer.WriteString(fmt.Sprintf("%08b", n.IP[i])) + } + _, r, _ := tree.LongestPrefix(buffer.String()[:ones]) + if r == nil { + path.Validation = config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND + } else { + roa, _ := r.(*roa) + if roa.AS == path.GetSourceAs() { + path.Validation = config.RPKI_VALIDATION_RESULT_TYPE_VALID + } else { + path.Validation = config.RPKI_VALIDATION_RESULT_TYPE_INVALID + } + } + } + } +} + func newROAClient(url string) (*roaClient, error) { c := &roaClient{ - roas: make(map[bgp.RouteFamily]map[string]*roa), + url: url, + roas: make(map[bgp.RouteFamily]*radix.Tree), } - c.roas[bgp.RF_IPv4_UC] = make(map[string]*roa) - c.roas[bgp.RF_IPv6_UC] = make(map[string]*roa) + c.roas[bgp.RF_IPv4_UC] = radix.New() + c.roas[bgp.RF_IPv6_UC] = radix.New() if url == "" { return c, nil diff --git a/server/server.go b/server/server.go index b1d0d956..4c202209 100644 --- a/server/server.go +++ b/server/server.go @@ -683,6 +683,10 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *fsmMsg, incoming chan * msgs = append(msgs, newSenderMsg(peer, msgList)) } break + } else { + if len(pathList) > 0 { + server.roaClient.validate(pathList) + } } msgs = append(msgs, server.propagateUpdate(peer.conf.NeighborConfig.NeighborAddress.String(), peer.isRouteServerClient(), pathList)...) diff --git a/table/path.go b/table/path.go index b3a84d9d..8025a63a 100644 --- a/table/path.go +++ b/table/path.go @@ -36,6 +36,7 @@ type Path struct { medSetByTargetNeighbor bool timestamp time.Time NoImplicitWithdraw bool + Validation config.RpkiValidationResultType } func NewPath(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool, pattrs []bgp.PathAttributeInterface, medSetByTargetNeighbor bool, timestamp time.Time, noImplicitWithdraw bool) *Path { @@ -156,6 +157,7 @@ func (path *Path) ToApiStruct() *api.Path { Pattrs: pattrs, Age: int64(time.Now().Sub(path.timestamp).Seconds()), IsWithdraw: path.IsWithdraw, + Validation: int32(path.Validation), } } @@ -189,7 +191,9 @@ func (path *Path) Clone(isWithdraw bool) *Path { newPathAttrs[i] = v } - return NewPath(path.source, nlri, isWithdraw, newPathAttrs, false, path.timestamp, path.NoImplicitWithdraw) + p := NewPath(path.source, nlri, isWithdraw, newPathAttrs, false, path.timestamp, path.NoImplicitWithdraw) + p.Validation = path.Validation + return p } func (path *Path) GetRouteFamily() bgp.RouteFamily { |