diff options
-rw-r--r-- | server/zclient.go | 38 | ||||
-rw-r--r-- | test/lib/gobgp.py | 4 | ||||
-rw-r--r-- | test/scenario_test/bgp_zebra_test.py | 100 |
3 files changed, 133 insertions, 9 deletions
diff --git a/server/zclient.go b/server/zclient.go index 1b37e5db..6da629c3 100644 --- a/server/zclient.go +++ b/server/zclient.go @@ -28,14 +28,23 @@ import ( "strings" ) -func newIPRouteMessage(path *table.Path) *zebra.Message { - if path == nil || path.IsFromExternal() { +func newIPRouteMessage(dst []*table.Path) *zebra.Message { + paths := make([]*table.Path, 0, len(dst)) + for _, path := range dst { + if path == nil || path.IsFromExternal() { + continue + } + paths = append(paths, path) + } + if len(paths) == 0 { return nil } + path := paths[0] + l := strings.SplitN(path.GetNlri().String(), "/", 2) var command zebra.API_TYPE var prefix net.IP - nexthops := []net.IP{} + nexthops := make([]net.IP, 0, len(paths)) switch path.GetRouteFamily() { case bgp.RF_IPv4_UC: if path.IsWithdraw == true { @@ -44,7 +53,9 @@ func newIPRouteMessage(path *table.Path) *zebra.Message { command = zebra.IPV4_ROUTE_ADD } prefix = net.ParseIP(l[0]).To4() - nexthops = append(nexthops, path.GetNexthop().To4()) + for _, p := range paths { + nexthops = append(nexthops, p.GetNexthop().To4()) + } case bgp.RF_IPv6_UC: if path.IsWithdraw == true { command = zebra.IPV6_ROUTE_DELETE @@ -52,11 +63,12 @@ func newIPRouteMessage(path *table.Path) *zebra.Message { command = zebra.IPV6_ROUTE_ADD } prefix = net.ParseIP(l[0]).To16() - nexthops = append(nexthops, path.GetNexthop().To16()) + for _, p := range paths { + nexthops = append(nexthops, p.GetNexthop().To16()) + } default: return nil } - flags := uint8(zebra.MESSAGE_NEXTHOP) plen, _ := strconv.Atoi(l[1]) med, err := path.GetMed() @@ -203,9 +215,17 @@ func (w *zebraWatcher) loop() error { } case ev := <-w.ch: msg := ev.(*watcherEventBestPathMsg) - for _, path := range msg.pathList { - if m := newIPRouteMessage(path); m != nil { - w.client.Send(m) + if table.UseMultiplePaths.Enabled { + for _, dst := range msg.multiPathList { + if m := newIPRouteMessage(dst); m != nil { + w.client.Send(m) + } + } + } else { + for _, path := range msg.pathList { + if m := newIPRouteMessage([]*table.Path{path}); m != nil { + w.client.Send(m) + } } } } diff --git a/test/lib/gobgp.py b/test/lib/gobgp.py index cf72b721..07b2c8b0 100644 --- a/test/lib/gobgp.py +++ b/test/lib/gobgp.py @@ -237,6 +237,10 @@ class GoBGPContainer(BGPContainer): }, }, }} + + if self.zebra: + config['global']['use-multiple-paths'] = {'config': {'enabled': True}} + for peer, info in self.peers.iteritems(): afi_safi_list = [] version = netaddr.IPNetwork(info['neigh_addr']).version diff --git a/test/scenario_test/bgp_zebra_test.py b/test/scenario_test/bgp_zebra_test.py index 7a024534..6b33a9f9 100644 --- a/test/scenario_test/bgp_zebra_test.py +++ b/test/scenario_test/bgp_zebra_test.py @@ -176,6 +176,106 @@ class GoBGPTestBase(unittest.TestCase): o2.add_static_route(self.bridges['br02_v6'].subnet, next_hop) g1.get_reachablily('2001:30::2') + def test_07_mpath_test_setup(self): + g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1', + ctn_image_name=parser_option.gobgp_image, + log_level=parser_option.gobgp_log_level, + config_format=parser_option.config_format, + zebra=True) + g2 = GoBGPContainer(name='g2', asn=65001, router_id='192.168.0.2') + g3 = GoBGPContainer(name='g3', asn=65001, router_id='192.168.0.3') + g4 = GoBGPContainer(name='g4', asn=65000, router_id='192.168.0.4') + g5 = GoBGPContainer(name='g5', asn=65000, router_id='192.168.0.5') + + ctns = [g1, g2, g3, g4, g5] + for ctn in ctns: + self.ctns[ctn.name] = ctn + + initial_wait_time = max(ctn.run() for ctn in ctns) + + time.sleep(initial_wait_time) + + # advertise same prefix + g2.add_route('10.0.10.0/24') + g3.add_route('10.0.10.0/24') + g4.add_route('10.0.10.0/24') + g5.add_route('10.0.10.0/24') + + for g in [g2, g3, g4, g5]: + g1.add_peer(g) + g.add_peer(g1) + + def test_08_mpath_test_check_neighbor_established(self): + g1 = self.ctns['g1'] + g2 = self.ctns['g2'] + g3 = self.ctns['g3'] + g4 = self.ctns['g4'] + g5 = self.ctns['g5'] + for g in [g2, g3, g4, g5]: + g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=g) + time.sleep(3) + + def test_09_mpath_test_check_mpath_injected(self): + g1 = self.ctns['g1'] + g2 = self.ctns['g2'] + g3 = self.ctns['g3'] + g4 = self.ctns['g4'] + g5 = self.ctns['g5'] + + def nexthops(): + n = [] + for line in g1.local('ip route show 10.0.10.0/24', capture=True).split('\n'): + line = line.strip() + if 'via' in line: + n.append(line.split(' ')[2].strip()) + return n + + nhs = nexthops() + self.assertTrue(len(nhs) == 2) + self.assertTrue(g1.peers[g4]['neigh_addr'].split('/')[0] in nhs) + self.assertTrue(g1.peers[g5]['neigh_addr'].split('/')[0] in nhs) + + g4.local('gobgp g ri del 10.0.10.0/24') + time.sleep(3) + + nhs = nexthops() + self.assertTrue(len(nhs) == 1) + self.assertTrue(g1.peers[g5]['neigh_addr'].split('/')[0] in nhs) + + g4.local('gobgp g ri add 10.0.10.0/24 local-pref 200') + time.sleep(3) + + nhs = nexthops() + self.assertTrue(len(nhs) == 1) + self.assertTrue(g1.peers[g4]['neigh_addr'].split('/')[0] in nhs) + + g4.local('gobgp g ri del 10.0.10.0/24') + g5.local('gobgp g ri del 10.0.10.0/24') + time.sleep(3) + + nhs = nexthops() + self.assertTrue(len(nhs) == 2) + self.assertTrue(g1.peers[g2]['neigh_addr'].split('/')[0] in nhs) + self.assertTrue(g1.peers[g3]['neigh_addr'].split('/')[0] in nhs) + + g3.local('gobgp g ri del 10.0.10.0/24') + time.sleep(3) + + nhs = nexthops() + self.assertTrue(len(nhs) == 1) + self.assertTrue(g1.peers[g2]['neigh_addr'].split('/')[0] in nhs) + + g3.local('gobgp g ri add 10.0.10.0/24 med 10') + + nhs = nexthops() + self.assertTrue(len(nhs) == 1) + self.assertTrue(g1.peers[g2]['neigh_addr'].split('/')[0] in nhs) + + g2.local('gobgp g ri add 10.0.10.0/24 med 20') + + nhs = nexthops() + self.assertTrue(len(nhs) == 1) + self.assertTrue(g1.peers[g3]['neigh_addr'].split('/')[0] in nhs) if __name__ == '__main__': if os.geteuid() is not 0: |