# 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.

import unittest
from fabric.api import local
from lib import base
from lib.gobgp import *
from lib.quagga import *
from lib.exabgp import *
import sys
import os
import time
import nose
from noseplugin import OptionParser, parser_option


scenarios = {}


def scenario(idx):
    def wrapped(f):
        if idx not in scenarios:
            scenarios[idx] = {}
        if f.__name__ in scenarios[idx]:
            raise Exception('scenario index {0}. already exists'.format(idx))

        scenarios[idx][f.__name__] = f
    return wrapped


def wait_for(f, timeout=120):
    interval = 1
    count = 0
    while True:
        if f():
            return

        time.sleep(interval)
        count += interval
        if count >= timeout:
            raise Exception('timeout')


"""
  No.1 import-policy test
                          --------------------------------
  e1 ->(192.168.2.0/24)-> | ->  q1-rib -> q1-adj-rib-out | --> q1
                          |                              |
                          | ->x q2-rib                   |
                          --------------------------------
"""
@scenario(1)
def boot(env):
    gobgp_ctn_image_name = env.parser_option.gobgp_image
    log_level = env.parser_option.gobgp_log_level
    g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1',
                        ctn_image_name=gobgp_ctn_image_name,
                        log_level=log_level)
    e1 = ExaBGPContainer(name='e1', asn=65001, router_id='192.168.0.2')
    q1 = QuaggaBGPContainer(name='q1', asn=65002, router_id='192.168.0.3')
    q2 = QuaggaBGPContainer(name='q2', asn=65003, router_id='192.168.0.4')

    ctns = [g1, e1, q1, q2]
    initial_wait_time = max(ctn.run() for ctn in ctns)
    time.sleep(initial_wait_time)

    br01 = Bridge(name='br01', subnet='192.168.10.0/24')
    [br01.addif(ctn) for ctn in ctns]

    for q in [e1, q1, q2]:
        g1.add_peer(q, is_rs_client=True)
        q.add_peer(g1)

    env.g1 = g1
    env.e1 = e1
    env.q1 = q1
    env.q2 = q2

@scenario(1)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.0.0/16',
          'MasklengthRange': '16..24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[e1]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
               'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('192.168.2.0/24')
    # this will pass
    e1.add_route('192.168.2.0/15')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)


@scenario(1)
def check(env):
    wait_for(lambda: len(env.g1.get_local_rib(env.q1)) == 2)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q1)) == 2)
    wait_for(lambda: len(env.q1.get_global_rib()) == 2)
    wait_for(lambda: len(env.g1.get_local_rib(env.q2)) == 1)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q2)) == 1)
    wait_for(lambda: len(env.q2.get_global_rib()) == 1)

"""
  No.2 export-policy test
                          --------------------------------
  e1 ->(192.168.2.0/24)-> | -> q1-rib ->  q1-adj-rib-out | --> q1
                          |                              |
                          | -> q2-rib ->x q2-adj-rib-out |
                          --------------------------------
"""
@scenario(2)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(2)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.0.0/16',
          'MasklengthRange': '16..24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[q2]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
               'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('192.168.2.0/24')
    # this will pass
    e1.add_route('192.168.2.0/15')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(2)
def check(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_local_rib(q1)) == 2)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 2)
    wait_for(lambda : len(q1.get_global_rib()) == 2)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 2)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 1)
    wait_for(lambda : len(q2.get_global_rib()) == 1)

"""
  No.3 import-policy update test

  r1:192.168.2.0/24
  r2:192.168.20.0/24
  r3:192.168.200.0/24
                    -------------------------------------------------
                    | q1                                            |
  e1 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> q1
                    |                                               |
                    | q2                                            |
                    | ->(r1)->       rib ->(r1)->       adj-rib-out | ->(r1)-> q2
                    -------------------------------------------------
               |
       update gobgp.conf
               |
               V
                    -------------------------------------------------
                    | q1                                            |
  e1 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> q1
                    |                                               |
                    | q2                                            |
                    | ->(r1,r3)->    rib ->(r1,r3)->    adj-rib-out | ->(r1,r3)-> q2
                    -------------------------------------------------
"""
@scenario(3)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(3)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.20.0/24'}
    p1 = {'IpPrefix': '192.168.200.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0, p1]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[e1]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
               'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.2.0/24')
    e1.add_route('192.168.20.0/24')
    e1.add_route('192.168.200.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(3)
def check(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_local_rib(q1)) == 3)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 3)
    wait_for(lambda : len(q1.get_global_rib()) == 3)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 1)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 1)
    wait_for(lambda : len(q2.get_global_rib()) == 1)

@scenario(3)
def setup2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    g1.clear_policy()

    p0 = {'IpPrefix': '192.168.20.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[e1]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
                          'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)
    g1.softreset(e1)

@scenario(3)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_local_rib(q1)) == 3)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 3)
    wait_for(lambda : len(q1.get_global_rib()) == 3)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 2)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 2)
    wait_for(lambda : len(q2.get_global_rib()) == 2)

"""
  No.4 export-policy update test

  r1:192.168.2.0
  r2:192.168.20.0
  r3:192.168.200.0
                    -------------------------------------------------
                    | q1                                            |
  e1 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> q1
                    |                                               |
                    | q2                                            |
                    | ->(r1,r2,r3)-> rib ->(r1)->       adj-rib-out | ->(r1)-> q2
                    -------------------------------------------------
               |
       update gobgp.conf
               |
               V
                    -------------------------------------------------
                    | q1                                            |
  e1 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> q1
                    |                                               |
                    | q2                                            |
                    | ->(r1,r2,r3)-> rib ->(r1,r3)->    adj-rib-out | ->(r1,r3)-> q2
                    -------------------------------------------------
"""
@scenario(4)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(4)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    p0 = {'IpPrefix': '192.168.20.0/24'}
    p1 = {'IpPrefix': '192.168.200.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0, p1]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[q2]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
                          'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.2.0/24')
    e1.add_route('192.168.20.0/24')
    e1.add_route('192.168.200.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(4)
def check(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_local_rib(q1)) == 3)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 3)
    wait_for(lambda : len(q1.get_global_rib()) == 3)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 3)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 1)
    wait_for(lambda : len(q2.get_global_rib()) == 1)

@scenario(4)
def setup2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    g1.clear_policy()

    p0 = {'IpPrefix': '192.168.20.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[q2]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
                          'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # we need hard reset to flush q2's local rib
    g1.reset(e1)

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)


@scenario(4)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_local_rib(q1)) == 3)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 3)
    wait_for(lambda : len(q1.get_global_rib()) == 3)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 3)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 2)
    wait_for(lambda : len(q2.get_global_rib()) == 2)

"""
   No.5 IPv6 import-policy test

   r1=2001::/64
   r2=2001::/63
                  -------------------------------------------------
   e1 ->(r1,r2)-> | ->(r1,r2)-> q1-rib ->(r1,r2)-> q1-adj-rib-out | ->(r1,r2)-> q1
                  |                                               |
                  | ->(r2)   -> q2-rib ->(r2)   -> q2-adj-rib-out | ->(r2)-> q2
                  -------------------------------------------------
"""
@scenario(5)
def boot(env):
    gobgp_ctn_image_name = env.parser_option.gobgp_image
    log_level = env.parser_option.gobgp_log_level
    g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1',
                        ctn_image_name=gobgp_ctn_image_name,
                        log_level=log_level)
    e1 = ExaBGPContainer(name='e1', asn=65001, router_id='192.168.0.2')
    q1 = QuaggaBGPContainer(name='q1', asn=65002, router_id='192.168.0.3')
    q2 = QuaggaBGPContainer(name='q2', asn=65003, router_id='192.168.0.4')

    ctns = [g1, e1, q1, q2]
    initial_wait_time = max(ctn.run() for ctn in ctns)
    time.sleep(initial_wait_time)

    br01 = Bridge(name='br01', subnet='2001::/96')
    [br01.addif(ctn) for ctn in ctns]

    for q in [e1, q1, q2]:
        g1.add_peer(q, is_rs_client=True)
        q.add_peer(g1)

    env.g1 = g1
    env.e1 = e1
    env.q1 = q1
    env.q2 = q2

