Commit abf25568 authored by Pedro Oliveira's avatar Pedro Oliveira Committed by GitHub

Multiple VRFs (#4)

* First try IPv6 support... based on HPIM-DM IPv6 commit

* fix membership removal of interface (IGMP/MLD)

* Add support for unicast and multicast VRFs && remove some commented code && IGMP/MLD snake case global variables
parent 023dcf97
...@@ -5,7 +5,8 @@ from ctypes import create_string_buffer, addressof ...@@ -5,7 +5,8 @@ from ctypes import create_string_buffer, addressof
import netifaces import netifaces
from pimdm.Interface import Interface from pimdm.Interface import Interface
from pimdm.packet.ReceivedPacket import ReceivedPacket from pimdm.packet.ReceivedPacket import ReceivedPacket
from pimdm.igmp.igmp_globals import Version_1_Membership_Report, Version_2_Membership_Report, Leave_Group, Membership_Query from pimdm.igmp.igmp_globals import VERSION_1_MEMBERSHIP_REPORT, VERSION_2_MEMBERSHIP_REPORT, LEAVE_GROUP, \
MEMBERSHIP_QUERY
if not hasattr(socket, 'SO_BINDTODEVICE'): if not hasattr(socket, 'SO_BINDTODEVICE'):
socket.SO_BINDTODEVICE = 25 socket.SO_BINDTODEVICE = 25
...@@ -101,10 +102,10 @@ class InterfaceIGMP(Interface): ...@@ -101,10 +102,10 @@ class InterfaceIGMP(Interface):
return return
PKT_FUNCTIONS = { PKT_FUNCTIONS = {
Version_1_Membership_Report: receive_version_1_membership_report, VERSION_1_MEMBERSHIP_REPORT: receive_version_1_membership_report,
Version_2_Membership_Report: receive_version_2_membership_report, VERSION_2_MEMBERSHIP_REPORT: receive_version_2_membership_report,
Leave_Group: receive_leave_group, LEAVE_GROUP: receive_leave_group,
Membership_Query: receive_membership_query, MEMBERSHIP_QUERY: receive_membership_query,
} }
################## ##################
......
...@@ -8,6 +8,7 @@ from abc import abstractmethod, ABCMeta ...@@ -8,6 +8,7 @@ from abc import abstractmethod, ABCMeta
from pimdm import UnicastRouting, Main from pimdm import UnicastRouting, Main
from pimdm.rwlock.RWLock import RWLockWrite from pimdm.rwlock.RWLock import RWLockWrite
from pimdm.tree.globals import MULTICAST_TABLE_ID
from pimdm.InterfaceMLD import InterfaceMLD from pimdm.InterfaceMLD import InterfaceMLD
from pimdm.InterfaceIGMP import InterfaceIGMP from pimdm.InterfaceIGMP import InterfaceIGMP
...@@ -276,6 +277,13 @@ class Kernel4(Kernel): ...@@ -276,6 +277,13 @@ class Kernel4(Kernel):
def __init__(self): def __init__(self):
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IGMP) s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IGMP)
# MRT TABLE
if MULTICAST_TABLE_ID != 0:
try:
s.setsockopt(socket.IPPROTO_IP, self.MRT_TABLE, MULTICAST_TABLE_ID)
except:
traceback.print_exc()
# MRT INIT # MRT INIT
s.setsockopt(socket.IPPROTO_IP, self.MRT_INIT, 1) s.setsockopt(socket.IPPROTO_IP, self.MRT_INIT, 1)
...@@ -513,6 +521,13 @@ class Kernel6(Kernel): ...@@ -513,6 +521,13 @@ class Kernel6(Kernel):
def __init__(self): def __init__(self):
s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6) s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6)
# MRT TABLE
if MULTICAST_TABLE_ID != 0:
try:
s.setsockopt(socket.IPPROTO_IPV6, self.MRT6_TABLE, MULTICAST_TABLE_ID)
except:
traceback.print_exc()
# MRT INIT # MRT INIT
s.setsockopt(socket.IPPROTO_IPV6, self.MRT6_INIT, 1) s.setsockopt(socket.IPPROTO_IPV6, self.MRT6_INIT, 1)
......
...@@ -9,8 +9,9 @@ import _pickle as pickle ...@@ -9,8 +9,9 @@ import _pickle as pickle
from pimdm import Main from pimdm import Main
from pimdm.daemon.Daemon import Daemon from pimdm.daemon.Daemon import Daemon
from pimdm.tree.globals import MULTICAST_TABLE_ID
VERSION = "1.1" VERSION = "1.1.1"
def client_socket(data_to_send): def client_socket(data_to_send):
...@@ -162,9 +163,9 @@ def main(): ...@@ -162,9 +163,9 @@ def main():
sys.exit(0) sys.exit(0)
elif args.multicast_routes: elif args.multicast_routes:
if args.ipv4 or not args.ipv6: if args.ipv4 or not args.ipv6:
os.system("ip mroute show") os.system("ip mroute show table " + str(MULTICAST_TABLE_ID))
elif args.ipv6: elif args.ipv6:
os.system("ip -6 mroute show") os.system("ip -6 mroute show table " + str(MULTICAST_TABLE_ID))
sys.exit(0) sys.exit(0)
elif not daemon.is_running(): elif not daemon.is_running():
print("PIM-DM is not running") print("PIM-DM is not running")
......
...@@ -3,6 +3,7 @@ import ipaddress ...@@ -3,6 +3,7 @@ import ipaddress
from threading import RLock from threading import RLock
from socket import if_indextoname from socket import if_indextoname
from pyroute2 import IPDB from pyroute2 import IPDB
from pimdm.tree.globals import UNICAST_TABLE_ID
def get_route(ip_dst: str): def get_route(ip_dst: str):
...@@ -64,17 +65,18 @@ class UnicastRouting(object): ...@@ -64,17 +65,18 @@ class UnicastRouting(object):
dst_network = str(ipaddress.ip_interface(ip_dst + "/" + str(mask_len)).network) dst_network = str(ipaddress.ip_interface(ip_dst + "/" + str(mask_len)).network)
print(dst_network) print(dst_network)
if dst_network in ipdb.routes: if dst_network in ipdb.routes.tables[UNICAST_TABLE_ID]:
print(info) print(info)
if ipdb.routes[{'dst': dst_network, 'family': family}]['ipdb_scope'] != 'gc': if ipdb.routes[{'dst': dst_network, 'family': family,
info = ipdb.routes[dst_network] 'table': UNICAST_TABLE_ID}]['ipdb_scope'] != 'gc':
info = ipdb.routes[{'dst': dst_network, 'family': family, 'table': UNICAST_TABLE_ID}]
break break
else: else:
continue continue
if not info: if not info:
print("0.0.0.0/0 or ::/0") print("0.0.0.0/0 or ::/0")
if "default" in ipdb.routes: if "default" in ipdb.routes.tables[UNICAST_TABLE_ID]:
info = ipdb.routes[{'dst': 'default', 'family': family}] info = ipdb.routes[{'dst': 'default', 'family': family, 'table': UNICAST_TABLE_ID}]
print(info) print(info)
return info return info
......
...@@ -4,7 +4,7 @@ from threading import Timer ...@@ -4,7 +4,7 @@ from threading import Timer
from pimdm.utils import TYPE_CHECKING from pimdm.utils import TYPE_CHECKING
from .wrapper import NoMembersPresent from .wrapper import NoMembersPresent
from .igmp_globals import GroupMembershipInterval, LastMemberQueryInterval from .igmp_globals import GROUP_MEMBERSHIP_INTERVAL, LAST_MEMBER_QUERY_INTERVAL
if TYPE_CHECKING: if TYPE_CHECKING:
from .RouterState import RouterState from .RouterState import RouterState
...@@ -40,16 +40,22 @@ class GroupState(object): ...@@ -40,16 +40,22 @@ class GroupState(object):
# Set state # Set state
########################################### ###########################################
def set_state(self, state): def set_state(self, state):
"""
Set membership state regarding this Group
"""
self.state = state self.state = state
self.group_state_logger.debug("change membership state to: " + state.print_state()) self.group_state_logger.debug("change membership state to: " + state.print_state())
########################################### ###########################################
# Set timers # Set timers
########################################### ###########################################
def set_timer(self, alternative: bool=False, max_response_time: int=None): def set_timer(self, alternative: bool = False, max_response_time: int = None):
"""
Set timer
"""
self.clear_timer() self.clear_timer()
if not alternative: if not alternative:
time = GroupMembershipInterval time = GROUP_MEMBERSHIP_INTERVAL
else: else:
time = self.router_state.interface_state.get_group_membership_time(max_response_time) time = self.router_state.interface_state.get_group_membership_time(max_response_time)
...@@ -58,48 +64,74 @@ class GroupState(object): ...@@ -58,48 +64,74 @@ class GroupState(object):
self.timer = timer self.timer = timer
def clear_timer(self): def clear_timer(self):
"""
Stop timer
"""
if self.timer is not None: if self.timer is not None:
self.timer.cancel() self.timer.cancel()
def set_v1_host_timer(self): def set_v1_host_timer(self):
"""
Set v1 host timer
"""
self.clear_v1_host_timer() self.clear_v1_host_timer()
v1_host_timer = Timer(GroupMembershipInterval, self.group_membership_v1_timeout) v1_host_timer = Timer(GROUP_MEMBERSHIP_INTERVAL, self.group_membership_v1_timeout)
v1_host_timer.start() v1_host_timer.start()
self.v1_host_timer = v1_host_timer self.v1_host_timer = v1_host_timer
def clear_v1_host_timer(self): def clear_v1_host_timer(self):
"""
Stop v1 host timer
"""
if self.v1_host_timer is not None: if self.v1_host_timer is not None:
self.v1_host_timer.cancel() self.v1_host_timer.cancel()
def set_retransmit_timer(self): def set_retransmit_timer(self):
"""
Set retransmit timer
"""
self.clear_retransmit_timer() self.clear_retransmit_timer()
retransmit_timer = Timer(LastMemberQueryInterval, self.retransmit_timeout) retransmit_timer = Timer(LAST_MEMBER_QUERY_INTERVAL, self.retransmit_timeout)
retransmit_timer.start() retransmit_timer.start()
self.retransmit_timer = retransmit_timer self.retransmit_timer = retransmit_timer
def clear_retransmit_timer(self): def clear_retransmit_timer(self):
"""
Stop retransmit timer
"""
if self.retransmit_timer is not None: if self.retransmit_timer is not None:
self.retransmit_timer.cancel() self.retransmit_timer.cancel()
########################################### ###########################################
# Get group state from specific interface state # Get group state from specific interface state
########################################### ###########################################
def get_interface_group_state(self): def get_interface_group_state(self):
"""
Get specific implementation of the membership state machine (depending on the querier state machine)
"""
return self.state.get_state(self.router_state) return self.state.get_state(self.router_state)
########################################### ###########################################
# Timer timeout # Timer timeout
########################################### ###########################################
def group_membership_timeout(self): def group_membership_timeout(self):
"""
Timer has expired
"""
with self.lock: with self.lock:
self.get_interface_group_state().group_membership_timeout(self) self.get_interface_group_state().group_membership_timeout(self)
def group_membership_v1_timeout(self): def group_membership_v1_timeout(self):
"""
v1 host timer has expired
"""
with self.lock: with self.lock:
self.get_interface_group_state().group_membership_v1_timeout(self) self.get_interface_group_state().group_membership_v1_timeout(self)
def retransmit_timeout(self): def retransmit_timeout(self):
"""
Retransmit timer has expired
"""
with self.lock: with self.lock:
self.get_interface_group_state().retransmit_timeout(self) self.get_interface_group_state().retransmit_timeout(self)
...@@ -107,18 +139,30 @@ class GroupState(object): ...@@ -107,18 +139,30 @@ class GroupState(object):
# Receive Packets # Receive Packets
########################################### ###########################################
def receive_v1_membership_report(self): def receive_v1_membership_report(self):
"""
Received IGMP Version 1 Membership Report packet regarding this group
"""
with self.lock: with self.lock:
self.get_interface_group_state().receive_v1_membership_report(self) self.get_interface_group_state().receive_v1_membership_report(self)
def receive_v2_membership_report(self): def receive_v2_membership_report(self):
"""
Received IGMP Membership Report packet regarding this group
"""
with self.lock: with self.lock:
self.get_interface_group_state().receive_v2_membership_report(self) self.get_interface_group_state().receive_v2_membership_report(self)
def receive_leave_group(self): def receive_leave_group(self):
"""
Received IGMP Leave packet regarding this group
"""
with self.lock: with self.lock:
self.get_interface_group_state().receive_leave_group(self) self.get_interface_group_state().receive_leave_group(self)
def receive_group_specific_query(self, max_response_time: int): def receive_group_specific_query(self, max_response_time: int):
"""
Received IGMP Group Specific Query packet regarding this group
"""
with self.lock: with self.lock:
self.get_interface_group_state().receive_group_specific_query(self, max_response_time) self.get_interface_group_state().receive_group_specific_query(self, max_response_time)
...@@ -126,30 +170,52 @@ class GroupState(object): ...@@ -126,30 +170,52 @@ class GroupState(object):
# Notify Routing # Notify Routing
########################################### ###########################################
def notify_routing_add(self): def notify_routing_add(self):
"""
Notify all tree entries that IGMP considers to have hosts interested in this group
"""
with self.multicast_interface_state_lock: with self.multicast_interface_state_lock:
print("notify+", self.multicast_interface_state) print("notify+", self.multicast_interface_state)
for interface_state in self.multicast_interface_state: for interface_state in self.multicast_interface_state:
interface_state.notify_membership(has_members=True) interface_state.notify_membership(has_members=True)
def notify_routing_remove(self): def notify_routing_remove(self):
"""
Notify all tree entries that IGMP considers to have not hosts interested in this group
"""
with self.multicast_interface_state_lock: with self.multicast_interface_state_lock:
print("notify-", self.multicast_interface_state) print("notify-", self.multicast_interface_state)
for interface_state in self.multicast_interface_state: for interface_state in self.multicast_interface_state:
interface_state.notify_membership(has_members=False) interface_state.notify_membership(has_members=False)
def add_multicast_routing_entry(self, kernel_entry): def add_multicast_routing_entry(self, kernel_entry):
"""
A new tree is being monitored by the multicast routing protocol that has the same group
IGMP will store these entries in order to accelerate the notification process regarding changes in IGMP state
"""
with self.multicast_interface_state_lock: with self.multicast_interface_state_lock:
self.multicast_interface_state.append(kernel_entry) self.multicast_interface_state.append(kernel_entry)
return self.has_members() return self.has_members()
def remove_multicast_routing_entry(self, kernel_entry): def remove_multicast_routing_entry(self, kernel_entry):
"""
A tree is no longer being monitored by the multicast routing protocol
Remove this tree from this object
"""
with self.multicast_interface_state_lock: with self.multicast_interface_state_lock:
self.multicast_interface_state.remove(kernel_entry) self.multicast_interface_state.remove(kernel_entry)
def has_members(self): def has_members(self):
"""
Determine if IGMP considers to have hosts interested in receiving data packets
"""
return self.state is not NoMembersPresent return self.state is not NoMembersPresent
def remove(self): def remove(self):
"""
Remove this group from the IGMP process
Notify all trees that this group no longer considers to be connected to hosts
This method will be invoked whenever an IGMP interface is removed
"""
with self.multicast_interface_state_lock: with self.multicast_interface_state_lock:
self.clear_retransmit_timer() self.clear_retransmit_timer()
self.clear_timer() self.clear_timer()
......
...@@ -8,7 +8,7 @@ from pimdm.rwlock.RWLock import RWLockWrite ...@@ -8,7 +8,7 @@ from pimdm.rwlock.RWLock import RWLockWrite
from .querier.Querier import Querier from .querier.Querier import Querier
from .nonquerier.NonQuerier import NonQuerier from .nonquerier.NonQuerier import NonQuerier
from .GroupState import GroupState from .GroupState import GroupState
from .igmp_globals import Membership_Query, QueryResponseInterval, QueryInterval, OtherQuerierPresentInterval from .igmp_globals import MEMBERSHIP_QUERY, QUERY_RESPONSE_INTERVAL, QUERY_INTERVAL, OTHER_QUERIER_PRESENT_INTERVAL
if TYPE_CHECKING: if TYPE_CHECKING:
from pimdm.InterfaceIGMP import InterfaceIGMP from pimdm.InterfaceIGMP import InterfaceIGMP
...@@ -36,11 +36,11 @@ class RouterState(object): ...@@ -36,11 +36,11 @@ class RouterState(object):
self.group_state_lock = RWLockWrite() self.group_state_lock = RWLockWrite()
# send general query # send general query
packet = PacketIGMPHeader(type=Membership_Query, max_resp_time=QueryResponseInterval*10) packet = PacketIGMPHeader(type=MEMBERSHIP_QUERY, max_resp_time=QUERY_RESPONSE_INTERVAL * 10)
self.interface.send(packet.bytes()) self.interface.send(packet.bytes())
# set initial general query timer # set initial general query timer
timer = Timer(QueryInterval, self.general_query_timeout) timer = Timer(QUERY_INTERVAL, self.general_query_timeout)
timer.start() timer.start()
self.general_query_timer = timer self.general_query_timer = timer
...@@ -58,32 +58,53 @@ class RouterState(object): ...@@ -58,32 +58,53 @@ class RouterState(object):
return self.interface_state.state_name() return self.interface_state.state_name()
def set_general_query_timer(self): def set_general_query_timer(self):
"""
Set general query timer
"""
self.clear_general_query_timer() self.clear_general_query_timer()
general_query_timer = Timer(QueryInterval, self.general_query_timeout) general_query_timer = Timer(QUERY_INTERVAL, self.general_query_timeout)
general_query_timer.start() general_query_timer.start()
self.general_query_timer = general_query_timer self.general_query_timer = general_query_timer
def clear_general_query_timer(self): def clear_general_query_timer(self):
"""
Stop general query timer
"""
if self.general_query_timer is not None: if self.general_query_timer is not None:
self.general_query_timer.cancel() self.general_query_timer.cancel()
def set_other_querier_present_timer(self): def set_other_querier_present_timer(self):
"""
Set other querier present timer
"""
self.clear_other_querier_present_timer() self.clear_other_querier_present_timer()
other_querier_present_timer = Timer(OtherQuerierPresentInterval, self.other_querier_present_timeout) other_querier_present_timer = Timer(OTHER_QUERIER_PRESENT_INTERVAL, self.other_querier_present_timeout)
other_querier_present_timer.start() other_querier_present_timer.start()
self.other_querier_present_timer = other_querier_present_timer self.other_querier_present_timer = other_querier_present_timer
def clear_other_querier_present_timer(self): def clear_other_querier_present_timer(self):
"""
Stop other querier present timer
"""
if self.other_querier_present_timer is not None: if self.other_querier_present_timer is not None:
self.other_querier_present_timer.cancel() self.other_querier_present_timer.cancel()
def general_query_timeout(self): def general_query_timeout(self):
"""
General Query timer has expired
"""
self.interface_state.general_query_timeout(self) self.interface_state.general_query_timeout(self)
def other_querier_present_timeout(self): def other_querier_present_timeout(self):
"""
Other Querier Present timer has expired
"""
self.interface_state.other_querier_present_timeout(self) self.interface_state.other_querier_present_timeout(self)
def change_interface_state(self, querier: bool): def change_interface_state(self, querier: bool):
"""
Change state regarding querier state machine (Querier/NonQuerier)
"""
if querier: if querier:
self.interface_state = Querier self.interface_state = Querier
self.router_state_logger.debug('change querier state to -> Querier') self.router_state_logger.debug('change querier state to -> Querier')
...@@ -95,6 +116,9 @@ class RouterState(object): ...@@ -95,6 +116,9 @@ class RouterState(object):
# group state methods # group state methods
############################################ ############################################
def get_group_state(self, group_ip): def get_group_state(self, group_ip):
"""
Get object that monitors a given group (with group_ip IP address)
"""
with self.group_state_lock.genRlock(): with self.group_state_lock.genRlock():
if group_ip in self.group_state: if group_ip in self.group_state:
return self.group_state[group_ip] return self.group_state[group_ip]
...@@ -108,38 +132,42 @@ class RouterState(object): ...@@ -108,38 +132,42 @@ class RouterState(object):
return group_state return group_state
def receive_v1_membership_report(self, packet: ReceivedPacket): def receive_v1_membership_report(self, packet: ReceivedPacket):
"""
Received IGMP Version 1 Membership Report packet
"""
igmp_group = packet.payload.group_address igmp_group = packet.payload.group_address
#if igmp_group not in self.group_state:
# self.group_state[igmp_group] = GroupState(self, igmp_group)
#self.group_state[igmp_group].receive_v1_membership_report()
self.get_group_state(igmp_group).receive_v1_membership_report() self.get_group_state(igmp_group).receive_v1_membership_report()
def receive_v2_membership_report(self, packet: ReceivedPacket): def receive_v2_membership_report(self, packet: ReceivedPacket):
"""
Received IGMP Membership Report packet
"""
igmp_group = packet.payload.group_address igmp_group = packet.payload.group_address
#if igmp_group not in self.group_state:
# self.group_state[igmp_group] = GroupState(self, igmp_group)
#self.group_state[igmp_group].receive_v2_membership_report()
self.get_group_state(igmp_group).receive_v2_membership_report() self.get_group_state(igmp_group).receive_v2_membership_report()
def receive_leave_group(self, packet: ReceivedPacket): def receive_leave_group(self, packet: ReceivedPacket):
"""
Received IGMP Leave packet
"""
igmp_group = packet.payload.group_address igmp_group = packet.payload.group_address
#if igmp_group in self.group_state:
# self.group_state[igmp_group].receive_leave_group()
self.get_group_state(igmp_group).receive_leave_group() self.get_group_state(igmp_group).receive_leave_group()
def receive_query(self, packet: ReceivedPacket): def receive_query(self, packet: ReceivedPacket):
"""
Received IGMP Query packet
"""
self.interface_state.receive_query(self, packet) self.interface_state.receive_query(self, packet)
igmp_group = packet.payload.group_address igmp_group = packet.payload.group_address
# process group specific query # process group specific query
if igmp_group != "0.0.0.0" and igmp_group in self.group_state: if igmp_group != "0.0.0.0" and igmp_group in self.group_state:
#if igmp_group != "0.0.0.0":
max_response_time = packet.payload.max_resp_time max_response_time = packet.payload.max_resp_time
#self.group_state[igmp_group].receive_group_specific_query(max_response_time)
self.get_group_state(igmp_group).receive_group_specific_query(max_response_time) self.get_group_state(igmp_group).receive_group_specific_query(max_response_time)
def remove(self): def remove(self):
"""
Remove this IGMP interface
Clear all state
"""
for group in self.group_state.values(): for group in self.group_state.values():
group.remove() group.remove()
# IGMP timers (in seconds) # IGMP timers (in seconds)
RobustnessVariable = 2 ROBUSTNESS_VARIABLE = 2
QueryInterval = 125 QUERY_INTERVAL = 125
QueryResponseInterval = 10 QUERY_RESPONSE_INTERVAL = 10
MaxResponseTime_QueryResponseInterval = QueryResponseInterval*10 MAX_RESPONSE_TIME_QUERY_RESPONSE_INTERVAL = QUERY_RESPONSE_INTERVAL * 10
GroupMembershipInterval = RobustnessVariable * QueryInterval + QueryResponseInterval GROUP_MEMBERSHIP_INTERVAL = ROBUSTNESS_VARIABLE * QUERY_INTERVAL + QUERY_RESPONSE_INTERVAL
OtherQuerierPresentInterval = RobustnessVariable * QueryInterval + QueryResponseInterval/2 OTHER_QUERIER_PRESENT_INTERVAL = ROBUSTNESS_VARIABLE * QUERY_INTERVAL + QUERY_RESPONSE_INTERVAL / 2
StartupQueryInterval = QueryInterval / 4 STARTUP_QUERY_INTERVAL = QUERY_INTERVAL / 4
StartupQueryCount = RobustnessVariable STARTUP_QUERY_COUNT = ROBUSTNESS_VARIABLE
LastMemberQueryInterval = 1 LAST_MEMBER_QUERY_INTERVAL = 1
MaxResponseTime_LastMemberQueryInterval = LastMemberQueryInterval*10 MAX_RESPONSE_TIME_LAST_MEMBER_QUERY_INTERVAL = LAST_MEMBER_QUERY_INTERVAL * 10
LastMemberQueryCount = RobustnessVariable LAST_MEMBER_QUERY_COUNT = ROBUSTNESS_VARIABLE
UnsolicitedReportInterval = 10 UNSOLICITED_REPORT_INTERVAL = 10
Version1RouterPresentTimeout = 400 VERSION_1_ROUTER_PRESENT_TIMEOUT = 400
# IGMP msg type # IGMP msg type
Membership_Query = 0x11 MEMBERSHIP_QUERY = 0x11
Version_1_Membership_Report = 0x12 VERSION_1_MEMBERSHIP_REPORT = 0x12
Version_2_Membership_Report = 0x16 VERSION_2_MEMBERSHIP_REPORT = 0x16
Leave_Group = 0x17 LEAVE_GROUP = 0x17
\ No newline at end of file
...@@ -7,6 +7,9 @@ if TYPE_CHECKING: ...@@ -7,6 +7,9 @@ if TYPE_CHECKING:
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier CheckingMembership: group_membership_timeout') group_state.group_state_logger.debug('NonQuerier CheckingMembership: group_membership_timeout')
group_state.set_state(NoMembersPresent) group_state.set_state(NoMembersPresent)
...@@ -15,35 +18,53 @@ def group_membership_timeout(group_state: 'GroupState'): ...@@ -15,35 +18,53 @@ def group_membership_timeout(group_state: 'GroupState'):
def group_membership_v1_timeout(group_state: 'GroupState'): def group_membership_v1_timeout(group_state: 'GroupState'):
"""
v1 host timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier CheckingMembership: group_membership_v1_timeout') group_state.group_state_logger.debug('NonQuerier CheckingMembership: group_membership_v1_timeout')
# do nothing # do nothing
return return
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier CheckingMembership: retransmit_timeout') group_state.group_state_logger.debug('NonQuerier CheckingMembership: retransmit_timeout')
# do nothing # do nothing
return return
def receive_v1_membership_report(group_state: 'GroupState'): def receive_v1_membership_report(group_state: 'GroupState'):
"""
Received IGMP Version 1 Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_v1_membership_report') group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_v1_membership_report')
receive_v2_membership_report(group_state) receive_v2_membership_report(group_state)
def receive_v2_membership_report(group_state: 'GroupState'): def receive_v2_membership_report(group_state: 'GroupState'):
"""
Received IGMP Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_v2_membership_report') group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_v2_membership_report')
group_state.set_timer() group_state.set_timer()
group_state.set_state(MembersPresent) group_state.set_state(MembersPresent)
def receive_leave_group(group_state: 'GroupState'): def receive_leave_group(group_state: 'GroupState'):
"""
Received IGMP Leave packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_leave_group') group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_leave_group')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received IGMP Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_group_specific_query') group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_group_specific_query')
# do nothing # do nothing
return return
...@@ -7,6 +7,9 @@ if TYPE_CHECKING: ...@@ -7,6 +7,9 @@ if TYPE_CHECKING:
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier MembersPresent: group_membership_timeout') group_state.group_state_logger.debug('NonQuerier MembersPresent: group_membership_timeout')
group_state.set_state(NoMembersPresent) group_state.set_state(NoMembersPresent)
...@@ -15,34 +18,52 @@ def group_membership_timeout(group_state: 'GroupState'): ...@@ -15,34 +18,52 @@ def group_membership_timeout(group_state: 'GroupState'):
def group_membership_v1_timeout(group_state: 'GroupState'): def group_membership_v1_timeout(group_state: 'GroupState'):
"""
v1 host timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier MembersPresent: group_membership_v1_timeout') group_state.group_state_logger.debug('NonQuerier MembersPresent: group_membership_v1_timeout')
# do nothing # do nothing
return return
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier MembersPresent: retransmit_timeout') group_state.group_state_logger.debug('NonQuerier MembersPresent: retransmit_timeout')
# do nothing # do nothing
return return
def receive_v1_membership_report(group_state: 'GroupState'): def receive_v1_membership_report(group_state: 'GroupState'):
"""
Received IGMP Version 1 Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_v1_membership_report') group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_v1_membership_report')
receive_v2_membership_report(group_state) receive_v2_membership_report(group_state)
def receive_v2_membership_report(group_state: 'GroupState'): def receive_v2_membership_report(group_state: 'GroupState'):
"""
Received IGMP Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_v2_membership_report') group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_v2_membership_report')
group_state.set_timer() group_state.set_timer()
def receive_leave_group(group_state: 'GroupState'): def receive_leave_group(group_state: 'GroupState'):
"""
Received IGMP Leave packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_leave_group') group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_leave_group')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received IGMP Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_group_specific_query') group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_group_specific_query')
group_state.set_timer(alternative=True, max_response_time=max_response_time) group_state.set_timer(alternative=True, max_response_time=max_response_time)
group_state.set_state(CheckingMembership) group_state.set_state(CheckingMembership)
...@@ -6,29 +6,44 @@ if TYPE_CHECKING: ...@@ -6,29 +6,44 @@ if TYPE_CHECKING:
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier NoMembersPresent: group_membership_timeout') group_state.group_state_logger.debug('NonQuerier NoMembersPresent: group_membership_timeout')
# do nothing # do nothing
return return
def group_membership_v1_timeout(group_state: 'GroupState'): def group_membership_v1_timeout(group_state: 'GroupState'):
"""
v1 host timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier NoMembersPresent: group_membership_v1_timeout') group_state.group_state_logger.debug('NonQuerier NoMembersPresent: group_membership_v1_timeout')
# do nothing # do nothing
return return
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier NoMembersPresent: retransmit_timeout') group_state.group_state_logger.debug('NonQuerier NoMembersPresent: retransmit_timeout')
# do nothing # do nothing
return return
def receive_v1_membership_report(group_state: 'GroupState'): def receive_v1_membership_report(group_state: 'GroupState'):
"""
Received IGMP Version 1 Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_v1_membership_report') group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_v1_membership_report')
receive_v2_membership_report(group_state) receive_v2_membership_report(group_state)
def receive_v2_membership_report(group_state: 'GroupState'): def receive_v2_membership_report(group_state: 'GroupState'):
"""
Received IGMP Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_v2_membership_report') group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_v2_membership_report')
group_state.set_timer() group_state.set_timer()
group_state.set_state(MembersPresent) group_state.set_state(MembersPresent)
...@@ -38,12 +53,18 @@ def receive_v2_membership_report(group_state: 'GroupState'): ...@@ -38,12 +53,18 @@ def receive_v2_membership_report(group_state: 'GroupState'):
def receive_leave_group(group_state: 'GroupState'): def receive_leave_group(group_state: 'GroupState'):
"""
Received IGMP Leave packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_leave_group') group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_leave_group')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received IGMP Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_group_specific_query') group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_group_specific_query')
# do nothing # do nothing
return return
from ipaddress import IPv4Address from ipaddress import IPv4Address
from pimdm.utils import TYPE_CHECKING from pimdm.utils import TYPE_CHECKING
from ..igmp_globals import Membership_Query, QueryResponseInterval, LastMemberQueryCount from pimdm.igmp.igmp_globals import MEMBERSHIP_QUERY, QUERY_RESPONSE_INTERVAL, LAST_MEMBER_QUERY_COUNT
from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader
from pimdm.packet.ReceivedPacket import ReceivedPacket from pimdm.packet.ReceivedPacket import ReceivedPacket
from . import NoMembersPresent, MembersPresent, CheckingMembership from . import NoMembersPresent, MembersPresent, CheckingMembership
...@@ -13,18 +13,24 @@ class NonQuerier: ...@@ -13,18 +13,24 @@ class NonQuerier:
@staticmethod @staticmethod
def general_query_timeout(router_state: 'RouterState'): def general_query_timeout(router_state: 'RouterState'):
"""
General Query timer has expired
"""
router_state.router_state_logger.debug('NonQuerier state: general_query_timeout') router_state.router_state_logger.debug('NonQuerier state: general_query_timeout')
# do nothing # do nothing
return return
@staticmethod @staticmethod
def other_querier_present_timeout(router_state: 'RouterState'): def other_querier_present_timeout(router_state: 'RouterState'):
"""
Other Query Present timer has expired
"""
router_state.router_state_logger.debug('NonQuerier state: other_querier_present_timeout') router_state.router_state_logger.debug('NonQuerier state: other_querier_present_timeout')
#change state to Querier #change state to Querier
router_state.change_interface_state(querier=True) router_state.change_interface_state(querier=True)
# send general query # send general query
packet = PacketIGMPHeader(type=Membership_Query, max_resp_time=QueryResponseInterval*10) packet = PacketIGMPHeader(type=MEMBERSHIP_QUERY, max_resp_time=QUERY_RESPONSE_INTERVAL * 10)
router_state.interface.send(packet.bytes()) router_state.interface.send(packet.bytes())
# set general query timer # set general query timer
...@@ -32,6 +38,9 @@ class NonQuerier: ...@@ -32,6 +38,9 @@ class NonQuerier:
@staticmethod @staticmethod
def receive_query(router_state: 'RouterState', packet: ReceivedPacket): def receive_query(router_state: 'RouterState', packet: ReceivedPacket):
"""
Interface associated with RouterState is NonQuerier and received a Query packet
"""
router_state.router_state_logger.debug('NonQuerier state: receive_query') router_state.router_state_logger.debug('NonQuerier state: receive_query')
source_ip = packet.ip_header.ip_src source_ip = packet.ip_header.ip_src
...@@ -49,21 +58,37 @@ class NonQuerier: ...@@ -49,21 +58,37 @@ class NonQuerier:
@staticmethod @staticmethod
def get_group_membership_time(max_response_time: int): def get_group_membership_time(max_response_time: int):
return (max_response_time/10.0) * LastMemberQueryCount """
Get time to set timer*
"""
return (max_response_time/10.0) * LAST_MEMBER_QUERY_COUNT
# State # State
@staticmethod @staticmethod
def get_checking_membership_state(): def get_checking_membership_state():
"""
Get implementation of CheckingMembership state machine of interface in NonQuerier state
"""
return CheckingMembership return CheckingMembership
@staticmethod @staticmethod
def get_members_present_state(): def get_members_present_state():
"""
Get implementation of MembersPresent state machine of interface in NonQuerier state
"""
return MembersPresent return MembersPresent
@staticmethod @staticmethod
def get_no_members_present_state(): def get_no_members_present_state():
"""
Get implementation of NoMembersPresent state machine of interface in NonQuerier state
"""
return NoMembersPresent return NoMembersPresent
@staticmethod @staticmethod
def get_version_1_members_present_state(): def get_version_1_members_present_state():
"""
Get implementation of Version1MembersPresent state machine of interface in NonQuerier state
This will return implementation of MembersPresent state machine
"""
return NonQuerier.get_members_present_state() return NonQuerier.get_members_present_state()
from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader
from pimdm.utils import TYPE_CHECKING from pimdm.utils import TYPE_CHECKING
from ..igmp_globals import Membership_Query, LastMemberQueryInterval from pimdm.igmp.igmp_globals import MEMBERSHIP_QUERY, LAST_MEMBER_QUERY_INTERVAL
from ..wrapper import NoMembersPresent, MembersPresent, Version1MembersPresent from ..wrapper import NoMembersPresent, MembersPresent, Version1MembersPresent
if TYPE_CHECKING: if TYPE_CHECKING:
from ..GroupState import GroupState from ..GroupState import GroupState
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier CheckingMembership: group_membership_timeout') group_state.group_state_logger.debug('Querier CheckingMembership: group_membership_timeout')
group_state.clear_retransmit_timer() group_state.clear_retransmit_timer()
group_state.set_state(NoMembersPresent) group_state.set_state(NoMembersPresent)
...@@ -16,21 +19,31 @@ def group_membership_timeout(group_state: 'GroupState'): ...@@ -16,21 +19,31 @@ def group_membership_timeout(group_state: 'GroupState'):
def group_membership_v1_timeout(group_state: 'GroupState'): def group_membership_v1_timeout(group_state: 'GroupState'):
"""
v1 host timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier CheckingMembership: group_membership_v1_timeout') group_state.group_state_logger.debug('Querier CheckingMembership: group_membership_v1_timeout')
# do nothing # do nothing
return return
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier CheckingMembership: retransmit_timeout') group_state.group_state_logger.debug('Querier CheckingMembership: retransmit_timeout')
group_addr = group_state.group_ip group_addr = group_state.group_ip
packet = PacketIGMPHeader(type=Membership_Query, max_resp_time=LastMemberQueryInterval*10, group_address=group_addr) packet = PacketIGMPHeader(type=MEMBERSHIP_QUERY, max_resp_time=LAST_MEMBER_QUERY_INTERVAL * 10,
group_address=group_addr)
group_state.router_state.send(data=packet.bytes(), address=group_addr) group_state.router_state.send(data=packet.bytes(), address=group_addr)
group_state.set_retransmit_timer() group_state.set_retransmit_timer()
def receive_v1_membership_report(group_state: 'GroupState'): def receive_v1_membership_report(group_state: 'GroupState'):
"""
Received IGMP Version 1 Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier CheckingMembership: receive_v1_membership_report') group_state.group_state_logger.debug('Querier CheckingMembership: receive_v1_membership_report')
group_state.set_timer() group_state.set_timer()
group_state.set_v1_host_timer() group_state.set_v1_host_timer()
...@@ -38,18 +51,27 @@ def receive_v1_membership_report(group_state: 'GroupState'): ...@@ -38,18 +51,27 @@ def receive_v1_membership_report(group_state: 'GroupState'):
def receive_v2_membership_report(group_state: 'GroupState'): def receive_v2_membership_report(group_state: 'GroupState'):
"""
Received IGMP Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier CheckingMembership: receive_v2_membership_report') group_state.group_state_logger.debug('Querier CheckingMembership: receive_v2_membership_report')
group_state.set_timer() group_state.set_timer()
group_state.set_state(MembersPresent) group_state.set_state(MembersPresent)
def receive_leave_group(group_state: 'GroupState'): def receive_leave_group(group_state: 'GroupState'):
"""
Received IGMP Leave packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier CheckingMembership: receive_leave_group') group_state.group_state_logger.debug('Querier CheckingMembership: receive_leave_group')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received IGMP Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier CheckingMembership: receive_group_specific_query') group_state.group_state_logger.debug('Querier CheckingMembership: receive_group_specific_query')
# do nothing # do nothing
return return
from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader
from pimdm.utils import TYPE_CHECKING from pimdm.utils import TYPE_CHECKING
from ..igmp_globals import Membership_Query, LastMemberQueryInterval from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader
from pimdm.igmp.igmp_globals import MEMBERSHIP_QUERY, LAST_MEMBER_QUERY_INTERVAL
from ..wrapper import Version1MembersPresent, CheckingMembership, NoMembersPresent from ..wrapper import Version1MembersPresent, CheckingMembership, NoMembersPresent
if TYPE_CHECKING: if TYPE_CHECKING:
from ..GroupState import GroupState from ..GroupState import GroupState
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier MembersPresent: group_membership_timeout') group_state.group_state_logger.debug('Querier MembersPresent: group_membership_timeout')
group_state.set_state(NoMembersPresent) group_state.set_state(NoMembersPresent)
...@@ -15,18 +18,27 @@ def group_membership_timeout(group_state: 'GroupState'): ...@@ -15,18 +18,27 @@ def group_membership_timeout(group_state: 'GroupState'):
def group_membership_v1_timeout(group_state: 'GroupState'): def group_membership_v1_timeout(group_state: 'GroupState'):
"""
v1 host timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier MembersPresent: group_membership_v1_timeout') group_state.group_state_logger.debug('Querier MembersPresent: group_membership_v1_timeout')
# do nothing # do nothing
return return
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier MembersPresent: retransmit_timeout') group_state.group_state_logger.debug('Querier MembersPresent: retransmit_timeout')
# do nothing # do nothing
return return
def receive_v1_membership_report(group_state: 'GroupState'): def receive_v1_membership_report(group_state: 'GroupState'):
"""
Received IGMP Version 1 Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier MembersPresent: receive_v1_membership_report') group_state.group_state_logger.debug('Querier MembersPresent: receive_v1_membership_report')
group_state.set_timer() group_state.set_timer()
group_state.set_v1_host_timer() group_state.set_v1_host_timer()
...@@ -34,24 +46,34 @@ def receive_v1_membership_report(group_state: 'GroupState'): ...@@ -34,24 +46,34 @@ def receive_v1_membership_report(group_state: 'GroupState'):
def receive_v2_membership_report(group_state: 'GroupState'): def receive_v2_membership_report(group_state: 'GroupState'):
"""
Received IGMP Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier MembersPresent: receive_v2_membership_report') group_state.group_state_logger.debug('Querier MembersPresent: receive_v2_membership_report')
group_state.set_timer() group_state.set_timer()
def receive_leave_group(group_state: 'GroupState'): def receive_leave_group(group_state: 'GroupState'):
"""
Received IGMP Leave packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier MembersPresent: receive_leave_group') group_state.group_state_logger.debug('Querier MembersPresent: receive_leave_group')
group_ip = group_state.group_ip group_ip = group_state.group_ip
group_state.set_timer(alternative=True) group_state.set_timer(alternative=True)
group_state.set_retransmit_timer() group_state.set_retransmit_timer()
packet = PacketIGMPHeader(type=Membership_Query, max_resp_time=LastMemberQueryInterval*10, group_address=group_ip) packet = PacketIGMPHeader(type=MEMBERSHIP_QUERY, max_resp_time=LAST_MEMBER_QUERY_INTERVAL * 10,
group_address=group_ip)
group_state.router_state.send(data=packet.bytes(), address=group_ip) group_state.router_state.send(data=packet.bytes(), address=group_ip)
group_state.set_state(CheckingMembership) group_state.set_state(CheckingMembership)
def receive_group_specific_query(group_state: 'GroupState', max_response_time): def receive_group_specific_query(group_state: 'GroupState', max_response_time):
"""
Received IGMP Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier MembersPresent: receive_group_specific_query') group_state.group_state_logger.debug('Querier MembersPresent: receive_group_specific_query')
# do nothing # do nothing
return return
...@@ -6,24 +6,36 @@ if TYPE_CHECKING: ...@@ -6,24 +6,36 @@ if TYPE_CHECKING:
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier NoMembersPresent: group_membership_timeout') group_state.group_state_logger.debug('Querier NoMembersPresent: group_membership_timeout')
# do nothing # do nothing
return return
def group_membership_v1_timeout(group_state: 'GroupState'): def group_membership_v1_timeout(group_state: 'GroupState'):
"""
v1 host timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier NoMembersPresent: group_membership_v1_timeout') group_state.group_state_logger.debug('Querier NoMembersPresent: group_membership_v1_timeout')
# do nothing # do nothing
return return
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier NoMembersPresent: retransmit_timeout') group_state.group_state_logger.debug('Querier NoMembersPresent: retransmit_timeout')
# do nothing # do nothing
return return
def receive_v1_membership_report(group_state: 'GroupState'): def receive_v1_membership_report(group_state: 'GroupState'):
"""
Received IGMP Version 1 Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier NoMembersPresent: receive_v1_membership_report') group_state.group_state_logger.debug('Querier NoMembersPresent: receive_v1_membership_report')
group_state.set_timer() group_state.set_timer()
group_state.set_v1_host_timer() group_state.set_v1_host_timer()
...@@ -34,6 +46,9 @@ def receive_v1_membership_report(group_state: 'GroupState'): ...@@ -34,6 +46,9 @@ def receive_v1_membership_report(group_state: 'GroupState'):
def receive_v2_membership_report(group_state: 'GroupState'): def receive_v2_membership_report(group_state: 'GroupState'):
"""
Received IGMP Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier NoMembersPresent: receive_v2_membership_report') group_state.group_state_logger.debug('Querier NoMembersPresent: receive_v2_membership_report')
group_state.set_timer() group_state.set_timer()
group_state.set_state(MembersPresent) group_state.set_state(MembersPresent)
...@@ -43,12 +58,18 @@ def receive_v2_membership_report(group_state: 'GroupState'): ...@@ -43,12 +58,18 @@ def receive_v2_membership_report(group_state: 'GroupState'):
def receive_leave_group(group_state: 'GroupState'): def receive_leave_group(group_state: 'GroupState'):
"""
Received IGMP Leave packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier NoMembersPresent: receive_leave_group') group_state.group_state_logger.debug('Querier NoMembersPresent: receive_leave_group')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received IGMP Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier NoMembersPresent: receive_group_specific_query') group_state.group_state_logger.debug('Querier NoMembersPresent: receive_group_specific_query')
# do nothing # do nothing
return return
from ipaddress import IPv4Address from ipaddress import IPv4Address
from pimdm.utils import TYPE_CHECKING from pimdm.utils import TYPE_CHECKING
from ..igmp_globals import Membership_Query, QueryResponseInterval, LastMemberQueryCount, LastMemberQueryInterval from ..igmp_globals import MEMBERSHIP_QUERY, QUERY_RESPONSE_INTERVAL, LAST_MEMBER_QUERY_COUNT, \
LAST_MEMBER_QUERY_INTERVAL
from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader
from pimdm.packet.ReceivedPacket import ReceivedPacket from pimdm.packet.ReceivedPacket import ReceivedPacket
...@@ -14,9 +15,12 @@ if TYPE_CHECKING: ...@@ -14,9 +15,12 @@ if TYPE_CHECKING:
class Querier: class Querier:
@staticmethod @staticmethod
def general_query_timeout(router_state: 'RouterState'): def general_query_timeout(router_state: 'RouterState'):
"""
General Query timer has expired
"""
router_state.router_state_logger.debug('Querier state: general_query_timeout') router_state.router_state_logger.debug('Querier state: general_query_timeout')
# send general query # send general query
packet = PacketIGMPHeader(type=Membership_Query, max_resp_time=QueryResponseInterval*10) packet = PacketIGMPHeader(type=MEMBERSHIP_QUERY, max_resp_time=QUERY_RESPONSE_INTERVAL * 10)
router_state.interface.send(packet.bytes()) router_state.interface.send(packet.bytes())
# set general query timer # set general query timer
...@@ -24,12 +28,18 @@ class Querier: ...@@ -24,12 +28,18 @@ class Querier:
@staticmethod @staticmethod
def other_querier_present_timeout(router_state: 'RouterState'): def other_querier_present_timeout(router_state: 'RouterState'):
"""
Other Querier Present timer has expired
"""
router_state.router_state_logger.debug('Querier state: other_querier_present_timeout') router_state.router_state_logger.debug('Querier state: other_querier_present_timeout')
# do nothing # do nothing
return return
@staticmethod @staticmethod
def receive_query(router_state: 'RouterState', packet: ReceivedPacket): def receive_query(router_state: 'RouterState', packet: ReceivedPacket):
"""
Interface associated with RouterState is Querier and received a Query packet
"""
router_state.router_state_logger.debug('Querier state: receive_query') router_state.router_state_logger.debug('Querier state: receive_query')
source_ip = packet.ip_header.ip_src source_ip = packet.ip_header.ip_src
...@@ -54,22 +64,37 @@ class Querier: ...@@ -54,22 +64,37 @@ class Querier:
@staticmethod @staticmethod
def get_group_membership_time(max_response_time: int): def get_group_membership_time(max_response_time: int):
return LastMemberQueryInterval * LastMemberQueryCount """
Get time to set timer*
"""
return LAST_MEMBER_QUERY_INTERVAL * LAST_MEMBER_QUERY_COUNT
# State # State
@staticmethod @staticmethod
def get_checking_membership_state(): def get_checking_membership_state():
"""
Get implementation of CheckingMembership state machine of interface in Querier state
"""
return CheckingMembership return CheckingMembership
@staticmethod @staticmethod
def get_members_present_state(): def get_members_present_state():
"""
Get implementation of MembersPresent state machine of interface in Querier state
"""
return MembersPresent return MembersPresent
@staticmethod @staticmethod
def get_no_members_present_state(): def get_no_members_present_state():
"""
Get implementation of NoMembersPresent state machine of interface in Querier state
"""
return NoMembersPresent return NoMembersPresent
@staticmethod @staticmethod
def get_version_1_members_present_state(): def get_version_1_members_present_state():
"""
Get implementation of Version1MembersPresent state machine of interface in Querier state
"""
return Version1MembersPresent return Version1MembersPresent
...@@ -6,6 +6,9 @@ if TYPE_CHECKING: ...@@ -6,6 +6,9 @@ if TYPE_CHECKING:
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier Version1MembersPresent: group_membership_timeout') group_state.group_state_logger.debug('Querier Version1MembersPresent: group_membership_timeout')
group_state.set_state(NoMembersPresent) group_state.set_state(NoMembersPresent)
...@@ -14,33 +17,51 @@ def group_membership_timeout(group_state: 'GroupState'): ...@@ -14,33 +17,51 @@ def group_membership_timeout(group_state: 'GroupState'):
def group_membership_v1_timeout(group_state: 'GroupState'): def group_membership_v1_timeout(group_state: 'GroupState'):
"""
v1 host timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier Version1MembersPresent: group_membership_v1_timeout') group_state.group_state_logger.debug('Querier Version1MembersPresent: group_membership_v1_timeout')
group_state.set_state(MembersPresent) group_state.set_state(MembersPresent)
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier Version1MembersPresent: retransmit_timeout') group_state.group_state_logger.debug('Querier Version1MembersPresent: retransmit_timeout')
# do nothing # do nothing
return return
def receive_v1_membership_report(group_state: 'GroupState'): def receive_v1_membership_report(group_state: 'GroupState'):
"""
Received IGMP Version 1 Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_v1_membership_report') group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_v1_membership_report')
group_state.set_timer() group_state.set_timer()
group_state.set_v1_host_timer() group_state.set_v1_host_timer()
def receive_v2_membership_report(group_state: 'GroupState'): def receive_v2_membership_report(group_state: 'GroupState'):
"""
Received IGMP Membership Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_v2_membership_report') group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_v2_membership_report')
group_state.set_timer() group_state.set_timer()
def receive_leave_group(group_state: 'GroupState'): def receive_leave_group(group_state: 'GroupState'):
"""
Received IGMP Leave packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_leave_group') group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_leave_group')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received IGMP Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_group_specific_query') group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_group_specific_query')
# do nothing # do nothing
return return
...@@ -2,6 +2,7 @@ from pimdm.utils import TYPE_CHECKING ...@@ -2,6 +2,7 @@ from pimdm.utils import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from ..RouterState import RouterState from ..RouterState import RouterState
def get_state(router_state: 'RouterState'): def get_state(router_state: 'RouterState'):
return router_state.interface_state.get_no_members_present_state() return router_state.interface_state.get_no_members_present_state()
......
...@@ -4,7 +4,7 @@ from threading import Timer ...@@ -4,7 +4,7 @@ from threading import Timer
from pimdm.utils import TYPE_CHECKING from pimdm.utils import TYPE_CHECKING
from .wrapper import NoListenersPresent from .wrapper import NoListenersPresent
from .mld_globals import MulticastListenerInterval, LastListenerQueryInterval from .mld_globals import MULTICAST_LISTENER_INTERVAL, LAST_LISTENER_QUERY_INTERVAL
if TYPE_CHECKING: if TYPE_CHECKING:
from .RouterState import RouterState from .RouterState import RouterState
...@@ -39,16 +39,22 @@ class GroupState(object): ...@@ -39,16 +39,22 @@ class GroupState(object):
# Set state # Set state
########################################### ###########################################
def set_state(self, state): def set_state(self, state):
"""
Set membership state regarding this Group
"""
self.state = state self.state = state
self.group_state_logger.debug("change membership state to: " + state.print_state()) self.group_state_logger.debug("change membership state to: " + state.print_state())
########################################### ###########################################
# Set timers # Set timers
########################################### ###########################################
def set_timer(self, alternative: bool=False, max_response_time: int=None): def set_timer(self, alternative: bool = False, max_response_time: int = None):
"""
Set timer
"""
self.clear_timer() self.clear_timer()
if not alternative: if not alternative:
time = MulticastListenerInterval time = MULTICAST_LISTENER_INTERVAL
else: else:
time = self.router_state.interface_state.get_group_membership_time(max_response_time) time = self.router_state.interface_state.get_group_membership_time(max_response_time)
...@@ -57,34 +63,51 @@ class GroupState(object): ...@@ -57,34 +63,51 @@ class GroupState(object):
self.timer = timer self.timer = timer
def clear_timer(self): def clear_timer(self):
"""
Stop timer
"""
if self.timer is not None: if self.timer is not None:
self.timer.cancel() self.timer.cancel()
def set_retransmit_timer(self): def set_retransmit_timer(self):
"""
Set retransmit timer
"""
self.clear_retransmit_timer() self.clear_retransmit_timer()
retransmit_timer = Timer(LastListenerQueryInterval, self.retransmit_timeout) retransmit_timer = Timer(LAST_LISTENER_QUERY_INTERVAL, self.retransmit_timeout)
retransmit_timer.start() retransmit_timer.start()
self.retransmit_timer = retransmit_timer self.retransmit_timer = retransmit_timer
def clear_retransmit_timer(self): def clear_retransmit_timer(self):
"""
Stop retransmit timer
"""
if self.retransmit_timer is not None: if self.retransmit_timer is not None:
self.retransmit_timer.cancel() self.retransmit_timer.cancel()
########################################### ###########################################
# Get group state from specific interface state # Get group state from specific interface state
########################################### ###########################################
def get_interface_group_state(self): def get_interface_group_state(self):
"""
Get specific implementation of the membership state machine (depending on the querier state machine)
"""
return self.state.get_state(self.router_state) return self.state.get_state(self.router_state)
########################################### ###########################################
# Timer timeout # Timer timeout
########################################### ###########################################
def group_membership_timeout(self): def group_membership_timeout(self):
"""
Timer has expired
"""
with self.lock: with self.lock:
self.get_interface_group_state().group_membership_timeout(self) self.get_interface_group_state().group_membership_timeout(self)
def retransmit_timeout(self): def retransmit_timeout(self):
"""
Retransmit timer has expired
"""
with self.lock: with self.lock:
self.get_interface_group_state().retransmit_timeout(self) self.get_interface_group_state().retransmit_timeout(self)
...@@ -92,14 +115,23 @@ class GroupState(object): ...@@ -92,14 +115,23 @@ class GroupState(object):
# Receive Packets # Receive Packets
########################################### ###########################################
def receive_report(self): def receive_report(self):
"""
Received MLD Report packet regarding this group
"""
with self.lock: with self.lock:
self.get_interface_group_state().receive_report(self) self.get_interface_group_state().receive_report(self)
def receive_done(self): def receive_done(self):
"""
Received MLD Done packet regarding this group
"""
with self.lock: with self.lock:
self.get_interface_group_state().receive_done(self) self.get_interface_group_state().receive_done(self)
def receive_group_specific_query(self, max_response_time: int): def receive_group_specific_query(self, max_response_time: int):
"""
Received MLD Group Specific Query packet regarding this group
"""
with self.lock: with self.lock:
self.get_interface_group_state().receive_group_specific_query(self, max_response_time) self.get_interface_group_state().receive_group_specific_query(self, max_response_time)
...@@ -107,30 +139,52 @@ class GroupState(object): ...@@ -107,30 +139,52 @@ class GroupState(object):
# Notify Routing # Notify Routing
########################################### ###########################################
def notify_routing_add(self): def notify_routing_add(self):
"""
Notify all tree entries that MLD considers to have hosts interested in this group
"""
with self.multicast_interface_state_lock: with self.multicast_interface_state_lock:
print("notify+", self.multicast_interface_state) print("notify+", self.multicast_interface_state)
for interface_state in self.multicast_interface_state: for interface_state in self.multicast_interface_state:
interface_state.notify_membership(has_members=True) interface_state.notify_membership(has_members=True)
def notify_routing_remove(self): def notify_routing_remove(self):
"""
Notify all tree entries that MLD considers to have not hosts interested in this group
"""
with self.multicast_interface_state_lock: with self.multicast_interface_state_lock:
print("notify-", self.multicast_interface_state) print("notify-", self.multicast_interface_state)
for interface_state in self.multicast_interface_state: for interface_state in self.multicast_interface_state:
interface_state.notify_membership(has_members=False) interface_state.notify_membership(has_members=False)
def add_multicast_routing_entry(self, kernel_entry): def add_multicast_routing_entry(self, kernel_entry):
"""
A new tree is being monitored by the multicast routing protocol that has the same group
MLD will store these entries in order to accelerate the notification process regarding changes in MLD state
"""
with self.multicast_interface_state_lock: with self.multicast_interface_state_lock:
self.multicast_interface_state.append(kernel_entry) self.multicast_interface_state.append(kernel_entry)
return self.has_members() return self.has_members()
def remove_multicast_routing_entry(self, kernel_entry): def remove_multicast_routing_entry(self, kernel_entry):
"""
A tree is no longer being monitored by the multicast routing protocol
Remove this tree from this object
"""
with self.multicast_interface_state_lock: with self.multicast_interface_state_lock:
self.multicast_interface_state.remove(kernel_entry) self.multicast_interface_state.remove(kernel_entry)
def has_members(self): def has_members(self):
"""
Determine if MLD considers to have hosts interested in receiving data packets
"""
return self.state is not NoListenersPresent return self.state is not NoListenersPresent
def remove(self): def remove(self):
"""
Remove this group from the MLD process
Notify all trees that this group no longer considers to be connected to hosts
This method will be invoked whenever an MLD interface is removed
"""
with self.multicast_interface_state_lock: with self.multicast_interface_state_lock:
self.clear_retransmit_timer() self.clear_retransmit_timer()
self.clear_timer() self.clear_timer()
......
...@@ -8,7 +8,8 @@ from pimdm.rwlock.RWLock import RWLockWrite ...@@ -8,7 +8,8 @@ from pimdm.rwlock.RWLock import RWLockWrite
from .querier.Querier import Querier from .querier.Querier import Querier
from .nonquerier.NonQuerier import NonQuerier from .nonquerier.NonQuerier import NonQuerier
from .GroupState import GroupState from .GroupState import GroupState
from .mld_globals import QueryResponseInterval, QueryInterval, OtherQuerierPresentInterval, MULTICAST_LISTENER_QUERY_TYPE from .mld_globals import QUERY_RESPONSE_INTERVAL, QUERY_INTERVAL, OTHER_QUERIER_PRESENT_INTERVAL, \
MULTICAST_LISTENER_QUERY_TYPE
if TYPE_CHECKING: if TYPE_CHECKING:
from pimdm.InterfaceMLD import InterfaceMLD from pimdm.InterfaceMLD import InterfaceMLD
...@@ -36,11 +37,11 @@ class RouterState(object): ...@@ -36,11 +37,11 @@ class RouterState(object):
self.group_state_lock = RWLockWrite() self.group_state_lock = RWLockWrite()
# send general query # send general query
packet = PacketMLDHeader(type=MULTICAST_LISTENER_QUERY_TYPE, max_resp_delay=QueryResponseInterval*1000) packet = PacketMLDHeader(type=MULTICAST_LISTENER_QUERY_TYPE, max_resp_delay=QUERY_RESPONSE_INTERVAL * 1000)
self.interface.send(packet.bytes()) self.interface.send(packet.bytes())
# set initial general query timer # set initial general query timer
timer = Timer(QueryInterval, self.general_query_timeout) timer = Timer(QUERY_INTERVAL, self.general_query_timeout)
timer.start() timer.start()
self.general_query_timer = timer self.general_query_timer = timer
...@@ -58,32 +59,53 @@ class RouterState(object): ...@@ -58,32 +59,53 @@ class RouterState(object):
return self.interface_state.state_name() return self.interface_state.state_name()
def set_general_query_timer(self): def set_general_query_timer(self):
"""
Set general query timer
"""
self.clear_general_query_timer() self.clear_general_query_timer()
general_query_timer = Timer(QueryInterval, self.general_query_timeout) general_query_timer = Timer(QUERY_INTERVAL, self.general_query_timeout)
general_query_timer.start() general_query_timer.start()
self.general_query_timer = general_query_timer self.general_query_timer = general_query_timer
def clear_general_query_timer(self): def clear_general_query_timer(self):
"""
Stop general query timer
"""
if self.general_query_timer is not None: if self.general_query_timer is not None:
self.general_query_timer.cancel() self.general_query_timer.cancel()
def set_other_querier_present_timer(self): def set_other_querier_present_timer(self):
"""
Set other querier present timer
"""
self.clear_other_querier_present_timer() self.clear_other_querier_present_timer()
other_querier_present_timer = Timer(OtherQuerierPresentInterval, self.other_querier_present_timeout) other_querier_present_timer = Timer(OTHER_QUERIER_PRESENT_INTERVAL, self.other_querier_present_timeout)
other_querier_present_timer.start() other_querier_present_timer.start()
self.other_querier_present_timer = other_querier_present_timer self.other_querier_present_timer = other_querier_present_timer
def clear_other_querier_present_timer(self): def clear_other_querier_present_timer(self):
"""
Stop other querier present timer
"""
if self.other_querier_present_timer is not None: if self.other_querier_present_timer is not None:
self.other_querier_present_timer.cancel() self.other_querier_present_timer.cancel()
def general_query_timeout(self): def general_query_timeout(self):
"""
General Query timer has expired
"""
self.interface_state.general_query_timeout(self) self.interface_state.general_query_timeout(self)
def other_querier_present_timeout(self): def other_querier_present_timeout(self):
"""
Other Querier Present timer has expired
"""
self.interface_state.other_querier_present_timeout(self) self.interface_state.other_querier_present_timeout(self)
def change_interface_state(self, querier: bool): def change_interface_state(self, querier: bool):
"""
Change state regarding querier state machine (Querier/NonQuerier)
"""
if querier: if querier:
self.interface_state = Querier self.interface_state = Querier
self.router_state_logger.debug('change querier state to -> Querier') self.router_state_logger.debug('change querier state to -> Querier')
...@@ -95,6 +117,9 @@ class RouterState(object): ...@@ -95,6 +117,9 @@ class RouterState(object):
# group state methods # group state methods
############################################ ############################################
def get_group_state(self, group_ip): def get_group_state(self, group_ip):
"""
Get object that monitors a given group (with group_ip IP address)
"""
with self.group_state_lock.genRlock(): with self.group_state_lock.genRlock():
if group_ip in self.group_state: if group_ip in self.group_state:
return self.group_state[group_ip] return self.group_state[group_ip]
...@@ -108,30 +133,35 @@ class RouterState(object): ...@@ -108,30 +133,35 @@ class RouterState(object):
return group_state return group_state
def receive_report(self, packet: ReceivedPacket): def receive_report(self, packet: ReceivedPacket):
"""
Received MLD Report packet
"""
mld_group = packet.payload.group_address mld_group = packet.payload.group_address
#if igmp_group not in self.group_state:
# self.group_state[igmp_group] = GroupState(self, igmp_group)
#self.group_state[igmp_group].receive_v2_membership_report()
self.get_group_state(mld_group).receive_report() self.get_group_state(mld_group).receive_report()
def receive_done(self, packet: ReceivedPacket): def receive_done(self, packet: ReceivedPacket):
"""
Received MLD Done packet
"""
mld_group = packet.payload.group_address mld_group = packet.payload.group_address
#if igmp_group in self.group_state:
# self.group_state[igmp_group].receive_leave_group()
self.get_group_state(mld_group).receive_done() self.get_group_state(mld_group).receive_done()
def receive_query(self, packet: ReceivedPacket): def receive_query(self, packet: ReceivedPacket):
"""
Received MLD Query packet
"""
self.interface_state.receive_query(self, packet) self.interface_state.receive_query(self, packet)
mld_group = packet.payload.group_address mld_group = packet.payload.group_address
# process group specific query # process group specific query
if mld_group != "::" and mld_group in self.group_state: if mld_group != "::" and mld_group in self.group_state:
#if igmp_group != "0.0.0.0":
max_response_time = packet.payload.max_resp_delay max_response_time = packet.payload.max_resp_delay
#self.group_state[igmp_group].receive_group_specific_query(max_response_time)
self.get_group_state(mld_group).receive_group_specific_query(max_response_time) self.get_group_state(mld_group).receive_group_specific_query(max_response_time)
def remove(self): def remove(self):
"""
Remove this MLD interface
Clear all state
"""
for group in self.group_state.values(): for group in self.group_state.values():
group.remove() group.remove()
#MLD timers (in seconds) # MLD timers (in seconds)
RobustnessVariable = 2 ROBUSTNESS_VARIABLE = 2
QueryInterval = 125 QUERY_INTERVAL = 125
QueryResponseInterval = 10 QUERY_RESPONSE_INTERVAL = 10
MulticastListenerInterval = (RobustnessVariable * QueryInterval) + (QueryResponseInterval) MULTICAST_LISTENER_INTERVAL = (ROBUSTNESS_VARIABLE * QUERY_INTERVAL) + (QUERY_RESPONSE_INTERVAL)
OtherQuerierPresentInterval = (RobustnessVariable * QueryInterval) + 0.5 * QueryResponseInterval OTHER_QUERIER_PRESENT_INTERVAL = (ROBUSTNESS_VARIABLE * QUERY_INTERVAL) + 0.5 * QUERY_RESPONSE_INTERVAL
StartupQueryInterval = (1/4) * QueryInterval STARTUP_QUERY_INTERVAL = (1 / 4) * QUERY_INTERVAL
StartupQueryCount = RobustnessVariable STARTUP_QUERY_COUNT = ROBUSTNESS_VARIABLE
LastListenerQueryInterval = 1 LAST_LISTENER_QUERY_INTERVAL = 1
LastListenerQueryCount = RobustnessVariable LAST_LISTENER_QUERY_COUNT = ROBUSTNESS_VARIABLE
UnsolicitedReportInterval = 10 UNSOLICITED_REPORT_INTERVAL = 10
# MLD msg type # MLD msg type
......
...@@ -7,24 +7,36 @@ if TYPE_CHECKING: ...@@ -7,24 +7,36 @@ if TYPE_CHECKING:
def receive_report(group_state: 'GroupState'): def receive_report(group_state: 'GroupState'):
"""
Received MLD Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier CheckingListeners: receive_report') group_state.group_state_logger.debug('NonQuerier CheckingListeners: receive_report')
group_state.set_timer() group_state.set_timer()
group_state.set_state(ListenersPresent) group_state.set_state(ListenersPresent)
def receive_done(group_state: 'GroupState'): def receive_done(group_state: 'GroupState'):
"""
Received MLD Done packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier CheckingListeners: receive_done') group_state.group_state_logger.debug('NonQuerier CheckingListeners: receive_done')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received MLD Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier CheckingListeners: receive_group_specific_query') group_state.group_state_logger.debug('NonQuerier CheckingListeners: receive_group_specific_query')
# do nothing # do nothing
return return
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier CheckingListeners: group_membership_timeout') group_state.group_state_logger.debug('NonQuerier CheckingListeners: group_membership_timeout')
group_state.set_state(NoListenersPresent) group_state.set_state(NoListenersPresent)
...@@ -33,6 +45,9 @@ def group_membership_timeout(group_state: 'GroupState'): ...@@ -33,6 +45,9 @@ def group_membership_timeout(group_state: 'GroupState'):
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier CheckingListeners: retransmit_timeout') group_state.group_state_logger.debug('NonQuerier CheckingListeners: retransmit_timeout')
# do nothing # do nothing
return return
...@@ -7,23 +7,35 @@ if TYPE_CHECKING: ...@@ -7,23 +7,35 @@ if TYPE_CHECKING:
def receive_report(group_state: 'GroupState'): def receive_report(group_state: 'GroupState'):
"""
Received MLD Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier ListenersPresent: receive_report') group_state.group_state_logger.debug('NonQuerier ListenersPresent: receive_report')
group_state.set_timer() group_state.set_timer()
def receive_done(group_state: 'GroupState'): def receive_done(group_state: 'GroupState'):
"""
Received MLD Done packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier ListenersPresent: receive_done') group_state.group_state_logger.debug('NonQuerier ListenersPresent: receive_done')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received MLD Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier ListenersPresent: receive_group_specific_query') group_state.group_state_logger.debug('NonQuerier ListenersPresent: receive_group_specific_query')
group_state.set_timer(alternative=True, max_response_time=max_response_time) group_state.set_timer(alternative=True, max_response_time=max_response_time)
group_state.set_state(CheckingListeners) group_state.set_state(CheckingListeners)
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier ListenersPresent: group_membership_timeout') group_state.group_state_logger.debug('NonQuerier ListenersPresent: group_membership_timeout')
group_state.set_state(NoListenersPresent) group_state.set_state(NoListenersPresent)
...@@ -32,8 +44,9 @@ def group_membership_timeout(group_state: 'GroupState'): ...@@ -32,8 +44,9 @@ def group_membership_timeout(group_state: 'GroupState'):
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier ListenersPresent: retransmit_timeout') group_state.group_state_logger.debug('NonQuerier ListenersPresent: retransmit_timeout')
# do nothing # do nothing
return return
...@@ -6,6 +6,9 @@ if TYPE_CHECKING: ...@@ -6,6 +6,9 @@ if TYPE_CHECKING:
def receive_report(group_state: 'GroupState'): def receive_report(group_state: 'GroupState'):
"""
Received MLD Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier NoListenersPresent: receive_report') group_state.group_state_logger.debug('NonQuerier NoListenersPresent: receive_report')
group_state.set_timer() group_state.set_timer()
group_state.set_state(ListenersPresent) group_state.set_state(ListenersPresent)
...@@ -15,24 +18,36 @@ def receive_report(group_state: 'GroupState'): ...@@ -15,24 +18,36 @@ def receive_report(group_state: 'GroupState'):
def receive_done(group_state: 'GroupState'): def receive_done(group_state: 'GroupState'):
"""
Received MLD Done packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier NoListenersPresent: receive_done') group_state.group_state_logger.debug('NonQuerier NoListenersPresent: receive_done')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received MLD Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('NonQuerier NoListenersPresent: receive_group_specific_query') group_state.group_state_logger.debug('NonQuerier NoListenersPresent: receive_group_specific_query')
# do nothing # do nothing
return return
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier NoListenersPresent: group_membership_timeout') group_state.group_state_logger.debug('NonQuerier NoListenersPresent: group_membership_timeout')
# do nothing # do nothing
return return
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('NonQuerier NoListenersPresent: retransmit_timeout') group_state.group_state_logger.debug('NonQuerier NoListenersPresent: retransmit_timeout')
# do nothing # do nothing
return return
from ipaddress import IPv6Address from ipaddress import IPv6Address
from pimdm.utils import TYPE_CHECKING from pimdm.utils import TYPE_CHECKING
from ..mld_globals import QueryResponseInterval, LastListenerQueryCount from ..mld_globals import QUERY_RESPONSE_INTERVAL, LAST_LISTENER_QUERY_COUNT
from pimdm.packet.PacketMLDHeader import PacketMLDHeader from pimdm.packet.PacketMLDHeader import PacketMLDHeader
from pimdm.packet.ReceivedPacket import ReceivedPacket from pimdm.packet.ReceivedPacket import ReceivedPacket
from . import NoListenersPresent, ListenersPresent, CheckingListeners from . import NoListenersPresent, ListenersPresent, CheckingListeners
...@@ -12,19 +12,25 @@ if TYPE_CHECKING: ...@@ -12,19 +12,25 @@ if TYPE_CHECKING:
class NonQuerier: class NonQuerier:
@staticmethod @staticmethod
def general_query_timeout(router_state: 'RouterState'): def general_query_timeout(router_state: 'RouterState'):
"""
General Query timer has expired
"""
router_state.router_state_logger.debug('NonQuerier state: general_query_timeout') router_state.router_state_logger.debug('NonQuerier state: general_query_timeout')
# do nothing # do nothing
return return
@staticmethod @staticmethod
def other_querier_present_timeout(router_state: 'RouterState'): def other_querier_present_timeout(router_state: 'RouterState'):
"""
Other Query Present timer has expired
"""
router_state.router_state_logger.debug('NonQuerier state: other_querier_present_timeout') router_state.router_state_logger.debug('NonQuerier state: other_querier_present_timeout')
#change state to Querier #change state to Querier
router_state.change_interface_state(querier=True) router_state.change_interface_state(querier=True)
# send general query # send general query
packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE, packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE,
max_resp_delay=QueryResponseInterval*1000) max_resp_delay=QUERY_RESPONSE_INTERVAL * 1000)
router_state.interface.send(packet.bytes()) router_state.interface.send(packet.bytes())
# set general query timer # set general query timer
...@@ -32,6 +38,9 @@ class NonQuerier: ...@@ -32,6 +38,9 @@ class NonQuerier:
@staticmethod @staticmethod
def receive_query(router_state: 'RouterState', packet: ReceivedPacket): def receive_query(router_state: 'RouterState', packet: ReceivedPacket):
"""
Interface associated with RouterState is NonQuerier and received a Query packet
"""
router_state.router_state_logger.debug('NonQuerier state: receive_query') router_state.router_state_logger.debug('NonQuerier state: receive_query')
source_ip = packet.ip_header.ip_src source_ip = packet.ip_header.ip_src
...@@ -49,17 +58,29 @@ class NonQuerier: ...@@ -49,17 +58,29 @@ class NonQuerier:
@staticmethod @staticmethod
def get_group_membership_time(max_response_time: int): def get_group_membership_time(max_response_time: int):
return (max_response_time/1000.0) * LastListenerQueryCount """
Get time to set timer*
"""
return (max_response_time/1000.0) * LAST_LISTENER_QUERY_COUNT
# State # State
@staticmethod @staticmethod
def get_checking_listeners_state(): def get_checking_listeners_state():
"""
Get implementation of CheckingListeners state machine of interface in NonQuerier state
"""
return CheckingListeners return CheckingListeners
@staticmethod @staticmethod
def get_listeners_present_state(): def get_listeners_present_state():
"""
Get implementation of ListenersPresent state machine of interface in NonQuerier state
"""
return ListenersPresent return ListenersPresent
@staticmethod @staticmethod
def get_no_listeners_present_state(): def get_no_listeners_present_state():
"""
Get implementation of NoListenersPresent state machine of interface in NonQuerier state
"""
return NoListenersPresent return NoListenersPresent
from pimdm.packet.PacketMLDHeader import PacketMLDHeader from pimdm.packet.PacketMLDHeader import PacketMLDHeader
from pimdm.utils import TYPE_CHECKING from pimdm.utils import TYPE_CHECKING
from ..mld_globals import LastListenerQueryInterval from ..mld_globals import LAST_LISTENER_QUERY_INTERVAL
from ..wrapper import ListenersPresent, NoListenersPresent from ..wrapper import ListenersPresent, NoListenersPresent
if TYPE_CHECKING: if TYPE_CHECKING:
from ..GroupState import GroupState from ..GroupState import GroupState
def receive_report(group_state: 'GroupState'): def receive_report(group_state: 'GroupState'):
"""
Received MLD Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier CheckingListeners: receive_report') group_state.group_state_logger.debug('Querier CheckingListeners: receive_report')
group_state.set_timer() group_state.set_timer()
group_state.clear_retransmit_timer() group_state.clear_retransmit_timer()
group_state.set_state(ListenersPresent) group_state.set_state(ListenersPresent)
def receive_done(group_state: 'GroupState'): def receive_done(group_state: 'GroupState'):
"""
Received MLD Done packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier CheckingListeners: receive_done') group_state.group_state_logger.debug('Querier CheckingListeners: receive_done')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received MLD Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier CheckingListeners: receive_group_specific_query') group_state.group_state_logger.debug('Querier CheckingListeners: receive_group_specific_query')
# do nothing # do nothing
return return
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier CheckingListeners: group_membership_timeout') group_state.group_state_logger.debug('Querier CheckingListeners: group_membership_timeout')
group_state.clear_retransmit_timer() group_state.clear_retransmit_timer()
group_state.set_state(NoListenersPresent) group_state.set_state(NoListenersPresent)
...@@ -34,10 +47,13 @@ def group_membership_timeout(group_state: 'GroupState'): ...@@ -34,10 +47,13 @@ def group_membership_timeout(group_state: 'GroupState'):
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier CheckingListeners: retransmit_timeout') group_state.group_state_logger.debug('Querier CheckingListeners: retransmit_timeout')
group_addr = group_state.group_ip group_addr = group_state.group_ip
packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE, packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE,
max_resp_delay=LastListenerQueryInterval*1000, group_address=group_addr) max_resp_delay=LAST_LISTENER_QUERY_INTERVAL * 1000, group_address=group_addr)
group_state.router_state.send(data=packet.bytes(), address=group_addr) group_state.router_state.send(data=packet.bytes(), address=group_addr)
group_state.set_retransmit_timer() group_state.set_retransmit_timer()
from pimdm.packet.PacketMLDHeader import PacketMLDHeader from pimdm.packet.PacketMLDHeader import PacketMLDHeader
from pimdm.utils import TYPE_CHECKING from pimdm.utils import TYPE_CHECKING
from ..mld_globals import LastListenerQueryInterval from ..mld_globals import LAST_LISTENER_QUERY_INTERVAL
from ..wrapper import CheckingListeners, NoListenersPresent from ..wrapper import CheckingListeners, NoListenersPresent
if TYPE_CHECKING: if TYPE_CHECKING:
from ..GroupState import GroupState from ..GroupState import GroupState
def receive_report(group_state: 'GroupState'): def receive_report(group_state: 'GroupState'):
"""
Received MLD Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier ListenersPresent: receive_report') group_state.group_state_logger.debug('Querier ListenersPresent: receive_report')
group_state.set_timer() group_state.set_timer()
def receive_done(group_state: 'GroupState'): def receive_done(group_state: 'GroupState'):
"""
Received MLD Done packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier ListenersPresent: receive_done') group_state.group_state_logger.debug('Querier ListenersPresent: receive_done')
group_ip = group_state.group_ip group_ip = group_state.group_ip
...@@ -19,19 +25,25 @@ def receive_done(group_state: 'GroupState'): ...@@ -19,19 +25,25 @@ def receive_done(group_state: 'GroupState'):
group_state.set_retransmit_timer() group_state.set_retransmit_timer()
packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE, packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE,
max_resp_delay=LastListenerQueryInterval*1000, group_address=group_ip) max_resp_delay=LAST_LISTENER_QUERY_INTERVAL * 1000, group_address=group_ip)
group_state.router_state.send(data=packet.bytes(), address=group_ip) group_state.router_state.send(data=packet.bytes(), address=group_ip)
group_state.set_state(CheckingListeners) group_state.set_state(CheckingListeners)
def receive_group_specific_query(group_state: 'GroupState', max_response_time): def receive_group_specific_query(group_state: 'GroupState', max_response_time):
"""
Received MLD Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier ListenersPresent: receive_group_specific_query') group_state.group_state_logger.debug('Querier ListenersPresent: receive_group_specific_query')
# do nothing # do nothing
return return
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier ListenersPresent: group_membership_timeout') group_state.group_state_logger.debug('Querier ListenersPresent: group_membership_timeout')
group_state.set_state(NoListenersPresent) group_state.set_state(NoListenersPresent)
...@@ -40,8 +52,9 @@ def group_membership_timeout(group_state: 'GroupState'): ...@@ -40,8 +52,9 @@ def group_membership_timeout(group_state: 'GroupState'):
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier ListenersPresent: retransmit_timeout') group_state.group_state_logger.debug('Querier ListenersPresent: retransmit_timeout')
# do nothing # do nothing
return return
...@@ -5,6 +5,9 @@ if TYPE_CHECKING: ...@@ -5,6 +5,9 @@ if TYPE_CHECKING:
def receive_report(group_state: 'GroupState'): def receive_report(group_state: 'GroupState'):
"""
Received MLD Report packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier NoListenersPresent: receive_report') group_state.group_state_logger.debug('Querier NoListenersPresent: receive_report')
group_state.set_timer() group_state.set_timer()
group_state.set_state(ListenersPresent) group_state.set_state(ListenersPresent)
...@@ -14,25 +17,36 @@ def receive_report(group_state: 'GroupState'): ...@@ -14,25 +17,36 @@ def receive_report(group_state: 'GroupState'):
def receive_done(group_state: 'GroupState'): def receive_done(group_state: 'GroupState'):
"""
Received MLD Done packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier NoListenersPresent: receive_done') group_state.group_state_logger.debug('Querier NoListenersPresent: receive_done')
# do nothing # do nothing
return return
def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): def receive_group_specific_query(group_state: 'GroupState', max_response_time: int):
"""
Received MLD Group Specific Query packet regarding group GroupState
"""
group_state.group_state_logger.debug('Querier NoListenersPresent: receive_group_specific_query') group_state.group_state_logger.debug('Querier NoListenersPresent: receive_group_specific_query')
# do nothing # do nothing
return return
def group_membership_timeout(group_state: 'GroupState'): def group_membership_timeout(group_state: 'GroupState'):
"""
timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier NoListenersPresent: group_membership_timeout') group_state.group_state_logger.debug('Querier NoListenersPresent: group_membership_timeout')
# do nothing # do nothing
return return
def retransmit_timeout(group_state: 'GroupState'): def retransmit_timeout(group_state: 'GroupState'):
"""
retransmit timer associated with group GroupState object has expired
"""
group_state.group_state_logger.debug('Querier NoListenersPresent: retransmit_timeout') group_state.group_state_logger.debug('Querier NoListenersPresent: retransmit_timeout')
# do nothing # do nothing
return return
from ipaddress import IPv6Address from ipaddress import IPv6Address
from pimdm.utils import TYPE_CHECKING from pimdm.utils import TYPE_CHECKING
from ..mld_globals import LastListenerQueryInterval, LastListenerQueryCount, QueryResponseInterval from ..mld_globals import LAST_LISTENER_QUERY_INTERVAL, LAST_LISTENER_QUERY_COUNT, QUERY_RESPONSE_INTERVAL
from pimdm.packet.PacketMLDHeader import PacketMLDHeader from pimdm.packet.PacketMLDHeader import PacketMLDHeader
from pimdm.packet.ReceivedPacket import ReceivedPacket from pimdm.packet.ReceivedPacket import ReceivedPacket
...@@ -12,19 +12,11 @@ if TYPE_CHECKING: ...@@ -12,19 +12,11 @@ if TYPE_CHECKING:
class Querier: class Querier:
@staticmethod
def general_query_timeout(router_state: 'RouterState'):
router_state.router_state_logger.debug('Querier state: general_query_timeout')
# send general query
packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE,
max_resp_delay=QueryResponseInterval*1000)
router_state.interface.send(packet.bytes())
# set general query timer
router_state.set_general_query_timer()
@staticmethod @staticmethod
def receive_query(router_state: 'RouterState', packet: ReceivedPacket): def receive_query(router_state: 'RouterState', packet: ReceivedPacket):
"""
Interface associated with RouterState is Querier and received a Query packet
"""
router_state.router_state_logger.debug('Querier state: receive_query') router_state.router_state_logger.debug('Querier state: receive_query')
source_ip = packet.ip_header.ip_src source_ip = packet.ip_header.ip_src
...@@ -41,8 +33,25 @@ class Querier: ...@@ -41,8 +33,25 @@ class Querier:
router_state.clear_general_query_timer() router_state.clear_general_query_timer()
router_state.set_other_querier_present_timer() router_state.set_other_querier_present_timer()
@staticmethod
def general_query_timeout(router_state: 'RouterState'):
"""
General Query timer has expired
"""
router_state.router_state_logger.debug('Querier state: general_query_timeout')
# send general query
packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE,
max_resp_delay=QUERY_RESPONSE_INTERVAL * 1000)
router_state.interface.send(packet.bytes())
# set general query timer
router_state.set_general_query_timer()
@staticmethod @staticmethod
def other_querier_present_timeout(router_state: 'RouterState'): def other_querier_present_timeout(router_state: 'RouterState'):
"""
Other Querier Present timer has expired
"""
router_state.router_state_logger.debug('Querier state: other_querier_present_timeout') router_state.router_state_logger.debug('Querier state: other_querier_present_timeout')
# do nothing # do nothing
return return
...@@ -54,17 +63,29 @@ class Querier: ...@@ -54,17 +63,29 @@ class Querier:
@staticmethod @staticmethod
def get_group_membership_time(max_response_time: int): def get_group_membership_time(max_response_time: int):
return LastListenerQueryInterval * LastListenerQueryCount """
Get time to set timer*
"""
return LAST_LISTENER_QUERY_INTERVAL * LAST_LISTENER_QUERY_COUNT
# State # State
@staticmethod @staticmethod
def get_checking_listeners_state(): def get_checking_listeners_state():
"""
Get implementation of CheckingListeners state machine of interface in Querier state
"""
return CheckingListeners return CheckingListeners
@staticmethod @staticmethod
def get_listeners_present_state(): def get_listeners_present_state():
"""
Get implementation of ListenersPresent state machine of interface in Querier state
"""
return ListenersPresent return ListenersPresent
@staticmethod @staticmethod
def get_no_listeners_present_state(): def get_no_listeners_present_state():
"""
Get implementation of NoListenersPresent state machine of interface in Querier state
"""
return NoListenersPresent return NoListenersPresent
# PIM-DM TIMER VARIABLES
ASSERT_TIME = 180 ASSERT_TIME = 180
GRAFT_RETRY_PERIOD = 3 GRAFT_RETRY_PERIOD = 3
JP_OVERRIDE_INTERVAL = 3.0 JP_OVERRIDE_INTERVAL = 3.0
...@@ -7,8 +8,17 @@ REFRESH_INTERVAL = 60 # State Refresh Interval ...@@ -7,8 +8,17 @@ REFRESH_INTERVAL = 60 # State Refresh Interval
SOURCE_LIFETIME = 210 SOURCE_LIFETIME = 210
T_LIMIT = 210 T_LIMIT = 210
# PIM-DM VARIABLES
HELLO_HOLD_TIME_NO_TIMEOUT = 0xFFFF HELLO_HOLD_TIME_NO_TIMEOUT = 0xFFFF
HELLO_HOLD_TIME = 160 HELLO_HOLD_TIME = 160
HELLO_HOLD_TIME_TIMEOUT = 0 HELLO_HOLD_TIME_TIMEOUT = 0
ASSERT_CANCEL_METRIC = 0xFFFFFFFF ASSERT_CANCEL_METRIC = 0xFFFFFFFF
# MULTIPLE TABLES SUPPORT
# Define which unicast routing table to be used for RPF checks and to get route metric information
# Default unicast routing table is 254
UNICAST_TABLE_ID = 254
# Define which multicast routing table to be used for setting multicast trees
# Default multicast routing table is 0
MULTICAST_TABLE_ID = 0
...@@ -59,12 +59,11 @@ class TreeInterfaceUpstream(TreeInterface): ...@@ -59,12 +59,11 @@ class TreeInterfaceUpstream(TreeInterface):
self.logger.debug('Created UpstreamInterface') self.logger.debug('Created UpstreamInterface')
def socket_recv(self): def socket_recv(self):
while self.socket_is_enabled: while self.socket_is_enabled:
try: try:
self.socket_pkt.recvfrom(0) self.socket_pkt.recvfrom(0)
print("PACOTE DADOS RECEBIDO") print("DATA RECEIVED")
self.recv_data_msg() self.recv_data_msg()
except: except:
traceback.print_exc() traceback.print_exc()
...@@ -151,7 +150,6 @@ class TreeInterfaceUpstream(TreeInterface): ...@@ -151,7 +150,6 @@ class TreeInterfaceUpstream(TreeInterface):
if self._source_active_timer is not None: if self._source_active_timer is not None:
self._source_active_timer.cancel() self._source_active_timer.cancel()
########################################### ###########################################
# Timer timeout # Timer timeout
########################################### ###########################################
...@@ -182,7 +180,6 @@ class TreeInterfaceUpstream(TreeInterface): ...@@ -182,7 +180,6 @@ class TreeInterfaceUpstream(TreeInterface):
if interface is not None and interface.is_state_refresh_enabled(): if interface is not None and interface.is_state_refresh_enabled():
self._originator_state.recvDataMsgFromSource(self) self._originator_state.recvDataMsgFromSource(self)
def recv_join_msg(self, upstream_neighbor_address): def recv_join_msg(self, upstream_neighbor_address):
super().recv_join_msg(upstream_neighbor_address) super().recv_join_msg(upstream_neighbor_address)
if upstream_neighbor_address == self.get_neighbor_RPF(): if upstream_neighbor_address == self.get_neighbor_RPF():
...@@ -208,7 +205,6 @@ class TreeInterfaceUpstream(TreeInterface): ...@@ -208,7 +205,6 @@ class TreeInterfaceUpstream(TreeInterface):
elif prune_indicator == 0 and not self.is_prune_limit_timer_running(): elif prune_indicator == 0 and not self.is_prune_limit_timer_running():
self._graft_prune_state.stateRefreshArrivesRPFnbr_pruneIs0_PLTstoped(self) self._graft_prune_state.stateRefreshArrivesRPFnbr_pruneIs0_PLTstoped(self)
#################################### ####################################
def create_state_refresh_msg(self): def create_state_refresh_msg(self):
self._prune_now_counter+=1 self._prune_now_counter+=1
...@@ -235,7 +231,6 @@ class TreeInterfaceUpstream(TreeInterface): ...@@ -235,7 +231,6 @@ class TreeInterfaceUpstream(TreeInterface):
def olist_is_not_null(self): def olist_is_not_null(self):
self._graft_prune_state.olistIsNowNotNull(self) self._graft_prune_state.olistIsNowNotNull(self)
########################################### ###########################################
# Changes to RPF'(s) # Changes to RPF'(s)
########################################### ###########################################
...@@ -265,7 +260,6 @@ class TreeInterfaceUpstream(TreeInterface): ...@@ -265,7 +260,6 @@ class TreeInterfaceUpstream(TreeInterface):
else: else:
self._graft_prune_state.RPFnbrChanges_olistIsNotNull(self) self._graft_prune_state.RPFnbrChanges_olistIsNotNull(self)
#################################################################### ####################################################################
#Override #Override
def is_forwarding(self): def is_forwarding(self):
...@@ -300,10 +294,9 @@ class TreeInterfaceUpstream(TreeInterface): ...@@ -300,10 +294,9 @@ class TreeInterfaceUpstream(TreeInterface):
def is_originator(self): def is_originator(self):
return self._originator_state == OriginatorState.Originator return self._originator_state == OriginatorState.Originator
#------------------------------------------------------------------------- #########################################################################
# Properties # Properties
#------------------------------------------------------------------------- #########################################################################
@property @property
def t_override(self): def t_override(self):
oi = self.get_interface()._override_interval oi = self.get_interface()._override_interval
......
import sys import sys
from setuptools import setup, find_packages from setuptools import setup, find_packages
# we only support Python 3 version >= 3.4 # we only support Python 3 version >= 3.3
#if len(sys.argv) >= 2 and sys.argv[1] == "install" and sys.version_info < (3, 4): if len(sys.argv) >= 2 and sys.argv[1] == "install" and sys.version_info < (3, 3):
# raise SystemExit("Python 3.4 or higher is required") raise SystemExit("Python 3.3 or higher is required")
dependencies = open("requirements.txt", "r").read().splitlines() dependencies = open("requirements.txt", "r").read().splitlines()
...@@ -13,7 +13,7 @@ setup( ...@@ -13,7 +13,7 @@ setup(
long_description=open("README.md", "r").read(), long_description=open("README.md", "r").read(),
long_description_content_type="text/markdown", long_description_content_type="text/markdown",
keywords="PIM-DM Multicast Routing Protocol Dense-Mode Router RFC3973 IPv4 IPv6", keywords="PIM-DM Multicast Routing Protocol Dense-Mode Router RFC3973 IPv4 IPv6",
version="1.1", version="1.1.1",
url="http://github.com/pedrofran12/pim_dm", url="http://github.com/pedrofran12/pim_dm",
author="Pedro Oliveira", author="Pedro Oliveira",
author_email="pedro.francisco.oliveira@tecnico.ulisboa.pt", author_email="pedro.francisco.oliveira@tecnico.ulisboa.pt",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment