Main.py 8.59 KB
Newer Older
1
import sys
2 3
import time
import netifaces
4 5
import logging
import logging.handlers
6
from prettytable import PrettyTable
7

8 9
from pimdm import UnicastRouting
from pimdm.TestLogger import RootFilter
10 11 12

interfaces = {}  # interfaces with multicast routing enabled
igmp_interfaces = {}  # igmp interfaces
13 14
interfaces_v6 = {}  # pim v6 interfaces
mld_interfaces = {}  # mld interfaces
15
kernel = None
16
kernel_v6 = None
17
unicast_routing = None
18
logger = None
19

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

def add_pim_interface(interface_name, state_refresh_capable: bool = False, ipv4=True, ipv6=False):
    if interface_name == "*":
        for interface_name in netifaces.interfaces():
            add_pim_interface(interface_name, ipv4, ipv6)
        return

    if ipv4 and kernel is not None:
        kernel.create_pim_interface(interface_name=interface_name, state_refresh_capable=state_refresh_capable)
    if ipv6 and kernel_v6 is not None:
        kernel_v6.create_pim_interface(interface_name=interface_name, state_refresh_capable=state_refresh_capable)


def add_membership_interface(interface_name, ipv4=True, ipv6=False):
    if interface_name == "*":
        for interface_name in netifaces.interfaces():
            add_membership_interface(interface_name, ipv4, ipv6)
        return

    if ipv4 and kernel is not None:
        kernel.create_membership_interface(interface_name=interface_name)
    if ipv6 and kernel_v6 is not None:
        kernel_v6.create_membership_interface(interface_name=interface_name)


45 46 47 48 49 50
def remove_interface(interface_name, pim=False, membership=False, ipv4=True, ipv6=False):
    if interface_name == "*":
        for interface_name in netifaces.interfaces():
            remove_interface(interface_name, pim, membership, ipv4, ipv6)
        return

51
    if ipv4 and kernel is not None:
52
        kernel.remove_interface(interface_name, pim=pim, membership=membership)
53
    if ipv6 and kernel_v6 is not None:
54
        kernel_v6.remove_interface(interface_name, pim=pim, membership=membership)
55 56 57 58 59 60 61 62 63 64


def list_neighbors(ipv4=False, ipv6=False):
    if ipv4:
        interfaces_list = interfaces.values()
    elif ipv6:
        interfaces_list = interfaces_v6.values()
    else:
        return "Unknown IP family"

65 66 67 68 69 70 71 72 73 74 75 76 77
    t = PrettyTable(['Interface', 'Neighbor IP', 'Hello Hold Time', "Generation ID", "Uptime"])
    check_time = time.time()
    for interface in interfaces_list:
        for neighbor in interface.get_neighbors():
            uptime = check_time - neighbor.time_of_last_update
            uptime = 0 if (uptime < 0) else uptime

            t.add_row(
                [interface.interface_name, neighbor.ip, neighbor.hello_hold_time, neighbor.generation_id, time.strftime("%H:%M:%S", time.gmtime(uptime))])
    print(t)
    return str(t)


78 79 80 81 82 83 84 85 86 87 88 89 90 91
def list_enabled_interfaces(ipv4=False, ipv6=False):
    if ipv4:
        t = PrettyTable(['Interface', 'IP', 'PIM/IGMP Enabled', 'State Refresh Enabled', 'IGMP State'])
        family = netifaces.AF_INET
        pim_interfaces = interfaces
        membership_interfaces = igmp_interfaces
    elif ipv6:
        t = PrettyTable(['Interface', 'IP', 'PIM/MLD Enabled', 'State Refresh Enabled', 'MLD State'])
        family = netifaces.AF_INET6
        pim_interfaces = interfaces_v6
        membership_interfaces = mld_interfaces
    else:
        return "Unknown IP family"

92 93 94
    for interface in netifaces.interfaces():
        try:
            # TODO: fix same interface with multiple ips
95 96 97 98
            ip = netifaces.ifaddresses(interface)[family][0]['addr']
            pim_enabled = interface in pim_interfaces
            membership_enabled = interface in membership_interfaces
            enabled = str(pim_enabled) + "/" + str(membership_enabled)
99 100
            state_refresh_enabled = "-"
            if pim_enabled:
101 102 103 104 105
                state_refresh_enabled = pim_interfaces[interface].is_state_refresh_enabled()
            membership_state = "-"
            if membership_enabled:
                membership_state = membership_interfaces[interface].interface_state.print_state()
            t.add_row([interface, ip, enabled, state_refresh_enabled, membership_state])
106 107 108 109 110 111
        except Exception:
            continue
    print(t)
    return str(t)


112 113 114 115 116 117 118 119 120
def list_state(ipv4=True, ipv6=False):
    state_text = ""
    if ipv4:
        state_text = "IGMP State:\n{}\n\n\n\nMulticast Routing State:\n{}"
    elif ipv6:
        state_text = "MLD State:\n{}\n\n\n\nMulticast Routing State:\n{}"
    else:
        return state_text
    return state_text.format(list_membership_state(ipv4, ipv6), list_routing_state(ipv4, ipv6))
