示例#1
0
文件: freearp.py 项目: sinofeng/vlcp
            def packet_out_free_arp(logicalport, logicalnet, logicalnetid,
                                    phyportid):
                egress = self._parent._gettableindex(
                    "egress", self._connection.protocol.vhost)
                arp_request_packet = arp_packet_l4(
                    dl_src=mac_addr(logicalport.mac_address),
                    dl_dst=mac_addr("FF:FF:FF:FF:FF:FF"),
                    arp_op=ofdef.ARPOP_REQUEST,
                    arp_sha=mac_addr(logicalport.mac_address),
                    arp_spa=ip4_addr(logicalport.ip_address),
                    arp_tpa=ip4_addr(logicalport.ip_address))

                return ofdef.ofp_packet_out(
                    buffer_id=ofdef.OFP_NO_BUFFER,
                    in_port=ofdef.OFPP_CONTROLLER,
                    actions=[
                        ofdef.ofp_action_set_field(field=ofdef.create_oxm(
                            ofdef.NXM_NX_REG4, logicalnetid)),
                        ofdef.ofp_action_set_field(field=ofdef.create_oxm(
                            ofdef.NXM_NX_REG5, logicalnetid)),
                        ofdef.ofp_action_set_field(field=ofdef.create_oxm(
                            ofdef.NXM_NX_REG6, phyportid)),
                        ofdef.ofp_action_set_field(
                            field=ofdef.create_oxm(ofdef.NXM_NX_REG7, 0x4000)),
                        ofdef.nx_action_resubmit(table=egress)
                    ],
                    data=arp_request_packet._tobytes())
示例#2
0
    def _dhcp_handler(self):
        conn = self._connection
        ofdef = self._connection.openflowdef
        l3 = self._parent._gettableindex('l3input',
                                         self._connection.protocol.vhost)
        dhcp_packet_matcher = OpenflowAsyncMessageEvent.createMatcher(
            ofdef.OFPT_PACKET_IN, None, None, l3, 1, self._connection,
            self._connection.connmark)
        required_tags = [
            d.OPTION_MESSAGE_TYPE, d.OPTION_SERVER_IDENTIFIER,
            d.OPTION_NETMASK, d.OPTION_ROUTER, d.OPTION_DNSSERVER,
            d.OPTION_BROADCAST, d.OPTION_MTU, d.OPTION_LEASE_TIME, d.OPTION_T1,
            d.OPTION_T2
        ]
        server_mac = mac_addr(self._parent.servermac)
        trans_id = uint16.create(os.urandom(2))

        def set_options(payload,
                        option_dict,
                        provide_options,
                        message_type,
                        remove_lease=False):
            message_type_opt = d.dhcp_option_message_type(value=message_type)
            if d.OPTION_REQUESTED_OPTIONS in option_dict:
                reqs = set(option_dict[d.OPTION_REQUESTED_OPTIONS].value)
                send_tags = [t for t in option_dict[d.OPTION_REQUESTED_OPTIONS].value
                             if t == d.OPTION_MESSAGE_TYPE or t in provide_options] \
                            + [t for t in required_tags
                               if (t in provide_options or t == d.OPTION_MESSAGE_TYPE) and t not in reqs] \
                            + [t for t in provide_options
                               if t not in reqs and t not in required_tags]
            else:
                send_tags = [t for t in required_tags
                             if t in provide_options or t == d.OPTION_MESSAGE_TYPE] \
                            + [t for t in set(provide_options.keys()).difference(required_tags)]
            d.build_options(
                payload, [
                    message_type_opt
                    if t == d.OPTION_MESSAGE_TYPE else provide_options[t]
                    for t in send_tags
                    if not remove_lease or (t != d.OPTION_LEASE_TIME and t !=
                                            d.OPTION_T1 and t != OPTION_T2)
                ],
                max(min(option_dict[d.OPTION_MAX_MESSAGE_SIZE].value, 1400),
                    576) if d.OPTION_MAX_MESSAGE_SIZE in option_dict else 576)

        def send_packet(pid, packet):
            for m in self.execute_commands(conn, [
                    ofdef.ofp_packet_out(
                        buffer_id=ofdef.OFP_NO_BUFFER,
                        in_port=ofdef.OFPP_CONTROLLER,
                        actions=[
                            ofdef.ofp_action_output(
                                port=pid, max_len=ofdef.OFPCML_NO_BUFFER)
                        ],
                        data=packet._tobytes())
            ]):
                yield m

        while True:
            yield (dhcp_packet_matcher, )
            msg = self.event.message
            try:
                in_port = ofdef.ofp_port_no.create(
                    ofdef.get_oxm(msg.match.oxm_fields, ofdef.OXM_OF_IN_PORT))
                if in_port not in self._dhcpentries:
                    continue
                port_mac, port_ip, server_ip, provide_options = self._dhcpentries[
                    in_port]
                l7_packet = ethernet_l7.create(msg.data)
                dhcp_packet = d.dhcp_payload.create(l7_packet.data)
                if dhcp_packet.op != d.BOOTREQUEST or \
                        dhcp_packet.hlen != 6 or dhcp_packet.htype != 1 or \
                        dhcp_packet.magic_cookie != d.BOOTP_MAGIC_COOKIE or \
                        dhcp_packet.giaddr != 0:
                    raise ValueError('Unsupported DHCP packet')
                options = d.reassemble_options(dhcp_packet)
                option_dict = dict((o.tag, o) for o in options)
                if d.OPTION_MESSAGE_TYPE not in option_dict:
                    raise ValueError('Message type not found')
                message_type = option_dict[d.OPTION_MESSAGE_TYPE].value
                is_nak = False
                if message_type == d.DHCPDISCOVER:
                    if dhcp_packet.chaddr[:6].ljust(
                            6, b'\x00') != mac_addr.tobytes(port_mac):
                        # Ignore this packet
                        continue
                    dhcp_reply = d.dhcp_payload(
                        op=d.BOOTREPLY,
                        htype=1,
                        hlen=6,
                        hops=0,
                        xid=dhcp_packet.xid,
                        secs=0,
                        flags=dhcp_packet.flags,
                        ciaddr=0,
                        yiaddr=port_ip,
                        siaddr=0,
                        giaddr=dhcp_packet.giaddr,
                        chaddr=dhcp_packet.chaddr,
                        magic_cookie=d.BOOTP_MAGIC_COOKIE)
                    set_options(dhcp_reply, option_dict, provide_options,
                                d.DHCPOFFER)
                elif message_type == d.DHCPREQUEST:
                    if d.OPTION_SERVER_IDENTIFIER in option_dict and option_dict[
                            d.OPTION_SERVER_IDENTIFIER].value != server_ip:
                        # Ignore packets to wrong address
                        continue
                    if dhcp_packet.chaddr[:6].ljust(6, b'\x00') != mac_addr.tobytes(port_mac) \
                            or (d.OPTION_REQUESTED_IP in option_dict and option_dict[d.OPTION_REQUESTED_IP].value != port_ip) \
                            or (dhcp_packet.ciaddr != 0 and dhcp_packet.ciaddr != port_ip):
                        dhcp_reply = d.dhcp_payload(
                            op=d.BOOTREPLY,
                            htype=1,
                            hlen=6,
                            hops=0,
                            xid=dhcp_packet.xid,
                            secs=0,
                            flags=dhcp_packet.flags,
                            ciaddr=0,
                            yiaddr=0,
                            siaddr=0,
                            giaddr=dhcp_packet.giaddr,
                            chaddr=dhcp_packet.chaddr,
                            magic_cookie=d.BOOTP_MAGIC_COOKIE)
                        d.build_options(dhcp_reply, [
                            d.dhcp_option_message_type(value=d.DHCPNAK),
                            d.dhcp_option_address(
                                tag=d.OPTION_SERVER_IDENTIFIER,
                                value=server_ip)
                        ], 576, 0)
                        is_nak = True
                    else:
                        dhcp_reply = d.dhcp_payload(
                            op=d.BOOTREPLY,
                            htype=1,
                            hlen=6,
                            hops=0,
                            xid=dhcp_packet.xid,
                            secs=0,
                            flags=dhcp_packet.flags,
                            ciaddr=dhcp_packet.ciaddr,
                            yiaddr=port_ip,
                            siaddr=0,
                            giaddr=dhcp_packet.giaddr,
                            chaddr=dhcp_packet.chaddr,
                            magic_cookie=d.BOOTP_MAGIC_COOKIE)
                        set_options(dhcp_reply, option_dict, provide_options,
                                    d.DHCPACK)
                elif message_type == d.DHCPDECLINE:
                    self._logger.warning('DHCP client reports DHCPDECLINE, there should be some problems.'\
                                         ' Connection = %r(%016x), port = %d.',
                                         self._connection, self._connection.openflow_datapathid)
                elif message_type == d.DHCPRELEASE:
                    # Safe to ignore
                    continue
                elif message_type == d.DHCPINFORM:
                    dhcp_reply = d.dhcp_payload(
                        op=d.BOOTREPLY,
                        htype=1,
                        hlen=6,
                        hops=0,
                        xid=dhcp_packet.xid,
                        secs=0,
                        flags=dhcp_packet.flags,
                        ciaddr=dhcp_packet.ciaddr,
                        yiaddr=0,
                        siaddr=0,
                        giaddr=dhcp_packet.giaddr,
                        chaddr=dhcp_packet.chaddr,
                        magic_cookie=d.BOOTP_MAGIC_COOKIE)
                    set_options(dhcp_reply, option_dict, provide_options,
                                d.DHCPACK, True)
                trans_id = (trans_id + 1) & 0xffff
                if (dhcp_packet.flags & d.DHCPFLAG_BROADCAST) or is_nak:
                    dl_dst = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
                    ip_dst = 0xffffffff
                else:
                    dl_dst = l7_packet.dl_src
                    ip_dst = port_ip
                reply_packet = ip4_packet_l7((ip4_payload, ip4_udp_payload),
                                             dl_src=server_mac,
                                             dl_dst=dl_dst,
                                             identifier=trans_id,
                                             ttl=128,
                                             ip_src=server_ip,
                                             ip_dst=ip_dst,
                                             sport=67,
                                             dport=68,
                                             data=dhcp_reply._tobytes())
                self.subroutine(send_packet(in_port, reply_packet), True)
            except Exception:
                self._logger.info('Invalid DHCP packet received: %r',
                                  msg.data,
                                  exc_info=True)
