#!/usr/bin/env python
# vim:set sts=4 ts=8 sw=4:

# Copyright (c) 2001-2009 XORP, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, Version 2, June
# 1991 as published by the Free Software Foundation. Redistribution
# and/or modification of this program under the terms of any other
# version of the GNU General Public License is not permitted.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
# see the GNU General Public License, Version 2, a copy of which can be
# found in the XORP LICENSE.gpl file.
# 
# XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
# http://xorp.net

# $XORP: xorp/contrib/olsr/test_routing1.py,v 1.10 2008/10/02 21:56:36 bms Exp $

import getopt
import sys
import os
import time

from stat import *

TESTS=[
    # Fields:
    # 0: Test function
    # 1: True if this test works
    ['test_create', True],
    ['test_3line', True],
    ['test_3line_always', True],
    ['test_c4_partial', True],
    # currently broken, MPRs and thus TC are nondeterministic:
    #['test_c4_full', True],
    # No verification predicates yet other than N2:
    #['test_c5_partial', True],
    #['test_c5_full', True],
    #['test_c6_partial', True],
    #['test_c6_full', True],
    #['test_7up', True],
    ]

#############################################################################

def start_routing_interactive(verbose, valgrind):
    """
    Helper function to start the test_simulator program
    """

    flags = ""

    if verbose:
        flags = flags + ' -v -l 2'

    command = os.path.abspath('test_simulator') + flags;

    # I should really import a which() here.

    if valgrind:
	valgrind_path = "/usr/local/bin/valgrind"
	valgrind_flags = "--tool=memcheck " \
			 "--leak-check=yes " \
			 "--leak-resolution=high " \
			 "--num-callers=10 " \
			 "--show-reachable=yes " \
			 "--suppressions=/home/bms/.valgrind/fbsd.supp " \
			 "--suppressions=/home/bms/.valgrind/xorp.supp " \
			 "--logfile=test_simulator.log " \
			 "--demangle=no " \
			 "--verbose "
			 #"--undef-value-errors=no " # not in old valgrind
	command = valgrind_path + ' ' + valgrind_flags + command

    fp = os.popen(command, "w")

    return fp

#############################################################################

def test_create(verbose, valgrind):
    """
    Create an OLSR instance with two interfaces, and then destroy it.
    """

    # Don't bother with valgrind for the simple creation test.
    fp = start_routing_interactive(verbose, False)

    command = """
create 192.168.0.1 192.168.0.2
destroy 192.168.0.1
    """

    print >>fp, command

    if not fp.close():
        return True
    else:
        return False

#############################################################################

