summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/fsm.go20
-rw-r--r--server/peer.go48
-rw-r--r--server/server.go60
-rw-r--r--table/destination.go3
-rw-r--r--table/path.go40
-rw-r--r--table/path_test.go2
-rw-r--r--table/table.go4
-rw-r--r--table/table_manager.go6
-rw-r--r--table/table_test.go2
9 files changed, 145 insertions, 40 deletions
diff --git a/server/fsm.go b/server/fsm.go
index 849d8169..76ed85a6 100644
--- a/server/fsm.go
+++ b/server/fsm.go
@@ -110,11 +110,19 @@ func (fsm *FSM) PeerInfoGet() *table.PeerInfo {
}
func (fsm *FSM) createPeerInfo() {
+ var rf table.RouteFamily
+ if fsm.peerConfig.NeighborAddress.To4() != nil {
+ rf = table.RF_IPv4_UC
+ } else {
+ rf = table.RF_IPv6_UC
+ }
+
fsm.peerInfo = &table.PeerInfo{
AS: fsm.peerConfig.PeerAs,
ID: fsm.routerId,
VersionNum: fsm.sourceVerNum,
LocalID: fsm.globalConfig.RouterId,
+ RF: rf,
}
}
@@ -168,14 +176,20 @@ func (h *FSMHandler) active() bgp.FSMState {
return bgp.BGP_FSM_OPENSENT
}
-func buildopen(global *config.GlobalType, neighborT *config.NeighborType) *bgp.BGPMessage {
+func buildopen(global *config.GlobalType, peerConf *config.NeighborType) *bgp.BGPMessage {
+ var afi int
+ if peerConf.NeighborAddress.To4() != nil {
+ afi = bgp.AFI_IP
+ } else {
+ afi = bgp.AFI_IP6
+ }
p1 := bgp.NewOptionParameterCapability(
[]bgp.ParameterCapabilityInterface{bgp.NewCapRouteRefresh()})
p2 := bgp.NewOptionParameterCapability(
- []bgp.ParameterCapabilityInterface{bgp.NewCapMultiProtocol(bgp.AFI_IP, bgp.SAFI_UNICAST)})
+ []bgp.ParameterCapabilityInterface{bgp.NewCapMultiProtocol(uint16(afi), bgp.SAFI_UNICAST)})
p3 := bgp.NewOptionParameterCapability(
[]bgp.ParameterCapabilityInterface{bgp.NewCapFourOctetASNumber(global.As)})
- holdTime := uint16(neighborT.Timers.HoldTime)
+ holdTime := uint16(peerConf.Timers.HoldTime)
as := global.As
if as > (1<<16)-1 {
as = bgp.AS_TRANS
diff --git a/server/peer.go b/server/peer.go
index b3261dbd..fd36ce09 100644
--- a/server/peer.go
+++ b/server/peer.go
@@ -41,6 +41,8 @@ type Peer struct {
// 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
+ // for now we support only the same afi as transport
+ rf table.RouteFamily
}
func NewPeer(g config.GlobalType, peer config.NeighborType, outEventCh chan *message) *Peer {
@@ -55,6 +57,11 @@ func NewPeer(g config.GlobalType, peer config.NeighborType, outEventCh chan *mes
}
p.fsm = NewFSM(&g, &peer, p.acceptedConnCh, p.incoming, p.outgoing)
peer.BgpNeighborCommonState.State = uint32(bgp.BGP_FSM_IDLE)
+ if peer.NeighborAddress.To4() != nil {
+ p.rf = table.RF_IPv4_UC
+ } else {
+ p.rf = table.RF_IPv6_UC
+ }
p.adjRib = table.NewAdjRib()
p.rib = table.NewTableManager()
p.t.Go(p.loop)
@@ -67,7 +74,7 @@ func (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) {
switch m.Header.Type {
case bgp.BGP_MSG_ROUTE_REFRESH:
- pathList := peer.adjRib.GetOutPathList(table.RF_IPv4_UC)
+ pathList := peer.adjRib.GetOutPathList(peer.rf)
peer.sendMessages(peer.path2update(pathList))
case bgp.BGP_MSG_UPDATE:
peer.peerConfig.BgpNeighborCommonState.UpdateRecvTime = time.Now()
@@ -87,18 +94,40 @@ func (peer *Peer) sendMessages(msgs []*bgp.BGPMessage) {
}
}
+func path2v4update(path table.Path) *bgp.BGPMessage {
+ if path.IsWithdraw() {
+ draw := path.GetNlri().(*bgp.WithdrawnRoute)
+ 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})
+ }
+}
+
+func path2v6update(path table.Path) *bgp.BGPMessage {
+ if path.IsWithdraw() {
+ pathAttrs := path.GetPathAttrs()
+ return bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{}, pathAttrs, []bgp.NLRInfo{})
+ } else {
+ pathAttrs := path.GetPathAttrs()
+ return bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{}, pathAttrs, []bgp.NLRInfo{})
+ }
+}
+
func (peer *Peer) path2update(pathList []table.Path) []*bgp.BGPMessage {
// TODO: merge multiple messages
// TODO: 4bytes and 2bytes conversion.
msgs := make([]*bgp.BGPMessage, 0)
for _, p := range pathList {
- if p.IsWithdraw() {
- draw := p.GetNlri().(*bgp.WithdrawnRoute)
- msgs = append(msgs, bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{*draw}, []bgp.PathAttributeInterface{}, []bgp.NLRInfo{}))
+ if peer.rf != p.GetRouteFamily() {
+ continue
+ }
+
+ if peer.rf == table.RF_IPv4_UC {
+ msgs = append(msgs, path2v4update(p))
} else {
- pathAttrs := p.GetPathAttrs()
- nlri := p.GetNlri().(*bgp.NLRInfo)
- msgs = append(msgs, bgp.NewBGPUpdateMessage([]bgp.WithdrawnRoute{}, pathAttrs, []bgp.NLRInfo{*nlri}))
+ msgs = append(msgs, path2v6update(p))
}
}
return msgs
@@ -106,7 +135,7 @@ func (peer *Peer) path2update(pathList []table.Path) []*bgp.BGPMessage {
func (peer *Peer) handleREST(restReq *api.RestRequest) {
result := &api.RestResponse{}
- j, _ := json.Marshal(peer.rib.Tables[bgp.RF_IPv4_UC])
+ j, _ := json.Marshal(peer.rib.Tables[peer.rf])
result.Data = j
restReq.ResponseCh <- result
close(restReq.ResponseCh)
@@ -151,9 +180,8 @@ func (peer *Peer) loop() error {
peer.peerConfig.BgpNeighborCommonState.State = uint32(nextState)
peer.fsm.StateChange(nextState)
sameState = false
- // TODO: check peer's rf
if nextState == bgp.BGP_FSM_ESTABLISHED {
- pathList := peer.adjRib.GetOutPathList(table.RF_IPv4_UC)
+ pathList := peer.adjRib.GetOutPathList(peer.rf)
peer.sendMessages(peer.path2update(pathList))
peer.fsm.peerConfig.BgpNeighborCommonState.Uptime = time.Now()
peer.fsm.peerConfig.BgpNeighborCommonState.EstablishedCount++
diff --git a/server/server.go b/server/server.go
index e97d31c4..99ea974c 100644
--- a/server/server.go
+++ b/server/server.go
@@ -62,37 +62,67 @@ func NewBgpServer(port int) *BgpServer {
return &b
}
-func (server *BgpServer) Serve() {
- server.bgpConfig.Global = <-server.globalTypeCh
-
- service := ":" + strconv.Itoa(server.listenPort)
- addr, _ := net.ResolveTCPAddr("tcp", service)
+// avoid mapped IPv6 address
+func listenAndAccept(proto string, port int, ch chan *net.TCPConn) (*net.TCPListener, error) {
+ service := ":" + strconv.Itoa(port)
+ addr, _ := net.ResolveTCPAddr(proto, service)
- l, err := net.ListenTCP("tcp4", addr)
+ l, err := net.ListenTCP(proto, addr)
if err != nil {
- log.Fatal(err)
- os.Exit(1)
+ log.Info(err)
+ return nil, err
}
-
- acceptCh := make(chan *net.TCPConn)
go func() {
for {
- conn, err := l.Accept()
+ conn, err := l.AcceptTCP()
if err != nil {
log.Info(err)
continue
}
- acceptCh <- conn.(*net.TCPConn)
+ ch <- conn
}
}()
+ return l, nil
+}
+
+func (server *BgpServer) Serve() {
+ server.bgpConfig.Global = <-server.globalTypeCh
+
+ listenerMap := make(map[string]*net.TCPListener)
+ acceptCh := make(chan *net.TCPConn)
+ l4, err1 := listenAndAccept("tcp4", server.listenPort, acceptCh)
+ listenerMap["tcp4"] = l4
+ l6, err2 := listenAndAccept("tcp6", server.listenPort, acceptCh)
+ listenerMap["tcp6"] = l6
+ if err1 != nil && err2 != nil {
+ log.Fatal("can't listen either v4 and v6")
+ os.Exit(1)
+ }
+
+ listenFile := func(addr net.IP) *os.File {
+ var l *net.TCPListener
+ if addr.To4() != nil {
+ l = listenerMap["tcp4"]
+ } else {
+ l = listenerMap["tcp6"]
+ }
+ f, _ := l.File()
+ return f
+ }
+
server.peerMap = make(map[string]*Peer)
broadcastCh := make(chan *message)
for {
- f, _ := l.File()
select {
case conn := <-acceptCh:
- remoteAddr := strings.Split(conn.RemoteAddr().String(), ":")[0]
+ remoteAddr := func(addrPort string) string {
+ if strings.Index(addrPort, "[") == -1 {
+ return strings.Split(addrPort, ":")[0]
+ }
+ idx := strings.LastIndex(addrPort, ":")
+ return addrPort[1 : idx-1]
+ }(conn.RemoteAddr().String())
peer, found := server.peerMap[remoteAddr]
if found {
log.Info("accepted a new passive connection from ", remoteAddr)
@@ -103,11 +133,13 @@ func (server *BgpServer) Serve() {
}
case peer := <-server.addedPeerCh:
addr := peer.NeighborAddress.String()
+ f := listenFile(peer.NeighborAddress)
SetTcpMD5SigSockopts(int(f.Fd()), addr, peer.AuthPassword)
p := NewPeer(server.bgpConfig.Global, peer, broadcastCh)
server.peerMap[peer.NeighborAddress.String()] = p
case peer := <-server.deletedPeerCh:
addr := peer.NeighborAddress.String()
+ f := listenFile(peer.NeighborAddress)
SetTcpMD5SigSockopts(int(f.Fd()), addr, "")
p, found := server.peerMap[addr]
if found {
diff --git a/table/destination.go b/table/destination.go
index f99af8ef..4bb77ae7 100644
--- a/table/destination.go
+++ b/table/destination.go
@@ -45,6 +45,7 @@ type PeerInfo struct {
ID net.IP
VersionNum int
LocalID net.IP
+ RF RouteFamily
}
type Destination interface {
@@ -185,7 +186,7 @@ func (dd *DestinationDefault) removeOldPathsFromSource(source *PeerInfo) []Path
}
func (dd *DestinationDefault) validatePath(path Path) {
- if path == nil || path.getRouteFamily() != dd.ROUTE_FAMILY {
+ if path == nil || path.GetRouteFamily() != dd.ROUTE_FAMILY {
log.Error("Invalid path. Expected %s path got %s.", dd.ROUTE_FAMILY, path)
}
}
diff --git a/table/path.go b/table/path.go
index 66b2dc4a..1ccbb1a2 100644
--- a/table/path.go
+++ b/table/path.go
@@ -28,7 +28,7 @@ type Path interface {
String() string
GetPathAttrs() []bgp.PathAttributeInterface
GetPathAttr(bgp.BGPAttrType) (int, bgp.PathAttributeInterface)
- getRouteFamily() RouteFamily
+ GetRouteFamily() RouteFamily
setSource(source *PeerInfo)
getSource() *PeerInfo
setNexthop(nexthop net.IP)
@@ -100,7 +100,7 @@ func (pd *PathDefault) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Network string
//Nexthop string
- Attrs []bgp.PathAttributeInterface
+ Attrs []bgp.PathAttributeInterface
//Metric string
//origin string
Best string
@@ -108,8 +108,8 @@ func (pd *PathDefault) MarshalJSON() ([]byte, error) {
Network: prefix.String() + "/" + fmt.Sprint(prefixLen),
//Nexthop: pd.nexthop.String(),
//Metric: fmt.Sprint(med),
- Attrs: pd.GetPathAttrs(),
- Best: fmt.Sprint(pd.isBest),
+ Attrs: pd.GetPathAttrs(),
+ Best: fmt.Sprint(pd.isBest),
})
}
@@ -133,7 +133,7 @@ func (pd *PathDefault) Clone(isWithdraw bool) Path {
return CreatePath(pd.source, nlri, copiedAttrs, isWithdraw)
}
-func (pd *PathDefault) getRouteFamily() RouteFamily {
+func (pd *PathDefault) GetRouteFamily() RouteFamily {
return pd.routeFamily
}
@@ -293,6 +293,36 @@ func NewIPv6Path(source *PeerInfo, nlri bgp.AddrPrefixInterface, sourceVerNum in
return ipv6Path
}
+func (ipv6p *IPv6Path) Clone(isWithdraw bool) Path {
+ copiedAttrs := []bgp.PathAttributeInterface(nil)
+ nlri := ipv6p.nlri
+ if isWithdraw {
+ if !ipv6p.IsWithdraw() {
+ copiedAttrs = append(copiedAttrs, ipv6p.GetPathAttrs()...)
+ for i, attr := range copiedAttrs {
+ t, v := reflect.TypeOf(attr), reflect.ValueOf(attr)
+ newAttrObjp := reflect.New(t.Elem())
+ newAttrObjp.Elem().Set(v.Elem())
+ copiedAttrs[i] = newAttrObjp.Interface().(bgp.PathAttributeInterface)
+ }
+ idx, attr := ipv6p.GetPathAttr(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI)
+ reach := attr.(*bgp.PathAttributeMpReachNLRI)
+ copiedAttrs[idx] = bgp.NewPathAttributeMpUnreachNLRI(reach.Value)
+ } else {
+ copiedAttrs = ipv6p.GetPathAttrs()
+ }
+ } else {
+ copiedAttrs = append(copiedAttrs, ipv6p.pathAttrs...)
+ for i, attr := range copiedAttrs {
+ t, v := reflect.TypeOf(attr), reflect.ValueOf(attr)
+ newAttrObjp := reflect.New(t.Elem())
+ newAttrObjp.Elem().Set(v.Elem())
+ copiedAttrs[i] = newAttrObjp.Interface().(bgp.PathAttributeInterface)
+ }
+ }
+ return CreatePath(ipv6p.source, nlri, copiedAttrs, isWithdraw)
+}
+
func (ipv6p *IPv6Path) setPathDefault(pd *PathDefault) {
ipv6p.PathDefault = pd
}
diff --git a/table/path_test.go b/table/path_test.go
index b779c84b..786dad26 100644
--- a/table/path_test.go
+++ b/table/path_test.go
@@ -58,7 +58,7 @@ func TestPathIPv6GetDefault(t *testing.T) {
func TestPathGetRouteFamily(t *testing.T) {
pd := &PathDefault{routeFamily: RF_IPv6_UC}
- rf := pd.getRouteFamily()
+ rf := pd.GetRouteFamily()
assert.Equal(t, rf, RF_IPv6_UC)
}
diff --git a/table/table.go b/table/table.go
index a9d742aa..7021f025 100644
--- a/table/table.go
+++ b/table/table.go
@@ -63,7 +63,7 @@ func (td *TableDefault) MarshalJSON() ([]byte, error) {
})
}
-func (td *TableDefault) getRoutefamily() RouteFamily {
+func (td *TableDefault) GetRoutefamily() RouteFamily {
return td.ROUTE_FAMILY
}
@@ -142,7 +142,7 @@ func deleteDest(table Table, dest Destination) {
}
func (td *TableDefault) validatePath(path Path) {
- if path == nil || path.getRouteFamily() != td.ROUTE_FAMILY {
+ if path == nil || path.GetRouteFamily() != td.ROUTE_FAMILY {
log.Errorf("Invalid path. Expected instance of %s route family path, got %s.", td.ROUTE_FAMILY, path)
}
}
diff --git a/table/table_manager.go b/table/table_manager.go
index 18dbfb2d..4a0c70d6 100644
--- a/table/table_manager.go
+++ b/table/table_manager.go
@@ -223,14 +223,14 @@ func (manager *TableManager) calculate(destinationList []Destination) ([]Path, [
}
func (manager *TableManager) DeletePathsforPeer(peerInfo *PeerInfo) ([]Path, []Destination, error) {
- destinationList := manager.Tables[RF_IPv4_UC].DeleteDestByPeer(peerInfo)
+ destinationList := manager.Tables[peerInfo.RF].DeleteDestByPeer(peerInfo)
return manager.calculate(destinationList)
}
func (manager *TableManager) ProcessPaths(pathList []Path) ([]Path, []Destination, error) {
destinationList := make([]Destination, 0)
for _, path := range pathList {
- rf := path.getRouteFamily()
+ rf := path.GetRouteFamily()
// push Path into table
destination := insert(manager.Tables[rf], path)
destinationList = append(destinationList, destination)
@@ -277,7 +277,7 @@ func NewAdjRib() *AdjRib {
func (adj *AdjRib) update(rib map[RouteFamily]map[string]*ReceivedRoute, pathList []Path) {
for _, path := range pathList {
- rf := path.getRouteFamily()
+ rf := path.GetRouteFamily()
key := path.getPrefix().String()
if path.IsWithdraw() {
_, found := rib[rf][key]
diff --git a/table/table_test.go b/table/table_test.go
index 47213a82..8a347d30 100644
--- a/table/table_test.go
+++ b/table/table_test.go
@@ -71,7 +71,7 @@ func TestTableDeleteDest(t *testing.T) {
func TestTableGetRouteFamily(t *testing.T) {
ipv4t := NewIPv4Table(0)
- rf := ipv4t.getRoutefamily()
+ rf := ipv4t.GetRoutefamily()
assert.Equal(t, rf, RF_IPv4_UC)
}