示例#3
0
    def updateflow(self, connection, addvalues, removevalues, updatedvalues):
        try:
            allobjs = set(o for o in self._savedresult
                          if o is not None and not o.isdeleted())
            # Create DHCP entries
            lastlognetinfo = self._lastlognetinfo
            lastlogportinfo = self._lastlogportinfo
            lastserveraddresses = self._lastserveraddresses
            currentlognetinfo = dict(
                (n, id) for n, id in self._lastlognets if n in allobjs)
            currentlogportinfo = dict(
                (p,
                 (id, currentlognetinfo[p.network], p.ip_address,
                  p.mac_address,
                  getattr(p.subnet, 'dhcp_server', self._parent.serveraddress))
                 ) for p, id in self._lastlogports if p in allobjs
                and p.network in currentlognetinfo and hasattr(p, 'subnet'))
            currentserveraddresses = set(
                (v[4], self._parent.servermac, p.network.id, True)
                for p, v in currentlogportinfo.items())
            self._lastlognetinfo = currentlognetinfo
            self._lastlogportinfo = currentlogportinfo
            self._lastserveraddresses = currentserveraddresses
            dhcp_entries = {}
            t1 = self._parent.t1
            t2 = self._parent.t2
            for p in self._savedresult:
                if p is not None and not p.isdeleted() and p.isinstance(LogicalPort) and hasattr(p, 'subnet') \
                        and hasattr(p, 'ip_address') and hasattr(p, 'mac_address'):
                    if p.network in currentlognetinfo and p in currentlogportinfo:
                        try:
                            pid, _, ip_address, mac_address, server_address = currentlogportinfo[
                                p]
                            if getattr(p.subnet, 'dhcp_enabled', False):
                                continue
                            cidr = p.subnet.cidr
                            network, mask = parse_ip4_network(cidr)
                            # options from default settings
                            entries = {
                                d.OPTION_LEASE_TIME:
                                (lambda x: d.DHCPTIME_INFINITE
                                 if x is None else x)(self._parent.leasetime)
                            }
                            # options from network
                            if hasattr(p.network, 'dns_nameservers'):
                                entries[
                                    d.
                                    OPTION_DNSSERVER] = p.network.dns_nameservers
                            if hasattr(p.network, 'domain_name'):
                                entries[
                                    d.
                                    OPTION_DOMAINNAME] = p.network.domain_name
                            if hasattr(p.network, 'mtu'):
                                entries[d.OPTION_MTU] = p.network.mtu
                            if hasattr(p.network, 'ntp_servers'):
                                entries[
                                    d.OPTION_NTPSERVER] = p.network.ntp_servers
                            if hasattr(p.network, 'lease_time'):
                                entries[
                                    d.OPTION_LEASE_TIME] = p.network.lease_time
                            if hasattr(p.network, 'extra_dhcp_options'):
                                entries.update(p.network.extra_dhcp_options)
                            options = d.create_dhcp_options(
                                entries, True, True)
                            # options from subnet
                            entries = {
                                d.OPTION_NETMASK:
                                ip4_addr.formatter(get_netmask(mask)),
                                d.OPTION_BROADCAST:
                                ip4_addr.formatter(get_broadcast(
                                    network, mask))
                            }
                            if hasattr(p.subnet, 'gateway'):
                                entries[d.OPTION_ROUTER] = p.subnet.gateway
                            if hasattr(p.subnet, 'dns_nameservers'):
                                entries[
                                    d.
                                    OPTION_DNSSERVER] = p.subnet.dns_nameservers
                            if hasattr(p.subnet, 'domain_name'):
                                entries[
                                    d.OPTION_DOMAINNAME] = p.subnet.domain_name
                            if hasattr(p.subnet, 'mtu'):
                                entries[d.OPTION_MTU] = p.subnet.mtu
                            if hasattr(p.subnet, 'ntp_servers'):
                                entries[
                                    d.OPTION_NTPSERVER] = p.subnet.ntp_servers
                            if hasattr(p.subnet, 'lease_time'):
                                entries[
                                    d.OPTION_LEASE_TIME] = p.subnet.lease_time
                            # Routes is special
                            if hasattr(p.subnet, 'host_routes'):
                                routes = list(p.subnet.host_routes)
                                if routes and not any(
                                        parse_ip4_network(r[0]) == (0, 0)
                                        for r in routes):
                                    routes.append(
                                        ['0.0.0.0/0', p.subnet.gateway])
                                entries[d.OPTION_CLASSLESSROUTE] = routes
                            # TODO: add extra routes from routers
                            if hasattr(p.subnet, 'extra_dhcp_options'):
                                entries.update(p.subnet.extra_dhcp_options)
                            options.update(
                                d.create_dhcp_options(entries, True, True))
                            entries = {}
                            if hasattr(p, 'hostname'):
                                entries[d.OPTION_HOSTNAME] = p.hostname
                            if hasattr(p, 'extra_dhcp_options'):
                                entries.update(p.extra_dhcp_options)
                            options.update(
                                d.create_dhcp_options(entries, True, True))
                            entries = {
                                d.OPTION_SERVER_IDENTIFIER: server_address
                            }
                            options.update(
                                d.create_dhcp_options(entries, True, True))
                            options = dict((k, v) for k, v in options.items()
                                           if v is not None)
                            if d.OPTION_LEASE_TIME not in options:
                                options[
                                    d.
                                    OPTION_LEASE_TIME] = d.create_option_from_value(
                                        d.OPTION_LEASE_TIME,
                                        d.DHCPTIME_INFINITE)
                            if options[
                                    d.
                                    OPTION_LEASE_TIME].value != d.DHCPTIME_INFINITE:
                                leasetime = options[d.OPTION_LEASE_TIME].value
                                if d.OPTION_T1 not in options and t1 is not None and t1 < leasetime:
                                    options[
                                        d.
                                        OPTION_T1] = d.create_option_from_value(
                                            d.OPTION_T1, t1)
                                if d.OPTION_T2 not in options and t2 is not None and t2 < leasetime:
                                    options[
                                        d.
                                        OPTION_T1] = d.create_option_from_value(
                                            d.OPTION_T1, t2)
                            dhcp_entries[pid] = (mac_addr(mac_address),
                                                 ip4_addr(ip_address),
                                                 ip4_addr(server_address),
                                                 options)
                        except Exception:
                            self._logger.warning(
                                "Failed to create DHCP options for port id=%r. Will disable DHCP on this port",
                                p.id,
                                exc_info=True)
            self._dhcpentries = dhcp_entries
            # Create flows
            # For every logical port, create two flows
            ofdef = connection.openflowdef
            vhost = connection.protocol.vhost
            l3 = self._parent._gettableindex('l3input', vhost)
            cmds = []
            if connection.protocol.disablenxext:

                def match_network(nid):
                    return [
                        ofdef.create_oxm(ofdef.OXM_OF_METADATA_W,
                                         ((nid & 0xffff) << 32) |
                                         (0xffff << 16),
                                         b'\x00\x00\xff\xff\x40\x00\x00\x00')
                    ]
            else:

                def match_network(nid):
                    return [
                        ofdef.create_oxm(ofdef.NXM_NX_REG5, nid),
                        ofdef.create_oxm(ofdef.NXM_NX_REG7_W, 0x4000, 0x4000)
                    ]

            def _delete_flows(nid):
                return ofdef.ofp_flow_mod(
                    cookie=0x1,
                    cookie_mask=0xffffffffffffffff,
                    table_id=l3,
                    command=ofdef.OFPFC_DELETE,
                    priority=ofdef.OFP_DEFAULT_PRIORITY,
                    buffer_id=ofdef.OFP_NO_BUFFER,
                    out_port=ofdef.OFPP_ANY,
                    out_group=ofdef.OFPG_ANY,
                    match=ofdef.ofp_match_oxm(oxm_fields=match_network(nid) + [
                        ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE,
                                         ofdef.ETHERTYPE_IP),
                        ofdef.create_oxm(ofdef.OXM_OF_IP_PROTO,
                                         ofdef.IPPROTO_UDP),
                        ofdef.create_oxm(ofdef.OXM_OF_UDP_DST, 67)
                    ]))

            def _delete_flows2(nid, serveraddr):
                return ofdef.ofp_flow_mod(
                    cookie=0x1,
                    cookie_mask=0xffffffffffffffff,
                    table_id=l3,
                    command=ofdef.OFPFC_DELETE,
                    priority=ofdef.OFP_DEFAULT_PRIORITY,
                    buffer_id=ofdef.OFP_NO_BUFFER,
                    out_port=ofdef.OFPP_ANY,
                    out_group=ofdef.OFPG_ANY,
                    match=ofdef.ofp_match_oxm(oxm_fields=match_network(nid) + [
                        ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE,
                                         ofdef.ETHERTYPE_IP),
                        ofdef.create_oxm(ofdef.OXM_OF_IP_PROTO,
                                         ofdef.IPPROTO_UDP),
                        ofdef.create_oxm(ofdef.OXM_OF_IPV4_DST,
                                         ip4_addr_bytes(serveraddr)),
                        ofdef.create_oxm(ofdef.OXM_OF_UDP_DST, 67)
                    ]))

            def _create_flows(nid):
                return ofdef.ofp_flow_mod(
                    cookie=0x1,
                    cookie_mask=0xffffffffffffffff,
                    table_id=l3,
                    command=ofdef.OFPFC_ADD,
                    priority=ofdef.OFP_DEFAULT_PRIORITY,
                    buffer_id=ofdef.OFP_NO_BUFFER,
                    out_port=ofdef.OFPP_ANY,
                    out_group=ofdef.OFPG_ANY,
                    match=ofdef.ofp_match_oxm(oxm_fields=match_network(nid) + [
                        ofdef.create_oxm(ofdef.OXM_OF_ETH_DST_W,
                                         b'\x01\x00\x00\x00\x00\x00',
                                         b'\x01\x00\x00\x00\x00\x00'),
                        ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE,
                                         ofdef.ETHERTYPE_IP),
                        ofdef.create_oxm(ofdef.OXM_OF_IP_PROTO,
                                         ofdef.IPPROTO_UDP),
                        ofdef.create_oxm(ofdef.OXM_OF_UDP_DST, 67)
                    ]),
                    instructions=[
                        ofdef.ofp_instruction_actions(actions=[
                            ofdef.ofp_action_output(
                                port=ofdef.OFPP_CONTROLLER,
                                max_len=ofdef.OFPCML_NO_BUFFER)
                        ])
                    ])

            def _create_flows2(nid, serveraddr):
                return ofdef.ofp_flow_mod(
                    cookie=0x1,
                    cookie_mask=0xffffffffffffffff,
                    table_id=l3,
                    command=ofdef.OFPFC_ADD,
                    priority=ofdef.OFP_DEFAULT_PRIORITY,
                    buffer_id=ofdef.OFP_NO_BUFFER,
                    out_port=ofdef.OFPP_ANY,
                    out_group=ofdef.OFPG_ANY,
                    match=ofdef.ofp_match_oxm(oxm_fields=match_network(nid) + [
                        ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE,
                                         ofdef.ETHERTYPE_IP),
                        ofdef.create_oxm(ofdef.OXM_OF_IP_PROTO,
                                         ofdef.IPPROTO_UDP),
                        ofdef.create_oxm(ofdef.OXM_OF_IPV4_DST,
                                         ip4_addr_bytes(serveraddr)),
                        ofdef.create_oxm(ofdef.OXM_OF_UDP_DST, 67)
                    ]),
                    instructions=[
                        ofdef.ofp_instruction_actions(actions=[
                            ofdef.ofp_action_output(
                                port=ofdef.OFPP_CONTROLLER,
                                max_len=ofdef.OFPCML_NO_BUFFER)
                        ])
                    ])

            for n in removevalues:
                if n in lastlognetinfo:
                    nid = lastlognetinfo[n]
                    cmds.append(_delete_flows(nid))
            lastnetdict = {n.id: n for n in lastlognetinfo}
            for serveraddr in lastserveraddresses:
                if serveraddr not in currentserveraddresses:
                    addr, _, networkid, _ = serveraddr
                    if networkid in lastnetdict:
                        n = lastnetdict[networkid]
                        nid = lastlognetinfo[n]
                        cmds.append(_delete_flows2(nid, addr))
            for m in self.execute_commands(connection, cmds):
                yield m

            # Remove old ARP entries; Add new ARP entries
            remove_arps = lastserveraddresses.difference(
                currentserveraddresses)
            if remove_arps:
                for m in callAPI(self, 'arpresponder', 'removeproxyarp', {
                        'connection': connection,
                        'arpentries': remove_arps
                }):
                    yield m
            add_arps = currentserveraddresses.difference(lastserveraddresses)
            if add_arps:
                for m in callAPI(self, 'arpresponder', 'createproxyarp', {
                        'connection': connection,
                        'arpentries': add_arps
                }):
                    yield m
            del cmds[:]
            for n in addvalues:
                if n in currentlognetinfo:
                    nid = currentlognetinfo[n]
                    cmds.append(_create_flows(nid))
            currnetdict = {n.id: n for n in currentlognetinfo}
            for serveraddr in currentserveraddresses:
                if serveraddr not in lastserveraddresses:
                    addr, _, networkid, _ = serveraddr
                    if networkid in currnetdict:
                        n = currnetdict[networkid]
                        nid = currentlognetinfo[n]
                        cmds.append(_create_flows2(nid, addr))
            for m in self.execute_commands(connection, cmds):
                yield m
        except Exception:
            self._logger.warning(
                "Unexpected exception in DHCPUpdater. Will ignore and continue.",
                exc_info=True)