121 122


123
def list_membership_state(ipv4=True, ipv6=False):
124
    t = PrettyTable(['Interface', 'RouterState', 'Group Adress', 'GroupState'])
125 126 127 128 129 130 131 132
    if ipv4:
        membership_interfaces = igmp_interfaces
    elif ipv6:
        membership_interfaces = mld_interfaces
    else:
        membership_interfaces = {}

    for (interface_name, interface_obj) in list(membership_interfaces.items()):
133 134 135 136 137 138 139 140 141 142 143
        interface_state = interface_obj.interface_state
        state_txt = interface_state.print_state()
        print(interface_state.group_state.items())

        for (group_addr, group_state) in list(interface_state.group_state.items()):
            print(group_addr)
            group_state_txt = group_state.print_state()
            t.add_row([interface_name, state_txt, group_addr, group_state_txt])
    return str(t)


144 145 146 147 148 149 150 151 152 153 154 155
def list_routing_state(ipv4=False, ipv6=False):
    if ipv4:
        routes = kernel.routing.values()
        vif_indexes = kernel.vif_index_to_name_dic.keys()
        dict_index_to_name = kernel.vif_index_to_name_dic
    elif ipv6:
        routes = kernel_v6.routing.values()
        vif_indexes = kernel_v6.vif_index_to_name_dic.keys()
        dict_index_to_name = kernel_v6.vif_index_to_name_dic
    else:
        raise Exception("Unknown IP family")

156
    routing_entries = []
157
    for a in list(routes):
158 159
        for b in list(a.values()):
            routing_entries.append(b)
160

161
    t = PrettyTable(['SourceIP', 'GroupIP', 'Interface', 'PruneState', 'AssertState', 'LocalMembership', "Is Forwarding?"])
162 163 164 165 166 167 168
    for entry in routing_entries:
        ip = entry.source_ip
        group = entry.group_ip
        upstream_if_index = entry.inbound_interface_index

        for index in vif_indexes:
            interface_state = entry.interface_state[index]
169
            interface_name = dict_index_to_name[index]
170
            local_membership = type(interface_state._local_membership_state).__name__
171
            try:
172
                assert_state = type(interface_state._assert_state).__name__
173 174
                if index != upstream_if_index:
                    prune_state = type(interface_state._prune_state).__name__
175
                    is_forwarding = interface_state.is_forwarding()
176 177
                else:
                    prune_state = type(interface_state._graft_prune_state).__name__
178
                    is_forwarding = "upstream"
179 180 181
            except:
                prune_state = "-"
                assert_state = "-"
182
                is_forwarding = "-"
183

184
            t.add_row([ip, group, interface_name, prune_state, assert_state, local_membership, is_forwarding])
185 186 187 188
    return str(t)


def stop():
189 190 191 192 193
    remove_interface("*", pim=True, membership=True, ipv4=True, ipv6=True)
    if kernel is not None:
        kernel.exit()
    if kernel_v6 is not None:
        kernel_v6.exit()
194 195
    unicast_routing.stop()

196

197 198 199 200 201 202 203 204 205
def test(router_name, server_logger_ip):
    global logger
    socketHandler = logging.handlers.SocketHandler(server_logger_ip,
                                                   logging.handlers.DEFAULT_TCP_LOGGING_PORT)
    # don't bother with a formatter, since a socket handler sends the event as
    # an unformatted pickle
    socketHandler.addFilter(RootFilter(router_name))
    logger.addHandler(socketHandler)

206

207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
def enable_ipv6_kernel():
    """
    Function to explicitly enable IPv6 Multicast Routing stack.
    This may not be enabled by default due to some old linux kernels that may not have IPv6 stack or do not have
    IPv6 multicast routing support
    """
    global kernel_v6
    from pimdm.Kernel import Kernel6
    kernel_v6 = Kernel6()

    global interfaces_v6
    global mld_interfaces
    interfaces_v6 = kernel_v6.pim_interface
    mld_interfaces = kernel_v6.membership_interface


223
def main():
224 225 226 227 228 229
    # logging
    global logger
    logger = logging.getLogger('pim')
    logger.setLevel(logging.DEBUG)
    logger.addHandler(logging.StreamHandler(sys.stdout))

230
    global kernel
231 232
    from pimdm.Kernel import Kernel4
    kernel = Kernel4()
233

234 235
    global unicast_routing
    unicast_routing = UnicastRouting.UnicastRouting()
236 237 238 239

    global interfaces
    global igmp_interfaces
    interfaces = kernel.pim_interface
240 241 242 243 244
    igmp_interfaces = kernel.membership_interface

    try:
        enable_ipv6_kernel()
    except:
245
        pass