@scenario(5)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '2001::/32',
          'MasklengthRange': '64..128'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[e1]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
               'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('2001::/64', rf='ipv6')
    # this will pass
    e1.add_route('2001::/63', rf='ipv6')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(5)
def check(env):
    wait_for(lambda: len(env.g1.get_local_rib(env.q1, rf='ipv6')) == 2)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q1, rf='ipv6')) == 2)
    wait_for(lambda: len(env.q1.get_global_rib(rf='ipv6')) == 2)
    wait_for(lambda: len(env.g1.get_local_rib(env.q2, rf='ipv6')) == 1)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q2, rf='ipv6')) == 1)
    wait_for(lambda: len(env.q2.get_global_rib(rf='ipv6')) == 1)

"""
   No.6 IPv6 export-policy test

   r1=2001::/64
   r2=2001::/63
                  -------------------------------------------------
   e1 ->(r1,r2)-> | ->(r1,r2)-> q1-rib ->(r1,r2)-> q1-adj-rib-out | ->(r1,r2)-> q1
                  |                                               |
                  | ->(r1,r2)-> q2-rib ->(r2)   -> q2-adj-rib-out | ->(r2)-> q2
                  -------------------------------------------------
"""
@scenario(6)
def boot(env):
    scenarios[5]['boot'](env)

@scenario(6)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '2001::/32',
          'MasklengthRange': '64..128'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[q2]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
               'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('2001::/64', rf='ipv6')
    # this will pass
    e1.add_route('2001::/63', rf='ipv6')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(6)
def check(env):
    wait_for(lambda: len(env.g1.get_local_rib(env.q1, rf='ipv6')) == 2)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q1, rf='ipv6')) == 2)
    wait_for(lambda: len(env.q1.get_global_rib(rf='ipv6')) == 2)
    wait_for(lambda: len(env.g1.get_local_rib(env.q2, rf='ipv6')) == 2)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q2, rf='ipv6')) == 1)
    wait_for(lambda: len(env.q2.get_global_rib(rf='ipv6')) == 1)

"""
  No.7 IPv6 import-policy update test
  r1=2001:0:10:2::/64
  r2=2001:0:10:20::/64
  r3=2001:0:10:200::/64
                    -------------------------------------------------
                    | q1                                            |
  e1 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> q1
                    |                                               |
                    | q2                                            |
                    | ->(r1)->       rib ->(r1)->       adj-rib-out | ->(r1)-> q2
                    -------------------------------------------------
               |
       update gobgp.conf
               |
               V
                    -------------------------------------------------
                    | q1                                            |
  e1 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> q1
                    |                                               |
                    | q2                                            |
                    | ->(r1,r3)->    rib ->(r1,r3)->    adj-rib-out | ->(r1,r3)-> q2
                    -------------------------------------------------
"""
@scenario(7)
def boot(env):
    scenarios[5]['boot'](env)

@scenario(7)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '2001:0:10:2::/64'}
    p1 = {'IpPrefix': '2001:0:10:20::/64'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0, p1]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[e1]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
               'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('2001:0:10:2::/64', rf='ipv6')
    e1.add_route('2001:0:10:20::/64', rf='ipv6')
    e1.add_route('2001:0:10:200::/64', rf='ipv6')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(7)
def check(env):
    wait_for(lambda: len(env.g1.get_local_rib(env.q1, rf='ipv6')) == 3)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q1, rf='ipv6')) == 3)
    wait_for(lambda: len(env.q1.get_global_rib(rf='ipv6')) == 3)
    wait_for(lambda: len(env.g1.get_local_rib(env.q2, rf='ipv6')) == 1)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q2, rf='ipv6')) == 1)
    wait_for(lambda: len(env.q2.get_global_rib(rf='ipv6')) == 1)

@scenario(7)
def setup2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '2001:0:10:2::/64'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[e1]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
               'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)
    g1.softreset(e1, rf='ipv6')

@scenario(7)
def check2(env):
    wait_for(lambda: len(env.g1.get_local_rib(env.q1, rf='ipv6')) == 3)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q1, rf='ipv6')) == 3)
    wait_for(lambda: len(env.q1.get_global_rib(rf='ipv6')) == 3)
    wait_for(lambda: len(env.g1.get_local_rib(env.q2, rf='ipv6')) == 2)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q2, rf='ipv6')) == 2)
    wait_for(lambda: len(env.q2.get_global_rib(rf='ipv6')) == 2)

"""
  No.8 IPv6 export-policy update test
  r1=2001:0:10:2::/64
  r2=2001:0:10:20::/64
  r3=2001:0:10:200::/64
                    -------------------------------------------------
                    | q1                                            |
  e1 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> q1
                    |                                               |
                    | q2                                            |
                    | ->(r1,r2,r3)-> rib ->(r1)->       adj-rib-out | ->(r1)-> q2
                    -------------------------------------------------
               |
       update gobgp.conf
               |
               V
                    -------------------------------------------------
                    | q1                                            |
  e1 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> q1
                    |                                               |
                    | q2                                            |
                    | ->(r1,r2,r3)-> rib ->(r1,r3)->    adj-rib-out | ->(r1,r3)-> q2
                    -------------------------------------------------
"""
@scenario(8)
def boot(env):
    scenarios[5]['boot'](env)

@scenario(8)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '2001:0:10:2::/64'}
    p1 = {'IpPrefix': '2001:0:10:20::/64'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0, p1]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[q2]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
               'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('2001:0:10:2::/64', rf='ipv6')
    e1.add_route('2001:0:10:20::/64', rf='ipv6')
    e1.add_route('2001:0:10:200::/64', rf='ipv6')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(8)
def check(env):
    wait_for(lambda: len(env.g1.get_local_rib(env.q1, rf='ipv6')) == 3)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q1, rf='ipv6')) == 3)
    wait_for(lambda: len(env.q1.get_global_rib(rf='ipv6')) == 3)
    wait_for(lambda: len(env.g1.get_local_rib(env.q2, rf='ipv6')) == 3)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q2, rf='ipv6')) == 1)
    wait_for(lambda: len(env.q2.get_global_rib(rf='ipv6')) == 1)

@scenario(8)
def setup2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '2001:0:10:2::/64'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[q2]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
               'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)
    g1.reset(e1)

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(8)
def check2(env):
    wait_for(lambda: len(env.g1.get_local_rib(env.q1, rf='ipv6')) == 3)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q1, rf='ipv6')) == 3)
    wait_for(lambda: len(env.q1.get_global_rib(rf='ipv6')) == 3)
    wait_for(lambda: len(env.g1.get_local_rib(env.q2, rf='ipv6')) == 3)
    wait_for(lambda: len(env.g1.get_adj_rib_out(env.q2, rf='ipv6')) == 2)
    wait_for(lambda: len(env.q2.get_global_rib(rf='ipv6')) == 2)

"""
  No.9 aspath length condition import-policy test
                            --------------------------------
  e1 ->(aspath_length=10)-> | ->  q1-rib -> q1-adj-rib-out | --> q1
                            |                              |
                            | ->x q2-rib                   |
                            --------------------------------

"""
@scenario(9)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(9)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'AsPathLength':{'Operator': 'ge',
                                                          'Value': 10}}}}


    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('192.168.100.0/24', aspath=range(e1.asn, e1.asn-10, -1))
    # this will pass
    e1.add_route('192.168.200.0/24', aspath=range(e1.asn, e1.asn-8, -1))

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(9)
def check(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_local_rib(q1)) == 2)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 2)
    wait_for(lambda : len(q1.get_global_rib()) == 2)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 1)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 1)
    wait_for(lambda : len(q2.get_global_rib()) == 1)