示例#4
0
文件: typelib.py 项目: sinofeng/vlcp
                     convert=_type_assert(format_ip_address, ip_address_type))

cidr_type = extra()
cidr_type.bind(str,
               convert=_type_assert(partial(format_network_cidr, strict=True),
                                    cidr_type))

cidr_nonstrict_type = extra()
cidr_nonstrict_type.bind(str,
                         convert=_type_assert(format_network_cidr,
                                              cidr_nonstrict_type))

mac_address_type = extra()
mac_address_type.bind(str,
                      convert=_type_assert(
                          lambda x: mac_addr.formatter(mac_addr(x)),
                          mac_address_type, "Invalid MAC address"))


# Auto convert to number when calling from Web API
def _convert_to_int(s):
    try:
        return int(s)
    except ValueError:
        raise TypeMismatchException(s, autoint, "not an integer")


str_int = extra()
str_int.bind(str, convert=_type_assert(int, str_int, "not an integer"))

autoint = (int, str_int)
示例#5
0
    async def _dhcp_handler(self):
        """
        Mini DHCP server, respond DHCP packets from OpenFlow
        """
        conn = self._connection
        ofdef = self._connection.openflowdef
        l3 = self._parent._gettableindex('l3input',
                                         self._connection.protocol.vhost)
        dhcp_packet_matcher = OpenflowAsyncMessageEvent.createMatcher(
            ofdef.OFPT_PACKET_IN, None, None, l3, 1, self._connection,
            self._connection.connmark)
        # These tags are important options. They are sent first to make sure the client
        # correctly receive these options.
        required_tags = [
            d.OPTION_MESSAGE_TYPE, d.OPTION_SERVER_IDENTIFIER,
            d.OPTION_NETMASK, d.OPTION_ROUTER, d.OPTION_DNSSERVER,
            d.OPTION_BROADCAST, d.OPTION_MTU, d.OPTION_LEASE_TIME, d.OPTION_T1,
            d.OPTION_T2
        ]
        server_mac = mac_addr(self._parent.servermac)
        # IP fragment identifier
        trans_id = uint16.create(os.urandom(2))

        def set_options(payload,
                        option_dict,
                        provide_options,
                        message_type,
                        remove_lease=False):
            """
            Set DHCP options to output payload regarding the incoming request
            
            :param payload: output DHCP payload
            
            :param option_dict: incoming DHCP options in request
            
            :param provide_options: all DHCP options that are ready to sent to the client
            
            :param message_type: output DHCP message type
            
            :param remove_lease: remove all leases options. DHCPINFORM cannot contain
                                 leases options. See https://tools.ietf.org/html/rfc2131#section-3.4
            """
            message_type_opt = d.dhcp_option_message_type(value=message_type)
            if d.OPTION_REQUESTED_OPTIONS in option_dict:
                # First requested options, then required options, then others
                reqs = set(option_dict[d.OPTION_REQUESTED_OPTIONS].value)
                send_tags = [t for t in option_dict[d.OPTION_REQUESTED_OPTIONS].value
                             if t == d.OPTION_MESSAGE_TYPE or t in provide_options] \
                            + [t for t in required_tags
                               if (t in provide_options or t == d.OPTION_MESSAGE_TYPE) and t not in reqs] \
                            + [t for t in provide_options
                               if t not in reqs and t not in required_tags]
            else:
                # Required options, then others
                send_tags = [t for t in required_tags
                             if t in provide_options or t == d.OPTION_MESSAGE_TYPE] \
                            + [t for t in set(provide_options.keys()).difference(required_tags)]
            # If the client has sent an option for max message size, use it; or use the RFC required 576 bytes
            not_finished = d.build_options(
                payload, [
                    message_type_opt
                    if t == d.OPTION_MESSAGE_TYPE else provide_options[t]
                    for t in send_tags
                    if not remove_lease or (t != d.OPTION_LEASE_TIME and t !=
                                            d.OPTION_T1 and t != OPTION_T2)
                ],
                max(min(option_dict[d.OPTION_MAX_MESSAGE_SIZE].value, 1400),
                    576) if d.OPTION_MAX_MESSAGE_SIZE in option_dict else 576)

        async def send_packet(pid, packet):
            """
            Send DHCP packet to specified port
            """
            await self.execute_commands(conn, [
                ofdef.ofp_packet_out(buffer_id=ofdef.OFP_NO_BUFFER,
                                     in_port=ofdef.OFPP_CONTROLLER,
                                     actions=[
                                         ofdef.ofp_action_output(
                                             port=pid,
                                             max_len=ofdef.OFPCML_NO_BUFFER)
                                     ],
                                     data=packet._tobytes())
            ])

        while True:
            ev = await dhcp_packet_matcher
            msg = ev.message
            try:
                in_port = ofdef.ofp_port_no.create(
                    ofdef.get_oxm(msg.match.oxm_fields, ofdef.OXM_OF_IN_PORT))
                if in_port not in self._dhcpentries:
                    # Not a DHCP-enabled port
                    continue
                port_mac, port_ip, server_ip, provide_options = self._dhcpentries[
                    in_port]
                # Fragmented DHCP packets are not supported - this is allowed according
                # to RFC: server and clients are only needed to support at least 576 bytes
                # DHCP messages.
                l7_packet = ethernet_l7.create(msg.data)
                dhcp_packet = d.dhcp_payload.create(l7_packet.data)
                # We only process a DHCP request directly sent from the logical port
                if (dhcp_packet.op != d.BOOTREQUEST  # A DHCP server packet
                        or dhcp_packet.hlen != 6 or dhcp_packet.htype !=
                        1  # Hardware address not ethernet (48-bit)
                        or dhcp_packet.magic_cookie !=
                        d.BOOTP_MAGIC_COOKIE  # Magic cookie not match
                        or dhcp_packet.giaddr != 0):  # A relayed DHCP message
                    raise ValueError('Unsupported DHCP packet')
                # Reassemble DHCP options
                options = d.reassemble_options(dhcp_packet)
                option_dict = dict((o.tag, o) for o in options)
                if d.OPTION_MESSAGE_TYPE not in option_dict:
                    raise ValueError('Message type not found')
                message_type = option_dict[d.OPTION_MESSAGE_TYPE].value
                is_nak = False
                if message_type == d.DHCPDISCOVER:
                    # A DHCPDISCOVER should get a DHCPOFFER response
                    if dhcp_packet.chaddr[:6].ljust(
                            6, b'\x00') != mac_addr.tobytes(port_mac):
                        # MAC address not match, ignore this packet
                        continue
                    dhcp_reply = d.dhcp_payload(
                        op=d.BOOTREPLY,
                        htype=1,
                        hlen=6,
                        hops=0,
                        xid=dhcp_packet.xid,
                        secs=0,
                        flags=dhcp_packet.flags,
                        ciaddr=0,
                        yiaddr=port_ip,
                        siaddr=0,
                        giaddr=dhcp_packet.giaddr,
                        chaddr=dhcp_packet.chaddr,
                        magic_cookie=d.BOOTP_MAGIC_COOKIE)
                    set_options(dhcp_reply, option_dict, provide_options,
                                d.DHCPOFFER)
                elif message_type == d.DHCPREQUEST:
                    # A DHCPREQUEST should get a DHCPACK reply
                    if d.OPTION_SERVER_IDENTIFIER in option_dict and option_dict[
                            d.OPTION_SERVER_IDENTIFIER].value != server_ip:
                        # Ignore packets to wrong address
                        continue
                    if dhcp_packet.chaddr[:6].ljust(6, b'\x00') != mac_addr.tobytes(port_mac) \
                            or (d.OPTION_REQUESTED_IP in option_dict and option_dict[d.OPTION_REQUESTED_IP].value != port_ip) \
                            or (dhcp_packet.ciaddr != 0 and dhcp_packet.ciaddr != port_ip):
                        # Requested MAC or IP not matched, send a NACK
                        dhcp_reply = d.dhcp_payload(
                            op=d.BOOTREPLY,
                            htype=1,
                            hlen=6,
                            hops=0,
                            xid=dhcp_packet.xid,
                            secs=0,
                            flags=dhcp_packet.flags,
                            ciaddr=0,
                            yiaddr=0,
                            siaddr=0,
                            giaddr=dhcp_packet.giaddr,
                            chaddr=dhcp_packet.chaddr,
                            magic_cookie=d.BOOTP_MAGIC_COOKIE)
                        # Do not send more options in NACK
                        d.build_options(dhcp_reply, [
                            d.dhcp_option_message_type(value=d.DHCPNAK),
                            d.dhcp_option_address(
                                tag=d.OPTION_SERVER_IDENTIFIER,
                                value=server_ip)
                        ], 576, 0)
                        is_nak = True
                    else:
                        dhcp_reply = d.dhcp_payload(
                            op=d.BOOTREPLY,
                            htype=1,
                            hlen=6,
                            hops=0,
                            xid=dhcp_packet.xid,
                            secs=0,
                            flags=dhcp_packet.flags,
                            ciaddr=dhcp_packet.ciaddr,
                            yiaddr=port_ip,
                            siaddr=0,
                            giaddr=dhcp_packet.giaddr,
                            chaddr=dhcp_packet.chaddr,
                            magic_cookie=d.BOOTP_MAGIC_COOKIE)
                        set_options(dhcp_reply, option_dict, provide_options,
                                    d.DHCPACK)
                elif message_type == d.DHCPDECLINE:
                    # Address already in use?
                    self._logger.warning('DHCP client reports DHCPDECLINE, there should be some problems.'\
                                         ' Connection = %r(%016x), port = %d.',
                                         self._connection, self._connection.openflow_datapathid)
                elif message_type == d.DHCPRELEASE:
                    # Safe to ignore, we do not use a dynamic IP address pool
                    continue
                elif message_type == d.DHCPINFORM:
                    # Client setup IP addresses itself, but requesting more information
                    # DHCPINFORM reply cannot have lease options, and yiaddr = 0
                    dhcp_reply = d.dhcp_payload(
                        op=d.BOOTREPLY,
                        htype=1,
                        hlen=6,
                        hops=0,
                        xid=dhcp_packet.xid,
                        secs=0,
                        flags=dhcp_packet.flags,
                        ciaddr=dhcp_packet.ciaddr,
                        yiaddr=0,
                        siaddr=0,
                        giaddr=dhcp_packet.giaddr,
                        chaddr=dhcp_packet.chaddr,
                        magic_cookie=d.BOOTP_MAGIC_COOKIE)
                    set_options(dhcp_reply, option_dict, provide_options,
                                d.DHCPACK, True)
                trans_id = (trans_id + 1) & 0xffff
                if (dhcp_packet.flags & d.DHCPFLAG_BROADCAST) or is_nak:
                    # client request broadcast, or DHCPNAK
                    # RFC requires that DHCPNAK uses broadcast
                    dl_dst = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
                    ip_dst = 0xffffffff
                else:
                    dl_dst = l7_packet.dl_src
                    ip_dst = port_ip
                reply_packet = ip4_packet_l7((ip4_payload, ip4_udp_payload),
                                             dl_src=server_mac,
                                             dl_dst=dl_dst,
                                             identifier=trans_id,
                                             ttl=128,
                                             ip_src=server_ip,
                                             ip_dst=ip_dst,
                                             sport=67,
                                             dport=68,
                                             data=dhcp_reply._tobytes())
                # Send packet to the incoming port
                self.subroutine(send_packet(in_port, reply_packet), True)
            except Exception:
                self._logger.info('Invalid DHCP packet received: %r',
                                  msg.data,
                                  exc_info=True)