def test_3line(verbose, valgrind):
    """
    Simulate three OLSR nodes A-O-B and edges A-O, O-B, all connected
    in a straight line when embedded in the plane.

    * This test is designed to cover most of the core OLSR protocol
      functionality (HELLO, MID, HNA, TC).
    * TC_INTERVAL is set to 2s, therefore TOP_HOLD_TIME is 6s.
    * All other base timers default to 1s.
    * WILLINGNESS is set to 6, to simplify the metrics.
    * TC redundancy is set to the default -- it makes no difference in
      such a simple topology, as only 2 nodes will see the broadcasts.
    * We can't verify the internal routing entry fields from
      the simulator, just what the RIB would see.

    """

    ###############################################
    #
    #            A o			olsr2
    #		   | 192.168.1.2/32	    eth0
    #              |
    #              |
    #		   | 192.168.1.1/32	    eth0
    #		 O o			olsr1
    #		   | 192.168.2.1/32	    eth1
    #              |
    #              |			olsr3
    #		   | 192.168.2.2/32	    eth0
    #		 B o
    #
    ###############################################

    fp = start_routing_interactive(verbose, valgrind)

    # The order of creation and linkage here should make no difference.
    command = """
set_default_willingness 6
# TOP_HOLD_TIME is 2*3 = 6
set_default_tc_interval 2

create 192.168.1.1 192.168.2.1
create 192.168.1.2
create 192.168.2.2

# Event: O can now see A and B.
add_link 192.168.1.1 192.168.1.2
add_link 192.168.2.1 192.168.2.2

# 6 seconds is enough time for N1/N2/MID to show up,
# but not enough for TC to show up.
echo waiting for N2 advertisements to propagate
wait 6

# An extra second of slack is needed for the TC broadcasts
# to propagate to A and B; the TC timer may be firing just out of phase.
echo waiting for TC broadcast to propagate
wait 1


select 192.168.1.1
verify_n1 192.168.1.2 true
verify_n1 192.168.2.2 true
# WILL(A, B, O) != WILL_ALWAYS: O should not select any MPRs.
# O should become an MPR on behalf of both A and B regardless of the above.
verify_mpr_set empty
verify_mpr_selector_set 192.168.1.2 192.168.2.2
# O should only see 2 routes: an N1 route to A and an N1 route to B.
# A selects O as MPR, thus O lowers its metric to prefer A as an MPR selector.
# B selects O as MPR, thus O lowers its metric to prefer B as an MPR selector.
verify_routing_table_size 2
verify_routing_entry 192.168.1.2/32 192.168.1.2 1
verify_routing_entry 192.168.2.2/32 192.168.2.2 1
verify_mid_node_count 0
verify_mid_node_addrs 192.168.1.1 empty
verify_mid_node_addrs 192.168.2.2 empty
# O should never see any TC entries from anybody.
verify_tc_origin_count 0

# A should never become an MPR.
# B should be an N2 of A via O, therefore O must be A's MPR.
select 192.168.1.2
verify_n1 192.168.1.1 true
verify_n2 192.168.2.2 true
verify_mpr_set 192.168.1.1
verify_mpr_selector_set empty

# A should see an N1 route for O and an N2 route for B via O.
# A should also see a MID route for O's other address, which
# of course have a next-hop of O's main address.
# A's base cost for O will be 2 (1 hop away, 0 interface cost, and not
# an MPR selector). B is a further hop away, thus its cost is 3.
verify_routing_table_size 3
verify_routing_entry 192.168.1.1/32 192.168.1.1 2
verify_routing_entry 192.168.2.1/32 192.168.1.1 2
verify_routing_entry 192.168.2.2/32 192.168.1.1 3

# A should see a MID entry from O and always use it for routing,
# as it cannot infer the existence of the far side.
verify_mid_node_count 1
verify_mid_node_addrs 192.168.1.1 192.168.2.1
verify_mid_node_addrs 192.168.2.1 empty
verify_mid_distance 192.168.1.1 192.168.2.1 1

# A should see a single TC entry from O which is redundant for routing
# as it's within the 2 hop radius.
verify_tc_origin_count 1
verify_tc_ans 192.168.1.1 2 192.168.1.2 192.168.2.2
verify_tc_destination 192.168.1.2 1
verify_tc_destination 192.168.2.2 1
verify_tc_distance 192.168.1.1 192.168.1.2 2
verify_tc_distance 192.168.1.1 192.168.2.2 2


# B should never become an MPR.
# A should be an N2 of B via O, therefore O must be B's MPR.
# Note: verifying n1 status with non-link address.
select 192.168.2.2
verify_n1 192.168.1.1 true
verify_n2 192.168.1.2 true
verify_mpr_set 192.168.1.1
verify_mpr_selector_set empty
# B should see an N2 route for A, an N1 route to O, and
# a further route for O's main address (inferred because O's N1 link tuple
# has a different address from the origin field; for B, the MID is redundant).
# B's base cost for O will be 2 (1 hop away, 0 interface cost, and not
# an MPR selector). A is a further hop away, thus its cost is 3.
verify_routing_table_size 3
verify_routing_entry 192.168.1.1/32 192.168.2.1 2
verify_routing_entry 192.168.2.1/32 192.168.2.1 2
verify_routing_entry 192.168.1.2/32 192.168.2.1 3

verify_mid_node_count 1
verify_mid_node_addrs 192.168.1.1 192.168.2.1
verify_mid_node_addrs 192.168.2.1 empty
verify_mid_distance 192.168.1.1 192.168.2.1 1

# B should see a single TC entry from O which is redundant for routing
# as it's within the 2 hop radius.
verify_tc_origin_count 1
verify_tc_ans 192.168.1.1 2 192.168.1.2 192.168.2.2
verify_tc_destination 192.168.1.2 1
verify_tc_destination 192.168.2.2 1
verify_tc_distance 192.168.1.1 192.168.1.2 2
verify_tc_distance 192.168.1.1 192.168.2.2 2


# Event: Start advertising two HNA prefixes from B.
# Only O should see them.
echo advertising two HNA prefixes from B.
select 192.168.2.2
originate_hna 10.0.0.0/8
originate_hna 20.0.0.0/8

echo waiting 4 seconds for HNA to propagate.
wait 4

# Verify that O can see the networks B advertised.
select 192.168.1.1
verify_hna_entry_count 2
verify_hna_dest_count 2
verify_hna_origin_count 1
verify_hna_distance 10.0.0.0/8 192.168.2.2 1
verify_hna_distance 10.0.0.0/8 192.168.2.2 1
# O should see A,B as N1, *and* the two HNA routes B advertises,
# making a total of 4 routes.
# O's cost for both A and B is 1 as they are N1s.
# The HNA cost of B's advertised prefixes is the same as the cost to reach B.
verify_routing_table_size 4
verify_routing_entry 192.168.1.2/32 192.168.1.2 1
verify_routing_entry 192.168.2.2/32 192.168.2.2 1
verify_routing_entry 10.0.0.0/8 192.168.2.2 1
verify_routing_entry 20.0.0.0/8 192.168.2.2 1


# Verify that A can see B's prefixes; and that the next-hops resolved
# to O, its only upstream, thus 2 hops away.
select 192.168.1.2
verify_hna_entry_count 2
verify_hna_dest_count 2
verify_hna_origin_count 1
verify_hna_distance 10.0.0.0/8 192.168.2.2 2
verify_hna_distance 10.0.0.0/8 192.168.2.2 2
verify_routing_table_size 5
verify_routing_entry 192.168.1.1/32 192.168.1.1 2
verify_routing_entry 192.168.2.1/32 192.168.1.1 2
verify_routing_entry 192.168.2.2/32 192.168.1.1 3
verify_routing_entry 10.0.0.0/8 192.168.1.1 3
verify_routing_entry 20.0.0.0/8 192.168.1.1 3


# Verify that B can see no HNA whatsoever.
# [It advertises HNA, but should not learn HNA.]
# B should still see the N1 route for O and its MID entry, and the
# N2 route to A.
select 192.168.2.2
verify_hna_entry_count 0
verify_routing_table_size 3

echo withdrawing HNA prefixes at B.
select 192.168.2.2
withdraw_hna 10.0.0.0/8
withdraw_hna 20.0.0.0/8


# Verify that all HNA entries expire correctly.
echo waiting 4 seconds for HNA entries to time out.
wait 4

select 192.168.1.1
verify_hna_entry_count 0
select 192.168.1.2
verify_hna_entry_count 0
select 192.168.2.2
verify_hna_entry_count 0
echo end of HNA sub-test.


# Event: Take O's top interface down.
# Should take 1 tick + NEIGH_HOLD_TIME (usually 3 * refresh == 1) for
# the N2 deletion of A to propagate to B.
# Should take another 3s for the MPR selector tuple at B to expire,
# and for this to be seen by O, which causes O to stop being B's MPR.
# During this window the TC ANSN at O will bump to 3, then 4 once
# B's MPR selector tuple expires at O.
face_down 192.168.1.1
wait 7


# B should no longer be able to reach A as a two-hop neighbor.
# If B still thinks A is a two-hop neighbor, O will still
# think it's an MPR. None of these predicates should now hold.
# Note: verifying n1 status with non-link address.
select 192.168.2.2
verify_n1 192.168.1.1 true
verify_n2 192.168.1.2 false
verify_mpr_set empty
verify_mpr_selector_set empty
# B should now see an N1 route for O, and an inferred address for O's
# main address. MID should not influence B's routing table.
# The MID entry for O will have expired after MID_HOLD_TIME which
# in this case is (3 * 1) seconds.
verify_routing_table_size 2
verify_mid_node_count 0
verify_mid_node_addrs 192.168.1.1 empty
verify_mid_node_addrs 192.168.2.1 empty

# Any TC entries originated by O should now have expired at B,
# as O should no longer be an MPR, and O SHOULD have sent empty
# TCs to withdraw its advertised topology by now.
# [If this fails it is possible that TOP_HOLD_TIME is too high.]
verify_tc_origin_count 0
verify_tc_ans 192.168.1.1 4 empty


# A should no longer see any 2-hop or 1-hop neighbors.
# If A still thinks B is a two-hop neighbor, O will still
# think it's an MPR. None of these predicates should now hold.
# A should no longer see any MID entries.
select 192.168.1.2
verify_n1 192.168.1.1 false
verify_n2 192.168.2.2 false
verify_mpr_set empty
verify_mpr_selector_set empty
verify_routing_table_size 0
verify_mid_node_count 0
# Any TC entries originated by O should now have expired at A.
verify_tc_origin_count 0


# O should not see A.
# O should never see any MID entries.
# O should never see any TC entries.
select 192.168.1.1
verify_n1 192.168.1.2 false
verify_n1 192.168.2.2 true
# O should see only B now as an N1.
# O is no longer selected as an MPR by B so its cost for B goes back up.
verify_routing_table_size 1
# XXX Metric is not increasing correctly; this may need attention.
# Commented out for now. -bms
# XXX debug
#dump_routing_table 192.168.1.1
#verify_routing_entry 192.168.2.2/32 192.168.2.2 2
verify_mid_node_count 0
verify_tc_origin_count 0
verify_tc_origin_seen 192.168.1.1 false
verify_tc_origin_seen 192.168.1.2 false
verify_tc_origin_seen 192.168.2.2 false
# WILL(A, B, O) != WILL_ALWAYS:
#  O's MPR set should always be empty
#  O's MPR selector set should become empty.
verify_mpr_set empty
verify_mpr_selector_set empty


# Event: Simulate physical removal of O's links to A and B.
remove_link 192.168.1.1 192.168.1.2
remove_link 192.168.2.1 192.168.2.2
wait 5


# Verify that O can no longer see A or B, and has no routes.
select 192.168.1.1
verify_n1 192.168.1.2 false
verify_n1 192.168.2.2 false
verify_mpr_set empty
verify_mpr_selector_set empty
verify_routing_table_size 0
verify_mid_node_count 0
verify_tc_origin_count 0
verify_hna_entry_count 0

# Routing table paranoia for A and B.
# Any MID entries from O should now have expired.
# Any TC entries from O should now have expired.
select 192.168.1.2
verify_routing_table_size 0
verify_mid_node_count 0
verify_mid_node_addrs 192.168.1.1 empty
verify_tc_origin_count 0
verify_hna_entry_count 0

select 192.168.2.2
verify_routing_table_size 0
verify_mid_node_count 0
verify_mid_node_addrs 192.168.1.1 empty
verify_tc_origin_count 0
verify_hna_entry_count 0

    """

    print >>fp, command

    if not fp.close():
        return True
    else:
        return False

