diff options
Diffstat (limited to 'test/scenario_test/lib/gobgp.py')
-rw-r--r-- | test/scenario_test/lib/gobgp.py | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/test/scenario_test/lib/gobgp.py b/test/scenario_test/lib/gobgp.py new file mode 100644 index 00000000..d9115f1b --- /dev/null +++ b/test/scenario_test/lib/gobgp.py @@ -0,0 +1,175 @@ +# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from base import * +import json +import toml +import subprocess +import select + + +class GoBGPContainer(BGPContainer): + + PEER_TYPE_INTERNAL = 0 + PEER_TYPE_EXTERNAL = 1 + SHARED_VOLUME = '/root/shared_volume' + + def __init__(self, name, asn, router_id, ctn_image_name='gobgp', + log_level='debug'): + super(GoBGPContainer, self).__init__(name, asn, router_id, + ctn_image_name) + self.shared_volumes.append((self.config_dir, self.SHARED_VOLUME)) + self.log_level = log_level + + def _start_gobgp(self): + c = CmdBuffer() + c << '#!/bin/bash' + c << '/go/bin/gobgpd -f {0}/gobgpd.conf -l {1} -p > ' \ + '{0}/gobgpd.log 2>&1'.format(self.SHARED_VOLUME, self.log_level) + + cmd = 'echo "{0:s}" > {1}/start.sh'.format(c, self.config_dir) + local(cmd, capture=True) + cmd = "chmod 755 {0}/start.sh".format(self.config_dir) + local(cmd, capture=True) + cmd = 'docker exec -d {0} {1}/start.sh'.format(self.name, + self.SHARED_VOLUME) + local(cmd, capture=True) + + def run(self): + super(GoBGPContainer, self).run() + self._start_gobgp() + return self.WAIT_FOR_BOOT + + def get_local_rib(self, peer, rf='ipv4'): + 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] + gobgp = '/go/bin/gobgp' + cmd = CmdBuffer(' ') + cmd << "docker exec {0} {1}".format(self.name, gobgp) + cmd << "-j neighbor {0} local -a {1}".format(peer_addr, rf) + output = local(str(cmd), capture=True) + n = json.loads(output) + return n + + def get_global_rib(self, prefix='', rf='ipv4'): + gobgp = '/go/bin/gobgp' + cmd = 'docker exec {0} {1} -j global rib {2} -a {3}'.format(self.name, + gobgp, + prefix, + rf) + + output = local(cmd, capture=True) + n = json.loads(output) + return n + + def get_neighbor_state(self, 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] + gobgp = '/go/bin/gobgp' + cmd = 'docker exec {0} {1} -j neighbor {2}'.format(self.name, + gobgp, + peer_addr) + output = local(cmd, capture=True) + return json.loads(output)['info']['bgp_state'] + + def wait_for(self, expected_state, peer, timeout=20): + state = self.get_neighbor_state(peer) + y = colors.yellow + print y("{0}'s peer {1} state: {2}".format(self.router_id, + peer.router_id, + state)) + if state == expected_state: + return + + peer_addr = self.peers[peer]['neigh_addr'].split('/')[0] + gobgp = '/go/bin/gobgp' + cmd = 'docker exec {0} {1} monitor neighbor {2} -j'.format(self.name, + gobgp, + peer_addr) + process = subprocess.Popen(cmd, shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + poll = select.epoll() + poll.register(process.stdout, select.POLLIN) + + while True: + result = poll.poll(float(timeout)) + if result: + line = process.stdout.readline() + info = json.loads(line)['info'] + print y("{0}'s peer {1} state: {2}".format(self.router_id, + peer.router_id, + info['bgp_state'])) + if info['bgp_state'] == expected_state: + return + continue + raise Exception('timeout') + + + def create_config(self): + config = {'Global': {'As': self.asn, 'RouterId': self.router_id}} + for peer, info in self.peers.iteritems(): + if self.asn == peer.asn: + peer_type = self.PEER_TYPE_INTERNAL + else: + peer_type = self.PEER_TYPE_EXTERNAL + + afi_safi_list = [] + version = netaddr.IPNetwork(info['neigh_addr']).version + if version == 4: + afi_safi_list.append({'AfiSafiName': 'ipv4-unicast'}) + elif version == 6: + afi_safi_list.append({'AfiSafiName': 'ipv6-unicast'}) + else: + Exception('invalid ip address version. {0}'.format(version)) + + if info['evpn']: + afi_safi_list.append({'AfiSafiName': 'l2vpn-evpn'}) + afi_safi_list.append({'AfiSafiName': 'encap'}) + afi_safi_list.append({'AfiSafiName': 'rtc'}) + + n = {'NeighborAddress': info['neigh_addr'].split('/')[0], + 'PeerAs': peer.asn, + 'AuthPassword': info['passwd'], + 'PeerType': peer_type, + 'AfiSafiList': afi_safi_list} + + if info['passive']: + n['TransportOptions'] = {'PassiveMode': True} + + if info['is_rs_client']: + n['RouteServer'] = {'RouteServerClient': True} + + if info['is_rr_client']: + clusterId = info['cluster_id'] + n['RouteReflector'] = {'RouteReflectorClient': True, + 'RouteReflectorClusterId': clusterId} + + if 'NeighborList' not in config: + config['NeighborList'] = [] + + config['NeighborList'].append(n) + + with open('{0}/gobgpd.conf'.format(self.config_dir), 'w') as f: + print colors.yellow('[{0}\'s new config]'.format(self.name)) + print colors.yellow(indent(toml.dumps(config))) + f.write(toml.dumps(config)) + + def reload_config(self): + cmd = 'docker exec {0} /usr/bin/pkill gobgpd -SIGHUP'.format(self.name) + local(cmd, capture=True) |