test_pim6_prune_propagate.py::PIM6PrunePropagate

IPv6 PIM prune propagation test.

This test primarily checks two things:

  • prunes must not be delayed unnecessarily
  • MFIB state must be removed in response to prunes

As a necessity, this sets up a traffic flow first.

::startup
::prepare:#91:r1/pim6d/vtysh[show ipv6 pim neighbor json]
::prepare:#91:r2/pim6d/vtysh[show ipv6 pim neighbor json]
::prepare:#91:r3/pim6d/vtysh[show ipv6 pim neighbor json]
::prepare:#91:r4/pim6d/vtysh[show ipv6 pim neighbor json]
::join_traffic:#126#116:h1/scapy[h1-lan1/IPv6/UDP]
::join_traffic:#130:h4/h4-lan4/multicast-join[fdbc:1::fc05:ff:febc:100,ff35::2345]
::join_traffic:#132:r4/pim6d/log
::join_traffic:#139:r3/pim6d/log
::join_traffic:#139:r2/pim6d/log
::join_traffic:#139:r1/pim6d/log
::join_traffic:#148#116:h1/scapy[h1-lan1/IPv6/UDP]
::join_traffic:#157:lan4/packet
::join_traffic:#159#108:r1/pim6d/vtysh[show ipv6 pim join json]
::join_traffic:#160#108:r2/pim6d/vtysh[show ipv6 pim join json]
::join_traffic:#161#108:r3/pim6d/vtysh[show ipv6 pim join json]
::join_traffic:#163#108:r4/pim6d/vtysh[show ipv6 pim join json]
::mld_wait:#172:h4/h4-lan4/multicast-leave[fdbc:1::fc05:ff:febc:100,ff35::2345]
::mld_wait:#173:r4/pim6d/log
::mld_wait:#179:r4/pim6d/log
::prune:#192#108:r1/pim6d/vtysh[show ipv6 pim join json]
::prune:#193#108:r2/pim6d/vtysh[show ipv6 pim join json]
::prune:#194#108:r3/pim6d/vtysh[show ipv6 pim join json]
::prune:#196#108:r4/pim6d/vtysh[show ipv6 pim join json]
::prune:#199#116:h1/scapy[h1-lan1/IPv6/UDP]
::prune:#202:r4/pim6d/vtysh[show ipv6 mroute json]
::prune:#205:r3/pim6d/vtysh[show ipv6 mroute json]
::prune:#208:r2/pim6d/vtysh[show ipv6 mroute json]
::prune:#213:r1/pim6d/vtysh[show ipv6 mroute json]
::prune:#227#116:h1/scapy[h1-lan1/IPv6/UDP]
::shutdown

::startup

passed after 2.10s
('test_pim6_prune_propagate.py', -inf, 'startup')

::prepare

Wait for PIM neighbors to come up.

::prepare:#91:r1/pim6d/vtysh[show ipv6 pim neighbor json]

passed after 0.60s, CLI command: show ipv6 pim neighbor json
Expected output:
{'r1-r2': {'fe80::fc02:ff:fefe:100': {}}}
('test_pim6_prune_propagate.py', 91, '#91:r1/pim6d/vtysh[show ipv6 pim neighbor json]')

::prepare:#91:r2/pim6d/vtysh[show ipv6 pim neighbor json]

passed after 0.00s, CLI command: show ipv6 pim neighbor json
Expected output:
{'r2-r1': {'fe80::fc01:ff:fefe:200': {}}, 'r2-r3': {'fe80::fc03:ff:fefe:200': {}}}
('test_pim6_prune_propagate.py', 91, '#91:r2/pim6d/vtysh[show ipv6 pim neighbor json]')

::prepare:#91:r3/pim6d/vtysh[show ipv6 pim neighbor json]

passed after 0.00s, CLI command: show ipv6 pim neighbor json
Expected output:
{'r3-r2': {'fe80::fc02:ff:fefe:300': {}}, 'r3-r4': {'fe80::fc04:ff:fefe:300': {}}}
('test_pim6_prune_propagate.py', 91, '#91:r3/pim6d/vtysh[show ipv6 pim neighbor json]')

::prepare:#91:r4/pim6d/vtysh[show ipv6 pim neighbor json]

passed after 0.00s, CLI command: show ipv6 pim neighbor json
Expected output:
{'r4-r3': {'fe80::fc03:ff:fefe:400': {}}}
('test_pim6_prune_propagate.py', 91, '#91:r4/pim6d/vtysh[show ipv6 pim neighbor json]')

