netdriver.py 8.96 KB
Newer Older
1 2 3
import subprocess
import logging

Guba Sándor committed
4
from netcelery import celery
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
from os import getenv
from vm import VMNetwork

driver = getenv("HYPERVISOR_TYPE", "test")


@celery.task
def create(network):
        port_create(VMNetwork.deserialize(network))


@celery.task
def delete(network):
        port_delete(VMNetwork.deserialize(network))


def add_tuntap_interface(if_name):
    '''For testing purpose only adding tuntap interface.
    '''
    subprocess.call(['sudo', 'ip', 'tuntap', 'add', 'mode', 'tap', if_name])


def del_tuntap_interface(if_name):
    '''For testing purpose only deleting tuntap interface.
    '''
    subprocess.call(['sudo', 'ip', 'tuntap', 'del', 'mode', 'tap', if_name])
Guba Sándor committed
31

32

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
def ovs_command_execute(command):
    '''Execute OpenVSwitch commands
    command -   List of strings
    '''
    command = ['sudo', 'ovs-vsctl'] + command
    return_val = subprocess.call(command)
    logging.info('OVS command: %s executed.', command)
    return return_val


def ofctl_command_execute(command):
    '''Execute OpenVSwitch flow commands
    command -   List of strings
    '''
    command = ['sudo', 'ovs-ofctl'] + command
    return_val = subprocess.call(command)
    logging.info('OVS flow command: %s executed.', command)
    return return_val


53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
def build_flow_rule(
        in_port=None,
        dl_src=None,
        protocol=None,
        nw_src=None,
        ipv6_src=None,
        tp_dst=None,
        priority=None,
        actions=None):
    '''
    in_port     - Interface flow-port number
    dl_src      - Source mac addsress (virtual interface)
    protocol    - Protocol for the rule like ip,ipv6,arp,udp,tcp
    nw_src      - Source network IP(v4)
    ipv6_src    - Source network IP(v6)
    tp_dst      - Destination port
    priority    - Rule priority
    actions     - Action for the matching rule
    '''
    flow_rule = ""
    if in_port is None:
        raise AttributeError("Parameter in_port is mandantory")
    parameters = [('in_port=%s', in_port),
                  ('dl_src=%s', dl_src),
                  ('%s', protocol),
                  ('nw_src=%s', nw_src),
                  ('ipv6_src=%s', ipv6_src),
                  ('tp_dst=%s', tp_dst),
                  ('priority=%s', priority),
                  ('actions=%s', actions)]
    # Checking for values if not None making up rule list
    rule = [p1 % p2 for (p1, p2) in parameters if p2 is not None]
    # Generate rule string with comas, except the last item
    for i in rule[:-1]:
        flow_rule += i + ","
    else:
        flow_rule += rule[-1]
    return flow_rule


def set_port_vlan(network_name, vlan):
    ''' Setting vlan for interface named net_name
    '''
    cmd_list = ['set', 'Port', network_name, 'tag=' + str(vlan)]
    ovs_command_execute(cmd_list)


def add_port_to_bridge(network_name, bridge):
    cmd_list = ['add-port', bridge, network_name]
    ovs_command_execute(cmd_list)
Guba Sándor committed
103 104


105 106 107 108
def del_port_from_bridge(network_name):
    ovs_command_execute(['del-port', network_name])


109 110 111 112 113 114 115 116 117 118
def mac_filter(network, port_number, delete=False):
    if not delete:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   priority="40000", actions="normal")
        ofctl_command_execute(["add-flow", network.bridge, flow_cmd])
    else:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac)
        ofctl_command_execute(["del-flows", network.bridge, flow_cmd])


119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
def ban_dhcp_server(network, port_number, delete=False):
    if not delete:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   protocol="udp", tp_dst="68",
                                   priority="43000", actions="drop")
        ofctl_command_execute(["add-flow", network.bridge, flow_cmd])
    else:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   protocol="udp", tp_dst="68")
        ofctl_command_execute(["del-flows", network.bridge, flow_cmd])


def ipv4_filter(network, port_number, delete=False):
    if not delete:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   protocol="ip", nw_src=network.ipv4,
                                   priority=42000, actions="normal")
        ofctl_command_execute(["add-flow", network.bridge, flow_cmd])
    else:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   protocol="ip", nw_src=network.ipv4)
        ofctl_command_execute(["del-flows", network.bridge, flow_cmd])


