summaryrefslogtreecommitdiffhomepage
path: root/server/peer.go
diff options
context:
space:
mode:
Diffstat (limited to 'server/peer.go')
-rw-r--r--server/peer.go1080
1 files changed, 174 insertions, 906 deletions
diff --git a/server/peer.go b/server/peer.go
index 63c907ee..f3b6caf0 100644
--- a/server/peer.go
+++ b/server/peer.go
@@ -17,198 +17,77 @@ package server
import (
"encoding/json"
- "fmt"
log "github.com/Sirupsen/logrus"
"github.com/osrg/gobgp/api"
"github.com/osrg/gobgp/config"
"github.com/osrg/gobgp/packet"
"github.com/osrg/gobgp/policy"
"github.com/osrg/gobgp/table"
- "gopkg.in/tomb.v2"
"net"
- "strconv"
"time"
)
const (
- FSM_CHANNEL_LENGTH = 1024
- FLOP_THRESHOLD = time.Second * 30
- MIN_CONNECT_RETRY = 10
+ FLOP_THRESHOLD = time.Second * 30
+ MIN_CONNECT_RETRY = 10
)
-type peerMsgType int
-
-const (
- _ peerMsgType = iota
- PEER_MSG_PATH
- PEER_MSG_PEER_DOWN
-)
-
-type peerMsg struct {
- msgType peerMsgType
- msgData interface{}
-}
-
type Peer struct {
- t tomb.Tomb
globalConfig config.Global
- peerConfig config.Neighbor
- connCh chan net.Conn
- serverMsgCh chan *serverMsg
- peerMsgCh chan *peerMsg
- getActiveCh chan struct{}
+ config config.Neighbor
fsm *FSM
+ rfMap map[bgp.RouteFamily]bool
+ capMap map[bgp.BGPCapabilityCode]bgp.ParameterCapabilityInterface
adjRib *table.AdjRib
- // peer and rib are always not one-to-one so should not be
- // here but it's the simplest and works our first target.
- rib *table.TableManager
- isGlobalRib bool
- rfMap map[bgp.RouteFamily]bool
- capMap map[bgp.BGPCapabilityCode]bgp.ParameterCapabilityInterface
- peerInfo *table.PeerInfo
- siblings map[string]*serverMsgDataPeer
- outgoing chan *bgp.BGPMessage
- importPolicies []*policy.Policy
- defaultImportPolicy config.DefaultPolicyType
- exportPolicies []*policy.Policy
- defaultExportPolicy config.DefaultPolicyType
+ peerInfo *table.PeerInfo
+ outgoing chan *bgp.BGPMessage
}
-func NewPeer(g config.Global, peer config.Neighbor, serverMsgCh chan *serverMsg, peerMsgCh chan *peerMsg, peerList []*serverMsgDataPeer, isGlobalRib bool, policyMap map[string]*policy.Policy) *Peer {
- p := &Peer{
+func NewPeer(g config.Global, config config.Neighbor) *Peer {
+ peer := &Peer{
globalConfig: g,
- peerConfig: peer,
- connCh: make(chan net.Conn),
- serverMsgCh: serverMsgCh,
- peerMsgCh: peerMsgCh,
- getActiveCh: make(chan struct{}),
+ config: config,
rfMap: make(map[bgp.RouteFamily]bool),
capMap: make(map[bgp.BGPCapabilityCode]bgp.ParameterCapabilityInterface),
- isGlobalRib: isGlobalRib,
- }
- p.siblings = make(map[string]*serverMsgDataPeer)
- for _, s := range peerList {
- p.siblings[s.address.String()] = s
}
- p.fsm = NewFSM(&g, &peer, p.connCh)
- peer.BgpNeighborCommonState.State = uint32(bgp.BGP_FSM_IDLE)
- peer.BgpNeighborCommonState.Downtime = time.Now().Unix()
- for _, rf := range peer.AfiSafiList {
+
+ config.BgpNeighborCommonState.State = uint32(bgp.BGP_FSM_IDLE)
+ config.BgpNeighborCommonState.Downtime = time.Now().Unix()
+ for _, rf := range config.AfiSafiList {
k, _ := bgp.GetRouteFamily(rf.AfiSafiName)
- p.rfMap[k] = true
+ peer.rfMap[k] = true
}
- p.peerInfo = &table.PeerInfo{
- AS: peer.PeerAs,
+ peer.peerInfo = &table.PeerInfo{
+ AS: config.PeerAs,
LocalID: g.RouterId,
- Address: peer.NeighborAddress,
- }
- if isGlobalRib {
- p.peerInfo.ID = g.RouterId
- }
- rfList := p.configuredRFlist()
- p.adjRib = table.NewAdjRib(rfList)
- p.rib = table.NewTableManager(p.peerConfig.NeighborAddress.String(), rfList)
- p.setPolicy(policyMap)
- p.t.Go(p.loop)
- if !peer.TransportOptions.PassiveMode && !isGlobalRib {
- p.t.Go(p.connectLoop)
+ Address: config.NeighborAddress,
}
- return p
+ peer.adjRib = table.NewAdjRib(peer.configuredRFlist())
+ peer.fsm = NewFSM(&g, &config)
+ return peer
}
-func (peer *Peer) setPolicy(policyMap map[string]*policy.Policy) {
- // configure import policy
- policyConfig := peer.peerConfig.ApplyPolicy
- inPolicies := make([]*policy.Policy, 0)
- for _, policyName := range policyConfig.ImportPolicies {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "PolicyName": policyName,
- }).Info("import policy installed")
- if pol, ok := policyMap[policyName]; ok {
- log.Debug("import policy : ", pol)
- inPolicies = append(inPolicies, pol)
- }
- }
- peer.importPolicies = inPolicies
- peer.defaultImportPolicy = policyConfig.DefaultImportPolicy
-
- // configure export policy
- outPolicies := make([]*policy.Policy, 0)
- for _, policyName := range policyConfig.ExportPolicies {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "PolicyName": policyName,
- }).Info("export policy installed")
- if pol, ok := policyMap[policyName]; ok {
- log.Debug("export policy : ", pol)
- outPolicies = append(outPolicies, pol)
- }
- }
- peer.exportPolicies = outPolicies
- peer.defaultExportPolicy = policyConfig.DefaultExportPolicy
+func (peer *Peer) isRouteServerClient() bool {
+ return peer.config.RouteServer.RouteServerClient
}
func (peer *Peer) configuredRFlist() []bgp.RouteFamily {
rfList := []bgp.RouteFamily{}
- for _, rf := range peer.peerConfig.AfiSafiList {
+ for _, rf := range peer.config.AfiSafiList {
k, _ := bgp.GetRouteFamily(rf.AfiSafiName)
rfList = append(rfList, k)
}
return rfList
}
-func (peer *Peer) sendPathsToSiblings(pathList []table.Path) {
- if len(pathList) == 0 {
- return
- }
- for _, s := range peer.siblings {
- var pm *peerMsg
- if peer.peerConfig.RouteServer.RouteServerClient {
- checkas := func(asnum uint32, p []table.Path) []table.Path {
- plist := []table.Path{}
- for _, path := range p {
- asList := path.GetAsList()
- send := true
- for _, as := range asList {
- if as == asnum {
- send = false
- break
- }
- }
- if send {
- plist = append(plist, path)
- }
- }
- return plist
- }
- p := checkas(s.As, pathList)
- if len(p) == 0 {
- continue
- } else {
- pm = &peerMsg{
- msgType: PEER_MSG_PATH,
- msgData: p,
- }
- }
- } else {
- pm = &peerMsg{
- msgType: PEER_MSG_PATH,
- msgData: pathList,
- }
- }
- s.peerMsgCh <- pm
- }
-}
-
-func (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) {
+func (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) ([]table.Path, bool) {
+ pathList := []table.Path{}
log.WithFields(log.Fields{
"Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
+ "Key": peer.config.NeighborAddress,
"data": m,
}).Debug("received")
+ update := false
switch m.Header.Type {
case bgp.BGP_MSG_OPEN:
@@ -245,7 +124,7 @@ func (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) {
// by using the smaller of its configured Hold Time and the Hold Time
// received in the OPEN message.
holdTime := float64(body.HoldTime)
- myHoldTime := peer.fsm.peerConfig.Timers.HoldTime
+ myHoldTime := peer.config.Timers.HoldTime
if holdTime > myHoldTime {
peer.fsm.negotiatedHoldTime = myHoldTime
} else {
@@ -258,791 +137,60 @@ func (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) {
if _, ok := peer.rfMap[rf]; !ok {
log.WithFields(log.Fields{
"Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
+ "Key": peer.config.NeighborAddress,
"Data": rf,
}).Warn("Route family isn't supported")
- return
+ break
}
if _, ok := peer.capMap[bgp.BGP_CAP_ROUTE_REFRESH]; ok {
- pathList := peer.adjRib.GetOutPathList(rf)
- peer.sendMessages(table.CreateUpdateMsgFromPaths(pathList))
+ pathList = peer.adjRib.GetOutPathList(rf)
} else {
log.WithFields(log.Fields{
"Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
+ "Key": peer.config.NeighborAddress,
}).Warn("ROUTE_REFRESH received but the capability wasn't advertised")
}
+
case bgp.BGP_MSG_UPDATE:
- peer.peerConfig.BgpNeighborCommonState.UpdateRecvTime = time.Now().Unix()
+ update = true
+ peer.config.BgpNeighborCommonState.UpdateRecvTime = time.Now().Unix()
body := m.Body.(*bgp.BGPUpdate)
_, err := bgp.ValidateUpdateMsg(body, peer.rfMap)
if err != nil {
log.WithFields(log.Fields{
"Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
+ "Key": peer.config.NeighborAddress,
"error": err,
}).Warn("malformed BGP update message")
m := err.(*bgp.MessageError)
if m.TypeCode != 0 {
peer.outgoing <- bgp.NewBGPNotificationMessage(m.TypeCode, m.SubTypeCode, m.Data)
}
- return
+ break
}
table.UpdatePathAttrs4ByteAs(body)
- pathList := table.ProcessMessage(m, peer.peerInfo)
+ pathList = table.ProcessMessage(m, peer.peerInfo)
peer.adjRib.UpdateIn(pathList)
- peer.sendPathsToSiblings(pathList)
- }
-}
-
-func (peer *Peer) sendMessages(msgs []*bgp.BGPMessage) {
- for _, m := range msgs {
- if peer.peerConfig.BgpNeighborCommonState.State != uint32(bgp.BGP_FSM_ESTABLISHED) {
- continue
- }
-
- if m.Header.Type != bgp.BGP_MSG_UPDATE {
- log.Fatal("not update message ", m.Header.Type)
- }
-
- _, y := peer.capMap[bgp.BGP_CAP_FOUR_OCTET_AS_NUMBER]
- if !y {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "data": m,
- }).Debug("update for 2byte AS peer")
- table.UpdatePathAttrs2ByteAs(m.Body.(*bgp.BGPUpdate))
- }
-
- peer.outgoing <- m
- }
-}
-
-func (peer *Peer) handleGrpc(grpcReq *GrpcRequest) {
- result := &GrpcResponse{}
- switch grpcReq.RequestType {
- case REQ_GLOBAL_ADD, REQ_GLOBAL_DELETE:
- rf := grpcReq.RouteFamily
- path, ok := grpcReq.Data.(*api.Path)
- if !ok {
- result.ResponseErr = fmt.Errorf("type assertion failed")
- grpcReq.ResponseCh <- result
- close(grpcReq.ResponseCh)
- return
- }
- var isWithdraw bool
- if grpcReq.RequestType == REQ_GLOBAL_DELETE {
- isWithdraw = true
- }
-
- var nlri bgp.AddrPrefixInterface
- pattr := make([]bgp.PathAttributeInterface, 0)
- pattr = append(pattr, bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP))
- asparam := bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{peer.peerInfo.AS})
- pattr = append(pattr, bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{asparam}))
-
- switch rf {
- case bgp.RF_IPv4_UC:
- ip, net, _ := net.ParseCIDR(path.Nlri.Prefix)
- if ip.To4() == nil {
- result.ResponseErr = fmt.Errorf("Invalid ipv4 prefix: %s", path.Nlri.Prefix)
- grpcReq.ResponseCh <- result
- close(grpcReq.ResponseCh)
- return
- }
- ones, _ := net.Mask.Size()
- nlri = &bgp.NLRInfo{
- IPAddrPrefix: *bgp.NewIPAddrPrefix(uint8(ones), ip.String()),
- }
-
- pattr = append(pattr, bgp.NewPathAttributeNextHop("0.0.0.0"))
-
- case bgp.RF_IPv6_UC:
-
- ip, net, _ := net.ParseCIDR(path.Nlri.Prefix)
- if ip.To16() == nil {
- result.ResponseErr = fmt.Errorf("Invalid ipv6 prefix: %s", path.Nlri.Prefix)
- grpcReq.ResponseCh <- result
- close(grpcReq.ResponseCh)
- return
- }
- ones, _ := net.Mask.Size()
- nlri = bgp.NewIPv6AddrPrefix(uint8(ones), ip.String())
-
- pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("::", []bgp.AddrPrefixInterface{nlri}))
-
- case bgp.RF_EVPN:
- mac, err := net.ParseMAC(path.Nlri.EvpnNlri.MacIpAdv.MacAddr)
- if err != nil {
- result.ResponseErr = fmt.Errorf("Invalid mac: %s", path.Nlri.EvpnNlri.MacIpAdv.MacAddr)
- grpcReq.ResponseCh <- result
- close(grpcReq.ResponseCh)
- return
- }
- ip := net.ParseIP(path.Nlri.EvpnNlri.MacIpAdv.IpAddr)
- if ip == nil {
- result.ResponseErr = fmt.Errorf("Invalid ip prefix: %s", path.Nlri.EvpnNlri.MacIpAdv.IpAddr)
- grpcReq.ResponseCh <- result
- close(grpcReq.ResponseCh)
- return
- }
- iplen := net.IPv4len * 8
- if ip.To4() == nil {
- iplen = net.IPv6len * 8
- }
-
- macIpAdv := &bgp.EVPNMacIPAdvertisementRoute{
- RD: bgp.NewRouteDistinguisherTwoOctetAS(0, 0),
- ESI: bgp.EthernetSegmentIdentifier{
- Type: bgp.ESI_ARBITRARY,
- },
- MacAddressLength: 48,
- MacAddress: mac,
- IPAddressLength: uint8(iplen),
- IPAddress: ip,
- Labels: []uint32{0},
- }
- nlri = bgp.NewEVPNNLRI(bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, 0, macIpAdv)
- pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("0.0.0.0", []bgp.AddrPrefixInterface{nlri}))
- case bgp.RF_ENCAP:
- endpoint := net.ParseIP(path.Nlri.Prefix)
- if endpoint == nil {
- result.ResponseErr = fmt.Errorf("Invalid endpoint ip address: %s", path.Nlri.Prefix)
- grpcReq.ResponseCh <- result
- close(grpcReq.ResponseCh)
- return
-
- }
- nlri = bgp.NewEncapNLRI(endpoint.String())
- pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("0.0.0.0", []bgp.AddrPrefixInterface{nlri}))
-
- iterSubTlvs := func(subTlvs []*api.TunnelEncapSubTLV) {
- for _, subTlv := range subTlvs {
- if subTlv.Type == api.ENCAP_SUBTLV_TYPE_COLOR {
- color := subTlv.Color
- subTlv := &bgp.TunnelEncapSubTLV{
- Type: bgp.ENCAP_SUBTLV_TYPE_COLOR,
- Value: &bgp.TunnelEncapSubTLVColor{color},
- }
- tlv := &bgp.TunnelEncapTLV{
- Type: bgp.TUNNEL_TYPE_VXLAN,
- Value: []*bgp.TunnelEncapSubTLV{subTlv},
- }
- attr := bgp.NewPathAttributeTunnelEncap([]*bgp.TunnelEncapTLV{tlv})
- pattr = append(pattr, attr)
- break
- }
- }
- }
-
- iterTlvs := func(tlvs []*api.TunnelEncapTLV) {
- for _, tlv := range tlvs {
- if tlv.Type == api.TUNNEL_TYPE_VXLAN {
- iterSubTlvs(tlv.SubTlv)
- break
- }
- }
- }
-
- func(attrs []*api.PathAttr) {
- for _, attr := range attrs {
- if attr.Type == api.BGP_ATTR_TYPE_TUNNEL_ENCAP {
- iterTlvs(attr.TunnelEncap)
- break
- }
- }
- }(path.Attrs)
-
- case bgp.RF_RTC_UC:
- var ec bgp.ExtendedCommunityInterface
- target := path.Nlri.RtNlri.Target
- ec_type := target.Type
- ec_subtype := target.Subtype
- switch ec_type {
- case api.EXTENDED_COMMUNITIE_TYPE_TWO_OCTET_AS_SPECIFIC:
- if target.Asn == 0 && target.LocalAdmin == 0 {
- break
- }
- ec = &bgp.TwoOctetAsSpecificExtended{
- SubType: bgp.ExtendedCommunityAttrSubType(ec_subtype),
- AS: uint16(target.Asn),
- LocalAdmin: target.LocalAdmin,
- IsTransitive: true,
- }
- default:
- result.ResponseErr = fmt.Errorf("Invalid endpoint ip address: %s", path.Nlri.Prefix)
- grpcReq.ResponseCh <- result
- close(grpcReq.ResponseCh)
- return
- }
-
- nlri = bgp.NewRouteTargetMembershipNLRI(peer.globalConfig.As, ec)
-
- pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("0.0.0.0", []bgp.AddrPrefixInterface{nlri}))
-
- default:
- result.ResponseErr = fmt.Errorf("Unsupported address family: %s", rf)
- grpcReq.ResponseCh <- result
- close(grpcReq.ResponseCh)
- return
- }
-
- p, err := table.CreatePath(peer.peerInfo, nlri, pattr, isWithdraw, time.Now())
- if err != nil {
- result.ResponseErr = err
- grpcReq.ResponseCh <- result
- close(grpcReq.ResponseCh)
- return
- }
-
- pm := &peerMsg{
- msgType: PEER_MSG_PATH,
- msgData: []table.Path{p},
- }
- peer.peerMsgCh <- pm
-
- case REQ_LOCAL_RIB, REQ_GLOBAL_RIB:
- if peer.fsm.adminState == ADMIN_STATE_DOWN {
- close(grpcReq.ResponseCh)
- return
- }
- if t, ok := peer.rib.Tables[grpcReq.RouteFamily]; ok {
- for _, dst := range t.GetDestinations() {
- result := &GrpcResponse{}
- result.Data = dst.ToApiStruct()
- grpcReq.ResponseCh <- result
- }
- }
- close(grpcReq.ResponseCh)
- return
- case REQ_NEIGHBOR_SHUTDOWN:
- peer.outgoing <- bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN, nil)
- case REQ_NEIGHBOR_RESET:
- peer.fsm.idleHoldTime = peer.peerConfig.Timers.IdleHoldTimeAfterReset
- peer.outgoing <- bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_ADMINISTRATIVE_RESET, nil)
- case REQ_NEIGHBOR_SOFT_RESET, REQ_NEIGHBOR_SOFT_RESET_IN:
- // soft-reconfiguration inbound
- peer.sendPathsToSiblings(peer.adjRib.GetInPathList(grpcReq.RouteFamily))
- if grpcReq.RequestType == REQ_NEIGHBOR_SOFT_RESET_IN {
- break
- }
- fallthrough
- case REQ_NEIGHBOR_SOFT_RESET_OUT:
- pathList := peer.adjRib.GetOutPathList(grpcReq.RouteFamily)
- peer.sendMessages(table.CreateUpdateMsgFromPaths(pathList))
- case REQ_ADJ_RIB_IN, REQ_ADJ_RIB_OUT:
- rf := grpcReq.RouteFamily
- var paths []table.Path
-
- if grpcReq.RequestType == REQ_ADJ_RIB_IN {
- paths = peer.adjRib.GetInPathList(rf)
- log.Debugf("RouteFamily=%v adj-rib-in found : %d", rf.String(), len(paths))
- } else {
- paths = peer.adjRib.GetOutPathList(rf)
- log.Debugf("RouteFamily=%v adj-rib-out found : %d", rf.String(), len(paths))
- }
-
- for _, p := range paths {
- result := &GrpcResponse{}
- path := &api.Path{}
- j, _ := json.Marshal(p)
- err := json.Unmarshal(j, path)
- if err != nil {
- result.ResponseErr = err
- } else {
- result.Data = path
- }
- grpcReq.ResponseCh <- result
- }
- close(grpcReq.ResponseCh)
- return
- case REQ_NEIGHBOR_ENABLE, REQ_NEIGHBOR_DISABLE:
- var err api.Error
- if grpcReq.RequestType == REQ_NEIGHBOR_ENABLE {
- select {
- case peer.fsm.adminStateCh <- ADMIN_STATE_UP:
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- }).Debug("ADMIN_STATE_UP requested")
- err.Code = api.Error_SUCCESS
- err.Msg = "ADMIN_STATE_UP"
- default:
- log.Warning("previous request is still remaining. : ", peer.peerConfig.NeighborAddress)
- err.Code = api.Error_FAIL
- err.Msg = "previous request is still remaining"
- }
- } else {
- select {
- case peer.fsm.adminStateCh <- ADMIN_STATE_DOWN:
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- }).Debug("ADMIN_STATE_DOWN requested")
- err.Code = api.Error_SUCCESS
- err.Msg = "ADMIN_STATE_DOWN"
- default:
- log.Warning("previous request is still remaining. : ", peer.peerConfig.NeighborAddress)
- err.Code = api.Error_FAIL
- err.Msg = "previous request is still remaining"
- }
- }
- result.Data = err
- case REQ_NEIGHBOR_POLICY:
- resInPolicies := []*api.PolicyDefinition{}
- resOutPolicies := []*api.PolicyDefinition{}
- // Add importpolies that has been set in the configuration file to the list.
- // However, peer haven't target importpolicy when add PolicyDefinition of name only to the list.
- conInPolicyNames := peer.peerConfig.ApplyPolicy.ImportPolicies
- for _, conInPolicyName := range conInPolicyNames {
- match := false
- for _, inPolicy := range peer.importPolicies {
- if conInPolicyName == inPolicy.Name {
- match = true
- resInPolicies = append(resInPolicies, inPolicy.ToApiStruct())
- break
- }
- }
- if !match {
- resInPolicies = append(resInPolicies, &api.PolicyDefinition{PolicyDefinitionName: conInPolicyName})
- }
- }
- // Add importpolies that has been set in the configuration file to the list.
- // However, peer haven't target importpolicy when add PolicyDefinition of name only to the list.
- conOutPolicyNames := peer.peerConfig.ApplyPolicy.ExportPolicies
- for _, conOutPolicyName := range conOutPolicyNames {
- match := false
- for _, outPolicy := range peer.exportPolicies {
- if conOutPolicyName == outPolicy.Name {
- match = true
- resOutPolicies = append(resOutPolicies, outPolicy.ToApiStruct())
- break
- }
- }
- if !match {
- resOutPolicies = append(resOutPolicies, &api.PolicyDefinition{PolicyDefinitionName: conOutPolicyName})
- }
- }
- defaultInPolicy := policy.ROUTE_REJECT
- defaultOutPolicy := policy.ROUTE_REJECT
- if peer.defaultImportPolicy == config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE {
- defaultInPolicy = policy.ROUTE_ACCEPT
- }
- if peer.defaultExportPolicy == config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE {
- defaultOutPolicy = policy.ROUTE_ACCEPT
- }
- result.Data = &api.ApplyPolicy{
- DefaultImportPolicy: defaultInPolicy,
- ImportPolicies: resInPolicies,
- DefaultExportPolicy: defaultOutPolicy,
- ExportPolicies: resOutPolicies,
- }
- case REQ_NEIGHBOR_POLICY_ADD_IMPORT, REQ_NEIGHBOR_POLICY_ADD_EXPORT, REQ_NEIGHBOR_POLICY_DEL_IMPORT, REQ_NEIGHBOR_POLICY_DEL_EXPORT:
- data := grpcReq.Data.([]interface{})
- reqApplyPolicy := data[0].(*api.ApplyPolicy)
- reqPolicyMap := data[1].(map[string]*policy.Policy)
- applyPolicy := &peer.peerConfig.ApplyPolicy
- var defInPolicy, defOutPolicy config.DefaultPolicyType
- if grpcReq.RequestType == REQ_NEIGHBOR_POLICY_ADD_IMPORT {
- if reqApplyPolicy.DefaultImportPolicy != policy.ROUTE_ACCEPT {
- defInPolicy = config.DEFAULT_POLICY_TYPE_REJECT_ROUTE
- }
- peer.peerConfig.ApplyPolicy.DefaultImportPolicy = defInPolicy
- applyPolicy.ImportPolicies = policy.PoliciesToString(reqApplyPolicy.ImportPolicies)
- } else if grpcReq.RequestType == REQ_NEIGHBOR_POLICY_ADD_EXPORT {
- if reqApplyPolicy.DefaultExportPolicy != policy.ROUTE_ACCEPT {
- defOutPolicy = config.DEFAULT_POLICY_TYPE_REJECT_ROUTE
- }
- peer.peerConfig.ApplyPolicy.DefaultExportPolicy = defOutPolicy
- applyPolicy.ExportPolicies = policy.PoliciesToString(reqApplyPolicy.ExportPolicies)
- } else if grpcReq.RequestType == REQ_NEIGHBOR_POLICY_DEL_IMPORT {
- peer.peerConfig.ApplyPolicy.DefaultImportPolicy = config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE
- peer.peerConfig.ApplyPolicy.ImportPolicies = make([]string, 0)
- } else if grpcReq.RequestType == REQ_NEIGHBOR_POLICY_DEL_EXPORT {
- peer.peerConfig.ApplyPolicy.DefaultExportPolicy = config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE
- peer.peerConfig.ApplyPolicy.ExportPolicies = make([]string, 0)
- }
- peer.setPolicy(reqPolicyMap)
- }
- grpcReq.ResponseCh <- result
- close(grpcReq.ResponseCh)
-}
-
-func (peer *Peer) sendUpdateMsgFromPaths(pList []table.Path) {
- pList = func(arg []table.Path) []table.Path {
- ret := make([]table.Path, 0, len(arg))
- for _, path := range arg {
- if _, ok := peer.rfMap[path.GetRouteFamily()]; !ok {
- continue
- }
- if peer.peerConfig.NeighborAddress.Equal(path.GetSource().Address) {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "Data": path,
- }).Debug("From me, ignore.")
- continue
- }
-
- if peer.peerConfig.PeerAs == path.GetSourceAs() {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "Data": path,
- }).Debug("AS PATH loop, ignore.")
- continue
- }
-
- if !path.IsWithdraw() {
- var applied bool = false
- applied, path = peer.applyPolicies(peer.exportPolicies, path)
- if applied {
- if path == nil {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "Data": path,
- }).Debug("Export policy applied and rejected.")
- continue
- }
- } else if peer.defaultExportPolicy != config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "Data": path,
- }).Debug("Default export policy applied and rejected.")
- continue
- }
- }
-
- ret = append(ret, path.Clone(path.IsWithdraw()))
- }
- return ret
- }(pList)
-
- peer.adjRib.UpdateOut(pList)
-
- if bgp.FSMState(peer.peerConfig.BgpNeighborCommonState.State) != bgp.BGP_FSM_ESTABLISHED || len(pList) == 0 {
- return
- }
-
- pList = func(arg []table.Path) []table.Path {
- ret := make([]table.Path, 0, len(arg))
- for _, path := range pList {
- isLocal := path.GetSource().ID.Equal(peer.peerInfo.LocalID)
- if isLocal {
- path.SetNexthop(peer.peerConfig.LocalAddress)
- } else {
- table.UpdatePathAttrs(path, &peer.globalConfig, &peer.peerConfig)
- }
-
- ret = append(ret, path)
- }
- return ret
- }(pList)
-
- peer.sendMessages(table.CreateUpdateMsgFromPaths(pList))
-}
-
-// apply policies to the path
-// if multiple policies are defined,
-// this function applies each policy to the path in the order that
-// policies are stored in the array passed to this function.
-//
-// the way of applying statements inside a single policy
-// - apply statement until the condition in the statement matches.
-// if the condition matches the path, apply the action on the statement and
-// return value that indicates 'applied' to caller of this function
-// - if no statement applied, then process the next policy
-//
-// if no policy applied, return value that indicates 'not applied' to the caller of this function
-//
-// return values:
-// bool -- indicates that any of policy applied to the path that is passed to this function
-// table.Path -- indicates new path object that is the result of modification according to
-// policy's action.
-// If the applied policy doesn't have a modification action,
-// then return the path itself that is passed to this function, otherwise return
-// modified path.
-// If action of the policy is 'reject', return nil
-//
-func (peer *Peer) applyPolicies(policies []*policy.Policy, original table.Path) (bool, table.Path) {
-
- var applied bool = true
-
- for _, pol := range policies {
- if result, action, newpath := pol.Apply(original); result {
- log.Debug("newpath: ", newpath)
- if action == policy.ROUTE_TYPE_REJECT {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "NRLI": original.GetNlri(),
- }).Debug("path was rejected")
- // return applied, nil, this means path was rejected
- return applied, nil
- } else {
- // return applied, new path
- return applied, newpath
- }
- }
}
- log.Debug("no policy applied.", original)
- // return not applied, original path
- return !applied, original
+ return pathList, update
}
-func (peer *Peer) handlePeerMsg(m *peerMsg) {
- switch m.msgType {
- case PEER_MSG_PATH:
- pList := m.msgData.([]table.Path)
-
- tmp := make([]table.Path, 0, len(pList))
- for _, path := range pList {
- if path.IsWithdraw() {
- tmp = append(tmp, path)
- continue
- }
-
- applied, path := peer.applyPolicies(peer.importPolicies, path)
- if applied && path == nil {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "Data": path,
- }).Debug("Import policy applied, reject.")
- continue
- } else if peer.defaultImportPolicy != config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "Data": path,
- }).Debug("Default import policy applied, reject.")
- continue
- }
-
- tmp = append(tmp, path)
- }
- pList = tmp
-
- if peer.peerConfig.RouteServer.RouteServerClient || peer.isGlobalRib {
- pList, _ = peer.rib.ProcessPaths(pList)
- }
-
- if peer.isGlobalRib {
- peer.sendPathsToSiblings(pList)
- } else {
- peer.sendUpdateMsgFromPaths(pList)
- }
-
- case PEER_MSG_PEER_DOWN:
- for _, rf := range peer.configuredRFlist() {
- pList, _ := peer.rib.DeletePathsforPeer(m.msgData.(*table.PeerInfo), rf)
- if peer.peerConfig.RouteServer.RouteServerClient {
- peer.sendUpdateMsgFromPaths(pList)
- } else if peer.isGlobalRib {
- peer.sendPathsToSiblings(pList)
- }
- }
- }
-}
-
-func (peer *Peer) handleServerMsg(m *serverMsg) {
- switch m.msgType {
- case SRV_MSG_PEER_ADDED:
- d := m.msgData.(*serverMsgDataPeer)
- peer.siblings[d.address.String()] = d
- for _, rf := range peer.configuredRFlist() {
- if peer.peerConfig.RouteServer.RouteServerClient {
- peer.sendPathsToSiblings(peer.adjRib.GetInPathList(rf))
- } else if peer.isGlobalRib {
- peer.sendPathsToSiblings(peer.rib.GetPathList(rf))
- }
- }
- case SRV_MSG_PEER_DELETED:
- d := m.msgData.(*table.PeerInfo)
- if _, ok := peer.siblings[d.Address.String()]; ok {
- delete(peer.siblings, d.Address.String())
- for _, rf := range peer.configuredRFlist() {
- pList, _ := peer.rib.DeletePathsforPeer(d, rf)
- if peer.peerConfig.RouteServer.RouteServerClient {
- peer.sendUpdateMsgFromPaths(pList)
- } else {
- peer.sendPathsToSiblings(pList)
- }
- }
- } else {
- log.Warning("can not find peer: ", d.Address.String())
- }
- case SRV_MSG_API:
- peer.handleGrpc(m.msgData.(*GrpcRequest))
- case SRV_MSG_POLICY_UPDATED:
- log.Debug("policy updated")
- d := m.msgData.(map[string]*policy.Policy)
- peer.setPolicy(d)
- default:
- log.Fatal("unknown server msg type ", m.msgType)
- }
-}
-
-func (peer *Peer) connectLoop() error {
- var tick int
- if tick = int(peer.fsm.peerConfig.Timers.ConnectRetry); tick < MIN_CONNECT_RETRY {
- tick = MIN_CONNECT_RETRY
- }
-
- ticker := time.NewTicker(time.Duration(tick) * time.Second)
- ticker.Stop()
-
- connect := func() {
- if bgp.FSMState(peer.peerConfig.BgpNeighborCommonState.State) == bgp.BGP_FSM_ACTIVE {
- var host string
- addr := peer.peerConfig.NeighborAddress
-
- if addr.To4() != nil {
- host = addr.String() + ":" + strconv.Itoa(bgp.BGP_PORT)
- } else {
- host = "[" + addr.String() + "]:" + strconv.Itoa(bgp.BGP_PORT)
- }
-
- conn, err := net.DialTimeout("tcp", host, time.Duration(MIN_CONNECT_RETRY-1)*time.Second)
- if err == nil {
- peer.connCh <- conn
- } else {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- }).Debugf("failed to connect: %s", err)
- }
- }
- }
-
- for {
- select {
- case <-peer.t.Dying():
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- }).Debug("stop connect loop")
- ticker.Stop()
- return nil
- case <-ticker.C:
- connect()
- case <-peer.getActiveCh:
- ticker = time.NewTicker(time.Duration(tick) * time.Second)
- }
- }
-}
-
-// this goroutine handles routing table operations
-func (peer *Peer) loop() error {
- for {
- incoming := make(chan *fsmMsg, FSM_CHANNEL_LENGTH)
- peer.outgoing = make(chan *bgp.BGPMessage, FSM_CHANNEL_LENGTH)
-
- var h *FSMHandler
-
- if !peer.isGlobalRib {
- h = NewFSMHandler(peer.fsm, incoming, peer.outgoing)
- switch peer.peerConfig.BgpNeighborCommonState.State {
- case uint32(bgp.BGP_FSM_ESTABLISHED):
- peer.peerConfig.LocalAddress = peer.fsm.LocalAddr()
- for rf, _ := range peer.rfMap {
- pathList := peer.adjRib.GetOutPathList(rf)
- if !peer.peerConfig.RouteServer.RouteServerClient {
- for _, path := range pathList {
- path.SetNexthop(peer.peerConfig.LocalAddress)
- }
- }
- peer.sendMessages(table.CreateUpdateMsgFromPaths(pathList))
- }
- peer.fsm.peerConfig.BgpNeighborCommonState.Uptime = time.Now().Unix()
- peer.fsm.peerConfig.BgpNeighborCommonState.EstablishedCount++
- case uint32(bgp.BGP_FSM_ACTIVE):
- if !peer.peerConfig.TransportOptions.PassiveMode {
- peer.getActiveCh <- struct{}{}
- }
- fallthrough
- default:
- peer.fsm.peerConfig.BgpNeighborCommonState.Downtime = time.Now().Unix()
- }
- }
-
- sameState := true
- for sameState {
- select {
- case <-peer.t.Dying():
- close(peer.connCh)
- peer.outgoing <- bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_PEER_DECONFIGURED, nil)
- // h.t.Kill(nil) will be called
- // internall so even goroutines in
- // non-established will be killed.
- h.Stop()
- return nil
- case e := <-incoming:
- switch e.MsgType {
- case FSM_MSG_STATE_CHANGE:
- nextState := e.MsgData.(bgp.FSMState)
- // waits for all goroutines created for the current state
- h.Wait()
- oldState := bgp.FSMState(peer.peerConfig.BgpNeighborCommonState.State)
- peer.peerConfig.BgpNeighborCommonState.State = uint32(nextState)
- peer.fsm.StateChange(nextState)
- sameState = false
- if oldState == bgp.BGP_FSM_ESTABLISHED {
- t := time.Now()
- if t.Sub(time.Unix(peer.fsm.peerConfig.BgpNeighborCommonState.Uptime, 0)) < FLOP_THRESHOLD {
- peer.fsm.peerConfig.BgpNeighborCommonState.Flops++
- }
-
- for _, rf := range peer.configuredRFlist() {
- peer.adjRib.DropAllIn(rf)
- }
- pm := &peerMsg{
- msgType: PEER_MSG_PEER_DOWN,
- msgData: peer.peerInfo,
- }
- for _, s := range peer.siblings {
- s.peerMsgCh <- pm
- }
- }
-
- // clear counter
- if h.fsm.adminState == ADMIN_STATE_DOWN {
- h.fsm.peerConfig.BgpNeighborCommonState = config.BgpNeighborCommonState{}
- }
-
- case FSM_MSG_BGP_MESSAGE:
- switch m := e.MsgData.(type) {
- case *bgp.MessageError:
- peer.outgoing <- bgp.NewBGPNotificationMessage(m.TypeCode, m.SubTypeCode, m.Data)
- case *bgp.BGPMessage:
- peer.handleBGPmessage(m)
- default:
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": peer.peerConfig.NeighborAddress,
- "Data": e.MsgData,
- }).Panic("unknonw msg type")
- }
- }
- case m := <-peer.serverMsgCh:
- peer.handleServerMsg(m)
- case m := <-peer.peerMsgCh:
- peer.handlePeerMsg(m)
- }
+func (peer *Peer) getBests(loc *LocalRib) []table.Path {
+ pathList := []table.Path{}
+ for _, rf := range peer.configuredRFlist() {
+ for _, dst := range loc.rib.Tables[rf].GetDestinations() {
+ pathList = append(pathList, dst.GetBestPath())
}
}
+ return pathList
}
-func (peer *Peer) Stop() error {
- peer.t.Kill(nil)
- return peer.t.Wait()
+func (peer *Peer) startFSMHandler(incoming chan *fsmMsg) {
+ peer.fsm.h = NewFSMHandler(peer.fsm, incoming, peer.outgoing)
}
func (peer *Peer) PassConn(conn *net.TCPConn) {
- peer.connCh <- conn
+ peer.fsm.connCh <- conn
}
func (peer *Peer) MarshalJSON() ([]byte, error) {
@@ -1059,7 +207,7 @@ func (peer *Peer) ToApiStruct() *api.Peer {
remoteCap = append(remoteCap, c.ToApiStruct())
}
- caps := capabilitiesFromConfig(&peer.globalConfig, &peer.peerConfig)
+ caps := capabilitiesFromConfig(&peer.globalConfig, &peer.config)
localCap := make([]*api.Capability, 0, len(caps))
for _, c := range caps {
localCap = append(localCap, c.ToApiStruct())
@@ -1071,8 +219,8 @@ func (peer *Peer) ToApiStruct() *api.Peer {
RemoteAs: c.PeerAs,
RemoteCap: remoteCap,
LocalCap: localCap,
- KeepaliveInterval: uint32(peer.fsm.peerConfig.Timers.KeepaliveInterval),
- Holdtime: uint32(peer.fsm.peerConfig.Timers.HoldTime),
+ KeepaliveInterval: uint32(peer.config.Timers.KeepaliveInterval),
+ Holdtime: uint32(peer.config.Timers.HoldTime),
}
s := c.BgpNeighborCommonState
@@ -1099,10 +247,10 @@ func (peer *Peer) ToApiStruct() *api.Peer {
keepalive := uint32(0)
if f.negotiatedHoldTime != 0 {
- if f.negotiatedHoldTime < f.peerConfig.Timers.HoldTime {
+ if f.negotiatedHoldTime < c.Timers.HoldTime {
keepalive = uint32(f.negotiatedHoldTime / 3)
} else {
- keepalive = uint32(f.peerConfig.Timers.KeepaliveInterval)
+ keepalive = uint32(c.Timers.KeepaliveInterval)
}
}
@@ -1140,3 +288,123 @@ func (peer *Peer) ToApiStruct() *api.Peer {
Info: info,
}
}
+
+type LocalRib struct {
+ rib *table.TableManager
+ importPolicies []*policy.Policy
+ defaultImportPolicy config.DefaultPolicyType
+ exportPolicies []*policy.Policy
+ defaultExportPolicy config.DefaultPolicyType
+}
+
+func NewLocalRib(owner string, rfList []bgp.RouteFamily, policyMap map[string]*policy.Policy) *LocalRib {
+ return &LocalRib{
+ rib: table.NewTableManager(owner, rfList),
+ }
+}
+
+func (loc *LocalRib) OwnerName() string {
+ return loc.rib.OwnerName()
+}
+
+func (loc *LocalRib) isGlobal() bool {
+ return loc.OwnerName() == "global"
+}
+
+func (loc *LocalRib) setPolicy(peer *Peer, policyMap map[string]*policy.Policy) {
+ // configure import policy
+ policyConfig := peer.config.ApplyPolicy
+ inPolicies := make([]*policy.Policy, 0)
+ for _, policyName := range policyConfig.ImportPolicies {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": peer.config.NeighborAddress,
+ "PolicyName": policyName,
+ }).Info("import policy installed")
+ if pol, ok := policyMap[policyName]; ok {
+ log.Debug("import policy : ", pol)
+ inPolicies = append(inPolicies, pol)
+ }
+ }
+ loc.importPolicies = inPolicies
+ loc.defaultImportPolicy = policyConfig.DefaultImportPolicy
+
+ // configure export policy
+ outPolicies := make([]*policy.Policy, 0)
+ for _, policyName := range policyConfig.ExportPolicies {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": peer.config.NeighborAddress,
+ "PolicyName": policyName,
+ }).Info("export policy installed")
+ if pol, ok := policyMap[policyName]; ok {
+ log.Debug("export policy : ", pol)
+ outPolicies = append(outPolicies, pol)
+ }
+ }
+ loc.exportPolicies = outPolicies
+ loc.defaultExportPolicy = policyConfig.DefaultExportPolicy
+}
+
+// apply policies to the path
+// if multiple policies are defined,
+// this function applies each policy to the path in the order that
+// policies are stored in the array passed to this function.
+//
+// the way of applying statements inside a single policy
+// - apply statement until the condition in the statement matches.
+// if the condition matches the path, apply the action on the statement and
+// return value that indicates 'applied' to caller of this function
+// - if no statement applied, then process the next policy
+//
+// if no policy applied, return value that indicates 'not applied' to the caller of this function
+//
+// return values:
+// bool -- indicates that any of policy applied to the path that is passed to this function
+// table.Path -- indicates new path object that is the result of modification according to
+// policy's action.
+// If the applied policy doesn't have a modification action,
+// then return the path itself that is passed to this function, otherwise return
+// modified path.
+// If action of the policy is 'reject', return nil
+//
+func (loc *LocalRib) applyPolicies(isExport bool, original table.Path) (bool, table.Path) {
+
+ var applied bool = true
+ var policies []*policy.Policy
+ var direction string
+ if isExport == true {
+ policies = loc.exportPolicies
+ direction = "export"
+ } else {
+ policies = loc.importPolicies
+ direction = "import"
+ }
+
+ for _, pol := range policies {
+ if result, action, newpath := pol.Apply(original); result {
+ log.Debug("newpath: ", newpath)
+ if action == policy.ROUTE_TYPE_REJECT {
+ log.WithFields(log.Fields{
+ "Topic": "Loc",
+ "Key": loc.OwnerName(),
+ "NRLI": original.GetNlri(),
+ "Dir": direction,
+ }).Debug("path was rejected")
+ // return applied, nil, this means path was rejected
+ return applied, nil
+ } else {
+ // return applied, new path
+ return applied, newpath
+ }
+ }
+ }
+ log.WithFields(log.Fields{
+ "Topic": "Loc",
+ "Key": loc.OwnerName(),
+ "Len": len(policies),
+ "NRLI": original,
+ "Dir": direction,
+ }).Debug("no policy applied")
+ return !applied, original
+}