#############################################################################

def test_3line_always(verbose, valgrind):
    """
    Simulate three OLSR nodes A-O-B and edges A-O, O-B, all connected
    in a straight line when embedded in the plane.
    All three nodes have willingness of WILL_ALWAYS.
    A slightly higher TC interval is needed to increase TOP_HOLD_TIME,
    as TCs are now forwarded between all nodes.

    """

    ###############################################
    #
    #            A o			olsr2
    #		   | 192.168.1.2/32	    eth0
    #              |
    #              |
    #		   | 192.168.1.1/32	    eth0
    #		 O o			olsr1
    #		   | 192.168.2.1/32	    eth1
    #              |
    #              |			olsr3
    #		   | 192.168.2.2/32	    eth0
    #		 B o
    #
    ###############################################

    fp = start_routing_interactive(verbose, valgrind)

    command = """
set_default_willingness 7
set_default_tc_interval 3

create 192.168.1.1 192.168.2.1
create 192.168.1.2
create 192.168.2.2

add_link 192.168.1.1 192.168.1.2
add_link 192.168.2.1 192.168.2.2

# 5 seconds is enough time for N1/N2/MID to show up,
# but not enough for TC to show up.
echo waiting for N2 advertisements to propagate
wait 5

# Every direct neighbor is an MPR to every other direct neighbor.

select 192.168.1.1
verify_n1 192.168.1.2 true
verify_n1 192.168.2.2 true
verify_mpr_set 192.168.1.2 192.168.2.2
verify_mpr_selector_set 192.168.1.2 192.168.2.2

select 192.168.1.2
verify_n1 192.168.1.1 true
verify_n2 192.168.2.2 true
verify_mpr_set 192.168.1.1
verify_mpr_selector_set 192.168.1.1

select 192.168.2.2
verify_n1 192.168.1.1 true
verify_n2 192.168.1.2 true
verify_mpr_set 192.168.1.1
verify_mpr_selector_set 192.168.1.1

echo waiting 3 seconds for TC broadcasts to propagate
wait 3

select 192.168.1.1
verify_n1 192.168.1.2 true
verify_n1 192.168.2.2 true
verify_tc_origin_seen 192.168.1.1 false
verify_tc_origin_seen 192.168.2.1 false
verify_tc_origin_seen 192.168.1.2 true
verify_tc_origin_seen 192.168.2.2 true
verify_tc_ans 192.168.1.2 2 192.168.1.1
verify_tc_ans 192.168.2.2 2 192.168.1.1
verify_routing_table_size 2
verify_routing_entry 192.168.1.2/32 192.168.1.2 0
verify_routing_entry 192.168.2.2/32 192.168.2.2 0

select 192.168.1.2
verify_n1 192.168.1.1 true
verify_n2 192.168.2.2 true
verify_mpr_set 192.168.1.1
verify_tc_origin_seen 192.168.1.1 true
verify_tc_origin_seen 192.168.2.1 false
verify_tc_origin_seen 192.168.1.2 false
verify_tc_origin_seen 192.168.2.2 true
verify_tc_ans 192.168.1.1 2 192.168.1.2 192.168.2.2
verify_tc_ans 192.168.2.2 2 192.168.1.1
verify_routing_table_size 3
verify_routing_entry 192.168.1.1/32 192.168.1.1 0
verify_routing_entry 192.168.2.1/32 192.168.1.1 0
verify_routing_entry 192.168.2.2/32 192.168.1.1 1

select 192.168.2.2
verify_n1 192.168.1.1 true
verify_n2 192.168.1.2 true
verify_mpr_set 192.168.1.1
verify_tc_origin_seen 192.168.1.1 true
verify_tc_origin_seen 192.168.1.2 true
verify_tc_origin_seen 192.168.2.1 false
verify_tc_origin_seen 192.168.2.2 false
verify_tc_ans 192.168.1.1 2 192.168.1.2 192.168.2.2
verify_tc_ans 192.168.1.2 2 192.168.1.1
verify_routing_table_size 3
verify_routing_entry 192.168.1.1/32 192.168.2.1 0
verify_routing_entry 192.168.2.1/32 192.168.2.1 0
verify_routing_entry 192.168.1.2/32 192.168.2.1 1


# Set willingness of the stub nodes to 6 and
# wait for the MPR selector tuples for a,b at O to expire.
echo setting willingness of a,b to 6 and waiting for mpr selector expiry
set_willingness 192.168.1.2 6
set_willingness 192.168.2.2 6
# MS_time is same as HELLO_INTERVAL at the other nodes; but we
# may be out of phase so wait HELLO_INTERVAL * 2 + 1.
# However this also means that the TC entries will have expired.
wait 7

# verify that O is still MPR for A and B, but A and B
# are no longer MPRs themselves.
# also verify that the route metrics have correspondingly gone up
# at O; they will stay the same at A and B because whilst O
# no longer selects A, B as MPRs, O still appears to have
# a willingness of 7 to them.

select 192.168.1.1
verify_mpr_set empty
verify_mpr_selector_set 192.168.1.2 192.168.2.2
verify_tc_origin_seen 192.168.1.1 false
verify_tc_origin_seen 192.168.2.1 false
verify_tc_origin_seen 192.168.1.2 true
verify_tc_origin_seen 192.168.2.2 true
verify_tc_ans 192.168.1.2 3 empty
verify_tc_ans 192.168.2.2 3 empty
verify_routing_table_size 2
verify_routing_entry 192.168.1.2/32 192.168.1.2 1
verify_routing_entry 192.168.2.2/32 192.168.2.2 1

select 192.168.1.2
verify_mpr_set 192.168.1.1
verify_mpr_selector_set empty
verify_tc_origin_seen 192.168.1.1 true
verify_tc_origin_seen 192.168.2.1 false
verify_tc_origin_seen 192.168.1.2 false
verify_tc_origin_seen 192.168.2.2 true
verify_tc_ans 192.168.1.1 2 192.168.1.2 192.168.2.2
verify_tc_ans 192.168.2.2 3 empty
verify_routing_table_size 3
verify_routing_entry 192.168.1.1/32 192.168.1.1 1
verify_routing_entry 192.168.2.1/32 192.168.1.1 1
verify_routing_entry 192.168.2.2/32 192.168.1.1 2

select 192.168.2.2
verify_mpr_set 192.168.1.1
verify_mpr_selector_set empty
verify_tc_origin_seen 192.168.1.1 true
verify_tc_origin_seen 192.168.1.2 true
verify_tc_origin_seen 192.168.2.1 false
verify_tc_origin_seen 192.168.2.2 false
verify_tc_ans 192.168.1.1 2 192.168.1.2 192.168.2.2
verify_tc_ans 192.168.1.2 3 empty
verify_routing_table_size 3
verify_routing_entry 192.168.1.1/32 192.168.2.1 1
verify_routing_entry 192.168.2.1/32 192.168.2.1 1
verify_routing_entry 192.168.1.2/32 192.168.2.1 2

echo removing O's links and waiting 5s
remove_link 192.168.1.1 192.168.1.2
remove_link 192.168.2.1 192.168.2.2
wait 5

# At this point there is no way A, B or O can see any
# of each other's withdrawn ANSNs.

select 192.168.1.1
verify_n1 192.168.1.2 false
verify_n1 192.168.2.2 false
verify_mpr_set empty
verify_mpr_selector_set empty
verify_tc_origin_seen 192.168.1.1 false
verify_tc_origin_seen 192.168.2.1 false
verify_tc_origin_seen 192.168.1.2 true
verify_tc_origin_seen 192.168.2.2 true

select 192.168.1.2
verify_n1 192.168.1.1 false
verify_n2 192.168.2.2 false
verify_mpr_set empty
verify_mpr_selector_set empty
verify_tc_origin_seen 192.168.1.1 true
verify_tc_origin_seen 192.168.2.1 false
verify_tc_origin_seen 192.168.1.2 false
verify_tc_origin_seen 192.168.2.2 true

select 192.168.2.2
verify_n1 192.168.2.1 false
verify_n2 192.168.1.2 false
verify_mpr_set empty
verify_mpr_selector_set empty
verify_tc_origin_seen 192.168.1.1 true
verify_tc_origin_seen 192.168.1.2 true
verify_tc_origin_seen 192.168.2.1 false
verify_tc_origin_seen 192.168.2.2 false

    """

    print >>fp, command

    if not fp.close():
        return True
    else:
        return False