::join_traffic

Join S,G and push some traffic through.

::join_traffic:#126#116:h1/scapy[h1-lan1/IPv6/UDP]

passed after 0.27s, packet: Ether / IPv6 / UDP IPv6Address('fdbc:1::fc05:ff:febc:100'):9999 > ff35::2345:9999
###[ Ethernet ]### 
  dst       = 33:33:00:00:23:45
  src       = None
  type      = IPv6
###[ IPv6 ]### 
     version   = 6
     tc        = 0
     fl        = 0
     plen      = None
     nh        = UDP
     hlim      = 255
     src       = IPv6Address('fdbc:1::fc05:ff:febc:100')
     dst       = ff35::2345
###[ UDP ]### 
        sport     = 9999
        dport     = 9999
        len       = None
        chksum    = None

::join_traffic:#130:h4/h4-lan4/multicast-join[fdbc:1::fc05:ff:febc:100,ff35::2345]

passed after 0.00s
('test_pim6_prune_propagate.py', 130, '#130:h4/h4-lan4/multicast-join[fdbc:1::fc05:ff:febc:100,ff35::2345]')

::join_traffic:#132:r4/pim6d/log

passed after 0.01s
('test_pim6_prune_propagate.py', 132, '#132:r4/pim6d/log')

::join_traffic:#139:r3/pim6d/log

passed after 0.00s
('test_pim6_prune_propagate.py', 139, '#139:r3/pim6d/log')

::join_traffic:#139:r2/pim6d/log

passed after 0.00s
('test_pim6_prune_propagate.py', 139, '#139:r2/pim6d/log')

::join_traffic:#139:r1/pim6d/log

passed after 0.00s
('test_pim6_prune_propagate.py', 139, '#139:r1/pim6d/log')

::join_traffic:#148#116:h1/scapy[h1-lan1/IPv6/UDP]

passed after 33.08s, packet: Ether / IPv6 / UDP IPv6Address('fdbc:1::fc05:ff:febc:100'):9999 > ff35::2345:9999
###[ Ethernet ]### 
  dst       = 33:33:00:00:23:45
  src       = None
  type      = IPv6
###[ IPv6 ]### 
     version   = 6
     tc        = 0
     fl        = 0
     plen      = None
     nh        = UDP
     hlim      = 255
     src       = IPv6Address('fdbc:1::fc05:ff:febc:100')
     dst       = ff35::2345
###[ UDP ]### 
        sport     = 9999
        dport     = 9999
        len       = None
        chksum    = None

::join_traffic:#157:lan4/packet

passed after 0.00s
('test_pim6_prune_propagate.py', 157, '#157:lan4/packet')

::join_traffic:#159#108:r1/pim6d/vtysh[show ipv6 pim join json]

passed after 0.00s, CLI command: show ipv6 pim join json
Expected output:
{'r1-r2': {'ff35::2345': {'fdbc:1::fc05:ff:febc:100': {'channelJoinName': 'JOIN'}}}}
('test_pim6_prune_propagate.py', 159, '#159#108:r1/pim6d/vtysh[show ipv6 pim join json]')

::join_traffic:#160#108:r2/pim6d/vtysh[show ipv6 pim join json]

passed after 0.00s, CLI command: show ipv6 pim join json
Expected output:
{'r2-r3': {'ff35::2345': {'fdbc:1::fc05:ff:febc:100': {'channelJoinName': 'JOIN'}}}}
('test_pim6_prune_propagate.py', 160, '#160#108:r2/pim6d/vtysh[show ipv6 pim join json]')

::join_traffic:#161#108:r3/pim6d/vtysh[show ipv6 pim join json]

passed after 0.00s, CLI command: show ipv6 pim join json
Expected output:
{'r3-r4': {'ff35::2345': {'fdbc:1::fc05:ff:febc:100': {'channelJoinName': 'JOIN'}}}}
('test_pim6_prune_propagate.py', 161, '#161#108:r3/pim6d/vtysh[show ipv6 pim join json]')

::join_traffic:#163#108:r4/pim6d/vtysh[show ipv6 pim join json]

passed after 0.00s, CLI command: show ipv6 pim join json
Expected output:
{'r4-lan4': {'ff35::2345': {'fdbc:1::fc05:ff:febc:100': {'channelJoinName': 'NOINFO'}}}}
('test_pim6_prune_propagate.py', 163, '#163#108:r4/pim6d/vtysh[show ipv6 pim join json]')