"""
  No.10 aspath from condition import-policy test
                              --------------------------------
  e1 ->(aspath=[65100,...])-> | ->  q1-rib -> q1-adj-rib-out | --> q1
                              |                              |
                              | ->x q2-rib                   |
                              --------------------------------

"""
@scenario(10)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(10)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    as0 = {'AsPathSets': {'AsPathSetList': [{'AsPathSetName': 'as0', 'AsPathList': [{'AsPath': '^{0}'.format(e1.asn)}]}]}}

    g1.set_bgp_defined_set(as0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchAsPathSet':{'AsPathSet': 'as0'}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('192.168.100.0/24', aspath=range(e1.asn, e1.asn-10, -1))
    # this will pass
    e1.add_route('192.168.200.0/24', aspath=range(e1.asn-1, e1.asn-10, -1))

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(10)
def check(env):
    # same check function as previous No.1 scenario
    scenarios[1]['check'](env)

"""
  No.11 aspath any condition import-policy test
                                 --------------------------------
  e1 ->(aspath=[...65098,...])-> | ->  q1-rib -> q1-adj-rib-out | --> q1
                                 |                              |
                                 | ->x q2-rib                   |
                                 --------------------------------

"""
@scenario(11)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(11)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    as0 = {'AsPathSets': {'AsPathSetList': [{'AsPathSetName': 'as0', 'AsPathList': [{'AsPath': '65098'}]}]}}

    g1.set_bgp_defined_set(as0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchAsPathSet':{'AsPathSet': 'as0'}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('192.168.100.0/24', aspath=[65000, 65098, 65010])
    # this will pass
    e1.add_route('192.168.200.0/24', aspath=[65000, 65100, 65010])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(11)
def check(env):
    # same check function as previous No.1 scenario
    scenarios[1]['check'](env)

"""
  No.12 aspath origin condition import-policy test
                              --------------------------------
  e1 ->(aspath=[...,65090])-> | ->  q1-rib -> q1-adj-rib-out | --> q1
                              |                              |
                              | ->x q2-rib                   |
                              --------------------------------

"""
@scenario(12)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(12)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    as0 = {'AsPathSets': {'AsPathSetList': [{'AsPathSetName': 'as0', 'AsPathList': [{'AsPath': '65090$'}]}]}}

    g1.set_bgp_defined_set(as0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchAsPathSet':{'AsPathSet': 'as0'}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('192.168.100.0/24', aspath=[65000, 65098, 65090])
    # this will pass
    e1.add_route('192.168.200.0/24', aspath=[65000, 65100, 65010])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)



@scenario(12)
def check(env):
    # same check function as previous No.1 scenario
    scenarios[1]['check'](env)

"""
  No.13 aspath only condition import-policy test
                            --------------------------------
  e1 -> (aspath=[65100]) -> | ->  q1-rib -> q1-adj-rib-out | --> q1
                            |                              |
                            | ->x q2-rib                   |
                            --------------------------------

"""
@scenario(13)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(13)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    as0 = {'AsPathSets': {'AsPathSetList': [{'AsPathSetName': 'as0', 'AsPathList': [{'AsPath': '^65100$'}]}]}}

    g1.set_bgp_defined_set(as0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchAsPathSet':{'AsPathSet': 'as0'}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('192.168.100.0/24', aspath=[65100])
    # this will pass
    e1.add_route('192.168.200.0/24', aspath=[65000, 65100, 65010])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(13)
def check(env):
    # same check function as previous No.1 scenario
    scenarios[1]['check'](env)

"""
  No.14 aspath condition mismatch import-policy test
                                 -------------------------------
  exabgp ->(aspath=[...,65090])->| -> q1-rib -> q1-adj-rib-out | --> q1
                                 |                             |
                                 | -> q2-rib -> q2-adj-rib-out | --> q2
                                 -------------------------------
  This case check if policy passes the path to e1 because of condition mismatch.
"""
@scenario(14)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(14)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('192.168.100.0/24', aspath=[65100, 65090])
    # this will pass
    e1.add_route('192.168.200.0/24', aspath=[65000, 65100, 65010])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(14)
def check(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_local_rib(q1)) == 2)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 2)
    wait_for(lambda : len(q1.get_global_rib()) == 2)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 2)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 2)
    wait_for(lambda : len(q2.get_global_rib()) == 2)


"""
  No.15 community condition import-policy test
                              --------------------------------
  e1 ->(community=65100:10)-> | ->  q1-rib -> q1-adj-rib-out | --> q1
                              |                              |
                              | ->x q2-rib                   |
                              --------------------------------
"""
@scenario(15)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(15)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('192.168.100.0/24', community=['65100:10'])
    # this will pass
    e1.add_route('192.168.200.0/24', community=['65100:20'])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)



@scenario(15)
def check(env):
    # same check function as previous No.1 scenario
    scenarios[1]['check'](env)

"""
  No.16 community condition regexp import-policy test
                              --------------------------------
  e1 ->(community=65100:10)-> | ->  q1-rib -> q1-adj-rib-out | --> q1
                              |                              |
                              | ->x q2-rib                   |
                              --------------------------------
"""
@scenario(16)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(16)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '6[0-9]+:[0-9]+'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    # this will be blocked
    e1.add_route('192.168.100.0/24', community=['65100:10'])
    # this will pass
    e1.add_route('192.168.200.0/24', community=['55100:20'])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(16)
def check(env):
    # same check function as previous No.4 scenario
    scenarios[1]['check'](env)

"""
  No.17 community add action import-policy test
                              -------------------------------
  e1 ->(community=65100:10)-> | -> q1-rib -> q1-adj-rib-out | ->(community=65100:10)->          q1
                              |                             |
                              | -> q2-rib -> q2-adj-rib-out | ->(community=65100:10,65100:20)-> q2
                              |    apply action             |
                              -------------------------------
"""
@scenario(17)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(17)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetCommunity': {'Options': 'ADD',
                                      'SetCommunityMethod': {'Communities': ['65100:20']}}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', community=['65100:10'])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

def community_exists(path, com):
    a, b = com.split(':')
    com = (int(a) << 16) + int(b)
    for a in path['attrs']:
        if a['type'] == BGP_ATTR_TYPE_COMMUNITIES and com in a['communities']:
            return True
    return False

@scenario(17)
def check(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_local_rib(q1)) == 1)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 1)
    wait_for(lambda : len(q1.get_global_rib()) == 1)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 1)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 1)
    wait_for(lambda : len(q2.get_global_rib()) == 1)

@scenario(17)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2
    path = g1.get_adj_rib_out(q1)[0]
    env.assertTrue(community_exists(path, '65100:10'))
    env.assertFalse(community_exists(path, '65100:20'))
    path = g1.get_adj_rib_out(q2)[0]
    env.assertTrue(community_exists(path, '65100:10'))
    env.assertTrue(community_exists(path, '65100:20'))

"""
  No.18 community replace action import-policy test
                              -------------------------------
  e1 ->(community=65100:10)-> | -> q1-rib -> q1-adj-rib-out | ->(community=65100:10)-> q1
                              |                             |
                              | -> q2-rib -> q2-adj-rib-out | ->(community=65100:20)-> q2
                              |    apply action             |
                              -------------------------------
"""
@scenario(18)
def boot(env):
    scenarios[1]['boot'](env)


@scenario(18)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetCommunity': {'Options': 'REPLACE',
                                      'SetCommunityMethod': {'Communities': ['65100:20']}}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', community=['65100:10'])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)



@scenario(18)
def check(env):
    # same check function as previous No.17 scenario
    scenarios[17]['check'](env)