#############################################################################

def test_c4_partial(verbose, valgrind):
    """
    Simulate four OLSR nodes A-O-B-C and edges A-O, O-B, B-C.
    Build the topology in counter-clockwise order, numbering nodes in
    the fourth octet and links in the third octet in ascending order.
    Verify n1, n2 status, MPR status.
    As soon as O sees B's link to C, it should select B as an MPR; this
    relationship should be reciprocal -- as O provides connectivity for
    B to reach A.
    """

    ###############################################
    #
    # 192.168.2.4/32                 192.168.2.3/32
    #             C  o-----------o B
    #                            |   192.168.1.3/32
    #                            |
    #                            |
    #                            |
    #                            |   192.168.1.2/32
    #              A o-----------o O
    # 192.168.0.1/32                 192.168.0.2/32
    #
    ###############################################

    fp = start_routing_interactive(verbose, valgrind)

    command = """
# simplify the link costing by adopting a willingness of 6 (HIGH).
set_default_willingness 6
# only advertise MPR selectors in TC messages.
set_default_tc_redundancy 0
# TOP_HOLD_TIME is 3*3 = 9
set_default_tc_interval 3

create 192.168.0.1
create 192.168.0.2 192.168.1.2
create 192.168.1.3 192.168.2.3
create 192.168.2.4

add_link 192.168.0.1 192.168.0.2
add_link 192.168.1.2 192.168.1.3
wait 3
select 192.168.0.2
verify_n1 192.168.0.1 true
verify_n1 192.168.1.3 true

add_link 192.168.2.3 192.168.2.4
wait 3
select 192.168.2.3
verify_n1 192.168.2.4 true

wait 3
select 192.168.0.2
verify_n2 192.168.2.4 true

wait 1
select 192.168.1.3
verify_n2 192.168.0.1 true

#######################################################
# Wait for full link-state convergence (TC, N1, N2).

# N1/N2/MPR OK.
wait 5

# Wait at least 1 * TOP_HOLD_TIME.
wait 9

# XXX needed with aggressive eventloop?
#wait 1

#######################################################
# Verify that TCs are seen at either extremity.
# Only O and B should originate TCs.
# TC redundancy is set to 0 so only their MPR selectors
# should be advertised.

# Consider A.
select 192.168.0.1

# Only O and B should originate TCs.
verify_tc_origin_seen 192.168.0.1 false
verify_tc_origin_seen 192.168.0.2 true
verify_tc_origin_seen 192.168.1.3 true
verify_tc_origin_seen 192.168.2.4 false

# Should see O's advertisement of self as we select O as an MPR.
verify_tc_destination 192.168.0.1 1
# Should see O's advertisement of B, as B selects O as an MPR.
verify_tc_destination 192.168.1.3 1
# Should see B's advertisement of O, as O selects B as an MPR in
# order to reach C.
verify_tc_destination 192.168.0.2 1
# Should see B's advertisement of extremity C.
verify_tc_destination 192.168.2.4 1

# Consider C.
select 192.168.2.4

# Only O and B should originate TCs.
verify_tc_origin_seen 192.168.0.1 false
verify_tc_origin_seen 192.168.0.2 true
verify_tc_origin_seen 192.168.1.3 true
verify_tc_origin_seen 192.168.2.4 false

# Should see B's advertisement of self, as we select O as an MPR.
verify_tc_destination 192.168.2.4 1
# Should see B's advertisement of O, as O selects B as an MPR.
verify_tc_destination 192.168.0.2 1
# Should see O's advertisement of B, as B selects O as an MPR in
# order to reach A.
verify_tc_destination 192.168.1.3 1
# Should see O's advertisement of extremity A.
verify_tc_destination 192.168.0.1 1


#######################################################
# Verify everyone's MPR status when fully converged.

# Consider A.
select 192.168.0.1
# A must use O to reach everyone else.
verify_mpr_set 192.168.0.2
# Nothing uses A as a next hop.
verify_mpr_selector_set empty

# Consider O.
select 192.168.0.2
# O must use B to reach C.
verify_mpr_set 192.168.1.3
# A must use O to reach everyone else.
# B must use O to reach A.
verify_mpr_selector_set 192.168.0.1 192.168.1.3

# Consider B.
select 192.168.1.3
# B must use O to reach A.
verify_mpr_set 192.168.0.2
# O must use B to reach C.
# C must use B to reach everyone else.
verify_mpr_selector_set 192.168.0.2 192.168.2.4

# Consider C.
select 192.168.2.4
# C must use B to reach everyone else.
verify_mpr_set 192.168.1.3
# Nothing uses C as a next hop.
verify_mpr_selector_set empty


#######################################################
# Verify everyone's routing tables when fully converged.

# A's base cost for O will be 2 (1 hop away, 0 interface cost, and not
# an MPR selector). The cost of an N2 link is 1; the cost of any MID
# route is the same as the route to the main address upon which it
# is based.
# MPR selectors have their path cost decremented by 1 to prefer
# them over other hops.
# TC information comes into play as the extremities of this
# graph are >= 3 hops away, those peers will only find routes to
# each other in the TC information. The cost of a TC hop is 1 in
# RFC compliant OLSR.

select 192.168.0.1
# N1: O
verify_routing_entry 192.168.0.2/32 192.168.0.2 2
# MID: O
verify_routing_entry 192.168.1.2/32 192.168.0.2 2
# N2: B
verify_routing_entry 192.168.1.3/32 192.168.0.2 3
# MID: B
verify_routing_entry 192.168.2.3/32 192.168.0.2 3
# TC: C
verify_routing_entry 192.168.2.4/32 192.168.0.2 4


select 192.168.0.2
# N1: A [MPR selector]
verify_routing_entry 192.168.0.1/32 192.168.0.1 1
# N1: B [MPR selector]
verify_routing_entry 192.168.1.3/32 192.168.1.3 1
# MID: B
verify_routing_entry 192.168.2.3/32 192.168.1.3 1
# N2: C
verify_routing_entry 192.168.2.4/32 192.168.1.3 2


select 192.168.1.3
# N1: C [MPR selector]
verify_routing_entry 192.168.2.4/32 192.168.2.4 1
# N1: O [MPR selector]
verify_routing_entry 192.168.1.2/32 192.168.1.2 1
# MID: O
verify_routing_entry 192.168.0.2/32 192.168.1.2 1
# N2: A
verify_routing_entry 192.168.0.1/32 192.168.1.2 2


select 192.168.2.4
# N1: B
verify_routing_entry 192.168.2.3/32 192.168.2.3 2
# MID: B
verify_routing_entry 192.168.1.3/32 192.168.2.3 2
# N2: O
verify_routing_entry 192.168.1.2/32 192.168.2.3 3
# MID: O
verify_routing_entry 192.168.0.2/32 192.168.2.3 3
# TC: A
verify_routing_entry 192.168.0.1/32 192.168.2.3 4

#############################

# Disable edge B-C by taking down an interface,
# and verify links go down.
face_down 192.168.2.3
select 192.168.1.3
verify_n1 192.168.2.4 false

# Verify N2 tuple at O times out:
# vtime of N2(B) at O = 3 +
#  2 * ( HELLO_INTERVAL(1) + REFRESH_INTERVAL(1) ) for propagation.
wait 7
select 192.168.0.2
verify_n2 192.168.2.4 false

# Verify everyone's MPR status.
# B should be the only remaining MPR in the graph.

select 192.168.0.1
verify_mpr_set 192.168.0.2
verify_mpr_selector_set empty

select 192.168.0.2
verify_mpr_set empty
verify_mpr_selector_set 192.168.0.1 192.168.1.3

select 192.168.1.3
verify_mpr_set 192.168.0.2
verify_mpr_selector_set empty

select 192.168.2.4
verify_mpr_set empty
verify_mpr_selector_set empty

# Dismantle some of the other links.

remove_link 192.168.1.2 192.168.1.3
remove_link 192.168.0.1 192.168.0.2
wait 5
select 192.168.0.2
verify_n1 192.168.0.1 false
verify_n1 192.168.1.3 false

    """

    print >>fp, command

    if not fp.close():
        return True
    else:
        return False

