Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
pim_dm
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
pim_dm
Commits
77f16d47
Commit
77f16d47
authored
Oct 03, 2017
by
Pedro Oliveira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
assert
parent
2290b757
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
329 additions
and
153 deletions
+329
-153
Daemon/Daemon.py
Daemon/Daemon.py
+3
-2
Hello.py
Hello.py
+41
-81
InterfacePIM.py
InterfacePIM.py
+42
-1
Kernel.py
Kernel.py
+22
-3
Main.py
Main.py
+23
-8
Neighbor.py
Neighbor.py
+33
-11
Run.py
Run.py
+2
-2
UnicastRouting.py
UnicastRouting.py
+121
-0
tree/KernelEntry.py
tree/KernelEntry.py
+6
-30
tree/assert_.py
tree/assert_.py
+1
-1
tree/metric.py
tree/metric.py
+7
-4
tree/non_root_interface.py
tree/non_root_interface.py
+26
-8
tree/prune.py
tree/prune.py
+2
-2
No files found.
Daemon/Daemon.py
View file @
77f16d47
...
@@ -92,6 +92,7 @@ class Daemon:
...
@@ -92,6 +92,7 @@ class Daemon:
# Try killing the Daemon process
# Try killing the Daemon process
try
:
try
:
while
1
:
while
1
:
#os.killpg(os.getpgid(pid), signal.SIGTERM)
os
.
kill
(
pid
,
signal
.
SIGTERM
)
os
.
kill
(
pid
,
signal
.
SIGTERM
)
time
.
sleep
(
0.1
)
time
.
sleep
(
0.1
)
except
OSError
as
err
:
except
OSError
as
err
:
...
@@ -100,7 +101,7 @@ class Daemon:
...
@@ -100,7 +101,7 @@ class Daemon:
if
os
.
path
.
exists
(
self
.
pidfile
):
if
os
.
path
.
exists
(
self
.
pidfile
):
os
.
remove
(
self
.
pidfile
)
os
.
remove
(
self
.
pidfile
)
else
:
else
:
print
(
str
(
err
.
args
))
print
(
str
(
err
.
args
))
sys
.
exit
(
1
)
sys
.
exit
(
1
)
def
restart
(
self
):
def
restart
(
self
):
...
@@ -125,5 +126,5 @@ class Daemon:
...
@@ -125,5 +126,5 @@ class Daemon:
try
:
try
:
os
.
kill
(
pid
,
0
)
os
.
kill
(
pid
,
0
)
return
True
return
True
except
OSError
:
except
:
return
False
return
False
Hello.py
View file @
77f16d47
import
random
from
threading
import
Timer
from
Packet.Packet
import
Packet
from
Packet.ReceivedPacket
import
ReceivedPacket
from
Packet.ReceivedPacket
import
ReceivedPacket
from
Packet.PacketPimHello
import
PacketPimHello
from
Packet.PacketPimHeader
import
PacketPimHeader
from
Interface
import
Interface
import
Main
import
Main
from
utils
import
HELLO_HOLD_TIME_TIMEOUT
from
Neighbor
import
Neighbor
from
Neighbor
import
Neighbor
...
@@ -17,39 +10,6 @@ class Hello:
...
@@ -17,39 +10,6 @@ class Hello:
def
__init__
(
self
):
def
__init__
(
self
):
Main
.
add_protocol
(
Hello
.
TYPE
,
self
)
Main
.
add_protocol
(
Hello
.
TYPE
,
self
)
self
.
thread
=
Timer
(
Hello
.
TRIGGERED_HELLO_DELAY
,
self
.
send_handle
)
self
.
thread
.
start
()
def
send_handle
(
self
):
for
interface
in
list
(
Main
.
interfaces
.
values
()):
self
.
packet_send_handle
(
interface
)
# reschedule timer
self
.
thread
=
Timer
(
Hello
.
TRIGGERED_HELLO_DELAY
,
self
.
send_handle
)
self
.
thread
.
start
()
def
packet_send_handle
(
self
,
interface
:
Interface
):
pim_payload
=
PacketPimHello
()
pim_payload
.
add_option
(
1
,
3.5
*
Hello
.
TRIGGERED_HELLO_DELAY
)
pim_payload
.
add_option
(
20
,
interface
.
generation_id
)
ph
=
PacketPimHeader
(
pim_payload
)
packet
=
Packet
(
payload
=
ph
)
interface
.
send
(
packet
.
bytes
())
def
force_send
(
self
,
interface
:
Interface
):
# When PIM is enabled on an interface or when a router first starts, the Hello Timer (HT)
# MUST be set to random value between 0 and Triggered_Hello_Delay
hello_timer
=
random
.
uniform
(
0
,
Hello
.
TRIGGERED_HELLO_DELAY
)
Timer
(
hello_timer
,
self
.
packet_send_handle
,
args
=
[
interface
]).
start
()
def
force_send_remove
(
self
,
interface
:
Interface
):
pim_payload
=
PacketPimHello
()
pim_payload
.
add_option
(
1
,
HELLO_HOLD_TIME_TIMEOUT
)
pim_payload
.
add_option
(
20
,
interface
.
generation_id
)
ph
=
PacketPimHeader
(
pim_payload
)
packet
=
Packet
(
payload
=
ph
)
interface
.
send
(
packet
.
bytes
())
# receive handler
# receive handler
def
receive_handle
(
self
,
packet
:
ReceivedPacket
):
def
receive_handle
(
self
,
packet
:
ReceivedPacket
):
interface
=
packet
.
interface
interface
=
packet
.
interface
...
@@ -71,44 +31,44 @@ class Hello:
...
@@ -71,44 +31,44 @@ class Hello:
interface
.
neighbors
[
ip
]
=
Neighbor
(
interface
,
ip
,
generation_id
,
hello_hold_time
)
interface
.
neighbors
[
ip
]
=
Neighbor
(
interface
,
ip
,
generation_id
,
hello_hold_time
)
return
return
with
neighbor
.
neighbor_lock
:
neighbor
.
receive_hello
(
generation_id
,
hello_hold_time
)
# Already know Neighbor
"""
print
(
"neighbor conhecido"
)
with neighbor.neighbor_lock:
neighbor
.
heartbeat
()
# Already know Neighbor
if
neighbor
.
hello_hold_time
!=
hello_hold_time
:
print("neighbor conhecido")
print
(
"keep alive period diferente"
)
neighbor.heartbeat(
)
neighbor
.
set_hello_hold_time
(
hello_hold_time
)
if neighbor.hello_hold_time != hello_hold_time:
if
neighbor
.
generation_id
!=
generation_id
:
print("keep alive period diferente")
print
(
"neighbor reiniciado"
)
neighbor.set_hello_hold_time(hello_hold_time
)
neighbor
.
set_generation_id
(
generation_id
)
if neighbor.generation_id != generation_id:
print("neighbor reiniciado")
neighbor.set_generation_id(generation_id)
'''
with interface.neighbors_lock.genWlock():
with interface.neighbors_lock.genWlock():
#if interface.get_neighbor(ip) is None:
#if interface.get_neighbor(ip) is None:
if ip in interface.neighbors:
if ip in interface.neighbors:
# Unknown Neighbor
# Unknown Neighbor
if (1 in options) and (20 in options):
if (1 in options) and (20 in options):
try:
try:
#Main.add_neighbor(packet.interface, ip, options[20], options[1])
#Main.add_neighbor(packet.interface, ip, options[20], options[1])
print("non neighbor and options inside")
print("non neighbor and options inside")
except Exception:
except Exception:
# Received Neighbor with Timeout
# Received Neighbor with Timeout
print("non neighbor and options inside but neighbor timedout")
print("non neighbor and options inside but neighbor timedout")
pass
pass
return
return
print("non neighbor and required options not inside")
print("non neighbor and required options not inside")
else:
else:
# Already know Neighbor
# Already know Neighbor
print("neighbor conhecido")
print("neighbor conhecido")
neighbor = Main.get_neighbor(ip)
neighbor = Main.get_neighbor(ip)
neighbor.heartbeat()
neighbor.heartbeat()
if 1 in options and neighbor.hello_hold_time != options[1]:
if 1 in options and neighbor.hello_hold_time != options[1]:
print("keep alive period diferente")
print("keep alive period diferente")
neighbor.set_hello_hold_time(options[1])
neighbor.set_hello_hold_time(options[1])
if 20 in options and neighbor.generation_id != options[20]:
if 20 in options and neighbor.generation_id != options[20]:
print("neighbor reiniciado")
print("neighbor reiniciado")
neighbor.remove()
neighbor.remove()
Main.add_neighbor(packet.interface, ip, options[20], options[1])
Main.add_neighbor(packet.interface, ip, options[20], options[1])
'''
"""
\ No newline at end of file
InterfacePIM.py
View file @
77f16d47
...
@@ -5,7 +5,12 @@ from Packet.ReceivedPacket import ReceivedPacket
...
@@ -5,7 +5,12 @@ from Packet.ReceivedPacket import ReceivedPacket
import
Main
import
Main
import
traceback
import
traceback
from
RWLock.RWLock
import
RWLockWrite
from
RWLock.RWLock
import
RWLockWrite
from
Packet.PacketPimHello
import
PacketPimHello
from
Packet.PacketPimHeader
import
PacketPimHeader
from
Packet.Packet
import
Packet
from
Hello
import
Hello
from
utils
import
HELLO_HOLD_TIME_TIMEOUT
from
threading
import
Timer
class
InterfacePim
(
Interface
):
class
InterfacePim
(
Interface
):
MCAST_GRP
=
'224.0.0.13'
MCAST_GRP
=
'224.0.0.13'
...
@@ -20,6 +25,12 @@ class InterfacePim(Interface):
...
@@ -20,6 +25,12 @@ class InterfacePim(Interface):
self
.
neighbors
=
{}
self
.
neighbors
=
{}
self
.
neighbors_lock
=
RWLockWrite
()
self
.
neighbors_lock
=
RWLockWrite
()
# When PIM is enabled on an interface or when a router first starts, the Hello Timer (HT)
# MUST be set to random value between 0 and Triggered_Hello_Delay
hello_timer_time
=
random
.
uniform
(
0
,
Hello
.
TRIGGERED_HELLO_DELAY
)
self
.
hello_timer
=
Timer
(
hello_timer_time
,
self
.
send_hello
)
self
.
hello_timer
.
start
()
# run receive method in background
# run receive method in background
receive_thread
=
threading
.
Thread
(
target
=
self
.
receive
)
receive_thread
=
threading
.
Thread
(
target
=
self
.
receive
)
receive_thread
.
daemon
=
True
receive_thread
.
daemon
=
True
...
@@ -49,9 +60,35 @@ class InterfacePim(Interface):
...
@@ -49,9 +60,35 @@ class InterfacePim(Interface):
def
send
(
self
,
data
:
bytes
,
group_ip
:
str
=
MCAST_GRP
):
def
send
(
self
,
data
:
bytes
,
group_ip
:
str
=
MCAST_GRP
):
super
().
send
(
data
=
data
,
group_ip
=
group_ip
)
super
().
send
(
data
=
data
,
group_ip
=
group_ip
)
def
send_hello
(
self
):
self
.
hello_timer
.
cancel
()
pim_payload
=
PacketPimHello
()
pim_payload
.
add_option
(
1
,
3.5
*
Hello
.
TRIGGERED_HELLO_DELAY
)
pim_payload
.
add_option
(
20
,
self
.
generation_id
)
ph
=
PacketPimHeader
(
pim_payload
)
packet
=
Packet
(
payload
=
ph
)
self
.
send
(
packet
.
bytes
())
# reschedule hello_timer
self
.
hello_timer
=
Timer
(
Hello
.
TRIGGERED_HELLO_DELAY
,
self
.
send_hello
)
self
.
hello_timer
.
start
()
def
remove
(
self
):
def
remove
(
self
):
self
.
hello_timer
.
cancel
()
self
.
hello_timer
=
None
# send pim_hello timeout message
pim_payload
=
PacketPimHello
()
pim_payload
.
add_option
(
1
,
HELLO_HOLD_TIME_TIMEOUT
)
pim_payload
.
add_option
(
20
,
self
.
generation_id
)
ph
=
PacketPimHeader
(
pim_payload
)
packet
=
Packet
(
payload
=
ph
)
self
.
send
(
packet
.
bytes
())
super
().
remove
()
super
().
remove
()
def
add_neighbor
(
self
,
ip
,
random_number
,
hello_hold_time
):
def
add_neighbor
(
self
,
ip
,
random_number
,
hello_hold_time
):
with
self
.
neighbors_lock
.
genWlock
():
with
self
.
neighbors_lock
.
genWlock
():
if
ip
not
in
self
.
neighbors
:
if
ip
not
in
self
.
neighbors
:
...
@@ -69,3 +106,7 @@ class InterfacePim(Interface):
...
@@ -69,3 +106,7 @@ class InterfacePim(Interface):
def
get_neighbor
(
self
,
ip
):
def
get_neighbor
(
self
,
ip
):
with
self
.
neighbors_lock
.
genRlock
():
with
self
.
neighbors_lock
.
genRlock
():
return
self
.
neighbors
[
ip
]
return
self
.
neighbors
[
ip
]
def
remove_neighbor
(
self
,
ip
):
with
self
.
neighbors_lock
.
genWlock
():
del
self
.
neighbors
[
ip
]
Kernel.py
View file @
77f16d47
...
@@ -133,6 +133,7 @@ class Kernel:
...
@@ -133,6 +133,7 @@ class Kernel:
# MRT PIM
# MRT PIM
s
.
setsockopt
(
socket
.
IPPROTO_IP
,
Kernel
.
MRT_PIM
,
0
)
s
.
setsockopt
(
socket
.
IPPROTO_IP
,
Kernel
.
MRT_PIM
,
0
)
s
.
setsockopt
(
socket
.
IPPROTO_IP
,
Kernel
.
MRT_ASSERT
,
1
)
self
.
socket
=
s
self
.
socket
=
s
self
.
rwlock
=
RWLockWrite
()
self
.
rwlock
=
RWLockWrite
()
...
@@ -275,6 +276,7 @@ class Kernel:
...
@@ -275,6 +276,7 @@ class Kernel:
msg
=
self
.
socket
.
recv
(
5000
)
msg
=
self
.
socket
.
recv
(
5000
)
#print(len(msg))
#print(len(msg))
(
_
,
_
,
im_msgtype
,
im_mbz
,
im_vif
,
_
,
im_src
,
im_dst
)
=
struct
.
unpack
(
"II B B B B 4s 4s"
,
msg
[:
20
])
(
_
,
_
,
im_msgtype
,
im_mbz
,
im_vif
,
_
,
im_src
,
im_dst
)
=
struct
.
unpack
(
"II B B B B 4s 4s"
,
msg
[:
20
])
print
((
im_msgtype
,
im_mbz
,
socket
.
inet_ntoa
(
im_src
),
socket
.
inet_ntoa
(
im_dst
)))
if
im_mbz
!=
0
:
if
im_mbz
!=
0
:
continue
continue
...
@@ -284,7 +286,7 @@ class Kernel:
...
@@ -284,7 +286,7 @@ class Kernel:
print
(
im_vif
)
print
(
im_vif
)
print
(
socket
.
inet_ntoa
(
im_src
))
print
(
socket
.
inet_ntoa
(
im_src
))
print
(
socket
.
inet_ntoa
(
im_dst
))
print
(
socket
.
inet_ntoa
(
im_dst
))
print
(
struct
.
unpack
(
"II B B B B 4s 4s"
,
msg
[:
20
]
))
#print((im_msgtype, im_mbz, socket.inet_ntoa(im_src), socket.inet_ntoa(im_dst)
))
ip_src
=
socket
.
inet_ntoa
(
im_src
)
ip_src
=
socket
.
inet_ntoa
(
im_src
)
ip_dst
=
socket
.
inet_ntoa
(
im_dst
)
ip_dst
=
socket
.
inet_ntoa
(
im_dst
)
...
@@ -293,6 +295,7 @@ class Kernel:
...
@@ -293,6 +295,7 @@ class Kernel:
print
(
"IGMP NO CACHE"
)
print
(
"IGMP NO CACHE"
)
self
.
igmpmsg_nocache_handler
(
ip_src
,
ip_dst
,
im_vif
)
self
.
igmpmsg_nocache_handler
(
ip_src
,
ip_dst
,
im_vif
)
elif
im_msgtype
==
Kernel
.
IGMPMSG_WRONGVIF
:
elif
im_msgtype
==
Kernel
.
IGMPMSG_WRONGVIF
:
print
(
"WRONG VIF HANDLER"
)
self
.
igmpmsg_wrongvif_handler
(
ip_src
,
ip_dst
,
im_vif
)
self
.
igmpmsg_wrongvif_handler
(
ip_src
,
ip_dst
,
im_vif
)
else
:
else
:
raise
Exception
raise
Exception
...
@@ -333,7 +336,8 @@ class Kernel:
...
@@ -333,7 +336,8 @@ class Kernel:
# receive multicast (S,G) packet in a outbound_interface
# receive multicast (S,G) packet in a outbound_interface
def
igmpmsg_wrongvif_handler
(
self
,
ip_src
,
ip_dst
,
iif
):
def
igmpmsg_wrongvif_handler
(
self
,
ip_src
,
ip_dst
,
iif
):
#kernel_entry = self.routing[(ip_src, ip_dst)]
#kernel_entry = self.routing[(ip_src, ip_dst)]
self
.
get_routing_entry
((
ip_src
,
ip_dst
),
create_if_not_existent
=
True
).
recv_data_msg
(
iif
)
source_group_pair
=
(
ip_src
,
ip_dst
)
self
.
get_routing_entry
(
source_group_pair
,
create_if_not_existent
=
True
).
recv_data_msg
(
iif
)
#kernel_entry.recv_data_msg(iif)
#kernel_entry.recv_data_msg(iif)
"""
"""
...
@@ -357,4 +361,19 @@ class Kernel:
...
@@ -357,4 +361,19 @@ class Kernel:
#self.set_multicast_route(kernel_entry)
#self.set_multicast_route(kernel_entry)
return
kernel_entry
return
kernel_entry
else
:
else
:
return
None
return
None
\ No newline at end of file
def
neighbor_removed
(
self
,
interface_name
,
neighbor_ip
):
# todo
interface_index
=
self
.
vif_name_to_index_dic
[
interface_name
]
with
self
.
rwlock
.
genRlock
():
for
routing_entry
in
self
.
routing
.
values
():
routing_entry
.
nbr_died
(
interface_index
,
neighbor_ip
)
Main.py
View file @
77f16d47
...
@@ -6,6 +6,7 @@ from InterfacePIM import InterfacePim
...
@@ -6,6 +6,7 @@ from InterfacePIM import InterfacePim
from
InterfaceIGMP
import
InterfaceIGMP
from
InterfaceIGMP
import
InterfaceIGMP
from
Kernel
import
Kernel
from
Kernel
import
Kernel
from
threading
import
Lock
from
threading
import
Lock
import
UnicastRouting
interfaces
=
{}
# interfaces with multicast routing enabled
interfaces
=
{}
# interfaces with multicast routing enabled
igmp_interfaces
=
{}
# igmp interfaces
igmp_interfaces
=
{}
# igmp interfaces
...
@@ -13,15 +14,16 @@ protocols = {}
...
@@ -13,15 +14,16 @@ protocols = {}
kernel
=
None
kernel
=
None
igmp
=
None
igmp
=
None
def
add_interface
(
interface_name
,
pim
=
False
,
igmp
=
False
):
def
add_interface
(
interface_name
,
pim
=
False
,
igmp
=
False
):
if
pim
is
True
and
interface_name
not
in
interfaces
:
if
pim
is
True
and
interface_name
not
in
interfaces
:
interface
=
InterfacePim
(
interface_name
)
interface
=
InterfacePim
(
interface_name
)
interfaces
[
interface_name
]
=
interface
interfaces
[
interface_name
]
=
interface
protocols
[
0
].
force_send
(
interface
)
if
igmp
is
True
and
interface_name
not
in
igmp_interfaces
:
if
igmp
is
True
and
interface_name
not
in
igmp_interfaces
:
interface
=
InterfaceIGMP
(
interface_name
)
interface
=
InterfaceIGMP
(
interface_name
)
igmp_interfaces
[
interface_name
]
=
interface
igmp_interfaces
[
interface_name
]
=
interface
def
remove_interface
(
interface_name
,
pim
=
False
,
igmp
=
False
):
def
remove_interface
(
interface_name
,
pim
=
False
,
igmp
=
False
):
if
pim
is
True
and
((
interface_name
in
interfaces
)
or
interface_name
==
"*"
):
if
pim
is
True
and
((
interface_name
in
interfaces
)
or
interface_name
==
"*"
):
if
interface_name
==
"*"
:
if
interface_name
==
"*"
:
...
@@ -29,10 +31,12 @@ def remove_interface(interface_name, pim=False, igmp=False):
...
@@ -29,10 +31,12 @@ def remove_interface(interface_name, pim=False, igmp=False):
else
:
else
:
interface_name_list
=
[
interface_name
]
interface_name_list
=
[
interface_name
]
for
if_name
in
interface_name_list
:
for
if_name
in
interface_name_list
:
protocols
[
0
].
force_send_remove
(
interfaces
[
if_name
])
interface_obj
=
interfaces
.
pop
(
if_name
)
interfaces
[
if_name
].
remove
()
interface_obj
.
remove
()
del
interfaces
[
if_name
]
#interfaces[if_name].remove()
#del interfaces[if_name]
print
(
"removido interface"
)
print
(
"removido interface"
)
print
(
interfaces
)
if
igmp
is
True
and
((
interface_name
in
igmp_interfaces
)
or
interface_name
==
"*"
):
if
igmp
is
True
and
((
interface_name
in
igmp_interfaces
)
or
interface_name
==
"*"
):
if
interface_name
==
"*"
:
if
interface_name
==
"*"
:
...
@@ -43,6 +47,7 @@ def remove_interface(interface_name, pim=False, igmp=False):
...
@@ -43,6 +47,7 @@ def remove_interface(interface_name, pim=False, igmp=False):
igmp_interfaces
[
if_name
].
remove
()
igmp_interfaces
[
if_name
].
remove
()
del
igmp_interfaces
[
if_name
]
del
igmp_interfaces
[
if_name
]
print
(
"removido interface"
)
print
(
"removido interface"
)
print
(
igmp_interfaces
)
"""
"""
...
@@ -126,7 +131,7 @@ def list_enabled_interfaces():
...
@@ -126,7 +131,7 @@ def list_enabled_interfaces():
t
=
PrettyTable
([
'Interface'
,
'IP'
,
'PIM/I
MG
P Enabled'
,
'IGMP State'
])
t
=
PrettyTable
([
'Interface'
,
'IP'
,
'PIM/I
GM
P Enabled'
,
'IGMP State'
])
for
interface
in
netifaces
.
interfaces
():
for
interface
in
netifaces
.
interfaces
():
try
:
try
:
# TODO: fix same interface with multiple ips
# TODO: fix same interface with multiple ips
...
@@ -145,6 +150,11 @@ def list_enabled_interfaces():
...
@@ -145,6 +150,11 @@ def list_enabled_interfaces():
return
str
(
t
)
return
str
(
t
)
def
list_state
():
state_text
=
"IGMP State:
\
n
"
+
list_igmp_state
()
+
"
\
n
\
n
\
n
\
n
"
+
"Multicast Routing State:
\
n
"
+
list_routing_state
()
return
state_text
def
list_igmp_state
():
def
list_igmp_state
():
t
=
PrettyTable
([
'Interface'
,
'RouterState'
,
'Group Adress'
,
'GroupState'
])
t
=
PrettyTable
([
'Interface'
,
'RouterState'
,
'Group Adress'
,
'GroupState'
])
for
(
interface_name
,
interface_obj
)
in
list
(
igmp_interfaces
.
items
()):
for
(
interface_name
,
interface_obj
)
in
list
(
igmp_interfaces
.
items
()):
...
@@ -158,6 +168,7 @@ def list_igmp_state():
...
@@ -158,6 +168,7 @@ def list_igmp_state():
t
.
add_row
([
interface_name
,
state_txt
,
group_addr
,
group_state_txt
])
t
.
add_row
([
interface_name
,
state_txt
,
group_addr
,
group_state_txt
])
return
str
(
t
)
return
str
(
t
)
def
list_routing_state
():
def
list_routing_state
():
routing_entries
=
kernel
.
routing
.
values
()
routing_entries
=
kernel
.
routing
.
values
()
vif_indexes
=
kernel
.
vif_index_to_name_dic
.
keys
()
vif_indexes
=
kernel
.
vif_index_to_name_dic
.
keys
()
...
@@ -182,7 +193,13 @@ def list_routing_state():
...
@@ -182,7 +193,13 @@ def list_routing_state():
return
str
(
t
)
return
str
(
t
)
def
main
(
interfaces_to_add
=
[]):
def
stop
():
remove_interface
(
"*"
,
pim
=
True
,
igmp
=
True
)
kernel
.
exit
()
UnicastRouting
.
stop
()
def
main
():
from
Hello
import
Hello
from
Hello
import
Hello
from
IGMP
import
IGMP
from
IGMP
import
IGMP
from
Assert
import
Assert
from
Assert
import
Assert
...
@@ -196,5 +213,3 @@ def main(interfaces_to_add=[]):
...
@@ -196,5 +213,3 @@ def main(interfaces_to_add=[]):
global
igmp
global
igmp
igmp
=
IGMP
()
igmp
=
IGMP
()
for
interface
in
interfaces_to_add
:
add_interface
(
interface
)
Neighbor.py
View file @
77f16d47
from
threading
import
Timer
from
threading
import
Timer
import
time
import
time
from
utils
import
HELLO_HOLD_TIME_NO_TIMEOUT
,
HELLO_HOLD_TIME_TIMEOUT
from
utils
import
HELLO_HOLD_TIME_NO_TIMEOUT
,
HELLO_HOLD_TIME_TIMEOUT
,
TYPE_CHECKING
from
Interface
import
Interface
import
Main
from
threading
import
Lock
from
threading
import
Lock
import
Main
if
TYPE_CHECKING
:
from
InterfacePIM
import
InterfacePim
class
Neighbor
:
class
Neighbor
:
def
__init__
(
self
,
contact_interface
:
Interface
,
ip
,
generation_id
:
int
,
hello_hold_time
:
int
):
def
__init__
(
self
,
contact_interface
:
"InterfacePim"
,
ip
,
generation_id
:
int
,
hello_hold_time
:
int
):
if
hello_hold_time
==
HELLO_HOLD_TIME_TIMEOUT
:
if
hello_hold_time
==
HELLO_HOLD_TIME_TIMEOUT
:
raise
Exception
raise
Exception
self
.
contact_interface
=
contact_interface
self
.
contact_interface
=
contact_interface
...
@@ -19,8 +20,9 @@ class Neighbor:
...
@@ -19,8 +20,9 @@ class Neighbor:
self
.
time_of_last_update
=
time
.
time
()
self
.
time_of_last_update
=
time
.
time
()
self
.
neighbor_lock
=
Lock
()
self
.
neighbor_lock
=
Lock
()
# todo
# send hello to new neighbor
Main
.
protocols
[
0
].
force_send
(
contact_interface
)
self
.
contact_interface
.
send_hello
()
def
set_hello_hold_time
(
self
,
hello_hold_time
:
int
):
def
set_hello_hold_time
(
self
,
hello_hold_time
:
int
):
self
.
hello_hold_time
=
hello_hold_time
self
.
hello_hold_time
=
hello_hold_time
...
@@ -36,13 +38,13 @@ class Neighbor:
...
@@ -36,13 +38,13 @@ class Neighbor:
self
.
neighbor_liveness_timer
=
None
self
.
neighbor_liveness_timer
=
None
def
set_generation_id
(
self
,
generation_id
):
def
set_generation_id
(
self
,
generation_id
):
if
self
.
generation_id
is
None
:
# neighbor restarted
if
self
.
generation_id
!=
generation_id
:
self
.
generation_id
=
generation_id
self
.
generation_id
=
generation_id
elif
self
.
generation_id
!=
generation_id
:
self
.
contact_interface
.
send_hello
()
self
.
generation_id
=
generation_id
self
.
reset
()
self
.
set_hello_hold_time
(
self
.
hello_hold_time
)
self
.
time_of_last_update
=
time
.
time
()
"""
def heartbeat(self):
def heartbeat(self):
if (self.hello_hold_time != HELLO_HOLD_TIME_TIMEOUT) and
\
if (self.hello_hold_time != HELLO_HOLD_TIME_TIMEOUT) and
\
(self.hello_hold_time != HELLO_HOLD_TIME_NO_TIMEOUT):
(self.hello_hold_time != HELLO_HOLD_TIME_NO_TIMEOUT):
...
@@ -52,10 +54,30 @@ class Neighbor:
...
@@ -52,10 +54,30 @@ class Neighbor:
self.neighbor_liveness_timer = Timer(self.hello_hold_time, self.remove)
self.neighbor_liveness_timer = Timer(self.hello_hold_time, self.remove)
self.neighbor_liveness_timer.start()
self.neighbor_liveness_timer.start()
self.time_of_last_update = time.time()
self.time_of_last_update = time.time()
"""
def
remove
(
self
):
def
remove
(
self
):
print
(
'HELLO TIMER EXPIRED... remove neighbor'
)
print
(
'HELLO TIMER EXPIRED... remove neighbor'
)
if
self
.
neighbor_liveness_timer
is
not
None
:
if
self
.
neighbor_liveness_timer
is
not
None
:
self
.
neighbor_liveness_timer
.
cancel
()
self
.
neighbor_liveness_timer
.
cancel
()
#Main.remove_neighbor(self.ip)
#Main.remove_neighbor(self.ip)
interface_name
=
self
.
contact_interface
.
interface_name
neighbor_ip
=
self
.
ip
Main
.
kernel
.
neighbor_removed
(
interface_name
,
neighbor_ip
)
del
self
.
contact_interface
.
neighbors
[
self
.
ip
]
del
self
.
contact_interface
.
neighbors
[
self
.
ip
]
def
reset
(
self
):
interface_name
=
self
.
contact_interface
.
interface_name
neighbor_ip
=
self
.
ip
Main
.
kernel
.
neighbor_removed
(
interface_name
,
neighbor_ip
)
# todo new neighbor
def
receive_hello
(
self
,
generation_id
,
hello_hold_time
):
if
hello_hold_time
==
HELLO_HOLD_TIME_TIMEOUT
:
self
.
set_hello_hold_time
(
hello_hold_time
)
else
:
self
.
time_of_last_update
=
time
.
time
()
self
.
set_generation_id
(
generation_id
)
self
.
set_hello_hold_time
(
hello_hold_time
)
Run.py
View file @
77f16d47
...
@@ -62,7 +62,7 @@ class MyDaemon(Daemon):
...
@@ -62,7 +62,7 @@ class MyDaemon(Daemon):
elif
args
.
list_neighbors
:
elif
args
.
list_neighbors
:
connection
.
sendall
(
pickle
.
dumps
(
Main
.
list_neighbors
()))
connection
.
sendall
(
pickle
.
dumps
(
Main
.
list_neighbors
()))
elif
args
.
list_state
:
elif
args
.
list_state
:
connection
.
sendall
(
pickle
.
dumps
(
Main
.
list_
igmp_state
()
+
"
\
n
\
n
\
n
\
n
\
n
\
n
"
+
Main
.
list_routing_
state
()))
connection
.
sendall
(
pickle
.
dumps
(
Main
.
list_state
()))
elif
args
.
add_interface
:
elif
args
.
add_interface
:
Main
.
add_interface
(
args
.
add_interface
[
0
],
pim
=
True
)
Main
.
add_interface
(
args
.
add_interface
[
0
],
pim
=
True
)
connection
.
shutdown
(
socket
.
SHUT_RDWR
)
connection
.
shutdown
(
socket
.
SHUT_RDWR
)
...
@@ -76,7 +76,7 @@ class MyDaemon(Daemon):
...
@@ -76,7 +76,7 @@ class MyDaemon(Daemon):
Main
.
remove_interface
(
args
.
remove_interface_igmp
[
0
],
igmp
=
True
)
Main
.
remove_interface
(
args
.
remove_interface_igmp
[
0
],
igmp
=
True
)
connection
.
shutdown
(
socket
.
SHUT_RDWR
)
connection
.
shutdown
(
socket
.
SHUT_RDWR
)
elif
args
.
stop
:
elif
args
.
stop
:
Main
.
remove_interface
(
"*"
,
pim
=
True
,
igmp
=
True
)
Main
.
stop
(
)
connection
.
shutdown
(
socket
.
SHUT_RDWR
)
connection
.
shutdown
(
socket
.
SHUT_RDWR
)
except
Exception
:
except
Exception
:
connection
.
shutdown
(
socket
.
SHUT_RDWR
)
connection
.
shutdown
(
socket
.
SHUT_RDWR
)
...
...
UnicastRouting.py
0 → 100644
View file @
77f16d47
from
pyroute2
import
IPDB
,
IPRoute
import
socket
#ipdb = IPDB()
ipr
=
IPRoute
()
def
get_route
(
ip_dst
:
str
):
with
IPDB
()
as
ipdb
:
ip_bytes
=
socket
.
inet_aton
(
ip_dst
)
ip_int
=
int
.
from_bytes
(
ip_bytes
,
byteorder
=
'big'
)
info
=
None
for
mask_len
in
range
(
32
,
0
,
-
1
):
ip_bytes
=
(
ip_int
&
(
0xFFFFFFFF
<<
(
32
-
mask_len
))).
to_bytes
(
4
,
"big"
)
ip_dst
=
socket
.
inet_ntoa
(
ip_bytes
)
+
"/"
+
str
(
mask_len
)
print
(
ip_dst
)
try
:
info
=
ipdb
.
routes
[
ip_dst
]
break
except
:
continue
if
not
info
:
print
(
"0.0.0.0/0"
)
info
=
ipdb
.
routes
[
"default"
]
print
(
info
)
return
info
# get metrics (routing preference and cost) to IP ip_dst
def
get_metric
(
ip_dst
:
str
):
unicast_routing_entry
=
get_route
(
ip_dst
)
entry_protocol
=
unicast_routing_entry
[
"proto"
]
entry_cost
=
unicast_routing_entry
[
"priority"
]
return
(
entry_protocol
,
entry_cost
)
"""
def get_rpf(ip_dst: str):
unicast_routing_entry = get_route(ip_dst)
#interface_oif = unicast_routing_entry['oif']
if not unicast_routing_entry['multipath']:
interface_oif = unicast_routing_entry['oif']
else:
multiple_entries = unicast_routing_entry['multipath']
print(multiple_entries)
(entry0, _) = multiple_entries
print(entry0)
interface_oif = entry0['oif']
print("ola")
print(ipdb.interfaces[interface_oif]['ipaddr'])
for i in range(len(ipdb.interfaces[interface_oif]['ipaddr'])):
print("ola2")
interface = ipdb.interfaces[interface_oif]['ipaddr'][i]
print(interface)
if interface['family'] == socket.AF_INET:
return interface['address']
return None
"""
# get output interface IP, used to send data to IP ip_dst
# (root interface IP to ip_dst)
def
check_rpf
(
ip_dst
):
# obter index da interface
# rpf_interface_index = ipr.get_routes(family=socket.AF_INET, dst=ip)[0]['attrs'][2][1]
# interface_name = if_indextoname(rpf_interface_index)
# return interface_name
# obter ip da interface de saida
rpf_interface_source
=
ipr
.
get_routes
(
family
=
socket
.
AF_INET
,
dst
=
ip_dst
)[
0
][
'attrs'
][
3
][
1
]
return
rpf_interface_source
"""
def get_metric(ip_dst: str):
ip_bytes = socket.inet_aton(ip_dst)
ip_int = int.from_bytes(ip_bytes, byteorder='big')
info = None
for mask_len in range(32, 0, -1):
ip_bytes = (ip_int & (0xFFFFFFFF << (32 - mask_len))).to_bytes(4, "big")
ip_dst = socket.inet_ntoa(ip_bytes) + "/" + str(mask_len)
print(ip_dst)
try:
info = ipdb.routes[ip_dst]
break
except:
continue
if not info:
print("0.0.0.0/0")
info = ipdb.routes["default"]
print(info)
print("metric=", info["priority"])
print("proto=", info["proto"])
#print(info.keys())
#if info["gateway"]:
# print("next_hop=", info["gateway"])
#elif info["prefsrc"]:
# print("next_hop=", info["prefsrc"])
return (info["proto"], info["priority"])
def check_rpf(ip_dst: str):
from pyroute2 import IPRoute
# from utils import if_indextoname
ipr = IPRoute()
# obter index da interface
# rpf_interface_index = ipr.get_routes(family=socket.AF_INET, dst=ip)[0]['attrs'][2][1]
# interface_name = if_indextoname(rpf_interface_index)
# return interface_name
# obter ip da interface de saida
rpf_interface_source = ipr.get_routes(family=socket.AF_INET, dst=ip_dst)[0]['attrs'][3][1]
return rpf_interface_source
"""
def
stop
():
ipr
.
close
()
#ip = input("ip=")
#get_metric(ip)
\ No newline at end of file
tree/KernelEntry.py
View file @
77f16d47
import
Main
import
Main
import
socket
import
socket
import
netifaces
from
tree.root_interface
import
SFRMRootInterface
from
tree.root_interface
import
SFRMRootInterface
from
tree.non_root_interface
import
SFRMNonRootInterface
from
tree.non_root_interface
import
SFRMNonRootInterface
from
threading
import
Timer
,
Lock
from
threading
import
Timer
,
Lock
import
UnicastRouting
class
KernelEntry
:
class
KernelEntry
:
TREE_TIMEOUT
=
180
TREE_TIMEOUT
=
180
...
@@ -64,18 +64,7 @@ class KernelEntry:
...
@@ -64,18 +64,7 @@ class KernelEntry:
return
outbound_indexes
return
outbound_indexes
def
check_rpf
(
self
):
def
check_rpf
(
self
):
from
pyroute2
import
IPRoute
return
UnicastRouting
.
check_rpf
(
self
.
source_ip
)
# from utils import if_indextoname
ipr
=
IPRoute
()
# obter index da interface
# rpf_interface_index = ipr.get_routes(family=socket.AF_INET, dst=ip)[0]['attrs'][2][1]
# interface_name = if_indextoname(rpf_interface_index)
# return interface_name
# obter ip da interface de saida
rpf_interface_source
=
ipr
.
get_routes
(
family
=
socket
.
AF_INET
,
dst
=
self
.
source_ip
)[
0
][
'attrs'
][
3
][
1
]
return
rpf_interface_source
def
recv_data_msg
(
self
,
index
):
def
recv_data_msg
(
self
,
index
):
if
self
.
is_originater
():
if
self
.
is_originater
():
...
@@ -130,19 +119,16 @@ class KernelEntry:
...
@@ -130,19 +119,16 @@ class KernelEntry:
# todo
# todo
return
return
def
nbr_died
(
self
,
index
,
neighbor_ip
):
# todo
self
.
interface_state
[
index
].
nbr_died
(
neighbor_ip
)
def
is_in_group
(
self
):
def
is_in_group
(
self
):
# todo
# todo
#if self.get_has_members():
#if self.get_has_members():
#if True:
#if True:
# return True
# return True
"""
for index in Main.kernel.vif_index_to_name_dic.keys():
if self.interface_state[index].is_forwarding():
return True
return False
"""
for
interface
in
self
.
interface_state
.
values
():
for
interface
in
self
.
interface_state
.
values
():
if
interface
.
is_forwarding
():
if
interface
.
is_forwarding
():
return
True
return
True
...
@@ -176,16 +162,6 @@ class KernelEntry:
...
@@ -176,16 +162,6 @@ class KernelEntry:
def
get_group
(
self
):
def
get_group
(
self
):
return
self
.
group_ip
return
self
.
group_ip
def
get_has_members
(
self
):
#return self._has_members
return
True
def
set_has_members
(
self
,
value
):
assert
isinstance
(
value
,
bool
)
self
.
_has_members
=
value
self
.
evaluate_ingroup
()
def
change
(
self
):
def
change
(
self
):
# todo: changes on unicast routing or multicast routing...
# todo: changes on unicast routing or multicast routing...
with
self
.
_multicast_change
:
with
self
.
_multicast_change
:
...
...
tree/assert_.py
View file @
77f16d47
...
@@ -183,7 +183,7 @@ class SFMRAssertLooser(SFMRAssertABC):
...
@@ -183,7 +183,7 @@ class SFMRAssertLooser(SFMRAssertABC):
interface
.
_set_assert_state
(
AssertState
.
Winner
)
interface
.
_set_assert_state
(
AssertState
.
Winner
)
interface
.
_set_winner_metric
(
None
)
interface
.
_set_winner_metric
(
None
)
interface
.
send_assert
()
@
staticmethod
@
staticmethod
def
al_rpc_better_than_aw
(
interface
):
def
al_rpc_better_than_aw
(
interface
):
...
...
tree/metric.py
View file @
77f16d47
...
@@ -58,10 +58,13 @@ class SFMRAssertMetric(object):
...
@@ -58,10 +58,13 @@ class SFMRAssertMetric(object):
#metric._node = tree_if.get_node()
#metric._node = tree_if.get_node()
metric_preference
=
10
# todo check how to get metric preference
#metric_preference = 10 # todo check how to get metric preference
route_metric
=
tree_if
.
get_cost
()
#route_metric = tree_if.get_cost()
ip
=
tree_if
.
get_ip
()
import
UnicastRouting
metric
=
SFMRAssertMetric
(
metric_preference
=
metric_preference
,
route_metric
=
route_metric
,
ip_address
=
ip
)
(
source
,
group
)
=
tree_if
.
get_tree_id
()
(
metric_prefernce
,
metric
)
=
UnicastRouting
.
get_metric
(
source
)
interface_ip
=
tree_if
.
get_ip
()
metric
=
SFMRAssertMetric
(
metric_preference
=
metric_prefernce
,
route_metric
=
metric
,
ip_address
=
interface_ip
)
return
metric
return
metric
...
...
tree/non_root_interface.py
View file @
77f16d47
...
@@ -34,8 +34,10 @@ class SFRMNonRootInterface(SFRMTreeInterface):
...
@@ -34,8 +34,10 @@ class SFRMNonRootInterface(SFRMTreeInterface):
# Override
# Override
def
recv_data_msg
(
self
,
msg
=
None
,
sender
=
None
):
def
recv_data_msg
(
self
,
msg
=
None
,
sender
=
None
):
if
self
.
_prune_state
!=
SFMRPruneState
.
NDI
:
# todo perguntar ao prof
self
.
_assert_state
.
data_arrival
(
self
)
#if self._prune_state != SFMRPruneState.NDI:
# self._assert_state.data_arrival(self)
self
.
_assert_state
.
data_arrival
(
self
)
# Override
# Override
def
recv_assert_msg
(
self
,
msg
:
ReceivedPacket
,
sender
=
None
):
def
recv_assert_msg
(
self
,
msg
:
ReceivedPacket
,
sender
=
None
):
...
@@ -43,8 +45,9 @@ class SFRMNonRootInterface(SFRMTreeInterface):
...
@@ -43,8 +45,9 @@ class SFRMNonRootInterface(SFRMTreeInterface):
@type msg: SFMRAssertMsg
@type msg: SFMRAssertMsg
@type sender: Addr
@type sender: Addr
'''
'''
if
self
.
_prune_state
==
SFMRPruneState
.
NDI
:
# todo perguntar ao prof
return
#if self._prune_state == SFMRPruneState.NDI:
# return
if
self
.
_assert_state
==
AssertState
.
Looser
:
if
self
.
_assert_state
==
AssertState
.
Looser
:
winner_metric
=
self
.
_get_winner_metric
()
winner_metric
=
self
.
_get_winner_metric
()
...
@@ -55,8 +58,10 @@ class SFRMNonRootInterface(SFRMTreeInterface):
...
@@ -55,8 +58,10 @@ class SFRMNonRootInterface(SFRMTreeInterface):
pkt_assert
=
msg
.
payload
.
payload
# type: PacketPimAssert
pkt_assert
=
msg
.
payload
.
payload
# type: PacketPimAssert
msg_metric
=
SFMRAssertMetric
(
metric_preference
=
pkt_assert
.
metric_preference
,
route_metric
=
pkt_assert
.
metric
,
ip_address
=
ip_sender
)
msg_metric
=
SFMRAssertMetric
(
metric_preference
=
pkt_assert
.
metric_preference
,
route_metric
=
pkt_assert
.
metric
,
ip_address
=
ip_sender
)
if
winner_metric
.
is_worse_than
(
msg_metric
):
if
winner_metric
.
is_worse_than
(
msg_metric
):
print
(
"ASSERT BETTER"
)
self
.
_assert_state
.
recv_better_metric
(
self
,
msg_metric
)
self
.
_assert_state
.
recv_better_metric
(
self
,
msg_metric
)
else
:
else
:
print
(
"ASSERT WORSE"
)
self
.
_assert_state
.
recv_worse_metric
(
self
,
msg_metric
)
self
.
_assert_state
.
recv_worse_metric
(
self
,
msg_metric
)
# Override
# Override
...
@@ -85,7 +90,9 @@ class SFRMNonRootInterface(SFRMTreeInterface):
...
@@ -85,7 +90,9 @@ class SFRMNonRootInterface(SFRMTreeInterface):
from
Packet.Packet
import
Packet
from
Packet.Packet
import
Packet
from
Packet.PacketPimHeader
import
PacketPimHeader
from
Packet.PacketPimHeader
import
PacketPimHeader
from
Packet.PacketPimAssert
import
PacketPimAssert
from
Packet.PacketPimAssert
import
PacketPimAssert
ph
=
PacketPimAssert
(
multicast_group_address
=
group
,
source_address
=
source
,
metric_preference
=
10
,
metric
=
2
)
import
UnicastRouting
(
metric_preference
,
metric
)
=
UnicastRouting
.
get_metric
(
source
)
ph
=
PacketPimAssert
(
multicast_group_address
=
group
,
source_address
=
source
,
metric_preference
=
metric_preference
,
metric
=
metric
)
pckt
=
Packet
(
payload
=
PacketPimHeader
(
ph
))
pckt
=
Packet
(
payload
=
PacketPimHeader
(
ph
))
self
.
get_interface
().
send
(
pckt
.
bytes
())
self
.
get_interface
().
send
(
pckt
.
bytes
())
print
(
'sent assert msg'
)
print
(
'sent assert msg'
)
...
@@ -111,11 +118,22 @@ class SFRMNonRootInterface(SFRMTreeInterface):
...
@@ -111,11 +118,22 @@ class SFRMNonRootInterface(SFRMTreeInterface):
return
self
.
_prune_state
==
SFMRPruneState
.
NDI
return
self
.
_prune_state
==
SFMRPruneState
.
NDI
# Override
# Override
def
nbr_died
(
self
,
node
):
def
nbr_died
(
self
,
neighbor_ip
):
import
ipaddress
neighbor_ip
=
ipaddress
.
ip_address
(
neighbor_ip
)
# todo
# todo
#if self._get_winner_metric() is not None \
# and self._get_winner_metric().get_ip_address() == node\
# and self._prune_state != SFMRPruneState.NDI:
# self._assert_state.aw_failure(self)
winner_metric
=
self
.
_get_winner_metric
()
print
(
winner_metric
.
get_ip_address
())
print
(
neighbor_ip
)
print
(
winner_metric
.
get_route_metric
())
print
(
winner_metric
.
get_metric_preference
())
if
self
.
_get_winner_metric
()
is
not
None
\
if
self
.
_get_winner_metric
()
is
not
None
\
and
self
.
_get_winner_metric
().
get_ip_address
()
==
node
\
and
self
.
_get_winner_metric
().
get_ip_address
()
==
neighbor_ip
:
and
self
.
_prune_state
!=
SFMRPruneState
.
NDI
:
self
.
_assert_state
.
aw_failure
(
self
)
self
.
_assert_state
.
aw_failure
(
self
)
self
.
_prune_state
.
lost_nbr
(
self
)
self
.
_prune_state
.
lost_nbr
(
self
)
...
...
tree/prune.py
View file @
77f16d47
...
@@ -166,8 +166,8 @@ class SFMRDownstreamInterestedPending(SFMRPruneStateABC):
...
@@ -166,8 +166,8 @@ class SFMRDownstreamInterestedPending(SFMRPruneStateABC):
'''
'''
print
(
'lost_nbr, DIP -> DIP'
)
print
(
'lost_nbr, DIP -> DIP'
)
#todo alterado pelo Pedro... necessita de verificar se esta OK...
#todo alterado pelo Pedro... necessita de verificar se esta OK...
interface
.
send_prune
()
#
interface.send_prune()
interface
.
set_dipt_timer
()
#
interface.set_dipt_timer()
class
SFMRNoDownstreamInterested
(
SFMRPruneStateABC
):
class
SFMRNoDownstreamInterested
(
SFMRPruneStateABC
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment