diff options
author | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2014-12-05 11:27:47 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2014-12-05 11:27:47 +0900 |
commit | 39686e18dbbbcfb32d891b86c3b1a978525bf370 (patch) | |
tree | 017001d6c617b9b521cebb9a65f04e1618ce338a /table/destination.go | |
parent | 9dd3001830c17f08ce659af003fb21b18df4883c (diff) |
table: add initial code
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Diffstat (limited to 'table/destination.go')
-rw-r--r-- | table/destination.go | 835 |
1 files changed, 835 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 +} |