#############################################################################

def test_c4_full(verbose, valgrind):
    """
    Simulate four OLSR nodes A-B-C-D in the cyclic graph C[4].
    Each node has two interfaces.  The main address of each node is
    configured to be the lowest interface address.
    In this topology every node is an MPR, as the node at the extremity
    is a two-hop neighbor with two links, and MPR coverage has been set to 2.
    Ties must be broken before routes are sent to a non-ECMP capable RIB.
    The tie SHOULD be broken by selecting the node with the lowest
    main address, and this is the main condition for this test.
    All nodes SHOULD originate TC messages once the network has fully
    converged.
    """

    ###############################################
    #
    # 192.168.2.4/32                 192.168.2.3/32
    #             D  o-----------o C
    # 192.168.3.4/32 |           |   192.168.1.3/32
    #                |           |
    #                |           |
    #                |           |
    # 192.168.3.1/32 |           |   192.168.1.2/32
    #              A o-----------o B
    # 192.168.0.1/32                 192.168.0.2/32
    #
    ###############################################

    fp = start_routing_interactive(verbose, valgrind)

    command = """
# simplify the link costing by adopting a willingness of 6 (HIGH).
set_default_willingness 6
# only advertise MPR selectors in TC messages.
set_default_tc_redundancy 0
# TOP_HOLD_TIME is 3*3 = 9
set_default_tc_interval 3
# MPR coverage is 2.
#set_default_mpr_coverage 2

create 192.168.0.1 192.168.3.1
create 192.168.0.2 192.168.1.2
create 192.168.1.3 192.168.2.3
create 192.168.2.4 192.168.3.4

add_link 192.168.0.1 192.168.0.2
add_link 192.168.1.2 192.168.1.3
add_link 192.168.2.3 192.168.2.4
add_link 192.168.3.4 192.168.3.1

#######################################################
# Wait for partial link-state convergence (N1, N2).
# * Every node SHOULD have two N1 and one N2.
# * Remember: N1 and N2 are identified by main address.

wait 5

select 192.168.0.1
verify_n1 192.168.0.2 true
verify_n1 192.168.2.4 true
verify_n2 192.168.1.3 true

select 192.168.0.2
verify_n1 192.168.0.1 true
verify_n1 192.168.1.3 true
verify_n2 192.168.2.4 true

select 192.168.1.3
verify_n1 192.168.0.2 true
verify_n1 192.168.2.4 true
verify_n2 192.168.0.1 true

select 192.168.2.4
verify_n1 192.168.1.3 true
verify_n1 192.168.0.1 true
verify_n2 192.168.0.2 true

#######################################################
# Wait for full link-state convergence (TC, MPR).
# Wait at least 1 * TOP_HOLD_TIME.
wait 9

#######################################################
# Verify everyone's MPR status when fully converged.
# * MPR coverage is 2 for this test.
# * NOTE WELL: THE MPR SELECTION IS CURRENTLY CHAOTIC IN THAT YOU MUST
#   KNOW THE INITIAL CONDITIONS FOR THE N1 TO BE SELECTED AS FINAL MPR.
# * For each node: the N1 with highest main address should be selected
#   as MPR once the network has converged.

select 192.168.0.1
#verify_mpr_set 192.168.0.2 192.168.2.4
#verify_mpr_selector_set 192.168.0.2 192.168.2.4

select 192.168.0.2
#verify_mpr_set 192.168.0.1 192.168.1.3
#verify_mpr_selector_set 192.168.0.1 192.168.1.3

select 192.168.1.3
#verify_mpr_set 192.168.0.2 192.168.2.4
#verify_mpr_selector_set 192.168.0.2 192.168.2.4

select 192.168.2.4
#verify_mpr_set 192.168.0.1 192.168.1.3
#verify_mpr_selector_set 192.168.0.1 192.168.1.3


#######################################################
# Verify that TCs are seen at either extremity.
#
# * All nodes SHOULD originate TCs.
# * TC redundancy is set to 0 so only their MPR selectors
#   should be advertised, in this case both one-hop neighbors of each node.
# * Nodes SHOULD NOT process their own TC messages.
# * Each node should therefore see itself mentioned twice in TC by each
#   of its N1;
#    its N2 mentioned twice by each N1;
#    but both of its N1s should be mentioned once only by the node at
#    the opposite corner of the graph.
#
# XXX These predicates don't hold, why?

select 192.168.0.1
#verify_tc_origin_count 3

#verify_tc_origin_seen 192.168.0.1 false
#verify_tc_origin_seen 192.168.0.2 true
#verify_tc_origin_seen 192.168.1.3 true
#verify_tc_origin_seen 192.168.2.4 true

#verify_tc_destination 192.168.0.1 2
#verify_tc_destination 192.168.0.2 1
#verify_tc_destination 192.168.1.3 2
#verify_tc_destination 192.168.2.4 1


select 192.168.0.2
#verify_tc_origin_count 3

#verify_tc_origin_seen 192.168.0.1 true
#verify_tc_origin_seen 192.168.0.2 false
#verify_tc_origin_seen 192.168.1.3 true
#verify_tc_origin_seen 192.168.2.4 true

#verify_tc_destination 192.168.0.1 1
#verify_tc_destination 192.168.0.2 2
#verify_tc_destination 192.168.1.3 1
#verify_tc_destination 192.168.2.4 2


select 192.168.1.3
#verify_tc_origin_count 3

#verify_tc_origin_seen 192.168.0.1 true
#verify_tc_origin_seen 192.168.0.2 true
#verify_tc_origin_seen 192.168.1.3 false
#verify_tc_origin_seen 192.168.2.4 true

#verify_tc_destination 192.168.0.1 2
#verify_tc_destination 192.168.0.2 1
#verify_tc_destination 192.168.1.3 2
#verify_tc_destination 192.168.2.4 1


select 192.168.2.4
#verify_tc_origin_count 3

#verify_tc_origin_seen 192.168.0.1 true
#verify_tc_origin_seen 192.168.0.2 true
#verify_tc_origin_seen 192.168.1.3 true
#verify_tc_origin_seen 192.168.2.4 false

#verify_tc_destination 192.168.0.1 1
#verify_tc_destination 192.168.0.2 2
#verify_tc_destination 192.168.1.3 1
#verify_tc_destination 192.168.2.4 2


#######################################################
# Verify everyone's routing tables when fully converged.
#
# * Each node's cost towards any N1 will be 1 (1 hop away, 0 interface cost,
#   and ALWAYS an MPR selector).
# * Each node's cost towards any N2 will be 2 (1 + 1).
# * The cost of any MID route is the same as the route to the main address
#   upon which it is based; MID entries SHOULD exist for each node in the
#   topology as they all have >1 interface.
# * The link via the lowest main address MUST win in strict RFC 3626 OLSR.
#   However, the preferred next-hop address will be that of the interface
#   facing each node; it is easy to get confused below.
# * No TC information should be used for routing as it is totally
#   redundant in this example. ALL routes must be derived from N1/N2/MID.

select 192.168.0.1
verify_routing_table_size 6
verify_routing_entry 192.168.0.2/32 192.168.0.2 1
verify_routing_entry 192.168.1.2/32 192.168.0.2 1
verify_routing_entry 192.168.2.4/32 192.168.3.4 1
verify_routing_entry 192.168.3.4/32 192.168.3.4 1
verify_routing_entry 192.168.1.3/32 192.168.0.2 2
verify_routing_entry 192.168.2.3/32 192.168.0.2 2

select 192.168.0.2
verify_routing_table_size 6
verify_routing_entry 192.168.0.1/32 192.168.0.1 1
verify_routing_entry 192.168.3.1/32 192.168.0.1 1
verify_routing_entry 192.168.1.3/32 192.168.1.3 1
verify_routing_entry 192.168.2.3/32 192.168.1.3 1
verify_routing_entry 192.168.2.4/32 192.168.0.1 2
verify_routing_entry 192.168.3.4/32 192.168.0.1 2

select 192.168.1.3
verify_routing_table_size 6
verify_routing_entry 192.168.1.2/32 192.168.1.2 1
verify_routing_entry 192.168.0.2/32 192.168.1.2 1
verify_routing_entry 192.168.2.4/32 192.168.2.4 1
verify_routing_entry 192.168.3.4/32 192.168.2.4 1
verify_routing_entry 192.168.0.1/32 192.168.1.2 2
verify_routing_entry 192.168.3.1/32 192.168.1.2 2

select 192.168.2.4
verify_routing_table_size 6
verify_routing_entry 192.168.2.3/32 192.168.2.3 1
verify_routing_entry 192.168.1.3/32 192.168.2.3 1
verify_routing_entry 192.168.3.1/32 192.168.3.1 1
verify_routing_entry 192.168.0.1/32 192.168.3.1 1
verify_routing_entry 192.168.0.2/32 192.168.3.1 2
verify_routing_entry 192.168.1.2/32 192.168.3.1 2


#####################################################
# Take down the entire topology and validate that all state times out.

remove_link 192.168.0.1 192.168.0.2
remove_link 192.168.1.2 192.168.1.3
remove_link 192.168.2.3 192.168.2.4
remove_link 192.168.3.4 192.168.3.1

#remove_all_links
wait 15
#verify_all_link_state_empty

select 192.168.0.1
verify_n1 192.168.0.2 false
verify_n1 192.168.2.4 false
verify_n2 192.168.1.3 false
verify_mpr_set empty
verify_mpr_selector_set empty
verify_mid_node_count 0
verify_tc_origin_count 0
verify_routing_table_size 0

select 192.168.0.2
verify_n1 192.168.0.1 false
verify_n1 192.168.1.3 false
verify_n2 192.168.2.4 false
verify_mpr_set empty
verify_mpr_selector_set empty
verify_mid_node_count 0
verify_tc_origin_count 0
verify_routing_table_size 0

select 192.168.1.3
verify_n1 192.168.0.2 false
verify_n1 192.168.2.4 false
verify_n2 192.168.0.1 false
verify_mpr_set empty
verify_mpr_selector_set empty
verify_mid_node_count 0
verify_tc_origin_count 0
verify_routing_table_size 0

select 192.168.2.4
verify_n1 192.168.1.3 false
verify_n1 192.168.0.1 false
verify_n2 192.168.0.2 false
verify_mpr_set empty
verify_mpr_selector_set empty
verify_mid_node_count 0
verify_tc_origin_count 0
verify_routing_table_size 0

    """

    print >>fp, command

    if not fp.close():
        return True
    else:
        return False