@scenario(18)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    path = g1.get_adj_rib_out(q1)[0]
    env.assertTrue(community_exists(path, '65100:10'))
    env.assertFalse(community_exists(path, '65100:20'))
    path = g1.get_adj_rib_out(q2)[0]
    env.assertFalse(community_exists(path, '65100:10'))
    env.assertTrue(community_exists(path, '65100:20'))

"""
  No.19 community remove action import-policy test
                              -------------------------------
  e1 ->(community=65100:10)-> | -> q1-rib -> q1-adj-rib-out | ->(community=65100:10)-> q1
                              |                             |
                              | -> q2-rib -> q2-adj-rib-out | ->(community=null)->     q2
                              |    apply action             |
                              -------------------------------
"""
@scenario(19)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(19)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetCommunity': {'Options': 'REMOVE',
                                      'SetCommunityMethod': {'Communities': ['65100:10', '65100:20']}}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', community=['65100:10'])
    e1.add_route('192.168.110.0/24', community=['65100:10', '65100:20'])
    e1.add_route('192.168.120.0/24', community=['65100:10', '65100:30'])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(19)
def check(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_local_rib(q1)) == 3)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 3)
    wait_for(lambda : len(q1.get_global_rib()) == 3)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 3)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 3)
    wait_for(lambda : len(q2.get_global_rib()) == 3)

@scenario(19)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    adj_out = g1.get_adj_rib_out(q1)
    for path in adj_out:
        env.assertTrue(community_exists(path, '65100:10'))
        if path['nlri']['prefix'] == '192.168.110.0/24':
            env.assertTrue(community_exists(path, '65100:20'))
        if path['nlri']['prefix'] == '192.168.120.0/24':
            env.assertTrue(community_exists(path, '65100:30'))
    adj_out = g1.get_adj_rib_out(q2)
    for path in adj_out:
        env.assertFalse(community_exists(path, '65100:10'))
        if path['nlri']['prefix'] == '192.168.110.0/24':
            env.assertFalse(community_exists(path, '65100:20'))
        if path['nlri']['prefix'] == '192.168.120.0/24':
            env.assertTrue(community_exists(path, '65100:30'))

"""
  No.20 community null action import-policy test
                              -------------------------------
  e1 ->(community=65100:10)-> | -> q1-rib -> q1-adj-rib-out | ->(community=65100:10)-> q1
                              |                             |
                              | -> q2-rib -> q2-adj-rib-out | ->(community=null)->     q2
                              |    apply action             |
                              -------------------------------
"""
@scenario(20)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(20)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetCommunity': {'Options': 'REPLACE',
                                      'SetCommunityMethod': {'Communities': []}}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', community=['65100:10'])
    e1.add_route('192.168.110.0/24', community=['65100:10', '65100:20'])
    e1.add_route('192.168.120.0/24', community=['65100:10', '65100:30'])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(20)
def check(env):
    scenarios[19]['check'](env)

@scenario(20)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2
    adj_out = g1.get_adj_rib_out(q1)
    for path in adj_out:
        env.assertTrue(community_exists(path, '65100:10'))
        if path['nlri']['prefix'] == '192.168.110.0/24':
            env.assertTrue(community_exists(path, '65100:20'))
        if path['nlri']['prefix'] == '192.168.120.0/24':
            env.assertTrue(community_exists(path, '65100:30'))
    adj_out = g1.get_adj_rib_out(q2)
    for path in adj_out:
        env.assertFalse(community_exists(path, '65100:10'))
        if path['nlri']['prefix'] == '192.168.110.0/24':
            env.assertFalse(community_exists(path, '65100:20'))
        if path['nlri']['prefix'] == '192.168.120.0/24':
            env.assertFalse(community_exists(path, '65100:30'))


"""
  No.21 community add action export-policy test
                              -------------------------------
  e1 ->(community=65100:10)-> | -> q1-rib -> q1-adj-rib-out | ->(community=65100:10)-> q1
                              |                             |
                              | -> q2-rib -> q2-adj-rib-out | ->(community=null)->     q2
                              |              apply action   |
                              -------------------------------
"""
@scenario(21)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(21)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetCommunity': {'Options': 'ADD',
                                      'SetCommunityMethod': {'Communities': ['65100:20']}}}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', community=['65100:10'])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(21)
def check(env):
    scenarios[17]['check'](env)

@scenario(21)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2

    adj_out = g1.get_adj_rib_out(q1)
    for path in adj_out:
        env.assertTrue(community_exists(path, '65100:10'))
        env.assertFalse(community_exists(path, '65100:20'))

    local_rib = g1.get_local_rib(q2)
    for path in local_rib[0]['paths']:
        env.assertTrue(community_exists(path, '65100:10'))
        env.assertFalse(community_exists(path, '65100:20'))

    adj_out = g1.get_adj_rib_out(q2)
    for path in adj_out:
        env.assertTrue(community_exists(path, '65100:10'))
        env.assertTrue(community_exists(path, '65100:20'))

"""
  No.22 community replace action export-policy test
                              -------------------------------
  e1 ->(community=65100:10)-> | -> q1-rib -> q1-adj-rib-out | ->(community=65100:10)-> q1
                              |                             |
                              | -> q2-rib -> q2-adj-rib-out | ->(community=65100:20)-> q2
                              |              apply action   |
                              -------------------------------
"""
@scenario(22)
def boot(env):
    scenarios[1]['boot'](env)


@scenario(22)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetCommunity': {'Options': 'REPLACE',
                                      'SetCommunityMethod': {'Communities': ['65100:20']}}}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', community=['65100:10'])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(22)
def check(env):
    scenarios[17]['check'](env)

@scenario(22)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2

    adj_out = g1.get_adj_rib_out(q1)
    for path in adj_out:
        env.assertTrue(community_exists(path, '65100:10'))
        env.assertFalse(community_exists(path, '65100:20'))

    local_rib = g1.get_local_rib(q2)
    for path in local_rib[0]['paths']:
        env.assertTrue(community_exists(path, '65100:10'))
        env.assertFalse(community_exists(path, '65100:20'))

    adj_out = g1.get_adj_rib_out(q2)
    for path in adj_out:
        env.assertFalse(community_exists(path, '65100:10'))
        env.assertTrue(community_exists(path, '65100:20'))

"""
  No.23 community replace action export-policy test
                              -------------------------------
  e1 ->(community=65100:10)-> | -> q1-rib -> q1-adj-rib-out | ->(community=65100:10)-> q1
                              |                             |
                              | -> q2-rib -> q2-adj-rib-out | ->(community=null)->     q2
                              |              apply action   |
                              -------------------------------
"""
@scenario(23)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(23)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetCommunity': {'Options': 'REMOVE',
                                      'SetCommunityMethod': {'Communities': ['65100:20', '65100:30']}}}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', community=['65100:10', '65100:20', '65100:30'])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(23)
def check(env):
    scenarios[17]['check'](env)

@scenario(23)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2

    adj_out = g1.get_adj_rib_out(q1)
    for path in adj_out:
        env.assertTrue(community_exists(path, '65100:10'))
        env.assertTrue(community_exists(path, '65100:20'))
        env.assertTrue(community_exists(path, '65100:30'))

    local_rib = g1.get_local_rib(q2)
    for path in local_rib[0]['paths']:
        env.assertTrue(community_exists(path, '65100:10'))
        env.assertTrue(community_exists(path, '65100:20'))
        env.assertTrue(community_exists(path, '65100:30'))

    adj_out = g1.get_adj_rib_out(q2)
    for path in adj_out:
        env.assertTrue(community_exists(path, '65100:10'))
        env.assertFalse(community_exists(path, '65100:20'))
        env.assertFalse(community_exists(path, '65100:30'))

