diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2014-12-27 06:26:18 -0800 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2014-12-27 06:27:00 -0800 |
commit | eff70c21375742b44ae5ebfd845dba38d0f3fcfc (patch) | |
tree | b9d6cceaa69fc74250265f2df2262e65fe23ebda | |
parent | f5447b5599060a60acbf61ab7310807d85799628 (diff) |
support IPv6_UC route family
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | server/fsm.go | 20 | ||||
-rw-r--r-- | server/peer.go | 48 | ||||
-rw-r--r-- | server/server.go | 60 | ||||
-rw-r--r-- | table/destination.go | 3 | ||||
-rw-r--r-- | table/path.go | 40 | ||||
-rw-r--r-- | table/path_test.go | 2 | ||||
-rw-r--r-- | table/table.go | 4 | ||||
-rw-r--r-- | table/table_manager.go | 6 | ||||
-rw-r--r-- | table/table_test.go | 2 |
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) } |