diff options
-rw-r--r-- | server/server.go | 2 | ||||
-rw-r--r-- | table/path.go | 25 | ||||
-rw-r--r-- | test/scenario_test/bgp_router_test.py | 60 | ||||
-rw-r--r-- | test/scenario_test/lib/base.py | 18 | ||||
-rw-r--r-- | test/scenario_test/lib/gobgp.py | 30 |
5 files changed, 105 insertions, 30 deletions
diff --git a/server/server.go b/server/server.go index 683fcc6d..57f7c7ee 100644 --- a/server/server.go +++ b/server/server.go @@ -675,8 +675,6 @@ func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*t 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{peerInfo.AS}) - pattr = append(pattr, bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{asparam})) rf := grpcReq.RouteFamily path, ok := grpcReq.Data.(*api.Path) diff --git a/table/path.go b/table/path.go index 51be91af..bd368ec6 100644 --- a/table/path.go +++ b/table/path.go @@ -102,18 +102,21 @@ func (path *Path) UpdatePathAttrs(global *config.Global, peer *config.Neighbor) // segment, and places that segment into the AS_PATH. idx, originalAsPath := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS_PATH) if idx < 0 { - log.Fatal("missing AS_PATH mandatory attribute") - } - asPath := cloneAsPath(originalAsPath.(*bgp.PathAttributeAsPath)) - path.pathAttrs[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...) + asPath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{p}) + path.pathAttrs = append(path.pathAttrs, asPath) + } else { + asPath := cloneAsPath(originalAsPath.(*bgp.PathAttributeAsPath)) + path.pathAttrs[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 diff --git a/test/scenario_test/bgp_router_test.py b/test/scenario_test/bgp_router_test.py index 3bd5a82c..8b17e380 100644 --- a/test/scenario_test/bgp_router_test.py +++ b/test/scenario_test/bgp_router_test.py @@ -116,14 +116,11 @@ class GoBGPTestBase(unittest.TestCase): def test_03_check_gobgp_adj_out_rib(self): for q in self.quaggas.itervalues(): for path in self.gobgp.get_adj_rib_out(q): - asps = (p['as_paths'] for p in path['attrs'] if p['type'] == BGP_ATTR_TYPE_AS_PATH) - asps = chain.from_iterable(asps) - asns = (asp['asns'] for asp in asps) - asns = chain.from_iterable(asns) + asns = self.gobgp._get_as_path(path) self.assertTrue(self.gobgp.asn in asns) # check routes are properly advertised to all BGP speaker - def test_03_check_quagga_global_rib(self): + def test_04_check_quagga_global_rib(self): for q in self.quaggas.itervalues(): done = False for _ in range(self.retry_limit): @@ -146,7 +143,7 @@ class GoBGPTestBase(unittest.TestCase): # should not reach here self.assertTrue(False) - def test_04_add_quagga(self): + def test_05_add_quagga(self): q4 = QuaggaBGPContainer(name='q4', asn=65004, router_id='192.168.0.5') self.quaggas['q4'] = q4 @@ -160,22 +157,22 @@ class GoBGPTestBase(unittest.TestCase): self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q4) - def test_05_check_global_rib(self): + def test_06_check_global_rib(self): self.test_02_check_gobgp_global_rib() - self.test_03_check_quagga_global_rib() + self.test_04_check_quagga_global_rib() - def test_06_stop_one_quagga(self): + def test_07_stop_one_quagga(self): q4 = self.quaggas['q4'] q4.stop() self.gobgp.wait_for(expected_state=BGP_FSM_ACTIVE, peer=q4) del self.quaggas['q4'] # check gobgp properly send withdrawal message with q4's route - def test_07_check_global_rib(self): + def test_08_check_global_rib(self): self.test_02_check_gobgp_global_rib() - self.test_03_check_quagga_global_rib() + self.test_04_check_quagga_global_rib() - def test_08_add_distant_relative(self): + def test_09_add_distant_relative(self): q1 = self.quaggas['q1'] q2 = self.quaggas['q2'] q3 = self.quaggas['q3'] @@ -232,6 +229,45 @@ class GoBGPTestBase(unittest.TestCase): if not done: self.assertTrue(False) + def test_10_originate_path(self): + self.gobgp.add_route('10.10.0.0/24') + dst = self.gobgp.get_global_rib('10.10.0.0/24') + self.assertTrue(len(dst) == 1) + self.assertTrue(len(dst[0]['paths']) == 1) + path = dst[0]['paths'][0] + self.assertTrue(path['nexthop'] == '0.0.0.0') + self.assertTrue(len(self.gobgp._get_as_path(path)) == 0) + + def test_11_check_adj_rib_out(self): + for q in self.quaggas.itervalues(): + paths = self.gobgp.get_adj_rib_out(q, '10.10.0.0/24') + self.assertTrue(len(paths) == 1) + path = paths[0] + peer_info = self.gobgp.peers[q] + local_addr = peer_info['local_addr'].split('/')[0] + self.assertTrue(path['nexthop'] == local_addr) + self.assertTrue(self.gobgp._get_as_path(path) == [self.gobgp.asn]) + + def test_12_disable_peer(self): + q1 = self.quaggas['q1'] + self.gobgp.disable_peer(q1) + self.gobgp.wait_for(expected_state=BGP_FSM_IDLE, peer=q1) + + for route in q1.routes.iterkeys(): + dst = self.gobgp.get_global_rib(route) + self.assertTrue(len(dst) == 0) + + for q in self.quaggas.itervalues(): + paths = self.gobgp.get_adj_rib_out(q, route) + self.assertTrue(len(paths) == 0) + + def test_13_enable_peer(self): + q1 = self.quaggas['q1'] + self.gobgp.enable_peer(q1) + self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q1) + + def test_14_check_adj_rib_out(self): + self.test_11_check_adj_rib_out() if __name__ == '__main__': if os.geteuid() is not 0: diff --git a/test/scenario_test/lib/base.py b/test/scenario_test/lib/base.py index 119e188c..5dec078f 100644 --- a/test/scenario_test/lib/base.py +++ b/test/scenario_test/lib/base.py @@ -35,6 +35,7 @@ BGP_ATTR_TYPE_NEXT_HOP = 3 BGP_ATTR_TYPE_MULTI_EXIT_DISC = 4 BGP_ATTR_TYPE_LOCAL_PREF = 5 + def get_bridges(): return local("brctl show | awk 'NR > 1{print $1}'", capture=True).split('\n') @@ -196,9 +197,11 @@ class BGPContainer(Container): policies=None, passive=False, is_rr_client=False, cluster_id=''): neigh_addr = '' + local_addr = '' for me, you in itertools.product(self.ip_addrs, peer.ip_addrs): if me[2] == you[2]: neigh_addr = you[1] + local_addr = me[1] if neigh_addr == '': raise Exception('peer {0} seems not ip reachable'.format(peer)) @@ -213,7 +216,8 @@ class BGPContainer(Container): 'is_rr_client': is_rr_client, 'cluster_id': cluster_id, 'policies': policies, - 'passive': passive} + 'passive': passive, + 'local_addr': local_addr} if self.is_running: self.create_config() self.reload_config() @@ -224,8 +228,16 @@ class BGPContainer(Container): self.create_config() self.reload_config() - def add_route(self, route, attribute=''): - self.routes[route] = attribute + def disable_peer(self, peer): + raise Exception('implement disable_peer() method') + + def enable_peer(self, peer): + raise Exception('implement enable_peer() method') + + def add_route(self, route, rf='ipv4', attribute=''): + self.routes[route] = {'prefix': route, + 'rf': rf, + 'attr': attribute} if self.is_running: self.create_config() self.reload_config() diff --git a/test/scenario_test/lib/gobgp.py b/test/scenario_test/lib/gobgp.py index 4e26b922..3b7ec5ba 100644 --- a/test/scenario_test/lib/gobgp.py +++ b/test/scenario_test/lib/gobgp.py @@ -18,6 +18,7 @@ import json import toml import subprocess import select +from itertools import chain class GoBGPContainer(BGPContainer): @@ -52,6 +53,28 @@ class GoBGPContainer(BGPContainer): self._start_gobgp() return self.WAIT_FOR_BOOT + def _get_as_path(self, path): + asps = (p['as_paths'] for p in path['attrs'] if + p['type'] == BGP_ATTR_TYPE_AS_PATH) + asps = chain.from_iterable(asps) + asns = (asp['asns'] for asp in asps) + return list(chain.from_iterable(asns)) + + def _trigger_peer_cmd(self, cmd, peer): + if peer not in self.peers: + raise Exception('not found peer {0}'.format(peer.router_id)) + peer_addr = self.peers[peer]['neigh_addr'].split('/')[0] + cmd = "docker exec {0} gobgp neighbor {1} {2}".format(self.name, + peer_addr, + cmd) + local(str(cmd), capture=True) + + def disable_peer(self, peer): + self._trigger_peer_cmd('disable', peer) + + def enable_peer(self, peer): + self._trigger_peer_cmd('enable', peer) + def get_local_rib(self, peer, rf='ipv4'): if peer not in self.peers: raise Exception('not found peer {0}'.format(peer.router_id)) @@ -80,7 +103,7 @@ class GoBGPContainer(BGPContainer): gobgp = '/go/bin/gobgp' cmd = 'docker exec {0} {1} neighbor {2}'\ ' adj-{3} {4} -a {5} -j'.format(self.name, gobgp, peer_addr, - adj_type, prefix, rf) + adj_type, prefix, rf) output = local(cmd, capture=True) return json.loads(output) @@ -135,7 +158,6 @@ class GoBGPContainer(BGPContainer): continue raise Exception('timeout') - def create_config(self): config = {'Global': {'As': self.asn, 'RouterId': self.router_id}} for peer, info in self.peers.iteritems(): @@ -188,3 +210,7 @@ class GoBGPContainer(BGPContainer): def reload_config(self): cmd = 'docker exec {0} /usr/bin/pkill gobgpd -SIGHUP'.format(self.name) local(cmd, capture=True) + for v in self.routes.itervalues(): + cmd = 'docker exec {0} gobgp global '\ + 'rib add {1} -a {2}'.format(self.name, v['prefix'], v['rf']) + local(cmd, capture=True) |