#############################################################################

def test_c5_partial(verbose, valgrind):
    """
    Simulate five OLSR nodes A-B-C-D-E in a subgraph of C[5] which misses
    one link.
    Each node has two interfaces.  The main address of each node is
    configured to be the lowest interface address.
    """

    ###############################################
    #
    #          192.0.2.3  C  192.0.3.3
    #                     o
    #                    / \
    #                   /   \
    #       192.0.2.2  /     \  192.0.3.4
    #               B o       o D
    #       192.0.1.2 |       | 192.0.4.4
    #                 |       |
    #                 |       |
    #       192.0.1.1 |       | 192.0.4.5
    #               A o       o E
    #   n/c 192.0.5.1           192.0.5.5 n/c
    #
    ###############################################

    fp = start_routing_interactive(verbose, valgrind)

    command = """
# Simplify the link costing by adopting a willingness of 6 (HIGH).
# Only advertise MPR selectors in TC messages.
# TOP_HOLD_TIME is 3*4 = 12
set_default_willingness 6
set_default_tc_redundancy 0
set_default_tc_interval 3

create 192.0.1.1 192.0.5.1
create 192.0.1.2 192.0.2.2
create 192.0.2.3 192.0.3.3
create 192.0.3.4 192.0.4.4
create 192.0.4.5 192.0.5.5

add_link 192.0.1.1 192.0.1.2
add_link 192.0.2.2 192.0.2.3
add_link 192.0.3.3 192.0.3.4
add_link 192.0.4.4 192.0.4.5

wait 30

#######################################################
# N2 verification

select 192.0.1.1
verify_n2 192.0.2.3 true
verify_n2 192.0.3.4 false
select 192.0.1.2
verify_n2 192.0.3.4 true
verify_n2 192.0.4.5 false
select 192.0.2.3
verify_n2 192.0.1.1 true
verify_n2 192.0.4.5 true
select 192.0.3.4
verify_n2 192.0.1.1 false
verify_n2 192.0.1.2 true
select 192.0.4.5
verify_n2 192.0.1.2 false
verify_n2 192.0.2.3 true

#######################################################
# Cleanup

remove_all_links
wait 15
verify_all_link_state_empty

    """

    print >>fp, command

    if not fp.close():
        return True
    else:
        return False

