diff options
-rw-r--r-- | server/peer.go | 39 | ||||
-rw-r--r-- | table/message.go | 99 |
2 files changed, 104 insertions, 34 deletions
diff --git a/server/peer.go b/server/peer.go index 8379d079..35fc3d90 100644 --- a/server/peer.go +++ b/server/peer.go @@ -89,7 +89,7 @@ func (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) { case bgp.BGP_MSG_ROUTE_REFRESH: pathList := peer.adjRib.GetOutPathList(peer.rf) - peer.sendMessages(peer.path2update(pathList)) + peer.sendMessages(table.CreateUpdateMsgFromPaths(pathList)) case bgp.BGP_MSG_UPDATE: peer.peerConfig.BgpNeighborCommonState.UpdateRecvTime = time.Now() body := m.Body.(*bgp.BGPUpdate) @@ -106,31 +106,24 @@ func (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) { func (peer *Peer) sendMessages(msgs []*bgp.BGPMessage) { for _, m := range msgs { - if m.Header.Type == bgp.BGP_MSG_UPDATE { - _, y := peer.capMap[bgp.BGP_CAP_FOUR_OCTET_AS_NUMBER] - if !y { - log.Debug("update BGPUpdate for 2byte AS peer, ", peer.peerConfig.NeighborAddress.String()) - table.UpdatePathAttrs2ByteAs(m.Body.(*bgp.BGPUpdate)) - } + // FIXME: there is race where state change + // (established) event arrived before open message + if peer.peerConfig.BgpNeighborCommonState.State != uint32(bgp.BGP_FSM_ESTABLISHED) { + continue } - peer.outgoing <- m - } -} -func (peer *Peer) path2update(pathList []table.Path) []*bgp.BGPMessage { - msgs := make([]*bgp.BGPMessage, 0) - var pMsg *bgp.BGPMessage - for _, p := range pathList { - if peer.rf != p.GetRouteFamily() { - continue + if m.Header.Type != bgp.BGP_MSG_UPDATE { + log.Fatal("not update message ", m.Header.Type) } - msg, _ := table.CreateUpdateMsgFromPath(p, pMsg) - if msg != nil { - msgs = append(msgs, msg) - pMsg = msg + + _, y := peer.capMap[bgp.BGP_CAP_FOUR_OCTET_AS_NUMBER] + if !y { + log.Debug("update BGPUpdate for 2byte AS peer, ", peer.peerConfig.NeighborAddress.String()) + table.UpdatePathAttrs2ByteAs(m.Body.(*bgp.BGPUpdate)) } + + peer.outgoing <- m } - return msgs } func (peer *Peer) handleREST(restReq *api.RestRequest) { @@ -152,7 +145,7 @@ func (peer *Peer) handlePeermessage(m *message) { } } peer.adjRib.UpdateOut(pathList) - peer.sendMessages(peer.path2update(pathList)) + peer.sendMessages(table.CreateUpdateMsgFromPaths(pathList)) } switch m.event { @@ -183,7 +176,7 @@ func (peer *Peer) loop() error { sameState = false if nextState == bgp.BGP_FSM_ESTABLISHED { pathList := peer.adjRib.GetOutPathList(peer.rf) - peer.sendMessages(peer.path2update(pathList)) + peer.sendMessages(table.CreateUpdateMsgFromPaths(pathList)) peer.fsm.peerConfig.BgpNeighborCommonState.Uptime = time.Now() peer.fsm.peerConfig.BgpNeighborCommonState.EstablishedCount++ } diff --git a/table/message.go b/table/message.go index 0cfa07e8..b3f730a3 100644 --- a/table/message.go +++ b/table/message.go @@ -16,11 +16,13 @@ package table import ( + "bytes" "github.com/osrg/gobgp/packet" "reflect" ) func UpdatePathAttrs2ByteAs(msg *bgp.BGPUpdate) error { + // FIXME: clone var asAttr *bgp.PathAttributeAsPath for _, attr := range msg.PathAttributes { switch attr.(type) { @@ -129,28 +131,103 @@ func clonePathAttributes(attrs []bgp.PathAttributeInterface) []bgp.PathAttribute return clonedAttrs } -func CreateUpdateMsgFromPath(path Path, msg *bgp.BGPMessage) (*bgp.BGPMessage, error) { +func createUpdateMsgFromPath(path Path, msg *bgp.BGPMessage) *bgp.BGPMessage { rf := path.GetRouteFamily() if rf == bgp.RF_IPv4_UC { if path.IsWithdraw() { draw := path.getNlri().(*bgp.WithdrawnRoute) - return bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{*draw}, []bgp.PathAttributeInterface{}, []bgp.NLRInfo{}), nil + if msg != nil { + u := msg.Body.(*bgp.BGPUpdate) + u.WithdrawnRoutes = append(u.WithdrawnRoutes, *draw) + return nil + } else { + return bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{*draw}, []bgp.PathAttributeInterface{}, []bgp.NLRInfo{}) + } } else { nlri := path.getNlri().(*bgp.NLRInfo) - pathAttrs := path.getPathAttrs() - return bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{}, pathAttrs, []bgp.NLRInfo{*nlri}), nil + if msg != nil { + u := msg.Body.(*bgp.BGPUpdate) + u.NLRI = append(u.NLRI, *nlri) + } else { + pathAttrs := path.getPathAttrs() + return bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{}, pathAttrs, []bgp.NLRInfo{*nlri}) + } } } else if rf == bgp.RF_IPv6_UC { if path.IsWithdraw() { - clonedAttrs := clonePathAttributes(path.getPathAttrs()) - idx, attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI) - reach := attr.(*bgp.PathAttributeMpReachNLRI) - clonedAttrs[idx] = bgp.NewPathAttributeMpUnreachNLRI(reach.Value) - return bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{}, clonedAttrs, []bgp.NLRInfo{}), nil + if msg != nil { + idx, _ := path.getPathAttr(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI) + u := msg.Body.(*bgp.BGPUpdate) + unreach := u.PathAttributes[idx].(*bgp.PathAttributeMpUnreachNLRI) + unreach.Value = append(unreach.Value, path.getNlri()) + } else { + clonedAttrs := clonePathAttributes(path.getPathAttrs()) + idx, attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI) + reach := attr.(*bgp.PathAttributeMpReachNLRI) + clonedAttrs[idx] = bgp.NewPathAttributeMpUnreachNLRI(reach.Value) + return bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{}, clonedAttrs, []bgp.NLRInfo{}) + } + } else { + if msg != nil { + idx, _ := path.getPathAttr(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI) + u := msg.Body.(*bgp.BGPUpdate) + reachAttr := u.PathAttributes[idx].(*bgp.PathAttributeMpReachNLRI) + reachAttr.Value = append(reachAttr.Value, path.getNlri()) + } else { + // we don't need to clone here but we + // might merge path to this message in + // the future so let's clone anyway. + clonedAttrs := clonePathAttributes(path.getPathAttrs()) + return bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{}, clonedAttrs, []bgp.NLRInfo{}) + } + } + } + return nil +} + +func isSamePathAttrs(pList1 []bgp.PathAttributeInterface, pList2 []bgp.PathAttributeInterface) bool { + if len(pList1) != len(pList2) { + return false + } + for i, p1 := range pList1 { + _, y := p1.(*bgp.PathAttributeMpReachNLRI) + if y { + continue + } + b1, _ := p1.Serialize() + b2, _ := pList2[i].Serialize() + + if bytes.Compare(b1, b2) != 0 { + return false + } + } + return true +} + +func isMergeable(p1 Path, p2 Path) bool { + if p1 == nil { + return false + } + if p1.getSource() == p2.getSource() && isSamePathAttrs(p1.getPathAttrs(), p2.getPathAttrs()) { + return true + } + return false +} + +func CreateUpdateMsgFromPaths(pathList []Path) []*bgp.BGPMessage { + var pre Path + var msgs []*bgp.BGPMessage + for _, path := range pathList { + y := isMergeable(pre, path) + if y { + msg := msgs[len(msgs)-1] + createUpdateMsgFromPath(path, msg) } else { - return bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{}, path.getPathAttrs(), []bgp.NLRInfo{}), nil + msg := createUpdateMsgFromPath(path, nil) + pre = path + msgs = append(msgs, msg) } } - return nil, nil + return msgs } |