"""
  No.24 community null action export-policy test
                              -------------------------------
  e1 ->(community=65100:10)-> | -> q1-rib -> q1-adj-rib-out | ->(community=65100:10)-> q1
                              |                             |
                              | -> q2-rib -> q2-adj-rib-out | ->(community=null)->     q2
                              |              apply action   |
                              -------------------------------
"""
@scenario(24)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(24)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetCommunity': {'Options': 'REPLACE',
                                      'SetCommunityMethod': {'Communities': []}}}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', community=['65100:10', '65100:20', '65100:30'])

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(24)
def check(env):
    scenarios[17]['check'](env)

@scenario(24)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2

    adj_out = g1.get_adj_rib_out(q1)
    for path in adj_out:
        env.assertTrue(community_exists(path, '65100:10'))
        env.assertTrue(community_exists(path, '65100:20'))
        env.assertTrue(community_exists(path, '65100:30'))

    local_rib = g1.get_local_rib(q2)
    for path in local_rib[0]['paths']:
        env.assertTrue(community_exists(path, '65100:10'))
        env.assertTrue(community_exists(path, '65100:20'))
        env.assertTrue(community_exists(path, '65100:30'))

    adj_out = g1.get_adj_rib_out(q2)
    for path in adj_out:
        env.assertFalse(community_exists(path, '65100:10'))
        env.assertFalse(community_exists(path, '65100:20'))
        env.assertFalse(community_exists(path, '65100:30'))

"""
  No.25 med replace action import-policy test
                   -------------------------------
  e1 ->(med=300)-> | -> q1-rib -> q1-adj-rib-out | ->(med=300)-> q1
                   |                             |
                   | -> q2-rib -> q2-adj-rib-out | ->(med=100)-> q2
                   |    apply action             |
                   -------------------------------
"""
@scenario(25)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(25)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    st0 = {'Name': 'st0',
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetMed': '100'}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', med=300)

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)



def metric(path):
    for a in path['attrs']:
        if 'metric' in a:
            return a['metric']
    return -1

@scenario(25)
def check(env):
    scenarios[17]['check'](env)

@scenario(25)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2

    adj_out = g1.get_adj_rib_out(q1)
    env.assertTrue(metric(adj_out[0]) == 300)

    local_rib = g1.get_local_rib(q2)
    env.assertTrue(metric(local_rib[0]['paths'][0]) == 100)

    adj_out = g1.get_adj_rib_out(q2)
    env.assertTrue(metric(adj_out[0]) == 100)

"""
  No.26 med add action import-policy test
                   -------------------------------
  e1 ->(med=300)-> | -> q1-rib -> q1-adj-rib-out | ->(med=300)->     q1
                   |                             |
                   | -> q2-rib -> q2-adj-rib-out | ->(med=300+100)-> q2
                   |    apply action             |
                   -------------------------------
"""
@scenario(26)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(26)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    st0 = {'Name': 'st0',
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetMed': '+100'}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', med=300)

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(26)
def check(env):
    scenarios[17]['check'](env)

@scenario(26)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2

    adj_out = g1.get_adj_rib_out(q1)
    env.assertTrue(metric(adj_out[0]) == 300)

    local_rib = g1.get_local_rib(q2)
    env.assertTrue(metric(local_rib[0]['paths'][0]) == 400)

    adj_out = g1.get_adj_rib_out(q2)
    env.assertTrue(metric(adj_out[0]) == 400)

"""
  No.27 med subtract action import-policy test
                   -------------------------------
  e1 ->(med=300)-> | -> q1-rib -> q1-adj-rib-out | ->(med=300)->     q1
                   |                             |
                   | -> q2-rib -> q2-adj-rib-out | ->(med=300-100)-> q2
                   |    apply action             |
                   -------------------------------
"""
@scenario(27)
def boot(env):
    scenarios[1]['boot'](env)


@scenario(27)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    st0 = {'Name': 'st0',
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetMed': '-100'}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', med=300)

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(27)
def check(env):
    scenarios[17]['check'](env)

@scenario(27)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2

    adj_out = g1.get_adj_rib_out(q1)
    env.assertTrue(metric(adj_out[0]) == 300)

    local_rib = g1.get_local_rib(q2)
    env.assertTrue(metric(local_rib[0]['paths'][0]) == 200)

    adj_out = g1.get_adj_rib_out(q2)
    env.assertTrue(metric(adj_out[0]) == 200)

"""
  No.28 med replace action export-policy test
                   -------------------------------
  e1 ->(med=300)-> | -> q1-rib -> q1-adj-rib-out | ->(med=300)-> q1
                   |                             |
                   | -> q2-rib -> q2-adj-rib-out | ->(med=100)-> q2
                   |              apply action   |
                   -------------------------------
"""
@scenario(28)
def boot(env):
    scenarios[1]['boot'](env)


@scenario(28)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    st0 = {'Name': 'st0',
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetMed': '100'}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', med=300)

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(28)
def check(env):
    scenarios[17]['check'](env)

@scenario(28)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2

    adj_out = g1.get_adj_rib_out(q1)
    env.assertTrue(metric(adj_out[0]) == 300)

    local_rib = g1.get_local_rib(q2)
    env.assertTrue(metric(local_rib[0]['paths'][0]) == 300)

    adj_out = g1.get_adj_rib_out(q2)
    env.assertTrue(metric(adj_out[0]) == 100)

"""
  No.29 med add action export-policy test
                   -------------------------------
  e1 ->(med=300)-> | -> q1-rib -> q1-adj-rib-out | ->(med=300)->     q1
                   |                             |
                   | -> q2-rib -> q2-adj-rib-out | ->(med=300+100)-> q2
                   |              apply action   |
                   -------------------------------
"""
@scenario(29)
def boot(env):
    scenarios[1]['boot'](env)


@scenario(29)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    st0 = {'Name': 'st0',
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetMed': '+100'}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', med=300)

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(29)
def check(env):
    scenarios[17]['check'](env)

@scenario(29)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2

    adj_out = g1.get_adj_rib_out(q1)
    env.assertTrue(metric(adj_out[0]) == 300)

    local_rib = g1.get_local_rib(q2)
    env.assertTrue(metric(local_rib[0]['paths'][0]) == 300)

    adj_out = g1.get_adj_rib_out(q2)
    env.assertTrue(metric(adj_out[0]) == 400)

"""
  No.30 med subtract action export-policy test
                   -------------------------------
  e1 ->(med=300)-> | -> q1-rib -> q1-adj-rib-out | ->(med=300)->     q1
                   |                             |
                   | -> q2-rib -> q2-adj-rib-out | ->(med=300-100)-> q2
                   |              apply action   |
                   -------------------------------
"""
@scenario(30)
def boot(env):
    scenarios[1]['boot'](env)


@scenario(30)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    st0 = {'Name': 'st0',
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetMed': '-100'}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.100.0/24', med=300)

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(30)
def check(env):
    scenarios[17]['check'](env)

@scenario(30)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2

    adj_out = g1.get_adj_rib_out(q1)
    env.assertTrue(metric(adj_out[0]) == 300)

    local_rib = g1.get_local_rib(q2)
    env.assertTrue(metric(local_rib[0]['paths'][0]) == 300)

    adj_out = g1.get_adj_rib_out(q2)
    env.assertTrue(metric(adj_out[0]) == 200)

"""
  No.31 in-policy reject test
                                    ----------------
  e1 ->r1(community=65100:10) ->  x | -> q1-rib -> | -> r2 --> q1
       r2(192.168.10.0/24)    ->  o |              |
                                    | -> q2-rib -> | -> r2 --> q2
                                    ----------------
"""
@scenario(31)
def boot(env):
    scenarios[1]['boot'](env)


@scenario(31)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}}}

    policy = {'name': 'policy0',
              'type': 'in',
              'statements': [st0]}
    g1.add_policy(policy, e1)

    e1.add_route('192.168.100.0/24', community=['65100:10'])
    e1.add_route('192.168.10.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(31)
def check(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_adj_rib_in(e1)) == 2)
    wait_for(lambda : len(g1.get_local_rib(q1)) == 1)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 1)
    wait_for(lambda : len(q1.get_global_rib()) == 1)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 1)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 1)
    wait_for(lambda : len(q2.get_global_rib()) == 1)