#############################################################################

def test_c5_full(verbose, valgrind):
    """
    Simulate five OLSR nodes A-B-C-D-E in the cyclic graph C[5].
    Each node has two interfaces.  The main address of each node is
    configured to be the lowest interface address.
    """

    ###############################################
    #
    #          192.0.2.3  C  192.0.3.3
    #                     o
    #                    / \
    #                   /   \
    #       192.0.2.2  /     \  192.0.3.4
    #               B o       o D
    #       192.0.1.2 |       | 192.0.4.4
    #                 |       |
    #                 |       |
    #       192.0.1.1 |       | 192.0.4.5
    #               A o-------o E
    #       192.0.5.1           192.0.5.5
    #
    ###############################################

    fp = start_routing_interactive(verbose, valgrind)

    command = """
# Simplify the link costing by adopting a willingness of 6 (HIGH).
# Only advertise MPR selectors in TC messages.
# TOP_HOLD_TIME is 3*4 = 12
set_default_willingness 6
set_default_tc_redundancy 0
set_default_tc_interval 3

create 192.0.1.1 192.0.5.1
create 192.0.1.2 192.0.2.2
create 192.0.2.3 192.0.3.3
create 192.0.3.4 192.0.4.4
create 192.0.4.5 192.0.5.5

add_link 192.0.1.1 192.0.1.2
add_link 192.0.2.2 192.0.2.3
add_link 192.0.3.3 192.0.3.4
add_link 192.0.4.4 192.0.4.5
add_link 192.0.5.5 192.0.5.1

wait 30

# N2 verification
select 192.0.1.1
verify_n2 192.0.2.3 true
verify_n2 192.0.3.4 true
select 192.0.1.2
verify_n2 192.0.3.4 true
verify_n2 192.0.4.5 true
select 192.0.2.3
verify_n2 192.0.1.1 true
verify_n2 192.0.4.5 true
select 192.0.3.4
verify_n2 192.0.1.1 true
verify_n2 192.0.1.2 true
select 192.0.4.5
verify_n2 192.0.1.2 true
verify_n2 192.0.2.3 true

#######################################################
# Cleanup

remove_all_links
wait 15
verify_all_link_state_empty

    """

    print >>fp, command

    if not fp.close():
        return True
    else:
        return False

#############################################################################

def test_c6_partial(verbose, valgrind):
    """
    Simulate six OLSR nodes A-B-C-D-E-F in a subgraph of C[6] which misses
    one link.
    Each node has two interfaces.  The main address of each node is
    configured to be the lowest interface address.
    """

    ###############################################
    #
    #      192.0.6.1       n/c       192.0.6.6
    #                 A           F
    #     192.0.1.1   o           o   192.0.5.6
    #                /             \
    #  192.0.1.2    /               \    192.0.5.5
    #            B o                 o E
    #  192.0.2.2    \               /    192.0.4.5
    #                \             /
    #     192.0.2.3   o-----------o   192.0.4.4
    #               C               D
    #     192.0.3.3                   192.0.3.4
    #
    ###############################################

    fp = start_routing_interactive(verbose, valgrind)

    command = """
# Simplify the link costing by adopting a willingness of 6 (HIGH).
# Only advertise MPR selectors in TC messages.
# TOP_HOLD_TIME is 3*4 = 12
set_default_willingness 6
set_default_tc_redundancy 0
set_default_tc_interval 3

create 192.0.1.1 192.0.6.1
create 192.0.1.2 192.0.2.2
create 192.0.2.3 192.0.3.3
create 192.0.3.4 192.0.4.4
create 192.0.4.5 192.0.5.5
create 192.0.5.6 192.0.6.6

add_link 192.0.1.1 192.0.1.2
add_link 192.0.2.2 192.0.2.3
add_link 192.0.3.3 192.0.3.4
add_link 192.0.4.4 192.0.4.5
add_link 192.0.5.5 192.0.5.6

wait 30

#######################################################
# N2 verification

select 192.0.1.1
verify_n2 192.0.2.3 true
verify_n2 192.0.4.5 false
select 192.0.1.2
verify_n2 192.0.3.4 true
verify_n2 192.0.5.6 false
select 192.0.2.3
verify_n2 192.0.1.1 true
verify_n2 192.0.4.5 true
select 192.0.3.4
verify_n2 192.0.1.2 true
verify_n2 192.0.5.6 true
select 192.0.4.5
verify_n2 192.0.1.1 false
verify_n2 192.0.2.3 true
select 192.0.5.6
verify_n2 192.0.1.2 false
verify_n2 192.0.3.4 true

#######################################################
# Cleanup

remove_all_links
wait 15
verify_all_link_state_empty
    """

    print >>fp, command

    if not fp.close():
        return True
    else:
        return False

#############################################################################

