summaryrefslogtreecommitdiffhomepage
path: root/table
diff options
context:
space:
mode:
Diffstat (limited to 'table')
-rw-r--r--table/destination.go835
-rw-r--r--table/destination_test.go207
-rw-r--r--table/path.go339
-rw-r--r--table/path_test.go270
-rw-r--r--table/table.go252
-rw-r--r--table/table_manager.go424
-rw-r--r--table/table_manager_test.go1482
-rw-r--r--table/temporary_structs.go34
8 files changed, 3843 insertions, 0 deletions
diff --git a/table/destination.go b/table/destination.go
new file mode 100644
index 00000000..7857c0fc
--- /dev/null
+++ b/table/destination.go
@@ -0,0 +1,835 @@
+// Copyright (C) 2014 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 table
+
+import (
+ "encoding/binary"
+ "fmt"
+ "github.com/osrg/gobgp/packet"
+ "net"
+ "reflect"
+)
+
+const (
+ BPR_UNKNOWN = "Unknown"
+ BPR_ONLY_PATH = "Only Path"
+ BPR_REACHABLE_NEXT_HOP = "Reachable Next Hop"
+ BPR_HIGHEST_WEIGHT = "Highest Weight"
+ BPR_LOCAL_PREF = "Local Pref"
+ BPR_LOCAL_ORIGIN = "Local Origin"
+ BPR_ASPATH = "AS Path"
+ BPR_ORIGIN = "Origin"
+ BPR_MED = "MED"
+ BPR_ASN = "ASN"
+ BPR_IGP_COST = "IGP Cost"
+ BPR_ROUTER_ID = "Router ID"
+)
+
+type Destination interface {
+ Calculate(localAsn uint32) (Path, string, error)
+ getRouteFamily() RouteFamily
+ setRouteFamily(ROUTE_FAMILY RouteFamily)
+ getNlri() bgp.AddrPrefixInterface
+ setNlri(nlri bgp.AddrPrefixInterface)
+ getBestPathReason() string
+ setBestPathReason(string)
+ getBestPath() Path
+ setBestPath(path Path)
+ getKnownPathList() []Path
+ String() string
+ addWithdraw(withdraw Path)
+ addNewPath(newPath Path)
+ addSentRoute(sentRoute *SentRoute)
+ removeSentRoute(peer *Peer) bool
+ constructWithdrawPath() Path
+ removeOldPathsFromSource(source *Peer) []Path
+}
+
+type DestinationDefault struct {
+ ROUTE_FAMILY RouteFamily
+ coreService CoreService
+ nlri bgp.AddrPrefixInterface
+ knownPathList []Path
+ withdrawList []Path
+ newPathList []Path
+ bestPath Path
+ bestPathReason string
+ sentRoutes map[*Peer]*SentRoute
+}
+
+func NewDestinationDefault(nlri bgp.AddrPrefixInterface) *DestinationDefault {
+ destination := &DestinationDefault{}
+ destination.ROUTE_FAMILY = RF_IPv4_UC
+ destination.nlri = nlri
+ destination.knownPathList = make([]Path, 0)
+ destination.withdrawList = make([]Path, 0)
+ destination.newPathList = make([]Path, 0)
+ destination.bestPath = nil
+ destination.bestPathReason = ""
+ destination.sentRoutes = make(map[*Peer]*SentRoute)
+ return destination
+}
+
+func (dd *DestinationDefault) getRouteFamily() RouteFamily {
+ return dd.ROUTE_FAMILY
+}
+
+func (dd *DestinationDefault) setRouteFamily(ROUTE_FAMILY RouteFamily) {
+ dd.ROUTE_FAMILY = ROUTE_FAMILY
+}
+
+func (dd *DestinationDefault) getNlri() bgp.AddrPrefixInterface {
+ return dd.nlri
+}
+
+func (dd *DestinationDefault) setNlri(nlri bgp.AddrPrefixInterface) {
+ dd.nlri = nlri
+}
+
+func (dd *DestinationDefault) getBestPathReason() string {
+ return dd.bestPathReason
+}
+
+func (dd *DestinationDefault) setBestPathReason(reason string) {
+ dd.bestPathReason = reason
+}
+
+func (dd *DestinationDefault) getBestPath() Path {
+ return dd.bestPath
+}
+
+func (dd *DestinationDefault) setBestPath(path Path) {
+ dd.bestPath = path
+}
+
+func (dd *DestinationDefault) getKnownPathList() []Path {
+ return dd.knownPathList
+}
+
+func (dd *DestinationDefault) addWithdraw(withdraw Path) {
+ dd.validatePath(withdraw)
+ dd.withdrawList = append(dd.withdrawList, withdraw)
+}
+func (dd *DestinationDefault) addNewPath(newPath Path) {
+ dd.validatePath(newPath)
+ dd.newPathList = append(dd.newPathList, newPath)
+}
+func (dd *DestinationDefault) addSentRoute(sentRoute *SentRoute) {
+ dd.sentRoutes[sentRoute.peer] = sentRoute
+}
+func (dd *DestinationDefault) removeSentRoute(peer *Peer) bool {
+ if dd.wasSentTo(peer) {
+ delete(dd.sentRoutes, peer)
+ return true
+ }
+ return false
+}
+func (dd *DestinationDefault) wasSentTo(peer *Peer) bool {
+ _, ok := dd.sentRoutes[peer]
+ if ok {
+ return true
+ }
+ return false
+}
+func (dd *DestinationDefault) removeOldPathsFromSource(source *Peer) []Path {
+ removePaths := make([]Path, 0)
+ sourceVerNum := source.VersionNum
+ tempKnownPathList := make([]Path, 0)
+
+ for _, path := range dd.knownPathList {
+ if path.getSource() == source && path.getSourceVerNum() < sourceVerNum {
+ removePaths = append(removePaths, path)
+ } else {
+ tempKnownPathList = append(tempKnownPathList, path)
+ }
+ }
+ dd.knownPathList = tempKnownPathList
+ return removePaths
+}
+
+func (dd *DestinationDefault) validatePath(path Path) {
+ if path == nil || path.getRouteFamily() != dd.ROUTE_FAMILY {
+ logger.Error("Invalid path. Expected %s path got %s.", dd.ROUTE_FAMILY, path)
+ }
+}
+
+// Calculates best-path among known paths for this destination.
+//
+// Returns: - Best path
+//
+// Modifies destination's state related to stored paths. Removes withdrawn
+// paths from known paths. Also, adds new paths to known paths.
+func (dest *DestinationDefault) Calculate(localAsn uint32) (Path, string, error) {
+
+ // First remove the withdrawn paths.
+ // Note: If we want to support multiple paths per destination we may
+ // have to maintain sent-routes per path.
+ dest.removeWithdrawls()
+
+ // Have to select best-path from available paths and new paths.
+ // If we do not have any paths, then we no longer have best path.
+ if len(dest.knownPathList) == 0 && len(dest.newPathList) == 1 {
+ // If we do not have any old but one new path
+ // it becomes best path.
+ dest.knownPathList = append(dest.knownPathList, dest.newPathList[0])
+ dest.newPathList, _ = deleteAt(dest.newPathList, 0)
+ logger.Debugf("best path : %s, reason=%s", dest.knownPathList[0], BPR_ONLY_PATH)
+
+ return dest.knownPathList[0], BPR_ONLY_PATH, nil
+ }
+
+ // If we have a new version of old/known path we use it and delete old
+ // one.
+ dest.removeOldPaths()
+ logger.Debugf("removeOldPaths")
+ // Collect all new paths into known paths.
+ dest.knownPathList = append(dest.knownPathList, dest.newPathList...)
+
+ // Clear new paths as we copied them.
+ dest.newPathList = make([]Path, 0)
+
+ // If we do not have any paths to this destination, then we do not have
+ // new best path.
+ if len(dest.knownPathList) == 0 {
+ return nil, BPR_UNKNOWN, nil
+ }
+
+ // Compute new best path
+ currentBestPath, reason, e := dest.computeKnownBestPath(localAsn)
+ if e != nil {
+ logger.Error(e)
+ }
+ return currentBestPath, reason, e
+
+}
+
+//"""Removes withdrawn paths.
+//
+//Note:
+//We may have disproportionate number of withdraws compared to know paths
+//since not all paths get installed into the table due to bgp policy and
+//we can receive withdraws for such paths and withdrawals may not be
+//stopped by the same policies.
+//"""
+func (dest *DestinationDefault) removeWithdrawls() {
+
+ logger.Debugf("Removing %d withdrawals", len(dest.withdrawList))
+
+ // If we have no withdrawals, we have nothing to do.
+ if len(dest.withdrawList) == 0 {
+ return
+ }
+
+ // If we have some withdrawals and no know-paths, it means it is safe to
+ // delete these withdraws.
+ if len(dest.knownPathList) == 0 {
+ logger.Debugf("Found %s withdrawals for path(s) that did not get installed", len(dest.withdrawList))
+ dest.withdrawList = dest.withdrawList[len(dest.withdrawList):]
+ }
+
+ // If we have some known paths and some withdrawals, we find matches and
+ // delete them first.
+ matches := make(map[string]Path)
+ wMatches := make(map[string]Path)
+ // Match all withdrawals from destination paths.
+ for _, wItem := range dest.withdrawList {
+ withdraw := wItem.(*PathDefault)
+ var isFound bool = false
+ for _, item := range dest.knownPathList {
+ path := item.(*PathDefault)
+ // We have a match if the source are same.
+ // TODO add GetSource to Path interface
+ if path.source == withdraw.source {
+ isFound = true
+ matches[path.String()] = path
+ wMatches[withdraw.String()] = withdraw
+ // One withdraw can remove only one path.
+ break
+ }
+ }
+
+ // We do no have any match for this withdraw.
+ if !isFound {
+ logger.Debugf("No matching path for withdraw found, may be path was not installed into table: %s", withdraw.String())
+ }
+ }
+
+ // If we have partial match.
+ if len(matches) != len(dest.withdrawList) {
+ logger.Debugf(
+ "Did not find match for some withdrawals. Number of matches(%d), number of withdrawals (%d)",
+ len(matches), len(dest.withdrawList))
+ }
+
+ // Clear matching paths and withdrawals.
+ for _, path := range matches {
+ var result bool = false
+ dest.knownPathList, result = removeWithPath(dest.knownPathList, path)
+ if !result {
+ logger.Debugf("could not remove path: %s from knownPathList", path.String())
+ }
+ }
+ for _, path := range wMatches {
+ var result bool = false
+ dest.withdrawList, result = removeWithPath(dest.withdrawList, path)
+ if !result {
+ logger.Debugf("could not remove path: %s from withdrawList", path.String())
+ }
+ }
+}
+
+func (dest *DestinationDefault) computeKnownBestPath(localAsn uint32) (Path, string, error) {
+
+ // """Computes the best path among known paths.
+ //
+ // Returns current best path among `knownPaths`.
+ if len(dest.knownPathList) == 0 {
+ return nil, "", fmt.Errorf("Need at-least one known path to compute best path")
+ }
+
+ logger.Debugf("computeKnownBestPath known pathlist: %d", len(dest.knownPathList))
+
+ // We pick the first path as current best path. This helps in breaking
+ // tie between two new paths learned in one cycle for which best-path
+ // calculation steps lead to tie.
+ currentBestPath := dest.knownPathList[0]
+ bestPathReason := BPR_ONLY_PATH
+ for _, nextPath := range dest.knownPathList[1:] {
+ // Compare next path with current best path.
+ // TODO make interface to get Local AS number
+ newBestPath, reason := computeBestPath(localAsn, currentBestPath, nextPath)
+ bestPathReason = reason
+ if newBestPath != nil {
+ currentBestPath = newBestPath
+ }
+ }
+ return currentBestPath, bestPathReason, nil
+}
+
+func (dest *DestinationDefault) removeOldPaths() {
+ // """Identifies which of known paths are old and removes them.
+ //
+ // Known paths will no longer have paths whose new version is present in
+ // new paths.
+ // """
+
+ newPaths := dest.newPathList
+ knownPaths := dest.knownPathList
+
+ for _, newPath := range newPaths {
+ oldPaths := make([]Path, 0)
+ for _, path := range knownPaths {
+ // Here we just check if source is same and not check if path
+ // version num. as newPaths are implicit withdrawal of old
+ // paths and when doing RouteRefresh (not EnhancedRouteRefresh)
+ // we get same paths again.
+ if newPath.getSource() == path.getSource() {
+ oldPaths = append(oldPaths, path)
+ break
+ }
+ }
+ for _, oldPath := range oldPaths {
+ match := false
+ knownPaths, match = removeWithPath(knownPaths, oldPath)
+ if !match {
+ logger.Debugf("not exist withdrawal of old path in known paths: %s ", oldPath.String())
+
+ }
+ logger.Debugf("Implicit withdrawal of old path, "+
+ "since we have learned new path from same source: %s", oldPath.String())
+ }
+ }
+ dest.knownPathList = knownPaths
+}
+
+func deleteAt(list []Path, pos int) ([]Path, bool) {
+ if list != nil {
+ list = append(list[:pos], list[pos+1:]...)
+ return list, true
+ }
+ return nil, false
+}
+
+// remove item from slice by object itself
+func removeWithPath(list []Path, path Path) ([]Path, bool) {
+
+ for index, p := range list {
+ if p == path {
+ pathList := append(list[:index], list[index+1:]...)
+ return pathList, true
+ }
+ }
+ return list, false
+}
+
+func computeBestPath(localAsn uint32, path1, path2 Path) (Path, string) {
+
+ //Compares given paths and returns best path.
+ //
+ //Parameters:
+ // -`localAsn`: asn of local bgpspeaker
+ // -`path1`: first path to compare
+ // -`path2`: second path to compare
+ //
+ // Best path processing will involve following steps:
+ // 1. Select a path with a reachable next hop.
+ // 2. Select the path with the highest weight.
+ // 3. If path weights are the same, select the path with the highest
+ // local preference value.
+ // 4. Prefer locally originated routes (network routes, redistributed
+ // routes, or aggregated routes) over received routes.
+ // 5. Select the route with the shortest AS-path length.
+ // 6. If all paths have the same AS-path length, select the path based
+ // on origin: IGP is preferred over EGP; EGP is preferred over
+ // Incomplete.
+ // 7. If the origins are the same, select the path with lowest MED
+ // value.
+ // 8. If the paths have the same MED values, select the path learned
+ // via EBGP over one learned via IBGP.
+ // 9. Select the route with the lowest IGP cost to the next hop.
+ // 10. Select the route received from the peer with the lowest BGP
+ // router ID.
+ //
+ // Returns None if best-path among given paths cannot be computed else best
+ // path.
+ // Assumes paths from NC has source equal to None.
+ //
+
+ var bestPath Path
+ bestPathReason := BPR_UNKNOWN
+
+ // Follow best path calculation algorithm steps.
+ // compare by reachability
+ if bestPath == nil {
+ bestPath = compareByReachableNexthop(path1, path2)
+ bestPathReason = BPR_REACHABLE_NEXT_HOP
+ }
+
+ if bestPath == nil {
+ bestPath = compareByHighestWeight(path1, path2)
+ bestPathReason = BPR_HIGHEST_WEIGHT
+ }
+
+ if bestPath == nil {
+ bestPath = compareByLocalPref(path1, path2)
+ bestPathReason = BPR_LOCAL_PREF
+ }
+ if bestPath == nil {
+ bestPath = compareByLocalOrigin(path1, path2)
+ bestPathReason = BPR_LOCAL_ORIGIN
+ }
+ if bestPath == nil {
+ bestPath = compareByASPath(path1, path2)
+ bestPathReason = BPR_ASPATH
+ }
+ if bestPath == nil {
+ bestPath = compareByOrigin(path1, path2)
+ bestPathReason = BPR_ORIGIN
+ }
+ if bestPath == nil {
+ bestPath = compareByMED(path1, path2)
+ bestPathReason = BPR_MED
+ }
+ if bestPath == nil {
+ bestPath = compareByASNumber(localAsn, path1, path2)
+ bestPathReason = BPR_ASN
+ }
+ if bestPath == nil {
+ bestPath = compareByIGPCost(path1, path2)
+ bestPathReason = BPR_IGP_COST
+ }
+ if bestPath == nil {
+ var e error = nil
+ bestPath, e = compareByRouterID(localAsn, path1, path2)
+ if e != nil {
+ logger.Error(e)
+ }
+ bestPathReason = BPR_ROUTER_ID
+ }
+ if bestPath == nil {
+ bestPathReason = BPR_UNKNOWN
+ }
+
+ return bestPath, bestPathReason
+}
+
+func compareByReachableNexthop(path1, path2 Path) Path {
+ // Compares given paths and selects best path based on reachable next-hop.
+ //
+ // If no path matches this criteria, return None.
+ // However RouteServer doesn't need to check reachability, so return nil.
+ logger.Debugf("enter compareByReachableNexthop")
+ logger.Debugf("path1: %s, path2: %s", path1, path2)
+ return nil
+}
+
+func compareByHighestWeight(path1, path2 Path) Path {
+ // Selects a path with highest weight.
+ //
+ // Weight is BGPS specific parameter. It is local to the router on which it
+ // is configured.
+ // Return:
+ // nil if best path among given paths cannot be decided, else best path.
+ logger.Debugf("enter compareByHighestWeight")
+ logger.Debugf("path1: %s, path2: %s", path1, path2)
+ return nil
+}
+
+func compareByLocalPref(path1, path2 Path) Path {
+ // Selects a path with highest local-preference.
+ //
+ // Unlike the weight attribute, which is only relevant to the local
+ // router, local preference is an attribute that routers exchange in the
+ // same AS. Highest local-pref is preferred. If we cannot decide,
+ // we return None.
+ //
+ // # Default local-pref values is 100
+ logger.Debugf("enter compareByLocalPref")
+ attribute1 := path1.getPathAttribute(bgp.BGP_ATTR_TYPE_LOCAL_PREF)
+ attribute2 := path2.getPathAttribute(bgp.BGP_ATTR_TYPE_LOCAL_PREF)
+
+ if attribute1 == nil || attribute2 == nil {
+ return nil
+ }
+
+ localPref1 := attribute1.(*bgp.PathAttributeLocalPref).Value
+ localPref2 := attribute2.(*bgp.PathAttributeLocalPref).Value
+
+ // Highest local-preference value is preferred.
+ if localPref1 > localPref2 {
+ return path1
+ } else if localPref1 < localPref2 {
+ return path2
+ } else {
+ return nil
+ }
+}
+
+func compareByLocalOrigin(path1, path2 Path) Path {
+
+ // """Select locally originating path as best path.
+ // Locally originating routes are network routes, redistributed routes,
+ // or aggregated routes.
+ // Returns None if given paths have same source.
+ // """
+ // # If both paths are from same sources we cannot compare them here.
+ logger.Debugf("enter compareByLocalOrigin")
+ if path1.getSource() == path2.getSource() {
+ return nil
+ }
+
+ // # Here we consider prefix from NC as locally originating static route.
+ // # Hence it is preferred.
+ if path1.getSource() == nil {
+ return path1
+ }
+
+ if path2.getSource() == nil {
+ return path2
+ }
+ return nil
+}
+
+func compareByASPath(path1, path2 Path) Path {
+ // Calculated the best-paths by comparing as-path lengths.
+ //
+ // Shortest as-path length is preferred. If both path have same lengths,
+ // we return None.
+ logger.Debugf("enter compareByASPath")
+ attribute1 := path1.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH)
+ attribute2 := path2.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH)
+
+ asPath1 := attribute1.(*bgp.PathAttributeAsPath)
+ asPath2 := attribute2.(*bgp.PathAttributeAsPath)
+
+ if asPath1 == nil || asPath2 == nil {
+ logger.Error("it is not possible to compare asPath are not present")
+ }
+
+ var l1, l2 int
+ for _, pathParam := range asPath1.Value {
+ l1 += pathParam.ASLen()
+ }
+
+ for _, pathParam := range asPath2.Value {
+ l2 += pathParam.ASLen()
+ }
+
+ logger.Debugf("l1: %d, l2: %d", l1, l2)
+ logger.Debug(reflect.TypeOf(asPath1.Value))
+ logger.Debug(asPath1.Value)
+ if l1 > l2 {
+ return path2
+ } else if l1 < l2 {
+ return path1
+ } else {
+ return nil
+ }
+}
+
+func compareByOrigin(path1, path2 Path) Path {
+ // Select the best path based on origin attribute.
+ //
+ // IGP is preferred over EGP; EGP is preferred over Incomplete.
+ // If both paths have same origin, we return None.
+ logger.Debugf("enter compareByOrigin")
+ attribute1 := path1.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN)
+ attribute2 := path2.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN)
+
+ if attribute1 == nil || attribute2 == nil {
+ logger.Error("it is not possible to compare origin are not present")
+ return nil
+ }
+
+ origin1, n1 := binary.Uvarint(attribute1.(*bgp.PathAttributeOrigin).Value)
+ origin2, n2 := binary.Uvarint(attribute2.(*bgp.PathAttributeOrigin).Value)
+ logger.Debugf("path1 origin value: %d, %d byte read", origin1, n1)
+ logger.Debugf("path2 origin value: %d, %d byte read", origin2, n2)
+
+ // If both paths have same origins
+ if origin1 == origin2 {
+ return nil
+ } else if origin1 < origin2 {
+ return path1
+ } else {
+ return path2
+ }
+}
+
+func compareByMED(path1, path2 Path) Path {
+ // Select the path based with lowest MED value.
+ //
+ // If both paths have same MED, return None.
+ // By default, a route that arrives with no MED value is treated as if it
+ // had a MED of 0, the most preferred value.
+ // RFC says lower MED is preferred over higher MED value.
+ // compare MED among not only same AS path but also all path,
+ // like bgp always-compare-med
+ logger.Debugf("enter compareByMED")
+ getMed := func(path Path) uint32 {
+ attribute := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC)
+ if attribute == nil {
+ return 0
+ }
+ med := attribute.(*bgp.PathAttributeMultiExitDisc).Value
+ return med
+ }
+
+ med1 := getMed(path1)
+ med2 := getMed(path2)
+
+ if med1 == med2 {
+ return nil
+ } else if med1 < med2 {
+ return path1
+ }
+ return path2
+}
+
+func compareByASNumber(localAsn uint32, path1, path2 Path) Path {
+
+ //Select the path based on source (iBGP/eBGP) peer.
+ //
+ //eBGP path is preferred over iBGP. If both paths are from same kind of
+ //peers, return None.
+ logger.Debugf("enter compareByASNumber")
+ getPathSourceAsn := func(path Path) uint32 {
+ var asn uint32
+ if path.getSource() == nil {
+ asn = localAsn
+ } else {
+ asn = path.getSource().RemoteAs
+ }
+ return asn
+ }
+
+ p1Asn := getPathSourceAsn(path1)
+ p2Asn := getPathSourceAsn(path2)
+ // If path1 is from ibgp peer and path2 is from ebgp peer.
+ if (p1Asn == localAsn) && (p2Asn != localAsn) {
+ return path2
+ }
+
+ // If path2 is from ibgp peer and path1 is from ebgp peer,
+ if (p2Asn == localAsn) && (p1Asn != localAsn) {
+ return path1
+ }
+
+ // If both paths are from ebgp or ibpg peers, we cannot decide.
+ return nil
+}
+
+func compareByIGPCost(path1, path2 Path) Path {
+ // Select the route with the lowest IGP cost to the next hop.
+ //
+ // Return None if igp cost is same.
+ // Currently BGPS has no concept of IGP and IGP cost.
+ logger.Debugf("enter compareByIGPCost")
+ logger.Debugf("path1: %s, path2: %s", path1, path2)
+ return nil
+}
+
+func compareByRouterID(localAsn uint32, path1, path2 Path) (Path, error) {
+ // Select the route received from the peer with the lowest BGP router ID.
+ //
+ // If both paths are eBGP paths, then we do not do any tie breaking, i.e we do
+ // not pick best-path based on this criteria.
+ // RFC: http://tools.ietf.org/html/rfc5004
+ // We pick best path between two iBGP paths as usual.
+ logger.Debugf("enter compareByRouterID")
+ getAsn := func(pathSource *Peer) uint32 {
+ if pathSource == nil {
+ return localAsn
+ } else {
+ return pathSource.RemoteAs
+ }
+ }
+
+ getRouterId := func(pathSource *Peer, localBgpId uint32) uint32 {
+ if pathSource == nil {
+ return localBgpId
+ } else {
+ routerId := pathSource.protocol.recvOpenMsg.ID
+ routerId_u32 := binary.BigEndian.Uint32(routerId)
+ return routerId_u32
+ }
+ }
+
+ pathSource1 := path1.getSource()
+ pathSource2 := path2.getSource()
+
+ // If both paths are from NC we have same router Id, hence cannot compare.
+ if pathSource1 == nil && pathSource2 == nil {
+ return nil, nil
+ }
+
+ asn1 := getAsn(pathSource1)
+ asn2 := getAsn(pathSource2)
+
+ isEbgp1 := asn1 != localAsn
+ isEbgp2 := asn2 != localAsn
+ // If both paths are from eBGP peers, then according to RFC we need
+ // not tie break using router id.
+ if isEbgp1 && isEbgp2 {
+ return nil, nil
+ }
+
+ if (isEbgp1 == true && isEbgp2 == false) ||
+ (isEbgp1 == false && isEbgp2 == true) {
+ return nil, fmt.Errorf("This method does not support comparing ebgp with ibgp path")
+ }
+
+ // At least one path is not coming from NC, so we get local bgp id.
+ var localBgpId_u32 uint32
+ if pathSource1 != nil {
+ localBgpId := pathSource1.protocol.sentOpenMsg.ID
+ localBgpId_u32 = binary.BigEndian.Uint32(localBgpId)
+ } else {
+ localBgpId := pathSource2.protocol.sentOpenMsg.ID
+ localBgpId_u32 = binary.BigEndian.Uint32(localBgpId)
+ }
+
+ // Get router ids.
+ routerId1_u32 := getRouterId(pathSource1, localBgpId_u32)
+ routerId2_u32 := getRouterId(pathSource2, localBgpId_u32)
+
+ // If both router ids are same/equal we cannot decide.
+ // This case is possible since router ids are arbitrary.
+ if routerId1_u32 == routerId2_u32 {
+ return nil, nil
+ }
+
+ if routerId1_u32 < routerId2_u32 {
+ return path1, nil
+ } else {
+ return path2, nil
+ }
+}
+
+// return Destination's string representation
+func (dest *DestinationDefault) String() string {
+ str := fmt.Sprintf("Destination NLRI: %s", dest.getPrefix().String())
+ return str
+}
+
+func (dest *DestinationDefault) constructWithdrawPath() Path {
+ path := &IPv4Path{}
+ return path
+}
+
+func (dest *DestinationDefault) getPrefix() net.IP {
+ var ip net.IP
+ switch p := dest.nlri.(type) {
+ case *bgp.NLRInfo:
+ ip = p.IPAddrPrefix.IPAddrPrefixDefault.Prefix
+ case *bgp.WithdrawnRoute:
+ ip = p.IPAddrPrefix.IPAddrPrefixDefault.Prefix
+ }
+ return ip
+}
+
+/*
+* Definition of inherited Destination interface
+ */
+
+type IPv4Destination struct {
+ *DestinationDefault
+ //need structure
+}
+
+func NewIPv4Destination(nlri bgp.AddrPrefixInterface) *IPv4Destination {
+ ipv4Destination := &IPv4Destination{}
+ ipv4Destination.DestinationDefault = NewDestinationDefault(nlri)
+ ipv4Destination.DestinationDefault.ROUTE_FAMILY = RF_IPv4_UC
+ //need Processing
+ return ipv4Destination
+}
+
+func (ipv4d *IPv4Destination) String() string {
+ str := fmt.Sprintf("Destination NLRI: %s", ipv4d.getPrefix().String())
+ return str
+}
+
+type IPv6Destination struct {
+ *DestinationDefault
+ //need structure
+}
+
+func NewIPv6Destination(nlri bgp.AddrPrefixInterface) *IPv6Destination {
+ ipv6Destination := &IPv6Destination{}
+ ipv6Destination.DestinationDefault = NewDestinationDefault(nlri)
+ ipv6Destination.DestinationDefault.ROUTE_FAMILY = RF_IPv6_UC
+ //need Processing
+ return ipv6Destination
+}
+
+func (ipv6d *IPv6Destination) String() string {
+
+ str := fmt.Sprintf("Destination NLRI: %s", ipv6d.getPrefix().String())
+ return str
+}
+
+func (ipv6d *IPv6Destination) getPrefix() net.IP {
+ var ip net.IP
+ logger.Debugf("type %s", reflect.TypeOf(ipv6d.nlri))
+ switch p := ipv6d.nlri.(type) {
+ case *bgp.IPv6AddrPrefix:
+ ip = p.IPAddrPrefix.IPAddrPrefixDefault.Prefix
+ case *bgp.WithdrawnRoute:
+ ip = p.IPAddrPrefix.IPAddrPrefixDefault.Prefix
+ }
+ return ip
+}
diff --git a/table/destination_test.go b/table/destination_test.go
new file mode 100644
index 00000000..03b839a8
--- /dev/null
+++ b/table/destination_test.go
@@ -0,0 +1,207 @@
+// Copyright (C) 2014 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 table
+
+import (
+ //"fmt"
+ "github.com/osrg/gobgp/packet"
+ "github.com/stretchr/testify/assert"
+ //"net"
+ "testing"
+)
+
+func updateMsgD1() *bgp.BGPMessage {
+
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65000})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("192.168.50.1")
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+
+ pathAttributes := []bgp.PathAttributeInterface{
+ origin,
+ aspath,
+ nexthop,
+ med,
+ }
+
+ nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes := []bgp.WithdrawnRoute{}
+ return bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+}
+
+func updateMsgD2() *bgp.BGPMessage {
+
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("192.168.100.1")
+ med := bgp.NewPathAttributeMultiExitDisc(100)
+
+ pathAttributes := []bgp.PathAttributeInterface{
+ origin,
+ aspath,
+ nexthop,
+ med,
+ }
+
+ nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "20.20.20.0")}
+ withdrawnRoutes := []bgp.WithdrawnRoute{}
+ return bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+}
+func updateMsgD3() *bgp.BGPMessage {
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("192.168.150.1")
+ med := bgp.NewPathAttributeMultiExitDisc(100)
+
+ pathAttributes := []bgp.PathAttributeInterface{
+ origin,
+ aspath,
+ nexthop,
+ med,
+ }
+
+ nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "30.30.30.0")}
+ w1 := bgp.WithdrawnRoute{*bgp.NewIPAddrPrefix(23, "40.40.40.0")}
+ withdrawnRoutes := []bgp.WithdrawnRoute{w1}
+ return bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+}
+func createDestinationCheck(t *testing.T, path Path) (Destination, string) {
+ dest := NewIPv4Destination(path.getNlri())
+ ar := assert.NotNil(t, dest)
+ if !ar {
+ return nil, "NG"
+ }
+ return dest, "OK"
+}
+
+func routeCheck(t *testing.T, dest Destination) string {
+ bgpMsg1 := updateMsgD1()
+ bgpMsg2 := updateMsgD2()
+ bgpMsg3 := updateMsgD3()
+ pr1 := &Peer{VersionNum: 2, RemoteAs: 65000}
+ pr2 := &Peer{VersionNum: 4, RemoteAs: 65001}
+ pr3 := &Peer{VersionNum: 4, RemoteAs: 65002}
+ msg1 := &ProcessMessage{innerMessage: bgpMsg1, fromPeer: pr1}
+ msg2 := &ProcessMessage{innerMessage: bgpMsg2, fromPeer: pr1}
+ msg3 := &ProcessMessage{innerMessage: bgpMsg3, fromPeer: pr2}
+ path1, _ := createPathCheck(t, msg1)
+ path2, _ := createPathCheck(t, msg2)
+ path3, _ := createPathCheck(t, msg3)
+
+ //best path selection
+ dest.addNewPath(path1)
+ dest.addNewPath(path2)
+ dest.addNewPath(path3)
+ dest.addWithdraw(path3)
+
+ _, _, e := dest.Calculate(uint32(100))
+ //bpath, str, e := dest.Calculate()
+ //t.Log(bpath)
+ //t.Log(str)
+ ar := assert.Nil(t, e)
+ if !ar {
+ return "NG"
+ }
+
+ //sent route and remove sent route
+ sroute1 := &SentRoute{path: path1, peer: pr1}
+ sroute2 := &SentRoute{path: path2, peer: pr1}
+ sroute3 := &SentRoute{path: path3, peer: pr2}
+ dest.addSentRoute(sroute1)
+ dest.addSentRoute(sroute2)
+ dest.addSentRoute(sroute3)
+ result := dest.removeSentRoute(pr3)
+ ar = assert.Equal(t, result, false)
+ if !ar {
+ return "NG"
+ }
+ result = dest.removeSentRoute(pr2)
+ ar = assert.Equal(t, result, true)
+ if !ar {
+ return "NG"
+ }
+
+ //remote old path
+ rpath := dest.removeOldPathsFromSource(pr1)
+ t.Log(rpath)
+ //t.Log(dest.getKnownPathList())
+ return "OK"
+}
+
+/*
+func getKnownPathListCheck(t *testing.T, dest Destination) string {
+ paths := dest.getKnownPathList()
+ t.Log(paths)
+ return "OK"
+}
+*/
+
+//getter&setter test
+func dgsTerCheck(t *testing.T, path Path) string {
+ dd := &DestinationDefault{}
+ //check Route Family
+ dd.setRouteFamily(RF_IPv4_UC)
+ rf := dd.getRouteFamily()
+ ar := assert.Equal(t, rf, RF_IPv4_UC)
+ if !ar {
+ return "NG"
+ }
+ //check nlri
+ nlri := bgp.NewNLRInfo(24, "13.2.3.1")
+ dd.setNlri(nlri)
+ r_nlri := dd.getNlri()
+ ar = assert.Equal(t, r_nlri, nlri)
+ if !ar {
+ return "NG"
+ }
+ // check best path reason
+ reason := "reason"
+ dd.setBestPathReason(reason)
+ r_reason := dd.getBestPathReason()
+ ar = assert.Equal(t, r_reason, reason)
+ if !ar {
+ return "NG"
+ }
+ //check best path
+ dd.setBestPath(path)
+ r_path := dd.getBestPath()
+ ar = assert.Equal(t, r_path, path)
+ if !ar {
+ return "NG"
+ }
+ return "OK"
+}
+func TestDestination(t *testing.T) {
+ bgpMsg1 := updateMsgD1()
+ pr1 := &Peer{VersionNum: 2, RemoteAs: 65000}
+ msg := &ProcessMessage{innerMessage: bgpMsg1, fromPeer: pr1}
+ path, _ := createPathCheck(t, msg)
+ t.Log("# CREATE PATH CHECK")
+ dest, result := createDestinationCheck(t, path)
+ t.Log("# CHECK END -> [ ", result, " ]")
+ t.Log("")
+ t.Log("# ROUTE CHECK")
+ result = routeCheck(t, dest)
+ t.Log("# CHECK END -> [ ", result, " ]")
+ t.Log("")
+ t.Log("# GETTER SETTER CHECK")
+ result = dgsTerCheck(t, path)
+ t.Log("# CHECK END -> [ ", result, " ]")
+ t.Log("")
+}
diff --git a/table/path.go b/table/path.go
new file mode 100644
index 00000000..93d09d8f
--- /dev/null
+++ b/table/path.go
@@ -0,0 +1,339 @@
+// Copyright (C) 2014 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 table
+
+import (
+ "fmt"
+ "github.com/osrg/gobgp/packet"
+ "github.com/osrg/gobgp/utils"
+ "net"
+)
+
+type Path interface {
+ String() string
+ getPathAttributeMap() *utils.OrderedMap
+ getPathAttribute(int) bgp.PathAttributeInterface
+ clone(forWithdrawal bool) Path
+ setRouteFamily(ROUTE_FAMILY RouteFamily)
+ getRouteFamily() RouteFamily
+ setSource(source *Peer)
+ getSource() *Peer
+ setNexthop(nexthop net.IP)
+ getNexthop() net.IP
+ setSourceVerNum(sourceVerNum int)
+ getSourceVerNum() int
+ setWithdraw(withdraw bool)
+ isWithdraw() bool
+ setNlri(nlri bgp.AddrPrefixInterface)
+ getNlri() bgp.AddrPrefixInterface
+ getPrefix() net.IP
+ setMedSetByTargetNeighbor(medSetByTargetNeighbor bool)
+ getMedSetByTargetNeighbor() bool
+}
+
+type PathDefault struct {
+ ROUTE_FAMILY RouteFamily
+ source *Peer
+ nexthop net.IP
+ sourceVerNum int
+ withdraw bool
+ nlri bgp.AddrPrefixInterface
+ pattrMap *utils.OrderedMap
+ medSetByTargetNeighbor bool
+}
+
+func NewPathDefault(source *Peer, nlri bgp.AddrPrefixInterface, sourceVerNum int, nexthop net.IP,
+ isWithdraw bool, pattr *utils.OrderedMap, medSetByTargetNeighbor bool) *PathDefault {
+ if source == nil {
+ logger.Error("Need to provide source")
+ return nil
+ }
+
+ if !isWithdraw && (pattr == nil || nexthop == nil) {
+ logger.Error("Need to provide nexthop and patattrs for path that is not a withdraw.")
+ return nil
+ }
+
+ path := &PathDefault{}
+ path.ROUTE_FAMILY = RF_IPv4_UC
+ path.pattrMap = utils.NewOrderedMap()
+ if pattr != nil {
+ keyList := pattr.KeyLists()
+ for key := keyList.Front(); key != nil; key = key.Next() {
+ key := key.Value
+ val := pattr.Get(key)
+ e := path.pattrMap.Append(key, val)
+ if e != nil {
+ logger.Error(e)
+ }
+ }
+ }
+ path.nlri = nlri
+ path.source = source
+ path.nexthop = nexthop
+ path.sourceVerNum = sourceVerNum
+ path.withdraw = isWithdraw
+ path.medSetByTargetNeighbor = medSetByTargetNeighbor
+
+ return path
+}
+
+func (pd *PathDefault) setRouteFamily(ROUTE_FAMILY RouteFamily) {
+ pd.ROUTE_FAMILY = ROUTE_FAMILY
+}
+func (pd *PathDefault) getRouteFamily() RouteFamily {
+ return pd.ROUTE_FAMILY
+}
+
+func (pd *PathDefault) setSource(source *Peer) {
+ pd.source = source
+}
+func (pd *PathDefault) getSource() *Peer {
+ return pd.source
+}
+
+func (pd *PathDefault) setNexthop(nexthop net.IP) {
+ pd.nexthop = nexthop
+}
+
+func (pd *PathDefault) getNexthop() net.IP {
+ return pd.nexthop
+}
+
+func (pd *PathDefault) setSourceVerNum(sourceVerNum int) {
+ pd.sourceVerNum = sourceVerNum
+}
+
+func (pd *PathDefault) getSourceVerNum() int {
+ return pd.sourceVerNum
+}
+
+func (pd *PathDefault) setWithdraw(withdraw bool) {
+ pd.withdraw = withdraw
+}
+
+func (pd *PathDefault) isWithdraw() bool {
+ return pd.withdraw
+}
+
+func (pd *PathDefault) setNlri(nlri bgp.AddrPrefixInterface) {
+ pd.nlri = nlri
+}
+
+func (pd *PathDefault) getNlri() bgp.AddrPrefixInterface {
+ return pd.nlri
+}
+
+func (pd *PathDefault) setMedSetByTargetNeighbor(medSetByTargetNeighbor bool) {
+ pd.medSetByTargetNeighbor = medSetByTargetNeighbor
+}
+
+func (pd *PathDefault) getMedSetByTargetNeighbor() bool {
+ return pd.medSetByTargetNeighbor
+}
+
+//Copy the entity
+func (pd *PathDefault) getPathAttributeMap() *utils.OrderedMap {
+ cpPattr := utils.NewOrderedMap()
+ keyList := pd.pattrMap.KeyLists()
+ for key := keyList.Front(); key != nil; key = key.Next() {
+ key := key.Value
+ val := pd.pattrMap.Get(key)
+ e := cpPattr.Append(key, val)
+ if e != nil {
+ logger.Error(e)
+ }
+ }
+ return cpPattr
+}
+
+func (pd *PathDefault) getPathAttribute(pattrType int) bgp.PathAttributeInterface {
+ attr := pd.pattrMap.Get(pattrType)
+ if attr == nil {
+ logger.Debugf("Attribute Type %s is not found", AttributeType(pattrType))
+ return nil
+ }
+ return attr.(bgp.PathAttributeInterface)
+}
+
+func (pi *PathDefault) clone(forWithdrawal bool) Path {
+ pathAttrs := utils.NewOrderedMap()
+ if !forWithdrawal {
+ pathAttrs = pi.getPathAttributeMap()
+ }
+ clone := NewPathDefault(pi.getSource(), pi.getNlri(), pi.getSourceVerNum(),
+ pi.getNexthop(), forWithdrawal, pathAttrs, pi.getMedSetByTargetNeighbor())
+ return clone
+}
+
+// return Path's string representation
+func (pi *PathDefault) String() string {
+ str := fmt.Sprintf("IPv4Path Source: %d, ", pi.getSourceVerNum())
+ str = str + fmt.Sprintf(" NLRI: %s, ", pi.getPrefix().String())
+ str = str + fmt.Sprintf(" nexthop: %s, ", pi.getNexthop().String())
+ str = str + fmt.Sprintf(" withdraw: %s, ", pi.isWithdraw())
+ str = str + fmt.Sprintf(" path attributes: %s, ", pi.getPathAttributeMap())
+ return str
+}
+
+func (pi *PathDefault) getPrefix() net.IP {
+ addrPrefix := pi.nlri.(*bgp.NLRInfo)
+ return addrPrefix.Prefix
+}
+
+func getNextHop(pathAttributes []bgp.PathAttributeInterface) net.IP {
+
+ for _, pathAttr := range pathAttributes {
+ switch p := pathAttr.(type) {
+ case *bgp.PathAttributeNextHop:
+ return p.Value
+ }
+ }
+ return nil
+
+}
+
+func createPathAttributeMap(pathAttributes []bgp.PathAttributeInterface) *utils.OrderedMap {
+
+ pathAttrMap := utils.NewOrderedMap()
+ for _, attr := range pathAttributes {
+ var err error
+ switch a := attr.(type) {
+ case *bgp.PathAttributeOrigin:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_ORIGIN, a)
+ case *bgp.PathAttributeAsPath:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_AS_PATH, a)
+ case *bgp.PathAttributeNextHop:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_NEXT_HOP, a)
+ case *bgp.PathAttributeMultiExitDisc:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC, a)
+ case *bgp.PathAttributeLocalPref:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_LOCAL_PREF, a)
+ case *bgp.PathAttributeAtomicAggregate:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_ATOMIC_AGGREGATE, a)
+ case *bgp.PathAttributeAggregator:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_AGGREGATOR, a)
+ case *bgp.PathAttributeCommunities:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_COMMUNITIES, a)
+ case *bgp.PathAttributeOriginatorId:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_ORIGINATOR_ID, a)
+ case *bgp.PathAttributeClusterList:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_CLUSTER_LIST, a)
+ case *bgp.PathAttributeMpReachNLRI:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI, a)
+ case *bgp.PathAttributeMpUnreachNLRI:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_MP_UNREACH_NLRI, a)
+ case *bgp.PathAttributeExtendedCommunities:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES, a)
+ case *bgp.PathAttributeAs4Path:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_AS4_PATH, a)
+ case *bgp.PathAttributeAs4Aggregator:
+ err = pathAttrMap.Append(bgp.BGP_ATTR_TYPE_AS4_AGGREGATOR, a)
+ }
+ if err != nil {
+ return nil
+ }
+ }
+ return pathAttrMap
+}
+
+// create Path object based on route family
+func CreatePath(source *Peer, nlri bgp.AddrPrefixInterface,
+ pathAttributes []bgp.PathAttributeInterface, isWithdraw bool) Path {
+
+ rf := RouteFamily(int(nlri.AFI())<<16 | int(nlri.SAFI()))
+ logger.Debugf("afi: %d, safi: %d ", int(nlri.AFI()), nlri.SAFI())
+ pathAttrMap := createPathAttributeMap(pathAttributes)
+ var path Path
+
+ switch rf {
+ case RF_IPv4_UC:
+ logger.Debugf("RouteFamily : %s", RF_IPv4_UC.String())
+ nexthop := getNextHop(pathAttributes)
+ path = NewIPv4Path(source, nlri, source.VersionNum, nexthop, isWithdraw, pathAttrMap, false)
+ case RF_IPv6_UC:
+ logger.Debugf("RouteFamily : %s", RF_IPv6_UC.String())
+ var mpattr *bgp.PathAttributeMpReachNLRI
+ var nexthop net.IP
+
+ if !isWithdraw {
+ mpattr = pathAttrMap.Get(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI).(*bgp.PathAttributeMpReachNLRI)
+ nexthop = mpattr.Nexthop
+ } else {
+ nexthop = nil
+ }
+
+ path = NewIPv6Path(source, nlri, source.VersionNum, nexthop, isWithdraw, pathAttrMap, false)
+ }
+ return path
+}
+
+/*
+* Definition of inherited Path interface
+ */
+type IPv4Path struct {
+ *PathDefault
+}
+
+func NewIPv4Path(source *Peer, nlri bgp.AddrPrefixInterface, sourceVerNum int, nexthop net.IP,
+ isWithdraw bool, pattr *utils.OrderedMap, medSetByTargetNeighbor bool) *IPv4Path {
+ ipv4Path := &IPv4Path{}
+ ipv4Path.PathDefault = NewPathDefault(source, nlri, sourceVerNum, nexthop, isWithdraw, pattr, medSetByTargetNeighbor)
+ ipv4Path.PathDefault.ROUTE_FAMILY = RF_IPv4_UC
+ return ipv4Path
+}
+
+func (ipv4p *IPv4Path) setPathDefault(pd *PathDefault) {
+ ipv4p.PathDefault = pd
+}
+func (ipv4p *IPv4Path) getPathDefault() *PathDefault {
+ return ipv4p.PathDefault
+}
+
+type IPv6Path struct {
+ *PathDefault
+}
+
+func NewIPv6Path(source *Peer, nlri bgp.AddrPrefixInterface, sourceVerNum int, nexthop net.IP,
+ isWithdraw bool, pattr *utils.OrderedMap, medSetByTargetNeighbor bool) *IPv6Path {
+ ipv6Path := &IPv6Path{}
+ ipv6Path.PathDefault = NewPathDefault(source, nlri, sourceVerNum, nexthop, isWithdraw, pattr, medSetByTargetNeighbor)
+ ipv6Path.PathDefault.ROUTE_FAMILY = RF_IPv6_UC
+ return ipv6Path
+}
+
+func (ipv6p *IPv6Path) setPathDefault(pd *PathDefault) {
+ ipv6p.PathDefault = pd
+}
+
+func (ipv6p *IPv6Path) getPathDefault() *PathDefault {
+ return ipv6p.PathDefault
+}
+
+func (ipv6p *IPv6Path) getPrefix() net.IP {
+ addrPrefix := ipv6p.nlri.(*bgp.IPv6AddrPrefix)
+ return addrPrefix.Prefix
+}
+
+// return IPv6Path's string representation
+func (ipv6p *IPv6Path) String() string {
+ str := fmt.Sprintf("IPv6Path Source: %d, ", ipv6p.getSourceVerNum())
+ str = str + fmt.Sprintf(" NLRI: %s, ", ipv6p.getPrefix().String())
+ str = str + fmt.Sprintf(" nexthop: %s, ", ipv6p.getNexthop().String())
+ str = str + fmt.Sprintf(" withdraw: %s, ", ipv6p.isWithdraw())
+ str = str + fmt.Sprintf(" path attributes: %s, ", ipv6p.getPathAttributeMap())
+ return str
+}
diff --git a/table/path_test.go b/table/path_test.go
new file mode 100644
index 00000000..d15a20f2
--- /dev/null
+++ b/table/path_test.go
@@ -0,0 +1,270 @@
+// path_test.go
+package table
+
+import (
+ //"fmt"
+ "github.com/osrg/gobgp/packet"
+ "github.com/stretchr/testify/assert"
+ "net"
+ "testing"
+)
+
+func updateMsg() *bgp.BGPMessage {
+ w1 := bgp.WithdrawnRoute{*bgp.NewIPAddrPrefix(23, "121.1.3.2")}
+ w2 := bgp.WithdrawnRoute{*bgp.NewIPAddrPrefix(17, "100.33.3.0")}
+ w := []bgp.WithdrawnRoute{w1, w2}
+ //w := []WithdrawnRoute{}
+
+ aspath1 := []bgp.AsPathParamInterface{
+ bgp.NewAsPathParam(2, []uint16{1000}),
+ bgp.NewAsPathParam(1, []uint16{1001, 1002}),
+ bgp.NewAsPathParam(2, []uint16{1003, 1004}),
+ }
+
+ aspath2 := []bgp.AsPathParamInterface{
+ bgp.NewAs4PathParam(2, []uint32{1000000}),
+ bgp.NewAs4PathParam(1, []uint32{1000001, 1002}),
+ bgp.NewAs4PathParam(2, []uint32{1003, 100004}),
+ }
+
+ aspath3 := []*bgp.As4PathParam{
+ bgp.NewAs4PathParam(2, []uint32{1000000}),
+ bgp.NewAs4PathParam(1, []uint32{1000001, 1002}),
+ bgp.NewAs4PathParam(2, []uint32{1003, 100004}),
+ }
+
+ ecommunities := []bgp.ExtendedCommunityInterface{
+ &bgp.TwoOctetAsSpecificExtended{SubType: 1, AS: 10003, LocalAdmin: 3 << 20},
+ &bgp.FourOctetAsSpecificExtended{SubType: 2, AS: 1 << 20, LocalAdmin: 300},
+ &bgp.IPv4AddressSpecificExtended{SubType: 3, IPv4: net.ParseIP("192.2.1.2").To4(), LocalAdmin: 3000},
+ &bgp.OpaqueExtended{Value: []byte{0, 1, 2, 3, 4, 5, 6, 7}},
+ &bgp.UnknownExtended{Type: 99, Value: []byte{0, 1, 2, 3, 4, 5, 6, 7}},
+ }
+
+ mp_nlri := []bgp.AddrPrefixInterface{
+ bgp.NewLabelledVPNIPAddrPrefix(20, "192.0.9.0", *bgp.NewLabel(1, 2, 3),
+ bgp.NewRouteDistinguisherTwoOctetAS(256, 10000)),
+ bgp.NewLabelledVPNIPAddrPrefix(26, "192.10.8.192", *bgp.NewLabel(5, 6, 7, 8),
+ bgp.NewRouteDistinguisherIPAddressAS("10.0.1.1", 10001)),
+ }
+
+ mp_nlri2 := []bgp.AddrPrefixInterface{bgp.NewIPv6AddrPrefix(100,
+ "fe80:1234:1234:5667:8967:af12:8912:1023")}
+
+ mp_nlri3 := []bgp.AddrPrefixInterface{bgp.NewLabelledVPNIPv6AddrPrefix(100,
+ "fe80:1234:1234:5667:8967:af12:1203:33a1", *bgp.NewLabel(5, 6),
+ bgp.NewRouteDistinguisherFourOctetAS(5, 6))}
+
+ mp_nlri4 := []bgp.AddrPrefixInterface{bgp.NewLabelledIPAddrPrefix(25, "192.168.0.0",
+ *bgp.NewLabel(5, 6, 7))}
+
+ p := []bgp.PathAttributeInterface{
+ bgp.NewPathAttributeOrigin(3),
+ bgp.NewPathAttributeAsPath(aspath1),
+ bgp.NewPathAttributeAsPath(aspath2),
+ bgp.NewPathAttributeNextHop("129.1.1.2"),
+ bgp.NewPathAttributeMultiExitDisc(1 << 20),
+ bgp.NewPathAttributeLocalPref(1 << 22),
+ bgp.NewPathAttributeAtomicAggregate(),
+ bgp.NewPathAttributeAggregator(uint16(30002), "129.0.2.99"),
+ bgp.NewPathAttributeAggregator(uint32(30002), "129.0.2.99"),
+ bgp.NewPathAttributeAggregator(uint32(300020), "129.0.2.99"),
+ bgp.NewPathAttributeCommunities([]uint32{1, 3}),
+ bgp.NewPathAttributeOriginatorId("10.10.0.1"),
+ bgp.NewPathAttributeClusterList([]string{"10.10.0.2", "10.10.0.3"}),
+ bgp.NewPathAttributeExtendedCommunities(ecommunities),
+ bgp.NewPathAttributeAs4Path(aspath3),
+ bgp.NewPathAttributeAs4Aggregator(10000, "112.22.2.1"),
+ bgp.NewPathAttributeMpReachNLRI("112.22.2.0", mp_nlri),
+ bgp.NewPathAttributeMpReachNLRI("1023::", mp_nlri2),
+ bgp.NewPathAttributeMpReachNLRI("fe80::", mp_nlri3),
+ bgp.NewPathAttributeMpReachNLRI("129.1.1.1", mp_nlri4),
+ bgp.NewPathAttributeMpUnreachNLRI(mp_nlri),
+ &bgp.PathAttributeUnknown{
+ PathAttribute: bgp.PathAttribute{
+ Flags: 1,
+ Type: 100,
+ Value: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ },
+ },
+ }
+ n := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "13.2.3.1"), *bgp.NewNLRInfo(24, "13.2.3.2")}
+ //n := []bgp.NLRInfo{*bgp.NewNLRInfo(100, "fe80:1234:1234:5667:8967:af12:1203:33a1")}
+ return bgp.NewBGPUpdateMessage(w, p, n)
+}
+
+func initMsg() *ProcessMessage {
+ bgpMessage := updateMsg()
+ peer := &Peer{}
+ peer.VersionNum = 4
+ peer.RemoteAs = 65000
+
+ msg := &ProcessMessage{
+ innerMessage: bgpMessage,
+ fromPeer: peer,
+ }
+ return msg
+}
+func createPathCheck(t *testing.T, msg *ProcessMessage) (Path, string) {
+ updateMsg := msg.innerMessage.Body.(*bgp.BGPUpdate)
+ nlriList := updateMsg.NLRI
+ pathAttributes := updateMsg.PathAttributes
+ nlri_info := nlriList[0]
+ path := CreatePath(msg.fromPeer, &nlri_info, pathAttributes, false)
+ ar := assert.NotNil(t, path, "Path is Nil")
+ if !ar {
+ return nil, "NG"
+ }
+ return path, "OK"
+}
+func getNextHopCheck(t *testing.T, msg *ProcessMessage) string {
+ nexthop := "129.1.1.2"
+ pAttr := msg.innerMessage.Body.(*bgp.BGPUpdate).PathAttributes
+ r_nexthop := getNextHop(pAttr)
+ ar := assert.Equal(t, r_nexthop.String(), nexthop, "unmatch nexthop")
+ if !ar {
+ return "NG"
+ }
+ return "OK"
+}
+func getPrefixCheck(t *testing.T, path Path) string {
+ prefix := "13.2.3.1"
+ //prefix := "fe80:1234:1234:5667:8967:af12:1203:33a1"
+ r_prefix := path.getPrefix()
+ ar := assert.Equal(t, r_prefix.String(), prefix, "unmatch prefix")
+ if !ar {
+ return "NG"
+ }
+ return "OK"
+}
+
+func getPathAttributeCheck(t *testing.T, path Path) string {
+ nh := "129.1.1.2"
+ pa := path.getPathAttribute(bgp.BGP_ATTR_TYPE_NEXT_HOP)
+ r_nh := pa.(*bgp.PathAttributeNextHop).Value.String()
+ ar := assert.Equal(t, r_nh, nh, "unmatch nexthop")
+ if !ar {
+ return "NG"
+ }
+ return "OK"
+}
+
+func cloneCheck(t *testing.T, path Path) string {
+
+ prefix := path.getPrefix()
+ cl := path.clone(false)
+ r_prefix := cl.getPrefix()
+ ar := assert.Equal(t, r_prefix, prefix, "unmatch prefix in clone element")
+ if !ar {
+ return "NG"
+ }
+ return "OK"
+}
+
+//getter&setter test
+func pgsTerCheck(t *testing.T) string {
+ pd := &PathDefault{}
+ //check Route Family
+ pd.setRouteFamily(RF_IPv4_UC)
+ rf := pd.getRouteFamily()
+ ar := assert.Equal(t, rf, RF_IPv4_UC, "unmatch route family")
+ if !ar {
+ return "NG"
+ }
+
+ //check source
+ pr := &Peer{
+ RemoteAs: 65000,
+ VersionNum: 4,
+ }
+ pd.setSource(pr)
+ r_pr := pd.getSource()
+ ar = assert.Equal(t, r_pr, pr, "unmatch source")
+ if !ar {
+ return "NG"
+ }
+ //check nexthop
+ ip := net.ParseIP("192.168.0.1")
+ pd.setNexthop(ip)
+ nh := pd.getNexthop()
+ ar = assert.Equal(t, nh, ip, "unmatch nexthop")
+ if !ar {
+ return "NG"
+ }
+ //check source version num
+ svn := 4
+ pd.setSourceVerNum(svn)
+ r_svn := pd.getSourceVerNum()
+ ar = assert.Equal(t, r_svn, svn, "unmatch source ver num")
+ if !ar {
+ return "NG"
+ }
+ //check wighdrow
+ wd := true
+ pd.setWithdraw(wd)
+ r_wd := pd.isWithdraw()
+ ar = assert.Equal(t, r_wd, wd, "unmatch withdrow flg")
+ if !ar {
+ return "NG"
+ }
+ //check nlri
+ nlri := bgp.NewNLRInfo(24, "13.2.3.1")
+ pd.setNlri(nlri)
+ r_nlri := pd.getNlri()
+ ar = assert.Equal(t, r_nlri, nlri, "unmatch nlri")
+ if !ar {
+ return "NG"
+ }
+ //check med set by targetNeighbor
+ msbt := true
+ pd.setMedSetByTargetNeighbor(msbt)
+ r_msbt := pd.getMedSetByTargetNeighbor()
+ ar = assert.Equal(t, r_msbt, msbt, "unmatch med flg")
+ if !ar {
+ return "NG"
+ }
+ //ipv4 pathDefault
+ ipv4 := &IPv4Path{}
+ ipv4.setPathDefault(pd)
+ r_pd4 := ipv4.getPathDefault()
+ ar = assert.Equal(t, r_pd4, pd, "unmatch path default")
+ if !ar {
+ return "NG"
+ }
+ //ipv6 pathDefault
+ ipv6 := &IPv6Path{}
+ ipv6.setPathDefault(pd)
+ r_pd6 := ipv6.getPathDefault()
+ ar = assert.Equal(t, r_pd6, pd, "unmatch path default")
+ if !ar {
+ return "NG"
+ }
+ return "OK"
+}
+func TestPath(t *testing.T) {
+ msg := initMsg()
+ t.Log("# CREATE PATH CHECK")
+ path, result := createPathCheck(t, msg)
+ t.Log("# CHECK END -> [ ", result, " ]")
+ t.Log("")
+ t.Log("# GET NEXTHOP CHECK")
+ result = getNextHopCheck(t, msg)
+ t.Log("# CHECK END -> [ ", result, " ]")
+ t.Log("")
+ t.Log("# GET PREFIX CHECK")
+ result = getPrefixCheck(t, path)
+ t.Log("# CHECK END -> [ ", result, " ]")
+ t.Log("")
+ t.Log("# GET PATH ATTRIBUTE CHECK")
+ result = getPathAttributeCheck(t, path)
+ t.Log("# CHECK END -> [ ", result, " ]")
+ t.Log("")
+ t.Log("# CLONE CHECK")
+ result = cloneCheck(t, path)
+ t.Log("# CHECK END -> [ ", result, " ]")
+ t.Log("")
+ t.Log("# GETTER SETTER CHECK")
+ result = pgsTerCheck(t)
+ t.Log("# CHECK END -> [ ", result, " ]")
+ t.Log("")
+}
diff --git a/table/table.go b/table/table.go
new file mode 100644
index 00000000..22554eba
--- /dev/null
+++ b/table/table.go
@@ -0,0 +1,252 @@
+// Copyright (C) 2014 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 table
+
+import (
+ "github.com/osrg/gobgp/packet"
+ "net"
+ "reflect"
+)
+
+type Table interface {
+ createDest(nlri bgp.AddrPrefixInterface) Destination
+ getDestinations() map[string]Destination
+ setDestinations(destinations map[string]Destination)
+ getDestination(key string) Destination
+ setDestination(key string, dest Destination)
+ tableKey(nlri bgp.AddrPrefixInterface) net.IP
+ validatePath(path Path)
+ validateNlri(nlri bgp.AddrPrefixInterface)
+}
+
+type TableDefault struct {
+ ROUTE_FAMILY RouteFamily
+ destinations map[string]Destination
+ coreService *CoreService
+ //need SignalBus
+}
+
+func NewTableDefault(scope_id, coreService *CoreService) *TableDefault {
+ table := &TableDefault{}
+ table.ROUTE_FAMILY = RF_IPv4_UC
+ table.destinations = make(map[string]Destination)
+ table.coreService = coreService
+ return table
+
+}
+
+func (td *TableDefault) getRoutefamily() RouteFamily {
+ return td.ROUTE_FAMILY
+}
+
+func (td *TableDefault) getCoreService() *CoreService {
+ return td.coreService
+}
+
+//Creates destination
+//Implements interface
+func (td *TableDefault) createDest(nlri *bgp.NLRInfo) Destination {
+ //return NewDestination(td, nlri)
+ logger.Error("CreateDest NotImplementedError")
+ return nil
+}
+
+func insert(table Table, path Path) Destination {
+ var dest Destination
+
+ table.validatePath(path)
+ table.validateNlri(path.getNlri())
+ dest = getOrCreateDest(table, path.getNlri())
+
+ if path.isWithdraw() {
+ // withdraw insert
+ dest.addWithdraw(path)
+ } else {
+ // path insert
+ dest.addNewPath(path)
+ }
+ return dest
+}
+func insertSentRoute(table Table, sentRoute *SentRoute) {
+ pd := sentRoute.path.(*PathDefault)
+ table.validatePath(pd)
+ dest := getOrCreateDest(table, pd.getNlri())
+ dest.(*DestinationDefault).addSentRoute(sentRoute)
+}
+
+//"Remove old paths from whose source is `peer`
+func (td *TableDefault) cleanupPathsForPeer(peer *Peer) {
+ for _, dest := range td.destinations {
+ dd := dest.(*DestinationDefault)
+ pathsDeleted := dd.removeOldPathsFromSource(peer)
+ hadSent := dd.removeSentRoute(peer)
+ if hadSent {
+ logger.Errorf("Cleaning paths from table %s for peer %s.", td, peer)
+ }
+ if pathsDeleted != nil {
+ //need _signal_bus.dest_changed(dest)
+ }
+ }
+}
+
+/*
+//Cleans table of any path that do not have any RT in common with interested_rts
+// Commented out because it is a VPN-related processing
+func (td *TableDefault) cleanUninterestingPaths(interested_rts) int {
+ uninterestingDestCount = 0
+ for _, dest := range td.destinations {
+ addedWithdraw :=dest.withdrawUnintrestingPaths(interested_rts)
+ if addedWithdraw{
+ //need _signal_bus.dest_changed(dest)
+ uninterestingDestCount += 1
+ }
+ }
+ return uninterestingDestCount
+ // need content
+}
+*/
+
+func deleteDestByNlri(table Table, nlri *bgp.NLRInfo) Destination {
+ table.validateNlri(nlri)
+ destinations := table.getDestinations()
+ dest := destinations[table.tableKey(nlri).String()]
+ if dest != nil {
+ delete(destinations, table.tableKey(nlri).String())
+ }
+ return dest
+}
+
+func deleteDest(table Table, dest Destination) {
+ destinations := table.getDestinations()
+ delete(destinations, table.tableKey(dest.getNlri()).String())
+}
+
+func (td *TableDefault) validatePath(path Path) {
+ if path == nil || path.getRouteFamily() != td.ROUTE_FAMILY {
+ logger.Errorf("Invalid path. Expected instance of %s route family path, got %s.", td.ROUTE_FAMILY, path)
+ }
+}
+func (td *TableDefault) validateNlri(nlri bgp.AddrPrefixInterface) {
+ if nlri == nil {
+ logger.Error("Invalid Vpnv4 prefix given.")
+ }
+}
+
+func getOrCreateDest(table Table, nlri bgp.AddrPrefixInterface) Destination {
+ logger.Debugf("Table type : %s", reflect.TypeOf(table))
+ tableKey := table.tableKey(nlri)
+ dest := table.getDestination(tableKey.String())
+ // If destination for given prefix does not exist we create it.
+ if dest == nil {
+ logger.Debugf("dest with key %s is not found", tableKey.String())
+ dest = table.createDest(nlri)
+ table.setDestination(tableKey.String(), dest)
+ }
+ return dest
+}
+
+func (td *TableDefault) getDestinations() map[string]Destination {
+ return td.destinations
+}
+func (td *TableDefault) setDestinations(destinations map[string]Destination) {
+ td.destinations = destinations
+}
+func (td *TableDefault) getDestination(key string) Destination {
+ dest, ok := td.destinations[key]
+ if ok {
+ return dest
+ } else {
+ return nil
+ }
+}
+
+func (td *TableDefault) setDestination(key string, dest Destination) {
+ td.destinations[key] = dest
+}
+
+//Implements interface
+func (td *TableDefault) tableKey(nlri bgp.AddrPrefixInterface) net.IP {
+ //need Inheritance over ride
+ //return &nlri.IPAddrPrefix.IPAddrPrefixDefault.Prefix
+ logger.Error("CreateDest NotImplementedError")
+ return nil
+}
+
+/*
+* Definition of inherited Table interface
+ */
+
+type IPv4Table struct {
+ *TableDefault
+ //need structure
+}
+
+func NewIPv4Table(scope_id, coreService *CoreService) *IPv4Table {
+ ipv4Table := &IPv4Table{}
+ ipv4Table.TableDefault = NewTableDefault(scope_id, coreService)
+ ipv4Table.TableDefault.ROUTE_FAMILY = RF_IPv4_UC
+ //need Processing
+ return ipv4Table
+}
+
+//Creates destination
+//Implements interface
+func (ipv4t *IPv4Table) createDest(nlri bgp.AddrPrefixInterface) Destination {
+ return NewIPv4Destination(nlri)
+}
+
+//make tablekey
+//Implements interface
+func (ipv4t *IPv4Table) tableKey(nlri bgp.AddrPrefixInterface) net.IP {
+ //addrPrefix := nlri.(*bgp.IPAddrPrefix)
+
+ var ip net.IP
+ switch p := nlri.(type) {
+ case *bgp.NLRInfo:
+ ip = p.IPAddrPrefix.IPAddrPrefixDefault.Prefix
+ case *bgp.WithdrawnRoute:
+ ip = p.IPAddrPrefix.IPAddrPrefixDefault.Prefix
+ }
+ return ip
+}
+
+type IPv6Table struct {
+ *TableDefault
+ //need structure
+}
+
+func NewIPv6Table(scope_id, coreService *CoreService) *IPv6Table {
+ ipv6Table := &IPv6Table{}
+ ipv6Table.TableDefault = NewTableDefault(scope_id, coreService)
+ ipv6Table.TableDefault.ROUTE_FAMILY = RF_IPv6_UC
+ //need Processing
+ return ipv6Table
+}
+
+//Creates destination
+//Implements interface
+func (ipv6t *IPv6Table) createDest(nlri bgp.AddrPrefixInterface) Destination {
+ return Destination(NewIPv6Destination(nlri))
+}
+
+//make tablekey
+//Implements interface
+func (ipv6t *IPv6Table) tableKey(nlri bgp.AddrPrefixInterface) net.IP {
+
+ addrPrefix := nlri.(*bgp.IPv6AddrPrefix)
+ return addrPrefix.IPAddrPrefixDefault.Prefix
+
+}
diff --git a/table/table_manager.go b/table/table_manager.go
new file mode 100644
index 00000000..448776a2
--- /dev/null
+++ b/table/table_manager.go
@@ -0,0 +1,424 @@
+// Copyright (C) 2014 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 table
+
+import (
+ log "github.com/Sirupsen/logrus"
+ "github.com/osrg/gobgp/packet"
+ "net"
+ "os"
+ "reflect"
+ "time"
+)
+
+var logger *log.Logger = &log.Logger{
+ Out: os.Stderr,
+ Formatter: new(log.JSONFormatter),
+ Hooks: make(map[log.Level][]log.Hook),
+ Level: log.InfoLevel,
+}
+
+type PeerCounterName string
+
+const (
+ RECV_PREFIXES PeerCounterName = "recv_prefixes"
+ RECV_UPDATES PeerCounterName = "recv_updates"
+ SENT_UPDATES PeerCounterName = "sent_updates"
+ RECV_NOTIFICATION PeerCounterName = "recv_notification"
+ SENT_NOTIFICATION PeerCounterName = "sent_notification"
+ SENT_REFRESH PeerCounterName = "sent_refresh"
+ RECV_REFRESH PeerCounterName = "recv_refresh"
+ FSM_ESTB_TRANSITIONS PeerCounterName = "fms_established_transitions"
+)
+
+type RouteFamily int
+
+const (
+ RF_IPv4_UC RouteFamily = bgp.RF_IPv4_UC
+ RF_IPv6_UC RouteFamily = bgp.RF_IPv6_UC
+ RF_IPv4_VPN RouteFamily = bgp.RF_IPv4_VPN
+ RF_IPv6_VPN RouteFamily = bgp.RF_IPv6_VPN
+ RF_IPv4_MPLS RouteFamily = bgp.RF_IPv4_MPLS
+ RF_IPv6_MPLS RouteFamily = bgp.RF_IPv6_MPLS
+ RF_RTC_UC RouteFamily = bgp.RF_RTC_UC
+)
+
+func (rf RouteFamily) String() string {
+ switch rf {
+ case RF_IPv4_UC:
+ return "RF_IPv4_UC"
+ case RF_IPv6_UC:
+ return "RF_IPv6_UC"
+ case RF_IPv4_VPN:
+ return "RF_IPv4_VPN"
+ case RF_IPv6_VPN:
+ return "RF_IPv6_VPN"
+ case RF_IPv4_MPLS:
+ return "RF_IPv4_MPLS"
+ case RF_IPv6_MPLS:
+ return "RF_IPv6_MPLS"
+ case RF_RTC_UC:
+ return "RF_RTC_UC"
+ default:
+ return "Unknown"
+ }
+}
+
+type AttributeType int
+
+const (
+ BGP_ATTR_TYPE_ORIGIN AttributeType = bgp.BGP_ATTR_TYPE_ORIGIN
+ BGP_ATTR_TYPE_AS_PATH AttributeType = bgp.BGP_ATTR_TYPE_AS_PATH
+ BGP_ATTR_TYPE_NEXT_HOP AttributeType = bgp.BGP_ATTR_TYPE_NEXT_HOP
+ BGP_ATTR_TYPE_MULTI_EXIT_DISC AttributeType = bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC
+ BGP_ATTR_TYPE_LOCAL_PREF AttributeType = bgp.BGP_ATTR_TYPE_LOCAL_PREF
+ BGP_ATTR_TYPE_ATOMIC_AGGREGATE AttributeType = bgp.BGP_ATTR_TYPE_ATOMIC_AGGREGATE
+ BGP_ATTR_TYPE_AGGREGATOR AttributeType = bgp.BGP_ATTR_TYPE_AGGREGATOR
+ BGP_ATTR_TYPE_COMMUNITIES AttributeType = bgp.BGP_ATTR_TYPE_COMMUNITIES
+ BGP_ATTR_TYPE_ORIGINATOR_ID AttributeType = bgp.BGP_ATTR_TYPE_ORIGINATOR_ID
+ BGP_ATTR_TYPE_CLUSTER_LIST AttributeType = bgp.BGP_ATTR_TYPE_CLUSTER_LIST
+ BGP_ATTR_TYPE_MP_REACH_NLRI AttributeType = bgp.BGP_ATTR_TYPE_MP_REACH_NLRI
+ BGP_ATTR_TYPE_MP_UNREACH_NLRI AttributeType = bgp.BGP_ATTR_TYPE_MP_UNREACH_NLRI
+ BGP_ATTR_TYPE_EXTENDED_COMMUNITIES AttributeType = bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES
+ BGP_ATTR_TYPE_AS4_PATH AttributeType = bgp.BGP_ATTR_TYPE_AS4_PATH
+ BGP_ATTR_TYPE_AS4_AGGREGATOR AttributeType = bgp.BGP_ATTR_TYPE_AS4_AGGREGATOR
+)
+
+func (attr AttributeType) String() string {
+ switch attr {
+ case BGP_ATTR_TYPE_ORIGIN:
+ return "BGP_ATTR_TYPE_ORIGIN"
+ case BGP_ATTR_TYPE_AS_PATH:
+ return "BGP_ATTR_TYPE_AS_PATH"
+ case BGP_ATTR_TYPE_NEXT_HOP:
+ return "BGP_ATTR_TYPE_NEXT_HOP"
+ case BGP_ATTR_TYPE_MULTI_EXIT_DISC:
+ return "BGP_ATTR_TYPE_MULTI_EXIT_DISC"
+ case BGP_ATTR_TYPE_LOCAL_PREF:
+ return "BGP_ATTR_TYPE_LOCAL_PREF"
+ case BGP_ATTR_TYPE_ATOMIC_AGGREGATE:
+ return "BGP_ATTR_TYPE_ATOMIC_AGGREGATE"
+ case BGP_ATTR_TYPE_AGGREGATOR:
+ return "BGP_ATTR_TYPE_AGGREGATOR"
+ case BGP_ATTR_TYPE_COMMUNITIES:
+ return "BGP_ATTR_TYPE_COMMUNITIES"
+ case BGP_ATTR_TYPE_ORIGINATOR_ID:
+ return "BGP_ATTR_TYPE_ORIGINATOR_ID"
+ case BGP_ATTR_TYPE_CLUSTER_LIST:
+ return "BGP_ATTR_TYPE_CLUSTER_LIST"
+ case BGP_ATTR_TYPE_MP_REACH_NLRI:
+ return "BGP_ATTR_TYPE_MP_REACH_NLRI"
+ case BGP_ATTR_TYPE_MP_UNREACH_NLRI:
+ return "BGP_ATTR_TYPE_MP_UNREACH_NLRI"
+ case BGP_ATTR_TYPE_EXTENDED_COMMUNITIES:
+ return "BGP_ATTR_TYPE_EXTENDED_COMMUNITIES"
+ case BGP_ATTR_TYPE_AS4_PATH:
+ return "BGP_ATTR_TYPE_AS4_PATH"
+ case BGP_ATTR_TYPE_AS4_AGGREGATOR:
+ return "BGP_ATTR_TYPE_AS4_AGGREGATOR"
+ default:
+ return "Unknown"
+ }
+}
+
+type TableManager struct {
+ Tables map[RouteFamily]Table
+ adjInLocalRib map[string]*ReceivedRoute
+ processMessages chan *ProcessMessage
+ Counter map[PeerCounterName]int
+ localAsn uint32
+}
+
+type ProcessMessage struct {
+ innerMessage *bgp.BGPMessage
+ fromPeer *Peer
+}
+
+func NewTableManager() *TableManager {
+ t := &TableManager{}
+ t.Tables = make(map[RouteFamily]Table)
+ t.Tables[RF_IPv4_UC] = NewIPv4Table(0, nil)
+ t.Tables[RF_IPv6_UC] = NewIPv6Table(0, nil)
+
+ t.processMessages = make(chan *ProcessMessage, 10)
+ // initialize prefix counter
+ t.Counter = make(map[PeerCounterName]int)
+ t.Counter[RECV_PREFIXES] = 0
+
+ return t
+}
+
+func setLogger(loggerInstance *log.Logger) {
+ logger = loggerInstance
+}
+
+func (manager *TableManager) incrCounter(name PeerCounterName, step int) {
+ val := manager.Counter[name]
+ val += step
+ manager.Counter[name] = val
+}
+
+// create destination list from nlri
+func (manager *TableManager) handleNlri(p *ProcessMessage) ([]Destination, error) {
+
+ updateMsg := p.innerMessage.Body.(*bgp.BGPUpdate)
+ nlriList := updateMsg.NLRI
+ pathAttributes := updateMsg.PathAttributes
+
+ destList := make([]Destination, 0)
+ for _, nlri_info := range nlriList {
+ // create Path object
+ path := CreatePath(p.fromPeer, &nlri_info, pathAttributes, false)
+ // TODO process filter
+
+ rf := path.getRouteFamily()
+ // push Path into table
+ destination := insert(manager.Tables[rf], path)
+
+ destList = append(destList, destination)
+ manager.incrCounter(RECV_PREFIXES, len(nlriList))
+ // TODO handle adj-in-loc-rib
+ // rr := NewReceivedRoute(path, p.fromPeer, false)
+ // manager.adjInLocalRib[p.fromPeer.String()] = rr
+ // manager.adjInChanged <- rr
+ }
+
+ logger.Debugf("destinationList contains %d destinations from nlri", len(destList))
+
+ return destList, nil
+}
+
+// create destination list from withdrawn routes
+func (manager *TableManager) handleWithdraw(p *ProcessMessage) ([]Destination, error) {
+
+ updateMsg := p.innerMessage.Body.(*bgp.BGPUpdate)
+ pathAttributes := updateMsg.PathAttributes
+ withdrawnRoutes := updateMsg.WithdrawnRoutes
+
+ wDestList := make([]Destination, 0)
+
+ // process withdraw path
+ for _, nlriWithdraw := range withdrawnRoutes {
+ // create withdrawn Path object
+ path := CreatePath(p.fromPeer, &nlriWithdraw, pathAttributes, true)
+ rf := path.getRouteFamily()
+ // push Path into table
+ destination := insert(manager.Tables[rf], path)
+ wDestList = append(wDestList, destination)
+ }
+
+ logger.Debugf("destinationList contains %d withdrawn destinations", len(wDestList))
+ return wDestList, nil
+}
+
+// create destination list from nlri
+func (manager *TableManager) handleMPReachNlri(p *ProcessMessage) ([]Destination, error) {
+
+ updateMsg := p.innerMessage.Body.(*bgp.BGPUpdate)
+ pathAttributes := updateMsg.PathAttributes
+ attrList := []*bgp.PathAttributeMpReachNLRI{}
+
+ for _, attr := range pathAttributes {
+ logger.Debugf("attr type: %s", reflect.TypeOf(attr))
+ switch a := attr.(type) {
+ case *bgp.PathAttributeMpReachNLRI:
+ attrList = append(attrList, a)
+ }
+ }
+
+ destList := make([]Destination, 0)
+ for _, mp := range attrList {
+ nlri_info := mp.Value
+
+ for _, nlri := range nlri_info {
+ path := CreatePath(p.fromPeer, nlri, pathAttributes, false)
+ // TODO process filter
+
+ rf := path.getRouteFamily()
+ // push Path into table
+ destination := insert(manager.Tables[rf], path)
+
+ destList = append(destList, destination)
+ manager.incrCounter(RECV_PREFIXES, len(nlri_info))
+ // TODO handle adj-in-loc-rib
+ // rr := NewReceivedRoute(path, p.fromPeer, false)
+ // manager.adjInLocalRib[p.fromPeer.String()] = rr
+ // manager.adjInChanged <- rr
+ }
+ }
+ logger.Debugf("destinationList contains %d destinations from MpReachNLRI", len(destList))
+
+ return destList, nil
+}
+
+// create destination list from nlri
+func (manager *TableManager) handleMPUNReachNlri(p *ProcessMessage) ([]Destination, error) {
+
+ updateMsg := p.innerMessage.Body.(*bgp.BGPUpdate)
+ pathAttributes := updateMsg.PathAttributes
+ attrList := []*bgp.PathAttributeMpUnreachNLRI{}
+
+ for _, attr := range pathAttributes {
+ switch a := attr.(type) {
+ case *bgp.PathAttributeMpUnreachNLRI:
+ attrList = append(attrList, a)
+ }
+ }
+
+ destList := make([]Destination, 0)
+ for _, mp := range attrList {
+ nlri_info := mp.Value
+
+ for _, nlri := range nlri_info {
+ path := CreatePath(p.fromPeer, nlri, pathAttributes, true)
+ // TODO process filter
+
+ rf := path.getRouteFamily()
+ // push Path into table
+ destination := insert(manager.Tables[rf], path)
+
+ destList = append(destList, destination)
+ manager.incrCounter(RECV_PREFIXES, len(nlri_info))
+ }
+ }
+ logger.Debugf("destinationList contains %d destinations from MpUnreachNLRI", len(destList))
+ return destList, nil
+}
+
+// process BGPUpdate message
+// this function processes only BGPUpdate
+func (manager *TableManager) ProcessUpdate(fromPeer *Peer, message *bgp.BGPMessage) ([]Path, []Path, error) {
+
+ var bestPaths []Path = make([]Path, 0)
+ var withdrawPaths []Path = make([]Path, 0)
+
+ // check msg's type if it's BGPUpdate
+ body := message.Body
+ switch body.(type) {
+ case *bgp.BGPUpdate:
+
+ msg := &ProcessMessage{
+ innerMessage: message,
+ fromPeer: fromPeer,
+ }
+
+ // get destination list
+ destList, err := manager.handleNlri(msg)
+ if err != nil {
+ logger.Error(err)
+ return nil, nil, err
+ }
+
+ wDestList, err := manager.handleWithdraw(msg)
+ if err != nil {
+ logger.Error(err)
+ return nil, nil, err
+ }
+
+ mpreachDestList, err := manager.handleMPReachNlri(msg)
+ if err != nil {
+ logger.Error(err)
+ return nil, nil, err
+ }
+
+ mpunreachDestList, err := manager.handleMPUNReachNlri(msg)
+ if err != nil {
+ logger.Error(err)
+ return nil, nil, err
+ }
+ // merge destList and wDestList
+ destinationList := append(destList, wDestList...)
+ destinationList = append(destinationList, mpreachDestList...)
+ destinationList = append(destinationList, mpunreachDestList...)
+
+ // check best path changed
+ if destinationList != nil {
+ for _, destination := range destinationList {
+ // compute best path
+ logger.Infof("Processing destination: %s", destination.String())
+ newBestPath, reason, err := destination.Calculate(manager.localAsn)
+
+ logger.Debugf("new best path: %s, reason=%s", newBestPath, reason)
+ logger.Infof("new best path: NLRI: %s, next_hop=%s, reason=%s", newBestPath.getPrefix().String(),
+ newBestPath.getNexthop().String(), reason)
+ if err != nil {
+ logger.Error(err)
+ continue
+ }
+
+ destination.setBestPathReason(reason)
+ currentBestPath := destination.getBestPath()
+
+ if newBestPath != nil && currentBestPath == newBestPath {
+ // best path is not changed
+ logger.Debug("best path is not changed")
+ continue
+ }
+
+ if newBestPath == nil {
+
+ logger.Debug("new best path is nil")
+
+ if len(destination.getKnownPathList()) == 0 {
+ // create withdraw path
+ if currentBestPath != nil {
+ withdrawPaths = append(withdrawPaths, currentBestPath)
+ }
+ destination.setBestPath(nil)
+ } else {
+ panic("known path list is not empty")
+ }
+ } else {
+ logger.Debug("best path : ", newBestPath.String())
+ bestPaths = append(bestPaths, newBestPath)
+ destination.setBestPath(newBestPath)
+ }
+
+ if len(destination.getKnownPathList()) == 0 && destination.getBestPath() == nil {
+ rf := destination.getRouteFamily()
+ t := manager.Tables[rf]
+ deleteDest(t, destination)
+ }
+ }
+ }
+ default:
+ logger.Warn("message is not BGPUpdate")
+ }
+
+ return bestPaths, withdrawPaths, nil
+}
+
+type ReceivedRoute struct {
+ path Path
+ fromPeer *net.IP
+ filtered bool
+ timestamp time.Time
+}
+
+func (rr *ReceivedRoute) String() string {
+ return rr.path.(*PathDefault).getPrefix().String()
+}
+
+func NewReceivedRoute(path Path, peer *net.IP, filtered bool) *ReceivedRoute {
+
+ rroute := &ReceivedRoute{
+ path: path,
+ fromPeer: peer,
+ filtered: filtered,
+ timestamp: time.Now(),
+ }
+ return rroute
+}
diff --git a/table/table_manager_test.go b/table/table_manager_test.go
new file mode 100644
index 00000000..8b1d7e2c
--- /dev/null
+++ b/table/table_manager_test.go
@@ -0,0 +1,1482 @@
+// Copyright (C) 2014 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 table
+
+import (
+ _ "fmt"
+ log "github.com/Sirupsen/logrus"
+ "github.com/osrg/gobgp/packet"
+ "github.com/stretchr/testify/assert"
+ "net"
+ "os"
+ "reflect"
+ "testing"
+)
+
+func getLogger() *log.Logger {
+ var l *log.Logger = &log.Logger{
+ Out: os.Stderr,
+ Formatter: new(log.JSONFormatter),
+ Hooks: make(map[log.Level][]log.Hook),
+ Level: log.InfoLevel,
+ }
+ return l
+}
+
+func peerR1() *Peer {
+ proto := &BgpProtocol{}
+ proto.sentOpenMsg = bgp.NewBGPOpenMessage(65000, 300, "10.0.0.1", nil).Body.(*bgp.BGPOpen)
+ proto.recvOpenMsg = bgp.NewBGPOpenMessage(65000, 300, "10.0.0.3", nil).Body.(*bgp.BGPOpen)
+
+ peer := &Peer{
+ VersionNum: 4,
+ RemoteAs: 65000,
+ protocol: proto,
+ }
+ return peer
+}
+
+func peerR2() *Peer {
+ peer := &Peer{
+ VersionNum: 4,
+ RemoteAs: 65100,
+ }
+ return peer
+}
+
+func peerR3() *Peer {
+ proto := &BgpProtocol{}
+ proto.sentOpenMsg = bgp.NewBGPOpenMessage(65000, 300, "10.0.0.1", nil).Body.(*bgp.BGPOpen)
+ proto.recvOpenMsg = bgp.NewBGPOpenMessage(65000, 300, "10.0.0.2", nil).Body.(*bgp.BGPOpen)
+
+ peer := &Peer{
+ VersionNum: 4,
+ RemoteAs: 65000,
+ protocol: proto,
+ }
+ return peer
+}
+
+// test best path calculation and check the result path is from R1
+func TestProcessBGPUpdate_0_select_onlypath_ipv4(t *testing.T) {
+
+ tm := NewTableManager()
+ setLogger(getLogger())
+
+ bgpMessage := update_fromR1()
+ peer := peerR1()
+ pList, wList, err := tm.ProcessUpdate(peer, bgpMessage)
+ assert.Equal(t, len(pList), 1, "pList length should be 1")
+ assert.Equal(t, len(wList), 0, "wList length should be 0")
+ assert.NoError(t, err, "err should be nil")
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv4Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType, "best path should be *table.IPv4Path")
+
+ // check PathAttribute
+ pathAttributes := bgpMessage.Body.(*bgp.BGPUpdate).PathAttributes
+ expectedOrigin := pathAttributes[0]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin, "PathAttributeOrigin should be ", expectedOrigin)
+
+ expectedAsPath := pathAttributes[1]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath, "PathAttributeAsPath should be ", expectedAsPath)
+
+ expectedNexthopAttr := pathAttributes[2]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_NEXT_HOP).(*bgp.PathAttributeNextHop)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr, "PathAttributeNextHop should be ", expectedNexthopAttr)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed, "PathAttributeMed should be ", expectedMed)
+
+ // check PathAttribute length
+ assert.Equal(t, 4, path.getPathAttributeMap().Len(), "PathAttribute length should be ", 4)
+
+ // check destination
+ expectedPrefix := "10.10.10.0"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String(), "prefix should be ", expectedPrefix)
+ // check nexthop
+ expectedNexthop := "192.168.50.1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String(), "nexthop should be ", expectedNexthop)
+
+}
+
+// test best path calculation and check the result path is from R1
+func TestProcessBGPUpdate_0_select_onlypath_ipv6(t *testing.T) {
+
+ tm := NewTableManager()
+ setLogger(getLogger())
+
+ bgpMessage := update_fromR1_ipv6()
+ peer := peerR1()
+ pList, wList, err := tm.ProcessUpdate(peer, bgpMessage)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv6Path"
+ assert.Equal(t, expectedType, reflect.TypeOf(path).String(), "best path should be *table.IPv6Path")
+
+ // check PathAttribute
+ pathAttributes := bgpMessage.Body.(*bgp.BGPUpdate).PathAttributes
+
+ expectedNexthopAttr := pathAttributes[0]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI).(*bgp.PathAttributeMpReachNLRI)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr, "PathAttributeNextHop should be ", expectedNexthopAttr)
+
+ expectedOrigin := pathAttributes[1]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin, "PathAttributeOrigin should be ", expectedOrigin)
+
+ expectedAsPath := pathAttributes[2]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath, "PathAttributeAsPath should be ", expectedAsPath)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed, "PathAttributeMed should be ", expectedMed)
+
+ // check PathAttribute length
+ assert.Equal(t, 4, path.getPathAttributeMap().Len(), "PathAttribute length should be ", 4)
+
+ // check destination
+ expectedPrefix := "2001:123:123:1::"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String(), "prefix should be ", expectedPrefix)
+ // check nexthop
+ expectedNexthop := "2001::192:168:50:1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String(), "nexthop should be ", expectedNexthop)
+
+}
+
+// test: compare localpref
+func TestProcessBGPUpdate_1_select_high_localpref_ipv4(t *testing.T) {
+
+ tm := NewTableManager()
+ var pList, wList []Path
+ var err error
+
+ // low localpref message
+ origin1 := bgp.NewPathAttributeOrigin(0)
+ aspath1 := createAsPathAttribute([]uint16{65000})
+ nexthop1 := bgp.NewPathAttributeNextHop("192.168.50.1")
+ med1 := bgp.NewPathAttributeMultiExitDisc(0)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ origin1, aspath1, nexthop1, med1, localpref1,
+ }
+ nlri1 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ // high localpref message
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{65100, 65000})
+ nexthop2 := bgp.NewPathAttributeNextHop("192.168.50.1")
+ med2 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref2 := bgp.NewPathAttributeLocalPref(200)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ origin2, aspath2, nexthop2, med2, localpref2,
+ }
+ nlri2 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList), "pList length should be 1")
+ assert.Equal(t, 0, len(wList), "wList length should be 0")
+ assert.NoError(t, err, "err should be nil")
+
+ peer2 := peerR2()
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList), "pList length should be 1")
+ assert.Equal(t, 0, len(wList), "wList length should be 0")
+ assert.NoError(t, err, "err should be nil")
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv4Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType, "best path should be *table.IPv4Path")
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+ expectedOrigin := pathAttributes[0]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin, "PathAttributeOrigin should be ", expectedOrigin)
+
+ expectedAsPath := pathAttributes[1]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath, "PathAttributeAsPath should be ", expectedAsPath)
+
+ expectedNexthopAttr := pathAttributes[2]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_NEXT_HOP).(*bgp.PathAttributeNextHop)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr, "PathAttributeNextHop should be ", expectedNexthopAttr)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed, "PathAttributeMed should be ", expectedMed)
+
+ // check PathAttribute length
+ assert.Equal(t, len(pathAttributes2), path.getPathAttributeMap().Len(), "PathAttribute length should be ", 4)
+
+ // check destination
+ expectedPrefix := "10.10.10.0"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String(), "prefix should be ", expectedPrefix)
+ // check nexthop
+ expectedNexthop := "192.168.50.1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String(), "nexthop should be ", expectedNexthop)
+
+}
+
+func TestProcessBGPUpdate_1_select_high_localpref_ipv6(t *testing.T) {
+
+ tm := NewTableManager()
+ var pList, wList []Path
+ var err error
+
+ origin1 := bgp.NewPathAttributeOrigin(0)
+ aspath1 := createAsPathAttribute([]uint16{65000})
+ mp_reach1 := createMpReach("2001::192:168:50:1", "2001:123:123:1::", 64)
+ med1 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ mp_reach1, origin1, aspath1, med1, localpref1,
+ }
+
+ nlri1 := []bgp.NLRInfo{}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{65100, 65000})
+ mp_reach2 := createMpReach("2001::192:168:100:1", "2001:123:123:1::", 64)
+ med2 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref2 := bgp.NewPathAttributeLocalPref(200)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ mp_reach2, origin2, aspath2, med2, localpref2,
+ }
+
+ nlri2 := []bgp.NLRInfo{}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ peer2 := peerR2()
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv6Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+
+ expectedNexthopAttr := pathAttributes[0]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI).(*bgp.PathAttributeMpReachNLRI)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedOrigin := pathAttributes[1]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[2]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, 5, path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "2001:123:123:1::"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "2001::192:168:100:1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+// test: compare localOrigin
+func TestProcessBGPUpdate_2_select_local_origin_ipv4(t *testing.T) {
+
+ tm := NewTableManager()
+ var pList, wList []Path
+ var err error
+
+ // low localpref message
+ origin1 := bgp.NewPathAttributeOrigin(0)
+ aspath1 := createAsPathAttribute([]uint16{65000})
+ nexthop1 := bgp.NewPathAttributeNextHop("192.168.50.1")
+ med1 := bgp.NewPathAttributeMultiExitDisc(0)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ origin1, aspath1, nexthop1, med1, localpref1,
+ }
+ nlri1 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ // high localpref message
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{})
+ nexthop2 := bgp.NewPathAttributeNextHop("0.0.0.0")
+ med2 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref2 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ origin2, aspath2, nexthop2, med2, localpref2,
+ }
+ nlri2 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ var peer2 *Peer = nil
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv4Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+ expectedOrigin := pathAttributes[0]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[1]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedNexthopAttr := pathAttributes[2]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_NEXT_HOP).(*bgp.PathAttributeNextHop)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, len(pathAttributes2), path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "10.10.10.0"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "0.0.0.0"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+func TestProcessBGPUpdate_2_select_local_origin_ipv6(t *testing.T) {
+
+ tm := NewTableManager()
+ var pList, wList []Path
+ var err error
+
+ origin1 := bgp.NewPathAttributeOrigin(0)
+ aspath1 := createAsPathAttribute([]uint16{65000})
+ mp_reach1 := createMpReach("2001::192:168:50:1", "2001:123:123:1::", 64)
+ med1 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ mp_reach1, origin1, aspath1, med1, localpref1,
+ }
+
+ nlri1 := []bgp.NLRInfo{}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{})
+ mp_reach2 := createMpReach("::", "2001:123:123:1::", 64)
+ med2 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref2 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ mp_reach2, origin2, aspath2, med2, localpref2,
+ }
+
+ nlri2 := []bgp.NLRInfo{}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ var peer2 *Peer = nil
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv6Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+
+ expectedNexthopAttr := pathAttributes[0]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI).(*bgp.PathAttributeMpReachNLRI)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedOrigin := pathAttributes[1]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[2]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, 5, path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "2001:123:123:1::"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "::"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+// test: compare AS_PATH
+func TestProcessBGPUpdate_3_select_aspath_ipv4(t *testing.T) {
+
+ tm := NewTableManager()
+ var pList, wList []Path
+ var err error
+
+ bgpMessage1 := update_fromR2viaR1()
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList), "pList length should be 1")
+ assert.Equal(t, 0, len(wList), "wList length should be 0")
+ assert.NoError(t, err, "err should be nil")
+ bgpMessage2 := update_fromR2()
+ peer2 := peerR2()
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList), "pList length should be 1")
+ assert.Equal(t, 0, len(wList), "wList length should be 0")
+ assert.NoError(t, err, "err should be nil")
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv4Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType, "best path should be *table.IPv4Path")
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+ expectedOrigin := pathAttributes[0]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin, "PathAttributeOrigin should be ", expectedOrigin)
+
+ expectedAsPath := pathAttributes[1]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath, "PathAttributeAsPath should be ", expectedAsPath)
+
+ expectedNexthopAttr := pathAttributes[2]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_NEXT_HOP).(*bgp.PathAttributeNextHop)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr, "PathAttributeNextHop should be ", expectedNexthopAttr)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed, "PathAttributeMed should be ", expectedMed)
+
+ // check PathAttribute length
+ assert.Equal(t, 4, path.getPathAttributeMap().Len(), "PathAttribute length should be ", 4)
+
+ // check destination
+ expectedPrefix := "20.20.20.0"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String(), "prefix should be ", expectedPrefix)
+ // check nexthop
+ expectedNexthop := "192.168.100.1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String(), "nexthop should be ", expectedNexthop)
+
+}
+
+func TestProcessBGPUpdate_3_select_aspath_ipv6(t *testing.T) {
+
+ tm := NewTableManager()
+ var pList, wList []Path
+ var err error
+
+ bgpMessage1 := update_fromR2viaR1_ipv6()
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+ bgpMessage2 := update_fromR2_ipv6()
+ peer2 := peerR2()
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv6Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType, "best path should be *table.IPv6Path")
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+
+ expectedNexthopAttr := pathAttributes[0]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI).(*bgp.PathAttributeMpReachNLRI)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr, "PathAttributeNextHop should be ", expectedNexthopAttr)
+
+ expectedOrigin := pathAttributes[1]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin, "PathAttributeOrigin should be ", expectedOrigin)
+
+ expectedAsPath := pathAttributes[2]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath, "PathAttributeAsPath should be ", expectedAsPath)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed, "PathAttributeMed should be ", expectedMed)
+
+ // check PathAttribute length
+ assert.Equal(t, 4, path.getPathAttributeMap().Len(), "PathAttribute length should be ", 4)
+
+ // check destination
+ expectedPrefix := "2002:223:123:1::"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String(), "prefix should be ", expectedPrefix)
+ // check nexthop
+ expectedNexthop := "2001::192:168:100:1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String(), "nexthop should be ", expectedNexthop)
+
+}
+
+// test: compare Origin
+func TestProcessBGPUpdate_4_select_low_origin_ipv4(t *testing.T) {
+
+ tm := NewTableManager()
+ var pList, wList []Path
+ var err error
+
+ // low origin message
+ origin1 := bgp.NewPathAttributeOrigin(1)
+ aspath1 := createAsPathAttribute([]uint16{65200, 65000})
+ nexthop1 := bgp.NewPathAttributeNextHop("192.168.50.1")
+ med1 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ origin1, aspath1, nexthop1, med1, localpref1,
+ }
+ nlri1 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ // high origin message
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{65100, 65000})
+ nexthop2 := bgp.NewPathAttributeNextHop("192.168.100.1")
+ med2 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref2 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ origin2, aspath2, nexthop2, med2, localpref2,
+ }
+ nlri2 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ peer2 := peerR2()
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv4Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+ expectedOrigin := pathAttributes[0]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[1]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedNexthopAttr := pathAttributes[2]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_NEXT_HOP).(*bgp.PathAttributeNextHop)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, len(pathAttributes2), path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "10.10.10.0"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "192.168.100.1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+func TestProcessBGPUpdate_4_select_low_origin_ipv6(t *testing.T) {
+
+ tm := NewTableManager()
+ var pList, wList []Path
+ var err error
+
+ origin1 := bgp.NewPathAttributeOrigin(1)
+ aspath1 := createAsPathAttribute([]uint16{65200, 65000})
+ mp_reach1 := createMpReach("2001::192:168:50:1", "2001:123:123:1::", 64)
+ med1 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ mp_reach1, origin1, aspath1, med1, localpref1,
+ }
+
+ nlri1 := []bgp.NLRInfo{}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{65100, 65000})
+ mp_reach2 := createMpReach("2001::192:168:100:1", "2001:123:123:1::", 64)
+ med2 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref2 := bgp.NewPathAttributeLocalPref(200)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ mp_reach2, origin2, aspath2, med2, localpref2,
+ }
+
+ nlri2 := []bgp.NLRInfo{}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ peer2 := peerR2()
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv6Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+
+ expectedNexthopAttr := pathAttributes[0]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI).(*bgp.PathAttributeMpReachNLRI)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedOrigin := pathAttributes[1]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[2]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, 5, path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "2001:123:123:1::"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "2001::192:168:100:1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+// test: compare MED
+func TestProcessBGPUpdate_5_select_low_med_ipv4(t *testing.T) {
+
+ tm := NewTableManager()
+ var pList, wList []Path
+ var err error
+
+ // low origin message
+ origin1 := bgp.NewPathAttributeOrigin(0)
+ aspath1 := createAsPathAttribute([]uint16{65200, 65000})
+ nexthop1 := bgp.NewPathAttributeNextHop("192.168.50.1")
+ med1 := bgp.NewPathAttributeMultiExitDisc(500)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ origin1, aspath1, nexthop1, med1, localpref1,
+ }
+ nlri1 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ // high origin message
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{65100, 65000})
+ nexthop2 := bgp.NewPathAttributeNextHop("192.168.100.1")
+ med2 := bgp.NewPathAttributeMultiExitDisc(100)
+ localpref2 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ origin2, aspath2, nexthop2, med2, localpref2,
+ }
+ nlri2 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ peer2 := peerR2()
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv4Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+ expectedOrigin := pathAttributes[0]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[1]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedNexthopAttr := pathAttributes[2]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_NEXT_HOP).(*bgp.PathAttributeNextHop)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, len(pathAttributes2), path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "10.10.10.0"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "192.168.100.1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+func TestProcessBGPUpdate_5_select_low_med_ipv6(t *testing.T) {
+
+ tm := NewTableManager()
+ var pList, wList []Path
+ var err error
+
+ origin1 := bgp.NewPathAttributeOrigin(0)
+ aspath1 := createAsPathAttribute([]uint16{65200, 65000})
+ mp_reach1 := createMpReach("2001::192:168:50:1", "2001:123:123:1::", 64)
+ med1 := bgp.NewPathAttributeMultiExitDisc(500)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ mp_reach1, origin1, aspath1, med1, localpref1,
+ }
+
+ nlri1 := []bgp.NLRInfo{}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{65100, 65000})
+ mp_reach2 := createMpReach("2001::192:168:100:1", "2001:123:123:1::", 64)
+ med2 := bgp.NewPathAttributeMultiExitDisc(200)
+ localpref2 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ mp_reach2, origin2, aspath2, med2, localpref2,
+ }
+
+ nlri2 := []bgp.NLRInfo{}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ peer2 := peerR2()
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv6Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+
+ expectedNexthopAttr := pathAttributes[0]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI).(*bgp.PathAttributeMpReachNLRI)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedOrigin := pathAttributes[1]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[2]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, 5, path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "2001:123:123:1::"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "2001::192:168:100:1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+// test: compare AS_NUMBER(prefer eBGP path)
+func TestProcessBGPUpdate_6_select_ebgp_path_ipv4(t *testing.T) {
+
+ tm := NewTableManager()
+ tm.localAsn = uint32(65000)
+
+ var pList, wList []Path
+ var err error
+
+ // low origin message
+ origin1 := bgp.NewPathAttributeOrigin(0)
+ aspath1 := createAsPathAttribute([]uint16{65000, 65200})
+ nexthop1 := bgp.NewPathAttributeNextHop("192.168.50.1")
+ med1 := bgp.NewPathAttributeMultiExitDisc(200)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ origin1, aspath1, nexthop1, med1, localpref1,
+ }
+ nlri1 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ // high origin message
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{65100, 65000})
+ nexthop2 := bgp.NewPathAttributeNextHop("192.168.100.1")
+ med2 := bgp.NewPathAttributeMultiExitDisc(200)
+ localpref2 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ origin2, aspath2, nexthop2, med2, localpref2,
+ }
+ nlri2 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ peer2 := peerR2()
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv4Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+ expectedOrigin := pathAttributes[0]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[1]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedNexthopAttr := pathAttributes[2]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_NEXT_HOP).(*bgp.PathAttributeNextHop)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, len(pathAttributes2), path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "10.10.10.0"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "192.168.100.1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+func TestProcessBGPUpdate_6_select_ebgp_path_ipv6(t *testing.T) {
+
+ tm := NewTableManager()
+ tm.localAsn = uint32(65000)
+ var pList, wList []Path
+ var err error
+
+ origin1 := bgp.NewPathAttributeOrigin(0)
+ aspath1 := createAsPathAttribute([]uint16{65000, 65200})
+ mp_reach1 := createMpReach("2001::192:168:50:1", "2001:123:123:1::", 64)
+ med1 := bgp.NewPathAttributeMultiExitDisc(200)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ mp_reach1, origin1, aspath1, med1, localpref1,
+ }
+
+ nlri1 := []bgp.NLRInfo{}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{65100, 65200})
+ mp_reach2 := createMpReach("2001::192:168:100:1", "2001:123:123:1::", 64)
+ med2 := bgp.NewPathAttributeMultiExitDisc(200)
+ localpref2 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ mp_reach2, origin2, aspath2, med2, localpref2,
+ }
+
+ nlri2 := []bgp.NLRInfo{}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ peer2 := peerR2()
+ pList, wList, err = tm.ProcessUpdate(peer2, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv6Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+
+ expectedNexthopAttr := pathAttributes[0]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI).(*bgp.PathAttributeMpReachNLRI)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedOrigin := pathAttributes[1]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[2]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, 5, path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "2001:123:123:1::"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "2001::192:168:100:1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+// test: compare IGP cost -> N/A
+
+// test: compare Router ID
+func TestProcessBGPUpdate_7_select_low_routerid_path_ipv4(t *testing.T) {
+
+ tm := NewTableManager()
+ tm.localAsn = uint32(65000)
+
+ var pList, wList []Path
+ var err error
+
+ // low origin message
+ origin1 := bgp.NewPathAttributeOrigin(0)
+ aspath1 := createAsPathAttribute([]uint16{65000, 65200})
+ nexthop1 := bgp.NewPathAttributeNextHop("192.168.50.1")
+ med1 := bgp.NewPathAttributeMultiExitDisc(200)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ origin1, aspath1, nexthop1, med1, localpref1,
+ }
+ nlri1 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ // high origin message
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{65000, 65100})
+ nexthop2 := bgp.NewPathAttributeNextHop("192.168.100.1")
+ med2 := bgp.NewPathAttributeMultiExitDisc(200)
+ localpref2 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ origin2, aspath2, nexthop2, med2, localpref2,
+ }
+ nlri2 := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ peer3 := peerR3()
+ pList, wList, err = tm.ProcessUpdate(peer3, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err)
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv4Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+ expectedOrigin := pathAttributes[0]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[1]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedNexthopAttr := pathAttributes[2]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_NEXT_HOP).(*bgp.PathAttributeNextHop)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, len(pathAttributes2), path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "10.10.10.0"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "192.168.100.1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+func TestProcessBGPUpdate_7_select_low_routerid_path_ipv6(t *testing.T) {
+
+ tm := NewTableManager()
+ tm.localAsn = uint32(65000)
+ var pList, wList []Path
+ var err error
+
+ origin1 := bgp.NewPathAttributeOrigin(0)
+ aspath1 := createAsPathAttribute([]uint16{65000, 65200})
+ mp_reach1 := createMpReach("2001::192:168:50:1", "2001:123:123:1::", 64)
+ med1 := bgp.NewPathAttributeMultiExitDisc(200)
+ localpref1 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes1 := []bgp.PathAttributeInterface{
+ mp_reach1, origin1, aspath1, med1, localpref1,
+ }
+
+ nlri1 := []bgp.NLRInfo{}
+ withdrawnRoutes1 := []bgp.WithdrawnRoute{}
+ bgpMessage1 := bgp.NewBGPUpdateMessage(withdrawnRoutes1, pathAttributes1, nlri1)
+
+ origin2 := bgp.NewPathAttributeOrigin(0)
+ aspath2 := createAsPathAttribute([]uint16{65100, 65200})
+ mp_reach2 := createMpReach("2001::192:168:100:1", "2001:123:123:1::", 64)
+ med2 := bgp.NewPathAttributeMultiExitDisc(200)
+ localpref2 := bgp.NewPathAttributeLocalPref(100)
+
+ pathAttributes2 := []bgp.PathAttributeInterface{
+ mp_reach2, origin2, aspath2, med2, localpref2,
+ }
+
+ nlri2 := []bgp.NLRInfo{}
+ withdrawnRoutes2 := []bgp.WithdrawnRoute{}
+ bgpMessage2 := bgp.NewBGPUpdateMessage(withdrawnRoutes2, pathAttributes2, nlri2)
+
+ peer1 := peerR1()
+ pList, wList, err = tm.ProcessUpdate(peer1, bgpMessage1)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ peer3 := peerR3()
+ pList, wList, err = tm.ProcessUpdate(peer3, bgpMessage2)
+ assert.Equal(t, 1, len(pList))
+ assert.Equal(t, 0, len(wList))
+ assert.NoError(t, err, "err should be nil")
+
+ // check type
+ path := pList[0]
+ expectedType := "*table.IPv6Path"
+ assert.Equal(t, reflect.TypeOf(path).String(), expectedType)
+
+ // check PathAttribute
+ pathAttributes := bgpMessage2.Body.(*bgp.BGPUpdate).PathAttributes
+
+ expectedNexthopAttr := pathAttributes[0]
+ pathNexthop := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI).(*bgp.PathAttributeMpReachNLRI)
+ assert.Equal(t, pathNexthop, expectedNexthopAttr)
+
+ expectedOrigin := pathAttributes[1]
+ pathOrigin := path.getPathAttribute(bgp.BGP_ATTR_TYPE_ORIGIN).(*bgp.PathAttributeOrigin)
+ assert.Equal(t, pathOrigin, expectedOrigin)
+
+ expectedAsPath := pathAttributes[2]
+ pathAspath := path.getPathAttribute(bgp.BGP_ATTR_TYPE_AS_PATH).(*bgp.PathAttributeAsPath)
+ assert.Equal(t, pathAspath, expectedAsPath)
+
+ expectedMed := pathAttributes[3]
+ pathMed := path.getPathAttribute(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC).(*bgp.PathAttributeMultiExitDisc)
+ assert.Equal(t, expectedMed, pathMed)
+
+ // check PathAttribute length
+ assert.Equal(t, 5, path.getPathAttributeMap().Len())
+
+ // check destination
+ expectedPrefix := "2001:123:123:1::"
+ assert.Equal(t, expectedPrefix, path.getPrefix().String())
+ // check nexthop
+ expectedNexthop := "2001::192:168:100:1"
+ assert.Equal(t, expectedNexthop, path.getNexthop().String())
+
+}
+
+func update_fromR1() *bgp.BGPMessage {
+
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65000})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("192.168.50.1")
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+
+ pathAttributes := []bgp.PathAttributeInterface{
+ origin,
+ aspath,
+ nexthop,
+ med,
+ }
+
+ nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.10.0")}
+ withdrawnRoutes := []bgp.WithdrawnRoute{}
+
+ return bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+}
+
+func update_fromR1_ipv6() *bgp.BGPMessage {
+
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65000})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+
+ mp_nlri := []bgp.AddrPrefixInterface{bgp.NewIPv6AddrPrefix(64, "2001:123:123:1::")}
+ mp_reach := bgp.NewPathAttributeMpReachNLRI("2001::192:168:50:1", mp_nlri)
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+
+ pathAttributes := []bgp.PathAttributeInterface{
+ mp_reach,
+ origin,
+ aspath,
+ med,
+ }
+ nlri := []bgp.NLRInfo{}
+ withdrawnRoutes := []bgp.WithdrawnRoute{}
+ return bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+}
+
+func update_fromR2() *bgp.BGPMessage {
+
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("192.168.100.1")
+ med := bgp.NewPathAttributeMultiExitDisc(100)
+
+ pathAttributes := []bgp.PathAttributeInterface{
+ origin,
+ aspath,
+ nexthop,
+ med,
+ }
+
+ nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "20.20.20.0")}
+ withdrawnRoutes := []bgp.WithdrawnRoute{}
+ return bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+}
+
+func update_fromR2_ipv6() *bgp.BGPMessage {
+
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspath := createAsPathAttribute([]uint16{65100})
+ mp_reach := createMpReach("2001::192:168:100:1", "2002:223:123:1::", 64)
+ med := bgp.NewPathAttributeMultiExitDisc(100)
+
+ pathAttributes := []bgp.PathAttributeInterface{
+ mp_reach,
+ origin,
+ aspath,
+ med,
+ }
+ nlri := []bgp.NLRInfo{}
+ withdrawnRoutes := []bgp.WithdrawnRoute{}
+ return bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+}
+
+func createAsPathAttribute(ases []uint16) *bgp.PathAttributeAsPath {
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, ases)}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ return aspath
+}
+
+func createMpReach(nexthop, nlri string, len uint8) *bgp.PathAttributeMpReachNLRI {
+ mp_nlri := []bgp.AddrPrefixInterface{bgp.NewIPv6AddrPrefix(len, nlri)}
+ mp_reach := bgp.NewPathAttributeMpReachNLRI(nexthop, mp_nlri)
+ return mp_reach
+}
+
+func update_fromR2viaR1() *bgp.BGPMessage {
+
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65000, 65100})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("192.168.50.1")
+
+ pathAttributes := []bgp.PathAttributeInterface{
+ origin,
+ aspath,
+ nexthop,
+ }
+
+ nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "20.20.20.0")}
+ withdrawnRoutes := []bgp.WithdrawnRoute{}
+ return bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+}
+
+func update_fromR2viaR1_ipv6() *bgp.BGPMessage {
+
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspath := createAsPathAttribute([]uint16{65000, 65100})
+ mp_reach := createMpReach("2001::192:168:50:1", "2002:223:123:1::", 64)
+ med := bgp.NewPathAttributeMultiExitDisc(100)
+
+ pathAttributes := []bgp.PathAttributeInterface{
+ mp_reach,
+ origin,
+ aspath,
+ med,
+ }
+ nlri := []bgp.NLRInfo{}
+ withdrawnRoutes := []bgp.WithdrawnRoute{}
+ return bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+
+}
+
+func update() *bgp.BGPMessage {
+ w1 := bgp.WithdrawnRoute{*bgp.NewIPAddrPrefix(23, "121.1.3.2")}
+ w2 := bgp.WithdrawnRoute{*bgp.NewIPAddrPrefix(17, "100.33.3.0")}
+ w := []bgp.WithdrawnRoute{w1, w2}
+ //w := []WithdrawnRoute{}
+
+ aspath1 := []bgp.AsPathParamInterface{
+ bgp.NewAsPathParam(2, []uint16{1000}),
+ bgp.NewAsPathParam(1, []uint16{1001, 1002}),
+ bgp.NewAsPathParam(2, []uint16{1003, 1004}),
+ }
+
+ aspath2 := []bgp.AsPathParamInterface{
+ bgp.NewAs4PathParam(2, []uint32{1000000}),
+ bgp.NewAs4PathParam(1, []uint32{1000001, 1002}),
+ bgp.NewAs4PathParam(2, []uint32{1003, 100004}),
+ }
+
+ aspath3 := []*bgp.As4PathParam{
+ bgp.NewAs4PathParam(2, []uint32{1000000}),
+ bgp.NewAs4PathParam(1, []uint32{1000001, 1002}),
+ bgp.NewAs4PathParam(2, []uint32{1003, 100004}),
+ }
+
+ ecommunities := []bgp.ExtendedCommunityInterface{
+ &bgp.TwoOctetAsSpecificExtended{SubType: 1, AS: 10003, LocalAdmin: 3 << 20},
+ &bgp.FourOctetAsSpecificExtended{SubType: 2, AS: 1 << 20, LocalAdmin: 300},
+ &bgp.IPv4AddressSpecificExtended{SubType: 3, IPv4: net.ParseIP("192.2.1.2").To4(), LocalAdmin: 3000},
+ &bgp.OpaqueExtended{Value: []byte{0, 1, 2, 3, 4, 5, 6, 7}},
+ &bgp.UnknownExtended{Type: 99, Value: []byte{0, 1, 2, 3, 4, 5, 6, 7}},
+ }
+
+ mp_nlri := []bgp.AddrPrefixInterface{
+ bgp.NewLabelledVPNIPAddrPrefix(20, "192.0.9.0", *bgp.NewLabel(1, 2, 3),
+ bgp.NewRouteDistinguisherTwoOctetAS(256, 10000)),
+ bgp.NewLabelledVPNIPAddrPrefix(26, "192.10.8.192", *bgp.NewLabel(5, 6, 7, 8),
+ bgp.NewRouteDistinguisherIPAddressAS("10.0.1.1", 10001)),
+ }
+
+ mp_nlri2 := []bgp.AddrPrefixInterface{bgp.NewIPv6AddrPrefix(100,
+ "fe80:1234:1234:5667:8967:af12:8912:1023")}
+
+ mp_nlri3 := []bgp.AddrPrefixInterface{bgp.NewLabelledVPNIPv6AddrPrefix(100,
+ "fe80:1234:1234:5667:8967:af12:1203:33a1", *bgp.NewLabel(5, 6),
+ bgp.NewRouteDistinguisherFourOctetAS(5, 6))}
+
+ mp_nlri4 := []bgp.AddrPrefixInterface{bgp.NewLabelledIPAddrPrefix(25, "192.168.0.0",
+ *bgp.NewLabel(5, 6, 7))}
+
+ p := []bgp.PathAttributeInterface{
+ bgp.NewPathAttributeOrigin(3),
+ bgp.NewPathAttributeAsPath(aspath1),
+ bgp.NewPathAttributeAsPath(aspath2),
+ bgp.NewPathAttributeNextHop("129.1.1.2"),
+ bgp.NewPathAttributeMultiExitDisc(1 << 20),
+ bgp.NewPathAttributeLocalPref(1 << 22),
+ bgp.NewPathAttributeAtomicAggregate(),
+ bgp.NewPathAttributeAggregator(uint16(30002), "129.0.2.99"),
+ bgp.NewPathAttributeAggregator(uint32(30002), "129.0.2.99"),
+ bgp.NewPathAttributeAggregator(uint32(300020), "129.0.2.99"),
+ bgp.NewPathAttributeCommunities([]uint32{1, 3}),
+ bgp.NewPathAttributeOriginatorId("10.10.0.1"),
+ bgp.NewPathAttributeClusterList([]string{"10.10.0.2", "10.10.0.3"}),
+ bgp.NewPathAttributeExtendedCommunities(ecommunities),
+ bgp.NewPathAttributeAs4Path(aspath3),
+ bgp.NewPathAttributeAs4Aggregator(10000, "112.22.2.1"),
+ bgp.NewPathAttributeMpReachNLRI("112.22.2.0", mp_nlri),
+ bgp.NewPathAttributeMpReachNLRI("1023::", mp_nlri2),
+ bgp.NewPathAttributeMpReachNLRI("fe80::", mp_nlri3),
+ bgp.NewPathAttributeMpReachNLRI("129.1.1.1", mp_nlri4),
+ bgp.NewPathAttributeMpUnreachNLRI(mp_nlri),
+ &bgp.PathAttributeUnknown{
+ PathAttribute: bgp.PathAttribute{
+ Flags: 1,
+ Type: 100,
+ Value: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ },
+ },
+ }
+ n := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "13.2.3.1")}
+ return bgp.NewBGPUpdateMessage(w, p, n)
+}
diff --git a/table/temporary_structs.go b/table/temporary_structs.go
new file mode 100644
index 00000000..6350d2e7
--- /dev/null
+++ b/table/temporary_structs.go
@@ -0,0 +1,34 @@
+// core.go
+package table
+
+import (
+ "github.com/osrg/gobgp/packet"
+ "net"
+)
+
+type CoreService struct {
+ CommonConf *Commons
+ NeighborsConf *Neighbors
+}
+type Neighbors struct {
+ //need to define a structure
+}
+type Commons struct {
+ //need to define a structure
+}
+type Peer struct {
+ //need to define a structure
+ RemoteAs uint32
+ VersionNum int
+ RemoteAddress net.IP
+ protocol *BgpProtocol
+}
+type SentRoute struct {
+ path Path
+ peer *Peer
+}
+type BgpProtocol struct {
+ //need to define a structure
+ recvOpenMsg *bgp.BGPOpen
+ sentOpenMsg *bgp.BGPOpen
+}