"""
  No.32 in-policy accept test
                                    ----------------
  e1 ->r1(community=65100:10) ->  x | -> q1-rib -> | -> r2 --> q1
       r2(192.168.10.0/24)    ->  o |              |
                                    | -> q2-rib -> | -> r2 --> q2
                                    ----------------
"""
@scenario(32)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(32)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions':{'RouteDisposition': {'AcceptRoute': True}}}

    policy = {'name': 'policy0',
              'type': 'in',
              'statements': [st0],
              'default': 'reject'}
    g1.add_policy(policy, e1)

    e1.add_route('192.168.100.0/24', community=['65100:10'])
    e1.add_route('192.168.10.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(32)
def check(env):
    scenarios[31]['check'](env)

"""
  No.33 in-policy set community action
                                    ----------------
  e1 ->r1(community=65100:10) ->  o | -> q1-rib -> | -> r1(community=65100:10, 65100:20), r2 --> q1
       r2(192.168.10.0/24)    ->  o |              |
                                    | -> q2-rib -> | -> r1(community=65100:10, 65100:20), r2 --> q2
                                    ----------------
"""
@scenario(33)
def boot(env):
    scenarios[1]['boot'](env)


@scenario(33)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetCommunity': {'Options': 'ADD',
                                      'SetCommunityMethod': {'Communities': ['65100:20']}}}}}

    policy = {'name': 'policy0',
              'type': 'in',
              'statements': [st0]}
    g1.add_policy(policy, e1)

    e1.add_route('192.168.100.0/24', community=['65100:10'])
    e1.add_route('192.168.10.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(33)
def check(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_adj_rib_in(e1)) == 2)
    wait_for(lambda : len(g1.get_local_rib(q1)) == 2)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 2)
    wait_for(lambda : len(q1.get_global_rib()) == 2)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 2)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 2)
    wait_for(lambda : len(q2.get_global_rib()) == 2)

@scenario(33)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2
    for q in [q1, q2]:
        adj_out = g1.get_adj_rib_out(q, prefix='192.168.100.0/24')
        env.assertTrue(len(adj_out) == 1)
        env.assertTrue(community_exists(adj_out[0], '65100:10'))
        env.assertTrue(community_exists(adj_out[0], '65100:20'))

        adj_out = g1.get_adj_rib_out(q, prefix='192.168.10.0/24')
        env.assertTrue(len(adj_out) == 1)
        env.assertFalse(community_exists(adj_out[0], '65100:10'))
        env.assertFalse(community_exists(adj_out[0], '65100:20'))

"""
  No.34 in-policy med add action
                                  -----------------
  e1 -> r1(med=300)         ->  o | -> q1-rib ->  | -> r1(med=400), r2 --> q1
        r2(192.168.10.0/24) ->  o |               |
                                  | -> q2-rib ->  | -> r1(med=400), r2 --> q2
                                  -----------------
"""
@scenario(34)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(34)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    cs0 = {'CommunitySets': {'CommunitySetList': [{'CommunitySetName': 'cs0', 'CommunityList': [{'Community': '65100:10'}]}]}}

    g1.set_bgp_defined_set(cs0)

    st0 = {'Name': 'st0',
           'Conditions':{'BgpConditions':{'MatchCommunitySet':{'CommunitySet': 'cs0'}}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetMed': '+100'}}}

    policy = {'name': 'policy0',
              'type': 'in',
              'statements': [st0]}
    g1.add_policy(policy, e1)

    e1.add_route('192.168.100.0/24', community=['65100:10'])
    e1.add_route('192.168.10.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(34)
def check(env):
    scenarios[33]['check'](env)

@scenario(34)
def check2(env):
    g1 = env.g1
    q1 = env.q1
    q2 = env.q2
    for q in [q1, q2]:
        adj_out = g1.get_adj_rib_out(q, prefix='192.168.100.0/24')
        env.assertTrue(len(adj_out) == 1)
        env.assertTrue(metric(adj_out[0]) == 100)

        adj_out = g1.get_adj_rib_out(q, prefix='192.168.10.0/24')
        env.assertTrue(len(adj_out) == 1)
        env.assertTrue(metric(adj_out[0]) == -1)

"""
  No.35 in-policy update test
  r1:192.168.2.0
  r2:192.168.20.0
  r3:192.168.200.0
                    -------------------------------------
                    | q1                                |
  e1 ->(r1,r2,r3)-> | ->(r1)-> rib ->(r1)-> adj-rib-out | ->(r1)-> q1
                    |                                   |
                    | q2                                |
                    | ->(r1)-> rib ->(r1)-> adj-rib-out | ->(r1)-> q2
                    -------------------------------------
               |
    update distribute policy
               |
               V
                    -------------------------------------------
                    | q1                                      |
  e1 ->(r1,r2,r3)-> | ->(r1,r2)-> rib ->(r1,r2)-> adj-rib-out | ->(r1,r2)-> q1
                    |                                         |
                    | q2                                      |
                    | ->(r1,r3)-> rib ->(r1,r3)-> adj-rib-out | ->(r1,r3)-> q2
                    -------------------------------------------
"""
@scenario(35)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(35)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.20.0/24'}
    p1 = {'IpPrefix': '192.168.200.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0, p1]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[e1]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
               'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'in',
              'statements': [st0]}
    g1.add_policy(policy, e1)

    e1.add_route('192.168.2.0/24')
    e1.add_route('192.168.20.0/24')
    e1.add_route('192.168.200.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(35)
def check(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_adj_rib_in(e1)) == 3)
    wait_for(lambda : len(g1.get_local_rib(q1)) == 1)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 1)
    wait_for(lambda : len(q1.get_global_rib()) == 1)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 1)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 1)
    wait_for(lambda : len(q2.get_global_rib()) == 1)

@scenario(35)
def setup2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    g1.clear_policy()

    p0 = {'IpPrefix': '192.168.20.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    n0 = {'Address': g1.peers[e1]['neigh_addr'].split('/')[0]}

    ns0 = {'NeighborSetName': 'ns0',
           'NeighborInfoList': [n0]}
    g1.set_neighbor_set(ns0)

    st0 = {'Name': 'st0',
           'Conditions': {'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']},
                          'MatchNeighborSet': {'NeighborSet': ns0['NeighborSetName']}}}

    policy = {'name': 'policy0',
              'type': 'in',
              'statements': [st0]}
    g1.add_policy(policy, e1)
    g1.softreset(e1)

@scenario(35)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    wait_for(lambda : len(g1.get_adj_rib_in(e1)) == 3)
    wait_for(lambda : len(g1.get_local_rib(q1)) == 2)
    wait_for(lambda : len(g1.get_adj_rib_out(q1)) == 2)
    wait_for(lambda : len(q1.get_global_rib()) == 2)
    wait_for(lambda : len(g1.get_local_rib(q2)) == 2)
    wait_for(lambda : len(g1.get_adj_rib_out(q2)) == 2)
    wait_for(lambda : len(q2.get_global_rib()) == 2)