::mld_wait

Give MLD 10 seconds to age out the join.

(Timing: query-max-response-time + robustness * interval)

::mld_wait:#172:h4/h4-lan4/multicast-leave[fdbc:1::fc05:ff:febc:100,ff35::2345]

passed after 0.00s
('test_pim6_prune_propagate.py', 172, '#172:h4/h4-lan4/multicast-leave[fdbc:1::fc05:ff:febc:100,ff35::2345]')

::mld_wait:#173:r4/pim6d/log

passed after 0.01s
('test_pim6_prune_propagate.py', 173, '#173:r4/pim6d/log')

::mld_wait:#179:r4/pim6d/log

passed after 1.31s
('test_pim6_prune_propagate.py', 179, '#179:r4/pim6d/log')

::prune

Ensure the PIM prune propagates and applies without unexpected delays.

::prune:#192#108:r1/pim6d/vtysh[show ipv6 pim join json]

failed after 1.00s, CLI command: show ipv6 pim join json
Expected output:
{'r1-r2': {'ff35::2345': {'fdbc:1::fc05:ff:febc:100': {'channelJoinName': 'NOINFO'}}}}
('test_pim6_prune_propagate.py', 192, '#192#108:r1/pim6d/vtysh[show ipv6 pim join json]')
self = <test_pim6_prune_propagate.PIM6PrunePropagate object at 0x7f776531bd50>, topo = <topotato.toponom.Network object at 0x7f7765a000d0>, r1 = <Router 1 "r1">, r2 = <Router 2 "r2">
r3 = <Router 3 "r3">, r4 = <Router 4 "r4">, h1 = <Router 5 "h1">, h4 = <Router 6 "h4">

    @topotatofunc
    def prune(self, topo, r1, r2, r3, r4, h1, h4):
        """
        Ensure the PIM prune propagates and applies without unexpected delays.
        """
        # r2 & r3 go through NOINFO for a little while for prune handling
>       yield from self.assert_join_state(r1, "r1-r2", "NOINFO", maxwait=1.0)
E       topotato.exceptions.TopotatoCLICompareFail: json["r1-r2"]["ff35::2345"]["fdbc:1::fc05:ff:febc:100"]["channelJoinName"] dict value is different (
E       --- Expected value
E       +++ Current value
E       @@ -1 +1 @@
E       -"NOINFO"
E       +"JOIN")

/home/equinox/python/topotato/test_pim6_prune_propagate.py:192: TopotatoCLICompareFail

::prune:#193#108:r2/pim6d/vtysh[show ipv6 pim join json]

failed after 0.00s, CLI command: show ipv6 pim join json
Expected output:
{'r2-r3': {'ff35::2345': {'fdbc:1::fc05:ff:febc:100': {'channelJoinName': 'NOINFO'}}}}
('test_pim6_prune_propagate.py', 193, '#193#108:r2/pim6d/vtysh[show ipv6 pim join json]')
self = <test_pim6_prune_propagate.PIM6PrunePropagate object at 0x7f776531bd50>, topo = <topotato.toponom.Network object at 0x7f7765a000d0>, r1 = <Router 1 "r1">, r2 = <Router 2 "r2">
r3 = <Router 3 "r3">, r4 = <Router 4 "r4">, h1 = <Router 5 "h1">, h4 = <Router 6 "h4">

    @topotatofunc
    def prune(self, topo, r1, r2, r3, r4, h1, h4):
        """
        Ensure the PIM prune propagates and applies without unexpected delays.
        """
        # r2 & r3 go through NOINFO for a little while for prune handling
        yield from self.assert_join_state(r1, "r1-r2", "NOINFO", maxwait=1.0)
>       yield from self.assert_join_state(r2, "r2-r3", "NOINFO", maxwait=1.0)
E       topotato.exceptions.TopotatoCLICompareFail: json["r2-r3"]["ff35::2345"]["fdbc:1::fc05:ff:febc:100"]["channelJoinName"] dict value is different (
E       --- Expected value
E       +++ Current value
E       @@ -1 +1 @@
E       -"NOINFO"
E       +"JOIN")

/home/equinox/python/topotato/test_pim6_prune_propagate.py:193: TopotatoCLICompareFail

::prune:#194#108:r3/pim6d/vtysh[show ipv6 pim join json]