示例#6
0
 def _dhcp_handler(self):
     conn = self._connection
     ofdef = self._connection.openflowdef
     l3 = self._parent._gettableindex('l3input', self._connection.protocol.vhost)
     dhcp_packet_matcher = OpenflowAsyncMessageEvent.createMatcher(ofdef.OFPT_PACKET_IN, None, None, l3, 1,
                                                           self._connection, self._connection.connmark)
     required_tags = [d.OPTION_MESSAGE_TYPE, d.OPTION_SERVER_IDENTIFIER,
                      d.OPTION_NETMASK, d.OPTION_ROUTER,
                      d.OPTION_DNSSERVER, d.OPTION_BROADCAST, d.OPTION_MTU,
                      d.OPTION_LEASE_TIME, d.OPTION_T1, d.OPTION_T2]
     server_mac = mac_addr(self._parent.servermac)
     trans_id = uint16.create(os.urandom(2))
     def set_options(payload, option_dict, provide_options, message_type, remove_lease = False):
         message_type_opt = d.dhcp_option_message_type(value = message_type)
         if d.OPTION_REQUESTED_OPTIONS in option_dict:
             reqs = set(option_dict[d.OPTION_REQUESTED_OPTIONS].value)
             send_tags = [t for t in option_dict[d.OPTION_REQUESTED_OPTIONS].value
                          if t == d.OPTION_MESSAGE_TYPE or t in provide_options] \
                         + [t for t in required_tags
                            if (t in provide_options or t == d.OPTION_MESSAGE_TYPE) and t not in reqs] \
                         + [t for t in provide_options
                            if t not in reqs and t not in required_tags]
         else:
             send_tags = [t for t in required_tags
                          if t in provide_options or t == d.OPTION_MESSAGE_TYPE] \
                         + [t for t in set(provide_options.keys()).difference(required_tags)]
         d.build_options(payload, [message_type_opt if t == d.OPTION_MESSAGE_TYPE
                                   else provide_options[t] for t in send_tags
                                   if not remove_lease or (t != d.OPTION_LEASE_TIME and t != d.OPTION_T1 and t != OPTION_T2)],
                         max(min(option_dict[d.OPTION_MAX_MESSAGE_SIZE].value, 1400), 576)
                         if d.OPTION_MAX_MESSAGE_SIZE in option_dict
                         else 576)
     def send_packet(pid, packet):
         for m in self.execute_commands(conn,
                         [ofdef.ofp_packet_out(
                                 buffer_id = ofdef.OFP_NO_BUFFER,
                                 in_port = ofdef.OFPP_CONTROLLER,
                                 actions = [ofdef.ofp_action_output(port = pid,
                                                                    max_len = ofdef.OFPCML_NO_BUFFER)],
                                 data = packet._tobytes()
                             )]):
             yield m
     while True:
         yield (dhcp_packet_matcher,)
         msg = self.event.message
         try:
             in_port = ofdef.ofp_port_no.create(ofdef.get_oxm(msg.match.oxm_fields, ofdef.OXM_OF_IN_PORT))
             if in_port not in self._dhcpentries:
                 continue
             port_mac, port_ip, server_ip, provide_options = self._dhcpentries[in_port]
             l7_packet = ethernet_l7.create(msg.data)
             dhcp_packet = d.dhcp_payload.create(l7_packet.data)
             if dhcp_packet.op != d.BOOTREQUEST or \
                     dhcp_packet.hlen != 6 or dhcp_packet.htype != 1 or \
                     dhcp_packet.magic_cookie != d.BOOTP_MAGIC_COOKIE or \
                     dhcp_packet.giaddr != 0:
                 raise ValueError('Unsupported DHCP packet')
             options = d.reassemble_options(dhcp_packet)
             option_dict = dict((o.tag, o) for o in options)
             if d.OPTION_MESSAGE_TYPE not in option_dict:
                 raise ValueError('Message type not found')
             message_type = option_dict[d.OPTION_MESSAGE_TYPE].value
             is_nak = False
             if message_type == d.DHCPDISCOVER:
                 if dhcp_packet.chaddr[:6].ljust(6, b'\x00') != mac_addr.tobytes(port_mac):
                     # Ignore this packet
                     continue
                 dhcp_reply = d.dhcp_payload(op = d.BOOTREPLY,
                                             htype = 1,
                                             hlen = 6,
                                             hops = 0,
                                             xid = dhcp_packet.xid,
                                             secs = 0,
                                             flags = dhcp_packet.flags,
                                             ciaddr = 0,
                                             yiaddr = port_ip,
                                             siaddr = 0,
                                             giaddr = dhcp_packet.giaddr,
                                             chaddr = dhcp_packet.chaddr,
                                             magic_cookie = d.BOOTP_MAGIC_COOKIE
                                             )
                 set_options(dhcp_reply, option_dict, provide_options, d.DHCPOFFER)
             elif message_type == d.DHCPREQUEST:
                 if d.OPTION_SERVER_IDENTIFIER in option_dict and option_dict[d.OPTION_SERVER_IDENTIFIER].value != server_ip:
                     # Ignore packets to wrong address
                     continue
                 if dhcp_packet.chaddr[:6].ljust(6, b'\x00') != mac_addr.tobytes(port_mac) \
                         or (d.OPTION_REQUESTED_IP in option_dict and option_dict[d.OPTION_REQUESTED_IP].value != port_ip) \
                         or (dhcp_packet.ciaddr != 0 and dhcp_packet.ciaddr != port_ip):
                     dhcp_reply = d.dhcp_payload(op = d.BOOTREPLY,
                                                 htype = 1,
                                                 hlen = 6,
                                                 hops = 0,
                                                 xid = dhcp_packet.xid,
                                                 secs = 0,
                                                 flags = dhcp_packet.flags,
                                                 ciaddr = 0,
                                                 yiaddr = 0,
                                                 siaddr = 0,
                                                 giaddr = dhcp_packet.giaddr,
                                                 chaddr = dhcp_packet.chaddr,
                                                 magic_cookie = d.BOOTP_MAGIC_COOKIE
                                                 )
                     d.build_options(dhcp_reply, [d.dhcp_option_message_type(value = d.DHCPNAK),
                                                  d.dhcp_option_address(tag = d.OPTION_SERVER_IDENTIFIER,
                                                                        value = server_ip)], 576, 0)
                     is_nak = True
                 else:
                     dhcp_reply = d.dhcp_payload(op = d.BOOTREPLY,
                                                 htype = 1,
                                                 hlen = 6,
                                                 hops = 0,
                                                 xid = dhcp_packet.xid,
                                                 secs = 0,
                                                 flags = dhcp_packet.flags,
                                                 ciaddr = dhcp_packet.ciaddr,
                                                 yiaddr = port_ip,
                                                 siaddr = 0,
                                                 giaddr = dhcp_packet.giaddr,
                                                 chaddr = dhcp_packet.chaddr,
                                                 magic_cookie = d.BOOTP_MAGIC_COOKIE
                                                 )
                     set_options(dhcp_reply, option_dict, provide_options, d.DHCPACK)
             elif message_type == d.DHCPDECLINE:
                 self._logger.warning('DHCP client reports DHCPDECLINE, there should be some problems.'\
                                      ' Connection = %r(%016x), port = %d.',
                                      self._connection, self._connection.openflow_datapathid)
             elif message_type == d.DHCPRELEASE:
                 # Safe to ignore
                 continue
             elif message_type == d.DHCPINFORM:
                 dhcp_reply = d.dhcp_payload(op = d.BOOTREPLY,
                                             htype = 1,
                                             hlen = 6,
                                             hops = 0,
                                             xid = dhcp_packet.xid,
                                             secs = 0,
                                             flags = dhcp_packet.flags,
                                             ciaddr = dhcp_packet.ciaddr,
                                             yiaddr = 0,
                                             siaddr = 0,
                                             giaddr = dhcp_packet.giaddr,
                                             chaddr = dhcp_packet.chaddr,
                                             magic_cookie = d.BOOTP_MAGIC_COOKIE
                                             )
                 set_options(dhcp_reply, option_dict, provide_options, d.DHCPACK, True)
             trans_id = (trans_id + 1) & 0xffff
             if (dhcp_packet.flags & d.DHCPFLAG_BROADCAST) or is_nak:
                 dl_dst = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
                 ip_dst = 0xffffffff
             else:
                 dl_dst = l7_packet.dl_src
                 ip_dst = port_ip
             reply_packet = ip4_packet_l7((ip4_payload, ip4_udp_payload),
                                        dl_src = server_mac,
                                        dl_dst = dl_dst,
                                        identifier = trans_id,
                                        ttl = 128,
                                        ip_src = server_ip,
                                        ip_dst = ip_dst,
                                        sport = 67,
                                        dport = 68,
                                        data = dhcp_reply._tobytes()
                                        )
             self.subroutine(send_packet(in_port, reply_packet), True)
         except Exception:
             self._logger.info('Invalid DHCP packet received: %r', msg.data, exc_info = True)