"""
  No.36 aspath prepend action import
                          --------------------------------
  e1 ->(aspath=[65001])-> | ->  p1-rib -> p1-adj-rib-out | -> p1
                          |                              |
                          | ->  p2-rib -> p2-adj-rib-out | -> p2
                          |     apply action             |
                          --------------------------------
"""
@scenario(36)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(36)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.20.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    st0 = {'Name': 'st0',
           'Conditions': {'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetAsPathPrepend': {'RepeatN': 5, 'As': "65005"}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.20.0/24')
    e1.add_route('192.168.200.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(36)
def check(env):
    scenarios[33]['check'](env)

@scenario(36)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    path = g1.get_adj_rib_out(q1, prefix='192.168.20.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])

    path = g1.get_adj_rib_out(q1, prefix='192.168.200.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])

    path = g1.get_local_rib(q2, prefix='192.168.20.0/24')[0]['paths'][0]
    env.assertTrue(path['as_path'] == [65005]*5 + [e1.asn])

    path = g1.get_adj_rib_out(q2, prefix='192.168.20.0/24')[0]
    env.assertTrue(path['as_path'] == [65005]*5 + [e1.asn])

    path = g1.get_adj_rib_out(q2, prefix='192.168.200.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])


"""
  No.37 aspath prepend action export
                          --------------------------------
  e1 ->(aspath=[65001])-> | ->  p1-rib -> p1-adj-rib-out | -> p1
                          |                              |
                          | ->  p2-rib -> p2-adj-rib-out | -> p2
                          |               apply action   |
                          --------------------------------
"""
@scenario(37)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(37)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.20.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    st0 = {'Name': 'st0',
           'Conditions': {'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetAsPathPrepend': {'RepeatN': 5, 'As': "65005"}}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.20.0/24')
    e1.add_route('192.168.200.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(37)
def check(env):
    scenarios[33]['check'](env)

@scenario(37)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    path = g1.get_adj_rib_out(q1, prefix='192.168.20.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])

    path = g1.get_adj_rib_out(q1, prefix='192.168.200.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])

    path = g1.get_local_rib(q2, prefix='192.168.20.0/24')[0]['paths'][0]
    env.assertTrue(path['as_path'] == [e1.asn])

    path = g1.get_adj_rib_out(q2, prefix='192.168.20.0/24')[0]
    env.assertTrue(path['as_path'] == [65005]*5 + [e1.asn])

    path = g1.get_adj_rib_out(q2, prefix='192.168.200.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])

"""
  No.38 aspath prepend action lastas import
                          --------------------------------
  e1 ->(aspath=[65001])-> | ->  p1-rib -> p1-adj-rib-out | -> p1
                          |                              |
                          | ->  p2-rib -> p2-adj-rib-out | -> p2
                          |     apply action             |
                          --------------------------------
"""
@scenario(38)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(38)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.20.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    st0 = {'Name': 'st0',
           'Conditions': {'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetAsPathPrepend': {'RepeatN': 5, 'As': "last-as"}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.20.0/24')
    e1.add_route('192.168.200.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(38)
def check(env):
    scenarios[33]['check'](env)

@scenario(38)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    path = g1.get_adj_rib_out(q1, prefix='192.168.20.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])

    path = g1.get_adj_rib_out(q1, prefix='192.168.200.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])

    path = g1.get_local_rib(q2, prefix='192.168.20.0/24')[0]['paths'][0]
    env.assertTrue(path['as_path'] == [e1.asn]*5 + [e1.asn])

    path = g1.get_adj_rib_out(q2, prefix='192.168.20.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn]*5 + [e1.asn])

    path = g1.get_adj_rib_out(q2, prefix='192.168.200.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])

"""
  No.39 aspath prepend action lastas export
                          --------------------------------
  e1 ->(aspath=[65001])-> | ->  p1-rib -> p1-adj-rib-out | -> p1
                          |                              |
                          | ->  p2-rib -> p2-adj-rib-out | -> p2
                          |     apply action             |
                          --------------------------------
"""
@scenario(39)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(39)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.20.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    st0 = {'Name': 'st0',
           'Conditions': {'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']}},
           'Actions': {'RouteDisposition': {'AcceptRoute': True},
                       'BgpActions': {'SetAsPathPrepend': {'RepeatN': 5, 'As': "last-as"}}}}

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.20.0/24')
    e1.add_route('192.168.200.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(39)
def check(env):
    scenarios[33]['check'](env)

@scenario(39)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    path = g1.get_adj_rib_out(q1, prefix='192.168.20.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])

    path = g1.get_adj_rib_out(q1, prefix='192.168.200.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])

    path = g1.get_local_rib(q2, prefix='192.168.20.0/24')[0]['paths'][0]
    env.assertTrue(path['as_path'] == [e1.asn])

    path = g1.get_adj_rib_out(q2, prefix='192.168.20.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn]*5 + [e1.asn])

    path = g1.get_adj_rib_out(q2, prefix='192.168.200.0/24')[0]
    env.assertTrue(path['as_path'] == [e1.asn])


"""
  No.40 extended community origin condition import
                                               --------------------------------
  e1 ->(extcommunity=origin:65001.65100:200)-> | ->  q1-rib -> q1-adj-rib-out | --> q1
                                               |                              |
                                               | ->x q2-rib                   |
                                               --------------------------------
"""
@scenario(40)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(40)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    es0 = {'ExtCommunitySets': {'ExtCommunitySetList': [{'ExtCommunitySetName': 'es0',
                                'ExtCommunityList': [{'ExtCommunity': 'SoO:65001.65100:200'}]}]}}

    g1.set_bgp_defined_set(es0)

    st0 = {'Name': 'st0',
            'Conditions': {'BgpConditions':{'MatchExtCommunitySet':{'ExtCommunitySet': 'es0'}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.20.0/24', extendedcommunity='origin:{0}:200'.format((65001 << 16) + 65100))
    e1.add_route('192.168.200.0/24', extendedcommunity='origin:{0}:100'.format((65001 << 16) + 65200))

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(40)
def check(env):
    scenarios[1]['check'](env)

"""
  No.41 extended community origin condition import
                                         --------------------------------
  e1 ->(extcommunity=target:65010:320)-> | ->  q1-rib -> q1-adj-rib-out | --> q1
                                         |                              |
                                         | ->x q2-rib                   |
                                         --------------------------------
"""
@scenario(41)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(41)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    es0 = {'ExtCommunitySets': {'ExtCommunitySetList': [{'ExtCommunitySetName': 'es0',
                                'ExtCommunityList': [{'ExtCommunity': 'RT:6[0-9]+:3[0-9]+'}]}]}}

    g1.set_bgp_defined_set(es0)

    st0 = {'Name': 'st0',
            'Conditions': {'BgpConditions':{'MatchExtCommunitySet':{'ExtCommunitySet': 'es0'}}}}

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.20.0/24', extendedcommunity='target:65010:320')
    e1.add_route('192.168.200.0/24', extendedcommunity='target:55000:320')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(41)
def check(env):
    scenarios[1]['check'](env)


"""
  No.42 prefix only condition accept in
                                    -----------------
  e1 ->r1(192.168.100.0/24)   ->  o | -> q1-rib ->  | -> r2 --> q1
       r2(192.168.10.0/24)    ->  x |               |
                                    | -> q2-rib ->  | -> r2 --> q2
                                    -----------------
"""
@scenario(42)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(42)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.10.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    st0 = {'Name': 'st0',
           'Conditions': {
               'MatchPrefixSet': {'PrefixSet': ps0['PrefixSetName']}}}

    policy = {'name': 'policy0',
              'type': 'in',
              'statements': [st0]}
    g1.add_policy(policy, e1)

    # this will be blocked
    e1.add_route('192.168.100.0/24')
    # this will pass
    e1.add_route('192.168.10.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(42)
def check(env):
    scenarios[31]['check'](env)


"""
  No.43 extended community add action import-policy test
                             ---------------------------------
  e1 ->(extcommunity=none) ->| ->  q1-rib ->  q1-adj-rib-out | --> q1
                             |                               |
                             | ->  q2-rib ->  q2-adj-rib-out | --> q2
                             |     add ext-community         |
                             ---------------------------------
"""
@scenario(43)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(43)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.10.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    st0 = {
            'Name': 'st0',
            'Conditions': {
                'MatchPrefixSet': {
                    'PrefixSet': ps0['PrefixSetName']
                }
            },
           'Actions': {
               'RouteDisposition': {'AcceptRoute': True},
               'BgpActions': {
                   'SetExtCommunity': {
                       'Options': 'ADD',
                       'SetExtCommunityMethod': {
                           'Communities': ['0:2:0xfd:0xe8:0:0:0:1']
                        }
                    },
                }
            }
        }

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.10.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(43)
def check(env):
    scenarios[17]['check'](env)

def ext_community_exists(path, extcomm):
    typ = extcomm.split(':')[0]
    value = ':'.join(extcomm.split(':')[1:])
    for a in path['attrs']:
        if a['type'] == BGP_ATTR_TYPE_EXTENDED_COMMUNITIES:
            for c in a['value']:
                if typ == 'RT' and c['type'] == 0 and c['subtype'] == 2 and c['value'] == value:
                    return True
    return False

@scenario(43)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    path = g1.get_adj_rib_out(q1)[0]
    env.assertFalse(ext_community_exists(path, 'RT:65000:1'))
    path = g1.get_adj_rib_out(q2)[0]
    env.assertTrue(ext_community_exists(path, 'RT:65000:1'))

"""
  No.44 extended community add action import-policy test
                                    --------------------------------
  e1 ->(extcommunity=RT:65000:1) -> | ->  q1-rib -> q1-adj-rib-out | --> q1
                                    |                              |
                                    | ->  q2-rib -> q2-adj-rib-out | --> q2
                                    |     add ext-community        |
                                    --------------------------------
"""
@scenario(44)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(44)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.10.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    st0 = {
            'Name': 'st0',
            'Conditions': {
                'MatchPrefixSet': {
                    'PrefixSet': ps0['PrefixSetName']
                }
            },
           'Actions': {
               'RouteDisposition': {'AcceptRoute': True},
               'BgpActions': {
                   'SetExtCommunity': {
                       'Options': 'ADD',
                       'SetExtCommunityMethod': {
                           'Communities': ['0:2:0xfe:0x4c:0:0:0:0x64']
                        }
                    },
                }
            }
        }

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.10.0/24', extendedcommunity='target:65000:1')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(44)
def check(env):
    scenarios[17]['check'](env)

@scenario(44)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    path = g1.get_adj_rib_out(q1)[0]
    env.assertTrue(ext_community_exists(path, 'RT:65000:1'))
    env.assertFalse(ext_community_exists(path, 'RT:65100:100'))
    path = g1.get_local_rib(q2)[0]['paths'][0]
    env.assertTrue(ext_community_exists(path, 'RT:65000:1'))
    env.assertTrue(ext_community_exists(path, 'RT:65100:100'))
    path = g1.get_adj_rib_out(q2)[0]
    env.assertTrue(ext_community_exists(path, 'RT:65000:1'))
    env.assertTrue(ext_community_exists(path, 'RT:65100:100'))

"""
  No.45 extended community add action multiple import-policy test
                                 ---------------------------------------
  exabgp ->(extcommunity=none) ->| ->  peer1-rib ->  peer1-adj-rib-out | --> peer1
                                 |                                     |
                                 | ->  peer2-rib ->  peer2-adj-rib-out | --> peer2
                                 |     add ext-community               |
                                 ---------------------------------------
"""
@scenario(45)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(45)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.10.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    st0 = {
            'Name': 'st0',
            'Conditions': {
                'MatchPrefixSet': {
                    'PrefixSet': ps0['PrefixSetName']
                }
            },
           'Actions': {
               'RouteDisposition': {'AcceptRoute': True},
               'BgpActions': {
                   'SetExtCommunity': {
                       'Options': 'ADD',
                       'SetExtCommunityMethod': {
                           'Communities': ['0:2:0xfe:0x4c:0:0:0:0x64', '0:2:0:0x64:0:0:0:0x64']
                        }
                    },
                }
            }
        }

    policy = {'name': 'policy0',
              'type': 'import',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.10.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(45)
def check(env):
    scenarios[17]['check'](env)

@scenario(45)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    path = g1.get_adj_rib_out(q1)[0]
    env.assertFalse(ext_community_exists(path, 'RT:65100:100'))
    env.assertFalse(ext_community_exists(path, 'RT:100:100'))
    path = g1.get_local_rib(q2)[0]['paths'][0]
    env.assertTrue(ext_community_exists(path, 'RT:65100:100'))
    env.assertTrue(ext_community_exists(path, 'RT:100:100'))
    path = g1.get_adj_rib_out(q2)[0]
    env.assertTrue(ext_community_exists(path, 'RT:65100:100'))
    env.assertTrue(ext_community_exists(path, 'RT:100:100'))

"""
  No.46 extended comunity add action export-policy test
                             ------------------------------------
  e1 ->(extcommunity=none) ->| ->  q1-rib ->  q1-adj-rib-out    | --> q1
                             |                                  |
                             | ->  q2-rib ->  q2-adj-rib-out    | --> q2
                             |                add ext-community |
                             ------------------------------------
"""
@scenario(46)
def boot(env):
    scenarios[1]['boot'](env)

@scenario(46)
def setup(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2

    p0 = {'IpPrefix': '192.168.10.0/24'}

    ps0 = {'PrefixSetName': 'ps0',
           'PrefixList': [p0]}
    g1.set_prefix_set(ps0)

    st0 = {
            'Name': 'st0',
            'Conditions': {
                'MatchPrefixSet': {
                    'PrefixSet': ps0['PrefixSetName']
                }
            },
           'Actions': {
               'RouteDisposition': {'AcceptRoute': True},
               'BgpActions': {
                   'SetExtCommunity': {
                       'Options': 'ADD',
                       'SetExtCommunityMethod': {
                           'Communities': ['0:2:0xfd:0xe8:0:0:0:1'],
                        }
                    },
                }
            }
        }

    policy = {'name': 'policy0',
              'type': 'export',
              'statements': [st0]}
    g1.add_policy(policy, q2)

    e1.add_route('192.168.10.0/24')

    for c in [e1, q1, q2]:
        g1.wait_for(BGP_FSM_ESTABLISHED, c)

@scenario(46)
def check(env):
    scenarios[17]['check'](env)

@scenario(46)
def check2(env):
    g1 = env.g1
    e1 = env.e1
    q1 = env.q1
    q2 = env.q2
    path = g1.get_adj_rib_out(q1)[0]
    env.assertFalse(ext_community_exists(path, 'RT:65000:1'))
    path = g1.get_local_rib(q2)[0]['paths'][0]
    env.assertFalse(ext_community_exists(path, 'RT:65000:1'))
    path = g1.get_adj_rib_out(q2)[0]
    env.assertTrue(ext_community_exists(path, 'RT:65000:1'))


class GoBGPTestBase(unittest.TestCase):

    wait_per_retry = 5
    retry_limit = 10

    @classmethod
    def setUpClass(cls):
        idx = parser_option.test_index
        base.TEST_PREFIX = parser_option.test_prefix
        cls.parser_option = parser_option

        if idx not in scenarios:
            print 'invalid test-index. # of scenarios: {0}'.format(len(scenarios))
            sys.exit(1)

        cls.boot = scenarios[idx]['boot']
        cls.setup = scenarios[idx]['setup']
        cls.check = scenarios[idx]['check']
        cls.setup2 = scenarios[idx]['setup2'] if 'setup2' in scenarios[idx] else None
        cls.check2 = scenarios[idx]['check2'] if 'check2' in scenarios[idx] else None

    def test(self):

        self.boot()

        self.setup()

        self.check()

        if self.setup2:
            self.setup2()

        if self.check2:
            self.check2()

if __name__ == '__main__':
    if os.geteuid() is not 0:
        print "you are not root."
        sys.exit(1)
    output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True)
    if int(output) is not 0:
        print "docker not found"
        sys.exit(1)

    nose.main(argv=sys.argv, addplugins=[OptionParser()],
              defaultTest=sys.argv[0])