passed after 0.00s, CLI command: show ipv6 pim join json
Expected output:
{'r3-r4': {'ff35::2345': {'fdbc:1::fc05:ff:febc:100': {'channelJoinName': 'NOINFO'}}}}
('test_pim6_prune_propagate.py', 194, '#194#108:r3/pim6d/vtysh[show ipv6 pim join json]')

::prune:#196#108:r4/pim6d/vtysh[show ipv6 pim join json]

passed after 0.00s, CLI command: show ipv6 pim join json
Expected output:
{'r4-lan4': None}
('test_pim6_prune_propagate.py', 196, '#196#108:r4/pim6d/vtysh[show ipv6 pim join json]')

::prune:#199#116:h1/scapy[h1-lan1/IPv6/UDP]

passed after 2.06s, packet: Ether / IPv6 / UDP IPv6Address('fdbc:1::fc05:ff:febc:100'):9999 > ff35::2345:9999
###[ Ethernet ]### 
  dst       = 33:33:00:00:23:45
  src       = None
  type      = IPv6
###[ IPv6 ]### 
     version   = 6
     tc        = 0
     fl        = 0
     plen      = None
     nh        = UDP
     hlim      = 255
     src       = IPv6Address('fdbc:1::fc05:ff:febc:100')
     dst       = ff35::2345
###[ UDP ]### 
        sport     = 9999
        dport     = 9999
        len       = None
        chksum    = None

::prune:#202:r4/pim6d/vtysh[show ipv6 mroute json]

passed after 0.00s, CLI command: show ipv6 mroute json
Expected output:
{'ff35::2345': None}
('test_pim6_prune_propagate.py', 202, '#202:r4/pim6d/vtysh[show ipv6 mroute json]')

::prune:#205:r3/pim6d/vtysh[show ipv6 mroute json]

failed after 0.93s, CLI command: show ipv6 mroute json
Expected output:
{'ff35::2345': None}
('test_pim6_prune_propagate.py', 205, '#205:r3/pim6d/vtysh[show ipv6 mroute json]')
self = <test_pim6_prune_propagate.PIM6PrunePropagate object at 0x7f776531bd50>, topo = <topotato.toponom.Network object at 0x7f7765a000d0>, r1 = <Router 1 "r1">, r2 = <Router 2 "r2">
r3 = <Router 3 "r3">, r4 = <Router 4 "r4">, h1 = <Router 5 "h1">, h4 = <Router 6 "h4">

        @topotatofunc
        def prune(self, topo, r1, r2, r3, r4, h1, h4):
            """
            Ensure the PIM prune propagates and applies without unexpected delays.
            """
            # r2 & r3 go through NOINFO for a little while for prune handling
            yield from self.assert_join_state(r1, "r1-r2", "NOINFO", maxwait=1.0)
            yield from self.assert_join_state(r2, "r2-r3", "NOINFO", maxwait=1.0)
            yield from self.assert_join_state(r3, "r3-r4", "NOINFO", maxwait=1.0)
            # MLD state is gone
            yield from self.assert_join_state(r4, "r4-lan4", None, maxwait=1.0)
    
    	# send some follow-on packets that should NOT get forwarded
            yield from self.pkt_send(h1, repeat=3, interval=1)
    
            # r2-4 should completely ditch source MFIB state
            yield from AssertVtysh.make(
                r4, "pim6d", "show ipv6 mroute json", {"ff35::2345": None}, maxwait=4.0
            )
>           yield from AssertVtysh.make(
                r3, "pim6d", "show ipv6 mroute json", {"ff35::2345": None}, maxwait=4.0
            )
E           topotato.exceptions.TopotatoCLICompareFail: "ff35::2345" should not exist in json (have {'ff35::2345'}):
E           --- Expected value
E           +++ Current value
E           @@ -1 +1,12 @@
E           -null
E           +{
E           +    "fdbc:1::fc05:ff:febc:100": {
E           +        "group": "ff35::2345",
E           +        "iif": "r3-r2",
E           +        "installed": 1,
E           +        "oilInheritedRescan": 0,
E           +        "oilSize": 0,
E           +        "refCount": 1,
E           +        "source": "fdbc:1::fc05:ff:febc:100",
E           +        "upTime": "00:00:38"
E           +    }
E           +}

/home/equinox/python/topotato/test_pim6_prune_propagate.py:205: TopotatoCLICompareFail

::prune:#208:r2/pim6d/vtysh[show ipv6 mroute json]