def test_c6_full(verbose, valgrind):
    """
    Simulate six OLSR nodes A-B-C-D-E-F in a subgraph of C[6] which misses
    one link.
    Each node has two interfaces.  The main address of each node is
    configured to be the lowest interface address.
    """

    ###############################################
    #
    #      192.0.6.1                 192.0.6.6
    #                 A           F
    #     192.0.1.1   o-----------o   192.0.5.6
    #                /             \
    #  192.0.1.2    /               \    192.0.5.5
    #            B o                 o E
    #  192.0.2.2    \               /    192.0.4.5
    #                \             /
    #     192.0.2.3   o-----------o   192.0.4.4
    #               C               D
    #     192.0.3.3                   192.0.3.4
    #
    ###############################################

    fp = start_routing_interactive(verbose, valgrind)

    command = """
# Simplify the link costing by adopting a willingness of 6 (HIGH).
# Only advertise MPR selectors in TC messages.
# TOP_HOLD_TIME is 3*4 = 12
set_default_willingness 6
set_default_tc_redundancy 0
set_default_tc_interval 3

create 192.0.1.1 192.0.6.1
create 192.0.1.2 192.0.2.2
create 192.0.2.3 192.0.3.3
create 192.0.3.4 192.0.4.4
create 192.0.4.5 192.0.5.5
create 192.0.5.6 192.0.6.6

add_link 192.0.1.1 192.0.1.2
add_link 192.0.2.2 192.0.2.3
add_link 192.0.3.3 192.0.3.4
add_link 192.0.4.4 192.0.4.5
add_link 192.0.5.5 192.0.5.6
add_link 192.0.6.6 192.0.6.1

wait 30

#######################################################
# N2 verification

select 192.0.1.1
verify_n2 192.0.2.3 true
verify_n2 192.0.4.5 false
select 192.0.1.2
verify_n2 192.0.3.4 true
verify_n2 192.0.5.6 false
select 192.0.2.3
verify_n2 192.0.1.1 true
verify_n2 192.0.4.5 true
select 192.0.3.4
verify_n2 192.0.1.2 true
verify_n2 192.0.5.6 true
select 192.0.4.5
verify_n2 192.0.1.1 false
verify_n2 192.0.2.3 true
select 192.0.5.6
verify_n2 192.0.1.2 false
verify_n2 192.0.3.4 true

#######################################################
# Cleanup

remove_all_links
wait 15
verify_all_link_state_empty
    """

    print >>fp, command

    if not fp.close():
        return True
    else:
        return False

#############################################################################

def test_7up(verbose, valgrind):
    """
    Simulate six OLSR nodes A-B-C-D-E-F, and an intermittent visitor G.
    All nodes have 3 interfaces.
    The main address of each node is the lowest interface address.
    Nodes are numbered x:1-8.
    Links are numbered n:1-10 in 192.0.n.x.  9,10 are allocated to G.
    G has intermittent connectivity to F and is not present initially.
    A and D are connected to each other using their third interface;
    the others may be regarded as omnidirectional antennae which G
    uses to roam.
    """

    ###############################################
    # 7up test.
    #
    #            A         G
    #            o        -o-
    #           /|\       /
    #       1  / | \  6  . 8
    #     x   /  |  \   .
    #      \ /   |   \ /
    #     B o    |    o F
    #       |    |    |
    #     2 |   7|    | 5
    #       |    |    |
    #       |    |    |
    #     C o    |    o E
    #      / \   |   / \
    #     x   \  |  /   x
    #       3  \ | /  4
    #           \|/
    #            o
    #            D
    #
    # Key:  o  - node
    #      /|\ - reliable link
    #       x  - unconnected link
    #       .  - intermittently connected link
    #
    ###############################################

    fp = start_routing_interactive(verbose, valgrind)

    command = """
# Simplify the link costing by adopting a willingness of 6 (HIGH).
# Only advertise MPR selectors in TC messages.
# TOP_HOLD_TIME is 3*4 = 12
set_default_willingness 6
set_default_tc_redundancy 0
set_default_tc_interval 3

# A
create 192.0.1.1 192.0.6.1 192.0.7.1
create 192.0.1.2 192.0.2.2 192.0.8.2
create 192.0.2.3 192.0.3.3 192.0.8.3
# D
create 192.0.3.4 192.0.4.4 192.0.7.4
create 192.0.4.5 192.0.5.5 192.0.8.5
# F
create 192.0.5.6 192.0.6.6 192.0.8.6
# Visitor G.
create 192.0.8.7 192.0.9.7 192.0.9.8

add_link 192.0.1.1 192.0.1.2
add_link 192.0.2.2 192.0.2.3
add_link 192.0.3.3 192.0.3.4
add_link 192.0.4.4 192.0.4.5
add_link 192.0.5.5 192.0.5.6
add_link 192.0.6.6 192.0.6.1

# A-D
add_link 192.0.7.1 192.0.7.4

wait 30

#######################################################
# N2 verification; no major changes from C[6].

select 192.0.1.1
verify_n2 192.0.2.3 true
verify_n2 192.0.4.5 true
select 192.0.1.2
verify_n2 192.0.3.4 true
verify_n2 192.0.5.6 true
select 192.0.2.3
verify_n2 192.0.1.1 true
verify_n2 192.0.4.5 true
select 192.0.3.4
verify_n2 192.0.1.2 true
verify_n2 192.0.5.6 true
select 192.0.4.5
verify_n2 192.0.1.1 true
verify_n2 192.0.2.3 true
select 192.0.5.6
verify_n2 192.0.1.2 true
verify_n2 192.0.3.4 true

# TODO: Introduce G and make sure E, A learn about G via N2,
# and that the others learn about G via TC.

# TODO: Verify TC which gets really interesting here.

#######################################################
# Cleanup

remove_all_links
wait 15
verify_all_link_state_empty
    """

    print >>fp, command

    if not fp.close():
        return True
    else:
        return False

#############################################################################

def main():
    def usage():
        us = \
           "usage: %s [-h|--help] [-g|--valgrind] [-v|--verbose] " \
	   "[-t|--test] [-b|--bad]"
        print us % sys.argv[0]
        

    try:
        opts, args = getopt.getopt(sys.argv[1:], "hgvt:b", \
                                   ["help", \
                                    "valgrind", \
                                    "verbose", \
                                    "test=", \
                                    "bad", \
                                    ])
    except getopt.GetoptError:
        usage()
        sys.exit(1)

    bad = False
    tests = []
    verbose = False
    valgrind = False
    for o, a in opts:
	if o in ("-h", "--help"):
	    usage()
	    sys.exit()
	if o in ("-v", "--verbose"):
            verbose = True
	if o in ("-g", "--valgrind"):
            valgrind = True
        if o in ("-t", "--test"):
            tests.append(a)
        if o in ("-b", "--bad"):
            bad = True

    if not tests:
        for i in TESTS:
            if bad != i[1]:
                tests.append(i[0])

    print tests

    for i in tests:
        protocol = 'unknown'
        for j in TESTS:
            if j[0] == i:
                if len(j) > 2:
                    protocol = j[2]
        test = i + '(verbose, valgrind)'
        print 'Running: ' + i,
        if not eval(test):
            print "FAILED"
            sys.exit(-1)
        else:
            print
        
    sys.exit(0)

main()

# Local Variables:
# mode: python
# py-indent-offset: 4
# End:
