summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--packet/bgp.go5
-rw-r--r--server/peer.go12
-rw-r--r--table/message.go11
-rw-r--r--table/path.go110
4 files changed, 124 insertions, 14 deletions
diff --git a/packet/bgp.go b/packet/bgp.go
index db7ff88a..f8d1f637 100644
--- a/packet/bgp.go
+++ b/packet/bgp.go
@@ -49,6 +49,11 @@ const (
)
const (
+ BGP_ASPATH_ATTR_TYPE_SET = 1
+ BGP_ASPATH_ATTR_TYPE_SEQ = 2
+)
+
+const (
_ = iota
BGP_MSG_OPEN
BGP_MSG_UPDATE
diff --git a/server/peer.go b/server/peer.go
index 77e6a01b..68e67254 100644
--- a/server/peer.go
+++ b/server/peer.go
@@ -24,6 +24,7 @@ import (
"github.com/osrg/gobgp/table"
"gopkg.in/tomb.v2"
"net"
+ "strings"
"time"
)
@@ -314,6 +315,8 @@ func (peer *Peer) handleREST(restReq *api.RestRequest) {
}
func (peer *Peer) sendUpdateMsgFromPaths(pList []table.Path) {
+ pList = table.CloneAndUpdatePathAttrs(pList, &peer.globalConfig, &peer.peerConfig)
+
peer.adjRib.UpdateOut(pList)
sendpathList := []table.Path{}
for _, p := range pList {
@@ -475,6 +478,15 @@ func (peer *Peer) Stop() error {
}
func (peer *Peer) PassConn(conn *net.TCPConn) {
+ localAddr := func(addrPort string) string {
+ if strings.Index(addrPort, "[") == -1 {
+ return strings.Split(addrPort, ":")[0]
+ }
+ idx := strings.LastIndex(addrPort, ":")
+ return addrPort[1 : idx-1]
+ }(conn.LocalAddr().String())
+
+ peer.peerConfig.LocalAddress = net.ParseIP(localAddr)
peer.acceptedConnCh <- conn
}
diff --git a/table/message.go b/table/message.go
index 12a51cf6..b19bcec2 100644
--- a/table/message.go
+++ b/table/message.go
@@ -17,6 +17,7 @@ package table
import (
"bytes"
+ "github.com/osrg/gobgp/config"
"github.com/osrg/gobgp/packet"
)
@@ -127,6 +128,16 @@ func cloneAttrSlice(attrs []bgp.PathAttributeInterface) []bgp.PathAttributeInter
return clonedAttrs
}
+func CloneAndUpdatePathAttrs(pathList []Path, global *config.Global, peer *config.Neighbor) []Path {
+ newPathList := make([]Path, 0, len(pathList))
+ for _, p := range pathList {
+ clone := p.clone(p.IsWithdraw())
+ clone.updatePathAttrs(global, peer)
+ newPathList = append(newPathList, clone)
+ }
+ return newPathList
+}
+
func createUpdateMsgFromPath(path Path, msg *bgp.BGPMessage) *bgp.BGPMessage {
rf := path.GetRouteFamily()
diff --git a/table/path.go b/table/path.go
index 832a0ec6..634eda39 100644
--- a/table/path.go
+++ b/table/path.go
@@ -19,6 +19,7 @@ import (
"encoding/json"
"fmt"
log "github.com/Sirupsen/logrus"
+ "github.com/osrg/gobgp/config"
"github.com/osrg/gobgp/packet"
"net"
"reflect"
@@ -29,6 +30,7 @@ type Path interface {
String() string
getPathAttrs() []bgp.PathAttributeInterface
getPathAttr(bgp.BGPAttrType) (int, bgp.PathAttributeInterface)
+ updatePathAttrs(global *config.Global, peer *config.Neighbor)
GetRouteFamily() bgp.RouteFamily
setSource(source *PeerInfo)
getSource() *PeerInfo
@@ -80,6 +82,99 @@ func NewPathDefault(rf bgp.RouteFamily, source *PeerInfo, nlri bgp.AddrPrefixInt
return path
}
+func cloneAsPath(asAttr *bgp.PathAttributeAsPath) *bgp.PathAttributeAsPath {
+ newASparams := make([]bgp.AsPathParamInterface, len(asAttr.Value))
+ for i, param := range asAttr.Value {
+ asParam := param.(*bgp.As4PathParam)
+ as := make([]uint32, len(asParam.AS))
+ copy(as, asParam.AS)
+ newASparams[i] = bgp.NewAs4PathParam(asParam.Type, as)
+ }
+ return bgp.NewPathAttributeAsPath(newASparams)
+}
+
+func (pd *PathDefault) updatePathAttrs(global *config.Global, peer *config.Neighbor) {
+ newPathAttrs := make([]bgp.PathAttributeInterface, len(pd.pathAttrs))
+ for i, v := range pd.pathAttrs {
+ newPathAttrs[i] = v
+ }
+ pd.pathAttrs = newPathAttrs
+
+ if peer.RouteServer.RouteServerClient {
+ return
+ }
+
+ if peer.PeerType == config.PEER_TYPE_EXTERNAL {
+ // NEXTHOP handling
+ idx, _ := pd.getPathAttr(bgp.BGP_ATTR_TYPE_NEXT_HOP)
+ if idx < 0 {
+ log.Fatal("missing NEXTHOP mandatory attribute")
+ }
+ newNexthop := bgp.NewPathAttributeNextHop(peer.LocalAddress.String())
+ newPathAttrs[idx] = newNexthop
+
+ // AS_PATH handling
+ //
+ // When a given BGP speaker advertises the route to an external
+ // peer, the advertising speaker updates the AS_PATH attribute
+ // as follows:
+ // 1) if the first path segment of the AS_PATH is of type
+ // AS_SEQUENCE, the local system prepends its own AS num as
+ // the last element of the sequence (put it in the left-most
+ // position with respect to the position of octets in the
+ // protocol message). If the act of prepending will cause an
+ // overflow in the AS_PATH segment (i.e., more than 255
+ // ASes), it SHOULD prepend a new segment of type AS_SEQUENCE
+ // and prepend its own AS number to this new segment.
+ //
+ // 2) if the first path segment of the AS_PATH is of type AS_SET
+ // , the local system prepends a new path segment of type
+ // AS_SEQUENCE to the AS_PATH, including its own AS number in
+ // that segment.
+ //
+ // 3) if the AS_PATH is empty, the local system creates a path
+ // segment of type AS_SEQUENCE, places its own AS into that
+ // segment, and places that segment into the AS_PATH.
+ idx, originalAsPath := pd.getPathAttr(bgp.BGP_ATTR_TYPE_AS_PATH)
+ if idx < 0 {
+ log.Fatal("missing AS_PATH mandatory attribute")
+ }
+ asPath := cloneAsPath(originalAsPath.(*bgp.PathAttributeAsPath))
+ newPathAttrs[idx] = asPath
+ fst := asPath.Value[0].(*bgp.As4PathParam)
+ if len(asPath.Value) > 0 && fst.Type == bgp.BGP_ASPATH_ATTR_TYPE_SEQ &&
+ fst.ASLen() < 255 {
+ fst.AS = append([]uint32{global.As}, fst.AS...)
+ fst.Num += 1
+ } else {
+ p := bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{global.As})
+ asPath.Value = append([]bgp.AsPathParamInterface{p}, asPath.Value...)
+ }
+
+ // MED Handling
+ idx, _ = pd.getPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC)
+ if idx >= 0 {
+ newPathAttrs = append(newPathAttrs[:idx], newPathAttrs[idx+1:]...)
+ }
+ } else if peer.PeerType == config.PEER_TYPE_INTERNAL {
+ // For iBGP peers we are required to send local-pref attribute
+ // for connected or local prefixes.
+ // We set default local-pref 100.
+ p := bgp.NewPathAttributeLocalPref(100)
+ idx, _ := pd.getPathAttr(bgp.BGP_ATTR_TYPE_LOCAL_PREF)
+ if idx < 0 {
+ newPathAttrs = append(newPathAttrs, p)
+ } else {
+ newPathAttrs[idx] = p
+ }
+ } else {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": peer.NeighborAddress,
+ }).Warnf("invalid peer type: %d", peer.PeerType)
+ }
+}
+
func (pd *PathDefault) getTimestamp() time.Time {
return pd.timestamp
}
@@ -107,11 +202,7 @@ func (pd *PathDefault) clone(isWithdraw bool) Path {
nlri := pd.nlri
if isWithdraw {
if pd.IsWithdraw() {
- log.WithFields(log.Fields{
- "Topic": "Table",
- "Key": pd.getNlri().String(),
- "Peer": pd.getSource().Address.String(),
- }).Fatal("Withdraw path is not supposed to be cloned")
+ nlri = pd.nlri
} else {
nlri = &bgp.WithdrawnRoute{pd.nlri.(*bgp.NLRInfo).IPAddrPrefix}
}
@@ -271,15 +362,6 @@ func NewIPv6Path(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool
func (ipv6p *IPv6Path) clone(isWithdraw bool) Path {
nlri := ipv6p.nlri
- if isWithdraw {
- if ipv6p.IsWithdraw() {
- log.WithFields(log.Fields{
- "Topic": "Table",
- "Key": ipv6p.getNlri().String(),
- "Peer": ipv6p.getSource().Address.String(),
- }).Fatal("Withdraw path is not supposed to be cloned")
- }
- }
return CreatePath(ipv6p.source, nlri, ipv6p.pathAttrs, isWithdraw, ipv6p.PathDefault.timestamp)
}