failed after 0.00s, CLI command: show ipv6 mroute json
Expected output:
{'ff35::2345': None}
('test_pim6_prune_propagate.py', 208, '#208:r2/pim6d/vtysh[show ipv6 mroute json]')
self = <test_pim6_prune_propagate.PIM6PrunePropagate object at 0x7f776531bd50>, topo = <topotato.toponom.Network object at 0x7f7765a000d0>, r1 = <Router 1 "r1">, r2 = <Router 2 "r2">
r3 = <Router 3 "r3">, r4 = <Router 4 "r4">, h1 = <Router 5 "h1">, h4 = <Router 6 "h4">

        @topotatofunc
        def prune(self, topo, r1, r2, r3, r4, h1, h4):
            """
            Ensure the PIM prune propagates and applies without unexpected delays.
            """
            # r2 & r3 go through NOINFO for a little while for prune handling
            yield from self.assert_join_state(r1, "r1-r2", "NOINFO", maxwait=1.0)
            yield from self.assert_join_state(r2, "r2-r3", "NOINFO", maxwait=1.0)
            yield from self.assert_join_state(r3, "r3-r4", "NOINFO", maxwait=1.0)
            # MLD state is gone
            yield from self.assert_join_state(r4, "r4-lan4", None, maxwait=1.0)
    
    	# send some follow-on packets that should NOT get forwarded
            yield from self.pkt_send(h1, repeat=3, interval=1)
    
            # r2-4 should completely ditch source MFIB state
            yield from AssertVtysh.make(
                r4, "pim6d", "show ipv6 mroute json", {"ff35::2345": None}, maxwait=4.0
            )
            yield from AssertVtysh.make(
                r3, "pim6d", "show ipv6 mroute json", {"ff35::2345": None}, maxwait=4.0
            )
>           yield from AssertVtysh.make(
                r2, "pim6d", "show ipv6 mroute json", {"ff35::2345": None}, maxwait=4.0
            )
E           topotato.exceptions.TopotatoCLICompareFail: "ff35::2345" should not exist in json (have {'ff35::2345'}):
E           --- Expected value
E           +++ Current value
E           @@ -1 +1,26 @@
E           -null
E           +{
E           +    "fdbc:1::fc05:ff:febc:100": {
E           +        "flags": "ST",
E           +        "group": "ff35::2345",
E           +        "iif": "r2-r1",
E           +        "installed": 1,
E           +        "oil": {
E           +            "r2-r3": {
E           +                "group": "ff35::2345",
E           +                "iVifI": 1,
E           +                "inboundInterface": "r2-r1",
E           +                "oVifI": 2,
E           +                "outboundInterface": "r2-r3",
E           +                "protocolPim": true,
E           +                "source": "fdbc:1::fc05:ff:febc:100",
E           +                "ttl": 1,
E           +                "upTime": "00:00:38"
E           +            }
E           +        },
E           +        "oilInheritedRescan": 0,
E           +        "oilSize": 1,
E           +        "refCount": 1,
E           +        "source": "fdbc:1::fc05:ff:febc:100",
E           +        "upTime": "00:00:38"
E           +    }
E           +}

/home/equinox/python/topotato/test_pim6_prune_propagate.py:208: TopotatoCLICompareFail

::prune:#213:r1/pim6d/vtysh[show ipv6 mroute json]

failed after 0.00s, CLI command: show ipv6 mroute json
Expected output:
{'ff35::2345': {'fdbc:1::fc05:ff:febc:100': {'oilSize': 0}}}
('test_pim6_prune_propagate.py', 213, '#213:r1/pim6d/vtysh[show ipv6 mroute json]')
self = <test_pim6_prune_propagate.PIM6PrunePropagate object at 0x7f776531bd50>, topo = <topotato.toponom.Network object at 0x7f7765a000d0>, r1 = <Router 1 "r1">, r2 = <Router 2 "r2">
r3 = <Router 3 "r3">, r4 = <Router 4 "r4">, h1 = <Router 5 "h1">, h4 = <Router 6 "h4">

        @topotatofunc
        def prune(self, topo, r1, r2, r3, r4, h1, h4):
            """
            Ensure the PIM prune propagates and applies without unexpected delays.
            """
            # r2 & r3 go through NOINFO for a little while for prune handling
            yield from self.assert_join_state(r1, "r1-r2", "NOINFO", maxwait=1.0)
            yield from self.assert_join_state(r2, "r2-r3", "NOINFO", maxwait=1.0)
            yield from self.assert_join_state(r3, "r3-r4", "NOINFO", maxwait=1.0)
            # MLD state is gone
            yield from self.assert_join_state(r4, "r4-lan4", None, maxwait=1.0)
    
    	# send some follow-on packets that should NOT get forwarded
            yield from self.pkt_send(h1, repeat=3, interval=1)
    
            # r2-4 should completely ditch source MFIB state
            yield from AssertVtysh.make(
                r4, "pim6d", "show ipv6 mroute json", {"ff35::2345": None}, maxwait=4.0
            )
            yield from AssertVtysh.make(
                r3, "pim6d", "show ipv6 mroute json", {"ff35::2345": None}, maxwait=4.0
            )
            yield from AssertVtysh.make(
                r2, "pim6d", "show ipv6 mroute json", {"ff35::2345": None}, maxwait=4.0
            )
    
            # r1 remembers the source but must have an empty OIL now
