func newIPRouteMessage(path *table.Path) *zebra.Message { l := strings.SplitN(path.GetNlri().String(), "/", 2) var command zebra.API_TYPE var prefix net.IP nexthops := []net.IP{} switch path.GetRouteFamily() { case bgp.RF_IPv4_UC: if path.IsWithdraw == true { command = zebra.IPV4_ROUTE_DELETE } else { command = zebra.IPV4_ROUTE_ADD } prefix = net.ParseIP(l[0]).To4() nexthops = append(nexthops, path.GetNexthop().To4()) case bgp.RF_IPv6_UC: if path.IsWithdraw == true { command = zebra.IPV6_ROUTE_DELETE } else { command = zebra.IPV6_ROUTE_ADD } prefix = net.ParseIP(l[0]).To16() nexthops = append(nexthops, path.GetNexthop().To16()) default: return nil } flags := uint8(zebra.MESSAGE_NEXTHOP) plen, _ := strconv.Atoi(l[1]) med, err := path.GetMed() if err == nil { flags |= zebra.MESSAGE_METRIC } return &zebra.Message{ Header: zebra.Header{ Len: zebra.HEADER_SIZE, Marker: zebra.HEADER_MARKER, Version: zebra.VERSION, Command: command, }, Body: &zebra.IPRouteBody{ Type: zebra.ROUTE_BGP, SAFI: zebra.SAFI_UNICAST, Message: flags, Prefix: prefix, PrefixLength: uint8(plen), Nexthops: nexthops, Metric: med, }, } }
func ipPrefixCalculate(path *table.Path, cPrefix Prefix) bool { rf := path.GetRouteFamily() log.Debug("path routefamily : ", rf.String()) var pAddr net.IP var pMasklen uint8 if rf != cPrefix.AddressFamily { return false } switch rf { case bgp.RF_IPv4_UC: pAddr = path.GetNlri().(*bgp.NLRInfo).IPAddrPrefix.Prefix pMasklen = path.GetNlri().(*bgp.NLRInfo).IPAddrPrefix.Length case bgp.RF_IPv6_UC: pAddr = path.GetNlri().(*bgp.IPv6AddrPrefix).Prefix pMasklen = path.GetNlri().(*bgp.IPv6AddrPrefix).Length default: return false } cp := fmt.Sprintf("%s/%d", cPrefix.Address, cPrefix.Masklength) rMin, okMin := cPrefix.MasklengthRange[MASK_LENGTH_RANGE_MIN] rMax, okMax := cPrefix.MasklengthRange[MASK_LENGTH_RANGE_MAX] if !okMin && !okMax { if pAddr.Equal(cPrefix.Address) && pMasklen == cPrefix.Masklength { return true } else { return false } } _, ipNet, e := net.ParseCIDR(cp) if e != nil { log.WithFields(log.Fields{ "Topic": "Policy", "Prefix": ipNet, "Error": e, }).Error("failed to parse the prefix of condition") return false } if ipNet.Contains(pAddr) && (rMin <= pMasklen && pMasklen <= rMax) { return true } return false }
func (peer *Peer) filterpath(path *table.Path) *table.Path { // special handling for RTC nlri // see comments in (*Destination).Calculate() if path != nil && path.GetRouteFamily() == bgp.RF_RTC_UC && !path.IsWithdraw { // if we already sent the same nlri, ignore this if peer.adjRibOut.Exists(path) { return nil } dst := peer.localRib.GetDestination(path) path = nil // we send a path even if it is not a best path for _, p := range dst.GetKnownPathList(peer.TableID()) { // just take care not to send back it if peer.ID() != p.GetSource().Address.String() { path = p break } } } if filterpath(peer, path) == nil { return nil } if !peer.isRouteServerClient() { path = path.Clone(path.IsWithdraw) path.UpdatePathAttrs(peer.fsm.gConf, peer.fsm.pConf) } options := &table.PolicyOptions{ Info: peer.fsm.peerInfo, } path = peer.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_EXPORT, path, options) // remove local-pref attribute // we should do this after applying export policy since policy may // set local-preference if path != nil && peer.fsm.pConf.Config.PeerType == config.PEER_TYPE_EXTERNAL { path.RemoveLocalPref() } return path }
func (peer *Peer) filterpath(path, old *table.Path) *table.Path { // special handling for RTC nlri // see comments in (*Destination).Calculate() if path != nil && path.GetRouteFamily() == bgp.RF_RTC_UC && !path.IsWithdraw { // If we already sent the same nlri, send unnecessary // update. Fix this after the API change between table // and server packages. dst := peer.localRib.GetDestination(path) path = nil // we send a path even if it is not a best path for _, p := range dst.GetKnownPathList(peer.TableID()) { // just take care not to send back it if peer.ID() != p.GetSource().Address.String() { path = p break } } } // only allow vpnv4 and vpnv6 paths to be advertised to VRFed neighbors. // also check we can import this path using table.CanImportToVrf() // if we can, make it local path by calling (*Path).ToLocal() if path != nil && peer.fsm.pConf.Config.Vrf != "" { if f := path.GetRouteFamily(); f != bgp.RF_IPv4_VPN && f != bgp.RF_IPv6_VPN { return nil } vrf := peer.localRib.Vrfs[peer.fsm.pConf.Config.Vrf] if table.CanImportToVrf(vrf, path) { path = path.ToLocal() } else { return nil } } if path = filterpath(peer, path, old); path == nil { return nil } path = path.Clone(path.IsWithdraw) path.UpdatePathAttrs(peer.fsm.gConf, peer.fsm.pConf) options := &table.PolicyOptions{ Info: peer.fsm.peerInfo, } path = peer.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_EXPORT, path, options) // draft-uttaro-idr-bgp-persistence-02 // 4.3. Processing LLGR_STALE Routes // // The route SHOULD NOT be advertised to any neighbor from which the // Long-lived Graceful Restart Capability has not been received. The // exception is described in the Optional Partial Deployment // Procedure section (Section 4.7). Note that this requirement // implies that such routes should be withdrawn from any such neighbor. if path != nil && !path.IsWithdraw && !peer.isLLGREnabledFamily(path.GetRouteFamily()) && path.IsLLGRStale() { // we send unnecessary withdrawn even if we didn't // sent the route. path = path.Clone(true) } // remove local-pref attribute // we should do this after applying export policy since policy may // set local-preference if path != nil && !peer.isIBGPPeer() && !peer.isRouteServerClient() { path.RemoveLocalPref() } return path }