示例#7
0
 def updateflow(self, connection, addvalues, removevalues, updatedvalues):
     try:
         allobjs = set(o for o in self._savedresult if o is not None and not o.isdeleted())
         # Create DHCP entries
         lastlognetinfo = self._lastlognetinfo
         lastlogportinfo = self._lastlogportinfo
         lastserveraddresses = self._lastserveraddresses
         currentlognetinfo = dict((n, id) for n,id in self._lastlognets if n in allobjs)
         currentlogportinfo = dict((p, (id, currentlognetinfo[p.network], p.ip_address, p.mac_address, getattr(p.subnet, 'dhcp_server', self._parent.serveraddress)))
                                   for p,id in self._lastlogports
                                   if p in allobjs and p.network in currentlognetinfo and hasattr(p,'subnet'))
         currentserveraddresses = set((v[4], self._parent.servermac, p.network.id, True)
                                      for p,v in currentlogportinfo.items())
         self._lastlognetinfo = currentlognetinfo
         self._lastlogportinfo = currentlogportinfo
         self._lastserveraddresses = currentserveraddresses
         dhcp_entries = {}
         t1 = self._parent.t1
         t2 = self._parent.t2
         for p in self._savedresult:
             if p is not None and not p.isdeleted() and p.isinstance(LogicalPort) and hasattr(p, 'subnet') \
                     and hasattr(p, 'ip_address') and hasattr(p, 'mac_address'):
                 if p.network in currentlognetinfo and p in currentlogportinfo:
                     try:
                         pid, _, ip_address, mac_address, server_address = currentlogportinfo[p]
                         if getattr(p.subnet, 'dhcp_enabled', False):
                             continue
                         cidr = p.subnet.cidr
                         network, mask = parse_ip4_network(cidr)
                         # options from default settings
                         entries = {d.OPTION_LEASE_TIME: (lambda x: d.DHCPTIME_INFINITE if x is None else x)(self._parent.leasetime)
                                    }
                         # options from network
                         if hasattr(p.network, 'dns_nameservers'):
                             entries[d.OPTION_DNSSERVER] = p.network.dns_nameservers
                         if hasattr(p.network, 'domain_name'):
                             entries[d.OPTION_DOMAINNAME] = p.network.domain_name
                         if hasattr(p.network, 'mtu'):
                             entries[d.OPTION_MTU] = p.network.mtu
                         if hasattr(p.network, 'ntp_servers'):
                             entries[d.OPTION_NTPSERVER] = p.network.ntp_servers
                         if hasattr(p.network, 'lease_time'):
                             entries[d.OPTION_LEASE_TIME] = p.network.lease_time
                         if hasattr(p.network, 'extra_dhcp_options'):
                             entries.update(p.network.extra_dhcp_options)
                         options = d.create_dhcp_options(entries, True, True)
                         # options from subnet
                         entries = {d.OPTION_NETMASK : ip4_addr.formatter(get_netmask(mask)),
                                    d.OPTION_BROADCAST : ip4_addr.formatter(get_broadcast(network, mask))}
                         if hasattr(p.subnet, 'gateway'):
                             entries[d.OPTION_ROUTER] = p.subnet.gateway
                         if hasattr(p.subnet, 'dns_nameservers'):
                             entries[d.OPTION_DNSSERVER] = p.subnet.dns_nameservers
                         if hasattr(p.subnet, 'domain_name'):
                             entries[d.OPTION_DOMAINNAME] = p.subnet.domain_name
                         if hasattr(p.subnet, 'mtu'):
                             entries[d.OPTION_MTU] = p.subnet.mtu
                         if hasattr(p.subnet, 'ntp_servers'):
                             entries[d.OPTION_NTPSERVER] = p.subnet.ntp_servers
                         if hasattr(p.subnet, 'lease_time'):
                             entries[d.OPTION_LEASE_TIME] = p.subnet.lease_time
                         # Routes is special
                         if hasattr(p.subnet, 'host_routes'):
                             routes = list(p.subnet.host_routes)
                             if routes and not any(parse_ip4_network(r[0]) == (0,0) for r in routes):
                                 routes.append(['0.0.0.0/0', p.subnet.gateway])
                             entries[d.OPTION_CLASSLESSROUTE] = routes
                         # TODO: add extra routes from routers
                         if hasattr(p.subnet, 'extra_dhcp_options'):
                             entries.update(p.subnet.extra_dhcp_options)
                         options.update(d.create_dhcp_options(entries, True, True))
                         entries = {}
                         if hasattr(p, 'hostname'):
                             entries[d.OPTION_HOSTNAME] = p.hostname
                         if hasattr(p, 'extra_dhcp_options'):
                             entries.update(p.extra_dhcp_options)
                         options.update(d.create_dhcp_options(entries, True, True))
                         entries = {d.OPTION_SERVER_IDENTIFIER: server_address}
                         options.update(d.create_dhcp_options(entries, True, True))
                         options = dict((k,v) for k,v in options.items() if v is not None)
                         if d.OPTION_LEASE_TIME not in options:
                             options[d.OPTION_LEASE_TIME] = d.create_option_from_value(d.OPTION_LEASE_TIME, d.DHCPTIME_INFINITE)
                         if options[d.OPTION_LEASE_TIME].value != d.DHCPTIME_INFINITE:
                             leasetime = options[d.OPTION_LEASE_TIME].value
                             if d.OPTION_T1 not in options and t1 is not None and t1 < leasetime:
                                 options[d.OPTION_T1] = d.create_option_from_value(d.OPTION_T1, t1)
                             if d.OPTION_T2 not in options and t2 is not None and t2 < leasetime:
                                 options[d.OPTION_T1] = d.create_option_from_value(d.OPTION_T1, t2)
                         dhcp_entries[pid] = (mac_addr(mac_address), ip4_addr(ip_address),
                                             ip4_addr(server_address), options)
                     except Exception:
                         self._logger.warning("Failed to create DHCP options for port id=%r. Will disable DHCP on this port",
                                              p.id, exc_info = True)
         self._dhcpentries = dhcp_entries
         # Create flows
         # For every logical port, create two flows
         ofdef = connection.openflowdef
         vhost = connection.protocol.vhost
         l3 = self._parent._gettableindex('l3input', vhost)
         cmds = []
         if connection.protocol.disablenxext:
             def match_network(nid):
                 return [ofdef.create_oxm(ofdef.OXM_OF_METADATA_W, ((nid & 0xffff) << 32) | (0xffff << 16),
                                         b'\x00\x00\xff\xff\x40\x00\x00\x00')]
         else:
             def match_network(nid):
                 return [ofdef.create_oxm(ofdef.NXM_NX_REG5, nid),
                         ofdef.create_oxm(ofdef.NXM_NX_REG7_W, 0x4000, 0x4000)]
         def _delete_flows(nid):
             return ofdef.ofp_flow_mod(cookie = 0x1,
                                            cookie_mask = 0xffffffffffffffff,
                                            table_id = l3,
                                            command = ofdef.OFPFC_DELETE,
                                            priority = ofdef.OFP_DEFAULT_PRIORITY,
                                            buffer_id = ofdef.OFP_NO_BUFFER,
                                            out_port = ofdef.OFPP_ANY,
                                            out_group = ofdef.OFPG_ANY,
                                            match = ofdef.ofp_match_oxm(
                                                         oxm_fields = 
                                                             match_network(nid) +
                                                             [ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_IP),
                                                             ofdef.create_oxm(ofdef.OXM_OF_IP_PROTO, ofdef.IPPROTO_UDP),
                                                             ofdef.create_oxm(ofdef.OXM_OF_UDP_DST, 67)
                                                             ]
                                                     )
                                            )
         def _delete_flows2(nid, serveraddr):
             return ofdef.ofp_flow_mod(cookie = 0x1,
                                            cookie_mask = 0xffffffffffffffff,
                                            table_id = l3,
                                            command = ofdef.OFPFC_DELETE,
                                            priority = ofdef.OFP_DEFAULT_PRIORITY,
                                            buffer_id = ofdef.OFP_NO_BUFFER,
                                            out_port = ofdef.OFPP_ANY,
                                            out_group = ofdef.OFPG_ANY,
                                            match = ofdef.ofp_match_oxm(
                                                         oxm_fields = 
                                                             match_network(nid) +
                                                             [ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_IP),
                                                             ofdef.create_oxm(ofdef.OXM_OF_IP_PROTO, ofdef.IPPROTO_UDP),
                                                             ofdef.create_oxm(ofdef.OXM_OF_IPV4_DST,
                                                                              ip4_addr_bytes(serveraddr)),
                                                             ofdef.create_oxm(ofdef.OXM_OF_UDP_DST, 67)
                                                             ]
                                                     )
                                            )
         def _create_flows(nid):
             return ofdef.ofp_flow_mod(cookie = 0x1,
                                        cookie_mask = 0xffffffffffffffff,
                                        table_id = l3,
                                        command = ofdef.OFPFC_ADD,
                                        priority = ofdef.OFP_DEFAULT_PRIORITY,
                                        buffer_id = ofdef.OFP_NO_BUFFER,
                                        out_port = ofdef.OFPP_ANY,
                                        out_group = ofdef.OFPG_ANY,
                                        match = ofdef.ofp_match_oxm(
                                                     oxm_fields = 
                                                         match_network(nid) +
                                                         [ofdef.create_oxm(ofdef.OXM_OF_ETH_DST_W, b'\x01\x00\x00\x00\x00\x00', b'\x01\x00\x00\x00\x00\x00'),
                                                         ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_IP),
                                                         ofdef.create_oxm(ofdef.OXM_OF_IP_PROTO, ofdef.IPPROTO_UDP),
                                                         ofdef.create_oxm(ofdef.OXM_OF_UDP_DST, 67)
                                                         ]
                                                 ),
                                        instructions = [
                                             ofdef.ofp_instruction_actions(
                                                         actions = [
                                                             ofdef.ofp_action_output(port = ofdef.OFPP_CONTROLLER,
                                                                                     max_len = ofdef.OFPCML_NO_BUFFER
                                                                                     )
                                                         ]
                                                     )
                                                 ]
                                        )
         def _create_flows2(nid, serveraddr):
             return ofdef.ofp_flow_mod(cookie = 0x1,
                                        cookie_mask = 0xffffffffffffffff,
                                        table_id = l3,
                                        command = ofdef.OFPFC_ADD,
                                        priority = ofdef.OFP_DEFAULT_PRIORITY,
                                        buffer_id = ofdef.OFP_NO_BUFFER,
                                        out_port = ofdef.OFPP_ANY,
                                        out_group = ofdef.OFPG_ANY,
                                        match = ofdef.ofp_match_oxm(
                                                     oxm_fields = match_network(nid) +
                                                         [ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_IP),
                                                         ofdef.create_oxm(ofdef.OXM_OF_IP_PROTO, ofdef.IPPROTO_UDP),
                                                         ofdef.create_oxm(ofdef.OXM_OF_IPV4_DST,
                                                                          ip4_addr_bytes(serveraddr)),
                                                         ofdef.create_oxm(ofdef.OXM_OF_UDP_DST, 67)
                                                         ]
                                                 ),
                                        instructions = [
                                             ofdef.ofp_instruction_actions(
                                                         actions = [
                                                             ofdef.ofp_action_output(port = ofdef.OFPP_CONTROLLER,
                                                                                     max_len = ofdef.OFPCML_NO_BUFFER
                                                                                     )
                                                         ]
                                                     )
                                                 ]
                                        )
         for n in removevalues:
             if n in lastlognetinfo:
                 nid = lastlognetinfo[n]
                 cmds.append(_delete_flows(nid))
         lastnetdict = dict((n.id,n) for n in lastlognetinfo)
         for serveraddr in lastserveraddresses:
             if serveraddr not in currentserveraddresses:
                 addr, _, networkid, _ = serveraddr
                 if networkid in lastnetdict:
                     n = lastnetdict[networkid]
                     nid = lastlognetinfo[n]
                     cmds.append(_delete_flows2(nid, addr))
         for m in self.execute_commands(connection, cmds):
             yield m
         
         # Remove old ARP entries; Add new ARP entries
         remove_arps = lastserveraddresses.difference(currentserveraddresses)
         if remove_arps:
             for m in callAPI(self, 'arpresponder', 'removeproxyarp', {'connection': connection,
                                                                       'arpentries': remove_arps}):
                 yield m
         add_arps = currentserveraddresses.difference(lastserveraddresses)
         if add_arps:
             for m in callAPI(self, 'arpresponder', 'createproxyarp', {'connection': connection,
                                                                       'arpentries': add_arps}):
                 yield m
         del cmds[:]
         for n in addvalues:
             if n in currentlognetinfo:
                 nid = currentlognetinfo[n]
                 cmds.append(_create_flows(nid))
         currnetdict = dict((n.id,n) for n in currentlognetinfo)
         for serveraddr in currentserveraddresses:
             if serveraddr not in lastserveraddresses:
                 addr, _, networkid, _ = serveraddr
                 if networkid in currnetdict:
                     n = currnetdict[networkid]
                     nid = currentlognetinfo[n]
                     cmds.append(_create_flows2(nid, addr))
         for m in self.execute_commands(connection, cmds):
             yield m
     except Exception:
         self._logger.warning("Unexpected exception in DHCPUpdater. Will ignore and continue.", exc_info = True)