>           yield from AssertVtysh.make(
                r1,
                "pim6d",
                "show ipv6 mroute json",
                {
                    "ff35::2345": {
                        str(self.srcaddr): {
                            "oilSize": 0,
                        },
                    },
                },
                maxwait=4.0,
            )
E           topotato.exceptions.TopotatoCLICompareFail: json["ff35::2345"]["fdbc:1::fc05:ff:febc:100"]["oilSize"] dict value is different (
E           --- Expected value
E           +++ Current value
E           @@ -1 +1 @@
E           -0
E           +1)

/home/equinox/python/topotato/test_pim6_prune_propagate.py:213: TopotatoCLICompareFail

::prune:#227#116:h1/scapy[h1-lan1/IPv6/UDP]

passed after 0.26s, packet: Ether / IPv6 / UDP IPv6Address('fdbc:1::fc05:ff:febc:100'):9999 > ff35::2345:9999
###[ Ethernet ]### 
  dst       = 33:33:00:00:23:45
  src       = None
  type      = IPv6
###[ IPv6 ]### 
     version   = 6
     tc        = 0
     fl        = 0
     plen      = None
     nh        = UDP
     hlim      = 255
     src       = IPv6Address('fdbc:1::fc05:ff:febc:100')
     dst       = ff35::2345
###[ UDP ]### 
        sport     = 9999
        dport     = 9999
        len       = None
        chksum    = None

::shutdown

passed after 1.29s
('test_pim6_prune_propagate.py', inf, 'shutdown')
net router-r1 r1 10.255.0.1/32 fd00::1/128 r1-r2 fe:01:00:fe:02:00 10.0.1.2/16 r1-lan1 fe:01:00:bc:01:00 10.101.0.1/16 fdbc:1::fc01:ff:febc:100/64 lan-lan1 lan1 10.101.0.0/16 fdbc:1::/64 router-r1:r1-lan1--lan-lan1 router-r1_router-r2_0 p2p#0 router-r1:r1-r2--router-r1_router-r2_0 router-r2 r2 10.255.0.2/32 fd00::2/128 r2-r1 fe:02:00:fe:01:00 10.0.2.1/16 r2-r3 fe:02:00:fe:03:00 10.1.2.3/16 router-r2:r2-r1--router-r1_router-r2_0 router-r2_router-r3_0 p2p#1 router-r2:r2-r3--router-r2_router-r3_0 router-r3 r3 10.255.0.3/32 fd00::3/128 r3-r2 fe:03:00:fe:02:00 10.1.3.2/16 r3-r4 fe:03:00:fe:04:00 10.2.3.4/16 router-r3:r3-r2--router-r2_router-r3_0 router-r3_router-r4_0 p2p#2 router-r3:r3-r4--router-r3_router-r4_0 router-r4 r4 10.255.0.4/32 fd00::4/128 r4-r3 fe:04:00:fe:03:00 10.2.4.3/16 r4-lan4 fe:04:00:bc:02:00 10.102.0.4/16 fdbc:2::fc04:ff:febc:200/64 lan-lan4 lan4 10.102.0.0/16 fdbc:2::/64 router-r4:r4-lan4--lan-lan4 router-r4:r4-r3--router-r3_router-r4_0 router-h1 h1 10.255.0.5/32 fd00::5/128 h1-lan1 fe:05:00:bc:01:00 10.101.0.5/16 fdbc:1::fc05:ff:febc:100/64 router-h1:h1-lan1--lan-lan1 router-h4 h4 10.255.0.6/32 fd00::6/128 h4-lan4 fe:06:00:bc:02:00 10.102.0.6/16 fdbc:2::fc06:ff:febc:200/64 router-h4:h4-lan4--lan-lan4