def ipv6_filter(network, port_number, delete=False):
    if not delete:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   protocol="ipv6", ipv6_src=network.ipv6,
                                   priority=42000, actions="normal")
        ofctl_command_execute(["add-flow", network.bridge, flow_cmd])
    else:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   protocol="ipv6", ipv6_src=network.ipv6)
        ofctl_command_execute(["del-flows", network.bridge, flow_cmd])


def arp_filter(network, port_number, delete=False):
    if not delete:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   protocol="arp", nw_src=network.ipv4,
                                   priority=41000, actions="normal")
        ofctl_command_execute(["add-flow", network.bridge, flow_cmd])
    else:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   protocol="arp", nw_src=network.ipv4)
        ofctl_command_execute(["del-flows", network.bridge, flow_cmd])


def enable_dhcp_client(network, port_number, delete=False):
    if not delete:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   protocol="udp", tp_dst="67",
                                   priority="40000", actions="normal")
        ofctl_command_execute(["add-flow", network.bridge, flow_cmd])
    else:
        flow_cmd = build_flow_rule(in_port=port_number, dl_src=network.mac,
                                   protocol="udp", tp_dst="67")
        ofctl_command_execute(["del-flows", network.bridge, flow_cmd])


def disable_all_not_allowed_trafic(network, port_number, delete=False):
    if not delete:
        flow_cmd = build_flow_rule(in_port=port_number,
182
                                   priority="30000", actions="drop")
183 184 185 186
        ofctl_command_execute(["add-flow", network.bridge, flow_cmd])
    else:
        flow_cmd = build_flow_rule(in_port=port_number)
        ofctl_command_execute(["del-flows", network.bridge, flow_cmd])
Guba Sándor committed
187 188


189
def port_create(network):
190
    ''' Adding port to bridge apply rules and pull up interface.
191
    '''
192 193 194 195
    # For testing purpose create tuntap iface
    if driver == "test":
        add_tuntap_interface(network.name)

196
    # Create the port for virtual network
197
    add_port_to_bridge(network.name, network.bridge)
198
    # Set VLAN parameter for tap interface
199
    set_port_vlan(network.name, network.vlan)
200 201

    # Getting network FlowPortNumber
202
    port_number = get_fport_for_network(network)
203 204

    # Set Flow rules to avoid mac or IP spoofing
205
    if network.managed:
206
        # Allow traffic from fource MAC and IP
207 208 209 210 211
        ban_dhcp_server(network, port_number)
        ipv4_filter(network, port_number)
        ipv6_filter(network, port_number)
        arp_filter(network, port_number)
        enable_dhcp_client(network, port_number)
212 213 214 215 216 217
    else:
        # Allow all traffic from source MAC address
        mac_filter(network, port_number)
    # Explicit deny all other traffic
    disable_all_not_allowed_trafic(network, port_number)
    pull_up_interface(network)
218 219 220


def port_delete(network):
221 222
    '''
    '''
Guba Sándor committed
223 224 225
    # Getting network FlowPortNumber
    port_number = get_fport_for_network(network)

226 227 228 229 230 231 232
    # Clear network rules
    if network.managed:
        ban_dhcp_server(network, port_number, delete=True)
        ipv4_filter(network, port_number, delete=True)
        ipv6_filter(network, port_number, delete=True)
        arp_filter(network, port_number, delete=True)
        enable_dhcp_client(network, port_number, delete=True)
233 234 235 236
    else:
        mac_filter(network, port_number, delete=True)
    # Explicit deny all other traffic
    disable_all_not_allowed_trafic(network, port_number, delete=True)
Guba Sándor committed
237 238

    # Delete port
239
    del_port_from_bridge(network.name)
240

241 242 243 244
    # For testing purpose dele tuntap iface
    if driver == "test":
        del_tuntap_interface(network.name)

245

246
def pull_up_interface(network):
247
    command = ['sudo', 'ip', 'link', 'set', 'up', network.name]
248 249 250 251 252
    return_val = subprocess.call(command)
    logging.info('IP command: %s executed.', command)
    return return_val


253
def get_fport_for_network(network):
254
    '''Returns the OpenFlow port number for a given network
255
    cmd: ovs-vsctl get Interface vm-88 ofport
256 257
    '''
    output = subprocess.check_output(
258
        ['sudo', 'ovs-vsctl', 'get', 'Interface', network.name, 'ofport'])
259
    return output.strip()