def check_ip_address(ipaddress): try: ip4_addr(ipaddress) except Exception: raise ValueError(" ip address illegal " + ipaddress) return ipaddress
def parser_ip_address(ipaddress): try: ip4_addr(ipaddress) except Exception: raise ValueError(" ip address illegal " + ipaddress) return ipaddress
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())
def check_ip_address(ipaddress): try: ip = ip4_addr(ipaddress) except Exception: raise ValueError("Invalid IP address " + ipaddress) return ip
def generate_route(r): r_g = {'Destination': r[0]} if ip4_addr(r[1]) == 0: r_g['RouteType'] = 1 else: r_g['RouteType'] = 0 r_g['NextHop'] = r[1]
def delete_interface(keys, values): rkeys = keys[0:len(routerkeys)] robjs = values[0:len(routerkeys)] snkeys = keys[len(routerkeys):len(routerkeys) + len(subnetkeys)] snobjs = values[len(routerkeys):len(routerkeys) + len(subnetkeys)] snmkeys = keys[len(routerkeys) + len(subnetkeys):len(routerkeys) + len(subnetkeys) + len(subnetmapkeys)] snmobjs = values[len(routerkeys) + len(subnetkeys):len(routerkeys) + len(subnetkeys) + len(subnetmapkeys)] rpkeys = keys[-len(routerportkeys):] rpobjs = values[-len(routerportkeys):] rdict = dict(zip(rkeys, robjs)) sndict = dict(zip(snkeys, snobjs)) snmdict = dict(zip(snmkeys, snmobjs)) rpdict = dict(zip(rpkeys, rpobjs)) for interface in delete_interfaces: r = rdict.get(VRouter.default_key(interface["router"]), None) sn = sndict.get(SubNet.default_key(interface["subnet"]), None) snm = snmdict.get(SubNetMap.default_key(interface["subnet"]), None) rp = rpdict.get( RouterPort.default_key(interface["routerport"]), None) if r and sn and snm and rp: # has not attr ip_address, means router port use subnet gateway as ip_address if hasattr(rp, 'ip_address'): # it means have allocated ip address in subnetmap, delete it ipaddress = ip4_addr(rp.ip_address) del snm.allocated_ips[str(ipaddress)] # one subnet only have one router , so del this attr if hasattr(sn, 'router'): delattr(sn, 'router') if rp.create_weakreference() in r.interfaces.dataset(): r.interfaces.dataset().discard( rp.create_weakreference()) else: raise ValueError("router " + interface["router"] + " have no router port " + interface["routerport"]) else: raise ValueError("route " + interface["router"] + " subnet " + interface["subnet"] + " routerport " + interface["routerport"] + " not existed!") return keys, robjs + snobjs + snmobjs + [None ] * len(routerportkeys)
def parse_ip4_network( network ): ip,f,prefix = network.rpartition('/') if not f or not prefix: raise ValueError('invalid cidr ' + network) if not 0 <= int(prefix) <= 32: raise ValueError("invalid prefix " + prefix) netmask = get_netmask(prefix) value = ip4_addr(ip) return value & netmask,int(prefix)
def parse_ip4_network( network ): ip,f,prefix = network.rpartition('/') if not f: raise ValueError('invalid cidr ' + prefix) if not 0 <= int(prefix) <= 32: raise ValueError("invalid prefix " + prefix) netmask = get_netmask(prefix) value = ip4_addr(ip) return value & netmask,int(prefix)
def removerouterinterface(keys,values): rkeys = keys[0:len(routerkeys)] robjs = values[0:len(routerkeys)] snkeys = keys[len(routerkeys):len(routerkeys) + len(subnetkeys)] snobjs = values[len(routerkeys):len(routerkeys) + len(subnetkeys)] snmkeys = keys[len(routerkeys) + len(subnetkeys):len(routerkeys) + len(subnetkeys) + len(subnetmapkeys)] snmobjs = values[len(routerkeys) + len(subnetkeys):len(routerkeys) + len(subnetmapkeys) + len(subnetmapkeys)] rportkeys = keys[len(routerkeys) + len(subnetkeys) + len(subnetmapkeys):] rportobjs = values[len(routerkeys) + len(subnetkeys) + len(subnetmapkeys):] # we get (routerkeys,routerobjs) on begin to get (router , subnet) attr # this is second get (routerkeys,routerobjs) , if (router,subnet) is different from last, Nothing can do! if [r.router.getkey() for r in routerportobjs] !=\ [r.router.getkey() if r is not None else None for r in rportobjs] and\ [r.subnet.getkey() for r in routerportobjs] !=\ [r.subnet.getkey() if r is not None else None for r in rportobjs]: raise ValueError(" conflict error, try again!") rdict = dict(zip(rkeys,robjs)) sndict = dict(zip(snkeys,zip(snobjs,snmobjs))) rportdict = dict(zip(rportkeys,rportobjs)) for interface in deleteinterfaces: routerobj = rdict[VRouter.default_key(interface['router'])] subnetobj,subnetmapobj = sndict[SubNet.default_key(interface['subnet'])] rportobj = rportdict[RouterPort.default_key(interface['id'])] if routerobj and subnetobj and subnetmapobj: # has not attr ip_address, means router port use subnet gateway as ip_address if hasattr(rportobj,'ip_address'): # it means have allocated ip address in subnetmap, delete it ipaddress = ip4_addr(rportobj.ip_address) del subnetmapobj.allocated_ips[str(ipaddress)] # one subnet only have one router , so del this attr if hasattr(subnetobj,'router'): delattr(subnetobj,'router') routerobj.interfaces.dataset().discard(rportobj.create_weakreference()) else: raise ValueError(" interface router " + interface['router']\ + "or subnet " + interface['subnet'] + "not existed") return keys,robjs + snobjs + snmobjs + [None] * len(routerportkeys)
async def ipam_releaseaddress(self, env, params): poolid = params['PoolID'] address = params['Address'] address = ip4_addr.formatter(ip4_addr(address)) def _updater(keys, values, timestamp): pool = values[0] if pool is None: return ((), ()) self._remove_staled_ips(pool, timestamp) if address in pool.reserved_ips: del pool.reserved_ips[address] return ((keys[0], ), (pool, )) await call_api( self, 'objectdb', 'transact', { 'keys': (IPAMReserve.default_key(poolid), ), 'updater': _updater, 'withtime': True }) env.outputjson({})
def __init__(self, parent): HttpHandler.__init__(self, parent.scheduler, False, parent.vhostbind) self._parent = parent self._logger = parent._logger self._macbase = uint64.create( create_binary(mac_addr_bytes(self._parent.mactemplate), 8)) cidrrange = parent.cidrrange try: subnet, mask = parse_ip4_network(cidrrange) if not (0 <= mask <= 24): raise ValueError except Exception: self._logger.warning( 'Invalid CIDR range: %r. Using default 10.0.0.0/8', cidrrange) subnet = ip4_addr('10.0.0.0') mask = 8 self.cidrrange_subnet = subnet self.cidrrange_mask = mask self.cidrrange_end = (1 << (24 - mask)) self.pooltimeout = parent.pooltimeout self.iptimeout = parent.iptimeout self._reqid = 0
def _create_dhcp_route(cidr, router): network, mask = parse_ip4_network(cidr) return dhcp_route(subnet = ip4_addr.tobytes(network), mask = mask, router = ip4_addr(router))
prepack = _prepack_dhcp_option, padding = 1 ) dhcp_option_single_byte = nstruct(name = 'dhcp_option_single_byte', base = dhcp_option, criteria = lambda x: x.tag in (OPTION_PAD, OPTION_END), init = packvalue(OPTION_PAD, 'tag')) dhcp_option_address = nstruct((ip4_addr, 'value'), name = 'dhcp_option_address', base = dhcp_option, criteria = lambda x: x.tag in (OPTION_NETMASK, OPTION_REQUESTED_IP, OPTION_SERVER_IDENTIFIER, OPTION_BROADCAST), init = packvalue(OPTION_NETMASK, 'tag')) dhcp_option_address._parse_from_value = lambda x: ip4_addr(x) dhcp_time_value = enum('dhcp_time_value', globals(), uint32, DHCPTIME_INFINITE = 0xffffffff ) dhcp_option_time = nstruct((dhcp_time_value, 'value'), name = 'dhcp_option_time', base = dhcp_option, criteria = lambda x: x.tag in (OPTION_TIME_OFFSET, OPTION_LEASE_TIME, OPTION_T1, OPTION_T2), init = packvalue(OPTION_LEASE_TIME, 'tag') ) dhcp_option_time._parse_from_value = lambda x: int(x) if x is not None and x != 'infinity' else DHCPTIME_INFINITE dhcp_option_servers = nstruct((ip4_addr[0], 'value'),
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)
def _get_ip(ip): try: return ip4_addr(ip) except Exception: return None
def createendpoint(self, env, params): lognet_id = 'docker-' + params['NetworkID'] + '-lognet' subnet_id = 'docker-' + params['NetworkID'] + '-subnet' logport_id = 'docker-' + params['EndpointID'] logport_params = {} if 'Options' in params: logport_params.update(params['Options']) logport_params['id'] = logport_id logport_params['logicalnetwork'] = lognet_id logport_params['subnet'] = subnet_id mac_address = None if 'Interface' in params: interface = params['Interface'] if 'Address' in interface and interface['Address']: ip, f, prefix = interface['Address'].partition('/') logport_params['ip_address'] = ip else: ip = None if 'MacAddress' in interface and interface['MacAddress']: logport_params['mac_address'] = interface['MacAddress'] mac_address = interface['MacAddress'] if mac_address is None: # Generate a MAC address if ip: # Generate MAC address based on IP address mac_num = self._macbase mac_num ^= ((hash(subnet_id) & 0xffffffff) << 8) mac_num ^= ip4_addr(ip) else: # Generate MAC address based on Port ID and random number mac_num = self._macbase mac_num ^= ((hash(logport_id) & 0xffffffff) << 8) mac_num ^= randint(0, 0xffffffff) mac_address = mac_addr_bytes.formatter(create_binary(mac_num, 6)) logport_params['mac_address'] = mac_address try: for m in callAPI(self, 'viperflow', 'createlogicalport', logport_params): yield m except Exception as exc: # There is an issue that docker daemon may not delete an endpoint correctly # If autoremoveports is enabled, we remove the logical port automatically # Note that created veth and Openvswitch ports are not cleared because they # may not on this server, so you must clean them yourself with vlcp_docker.cleanup if self._parent.autoremoveports: for m in callAPI(self, 'viperflow', 'listlogicalports', { 'logicalnetwork': lognet_id, 'ip_address': ip }): yield m if self.retvalue: if self.retvalue[0]['id'].startswith('docker-'): dup_pid = self.retvalue[0]['id'] self._logger.warning( 'Duplicated ports detected: %s (%s). Will remove it.', dup_pid, self.retvalue[0]['ip_address']) for m in callAPI(self, 'viperflow', 'deletelogicalport', {'id': dup_pid}): yield m # Retry create logical port for m in callAPI(self, 'viperflow', 'createlogicalport', logport_params): yield m else: self._logger.warning( 'Duplicated with a non-docker port') raise exc else: raise exc else: raise exc ip_address = self.retvalue[0]['ip_address'] subnet_cidr = self.retvalue[0]['subnet']['cidr'] mtu = self.retvalue[0]['network'].get('mtu', self._parent.mtu) _, _, prefix = subnet_cidr.partition('/') if 'docker_ipam_poolid' in self.retvalue[0]['subnet']: docker_ipam_poolid = self.retvalue[0]['subnet'][ 'docker_ipam_poolid'] def _remove_ip_reservation(): try: # The reservation is completed, remove the temporary reservation def _ipam_updater(keys, values, timestamp): pool = values[0] self._remove_staled_ips(pool, timestamp) if ip_address in pool.reserved_ips: del pool.reserved_ips[ip_address] return ((keys[0], ), (pool, )) for m in callAPI( self, 'objectdb', 'transact', { 'keys': (IPAMReserve.default_key(docker_ipam_poolid), ), 'updater': _ipam_updater, 'withtime': True }): yield m except Exception: self._logger.warning( 'Unexpected exception while removing reservation of IP address %r, will ignore and continue', ip_address, exc_info=True) self.subroutine(_remove_ip_reservation()) port_created = False try: for m in self._parent.taskpool.runTask( self, lambda: _create_veth(self._parent.ipcommand, self._parent. vethprefix, mac_address, mtu)): yield m port_created = True device_name, _ = self.retvalue info = DockerInfo.create_instance(logport_id) info.docker_port = device_name @updater def _updater(dockerinfo): dockerinfo = set_new(dockerinfo, info) return (dockerinfo, ) for m in callAPI(self, 'objectdb', 'transact', { 'keys': (info.getkey(), ), 'updater': _updater }): yield m for m in self._parent.taskpool.runTask( self, lambda: _plug_ovs(self._parent.ovscommand, self._parent. ovsbridge, device_name, logport_id)): yield m result = {'Interface': {'MacAddress': mac_address}} if 'Address' not in interface: result['Interface']['Address'] = ip_address + '/' + prefix env.outputjson(result) except Exception as exc: try: if port_created: for m in self._parent.taskpool.runTask( self, lambda: _delete_veth(self._parent.ipcommand, device_name)): yield m except Exception: pass try: for m in callAPI(self, 'viperflow', 'deletelogicalport', {'id': logport_id}): yield m except Exception: pass raise exc
def _updater(keys, values, timestamp): pool = values[0] if pool is None: raise ValueError('PoolID %r does not exist' % (poolid, )) self._remove_staled_ips(pool, timestamp) if len(values) > 1: subnetmap = values[1] if not hasattr( pool, 'subnetmap') or pool.subnetmap.getkey() != keys[1]: raise RetryUpdateException subnet = values[2] else: subnetmap = None if hasattr(pool, 'subnetmap'): raise RetryUpdateException if address: # check ip_address in cidr if address in pool.reserved_ips: raise ValueError("IP address " + address + " has been reserved") if pool.subpool: cidr = pool.subpool else: cidr = pool.pool network, mask = parse_ip4_network(cidr) addr_num = ip4_addr(address) if not ip_in_network(addr_num, network, mask): raise ValueError('IP address ' + address + " is not in the network CIDR") if subnetmap is not None: start = ip4_addr(subnet.allocated_start) end = ip4_addr(subnet.allocated_end) try: assert start <= addr_num <= end if hasattr(subnet, 'gateway'): assert addr_num != ip4_addr(subnet.gateway) except Exception: raise ValueError("specified IP address " + address + " is not valid") if str(addr_num) in subnetmap.allocated_ips: raise ValueError("IP address " + address + " has been used") new_address = address else: # allocated ip_address from cidr gateway = None cidr = pool.pool if pool.subpool: cidr = pool.subpool network, prefix = parse_ip4_network(cidr) start = network_first(network, prefix) end = network_last(network, prefix) if subnetmap is not None: start = max(start, ip4_addr(subnet.allocated_start)) end = min(end, ip4_addr(subnet.allocated_end)) if hasattr(subnet, "gateway"): gateway = ip4_addr(subnet.gateway) for ip_address in range(start, end): new_address = ip4_addr.formatter(ip_address) if ip_address != gateway and \ (subnetmap is None or str(ip_address) not in subnetmap.allocated_ips) and \ new_address not in pool.reserved_ips: break else: raise ValueError("No available IP address can be used") pool.reserved_ips[ new_address] = timestamp + self.iptimeout * 1000000 _, mask = parse_ip4_network(pool.pool) rets[:] = [new_address + '/' + str(mask)] return ((keys[0], ), (pool, ))
def ipam_requestaddress(self, env, params): poolid = params['PoolID'] address = params['Address'] if address: address = ip4_addr.formatter(ip4_addr(address)) reserve_key = IPAMReserve.default_key(poolid) rets = [] def _updater(keys, values, timestamp): pool = values[0] if pool is None: raise ValueError('PoolID %r does not exist' % (poolid, )) self._remove_staled_ips(pool, timestamp) if len(values) > 1: subnetmap = values[1] if not hasattr( pool, 'subnetmap') or pool.subnetmap.getkey() != keys[1]: raise RetryUpdateException subnet = values[2] else: subnetmap = None if hasattr(pool, 'subnetmap'): raise RetryUpdateException if address: # check ip_address in cidr if address in pool.reserved_ips: raise ValueError("IP address " + address + " has been reserved") if pool.subpool: cidr = pool.subpool else: cidr = pool.pool network, mask = parse_ip4_network(cidr) addr_num = ip4_addr(address) if not ip_in_network(addr_num, network, mask): raise ValueError('IP address ' + address + " is not in the network CIDR") if subnetmap is not None: start = ip4_addr(subnet.allocated_start) end = ip4_addr(subnet.allocated_end) try: assert start <= addr_num <= end if hasattr(subnet, 'gateway'): assert addr_num != ip4_addr(subnet.gateway) except Exception: raise ValueError("specified IP address " + address + " is not valid") if str(addr_num) in subnetmap.allocated_ips: raise ValueError("IP address " + address + " has been used") new_address = address else: # allocated ip_address from cidr gateway = None cidr = pool.pool if pool.subpool: cidr = pool.subpool network, prefix = parse_ip4_network(cidr) start = network_first(network, prefix) end = network_last(network, prefix) if subnetmap is not None: start = max(start, ip4_addr(subnet.allocated_start)) end = min(end, ip4_addr(subnet.allocated_end)) if hasattr(subnet, "gateway"): gateway = ip4_addr(subnet.gateway) for ip_address in range(start, end): new_address = ip4_addr.formatter(ip_address) if ip_address != gateway and \ (subnetmap is None or str(ip_address) not in subnetmap.allocated_ips) and \ new_address not in pool.reserved_ips: break else: raise ValueError("No available IP address can be used") pool.reserved_ips[ new_address] = timestamp + self.iptimeout * 1000000 _, mask = parse_ip4_network(pool.pool) rets[:] = [new_address + '/' + str(mask)] return ((keys[0], ), (pool, )) while True: # First get the current data, to determine that whether the pool has already # been connected to a network self._reqid += 1 reqid = ('dockerplugin_ipam', self._reqid) for m in callAPI(self, 'objectdb', 'get', { 'key': reserve_key, 'requestid': reqid, 'nostale': True }): yield m reserve_pool = self.retvalue with watch_context([reserve_key], [reserve_pool], reqid, self): if reserve_pool is None or reserve_pool.isdeleted(): raise ValueError('PoolID %r does not exist' % (poolid, )) if hasattr(reserve_pool, 'subnetmap'): # Retrieve both the reserve pool and the subnet map keys = (reserve_key, reserve_pool.subnetmap.getkey(), SubNet.default_key(reserve_pool.subnetmap.id)) else: keys = (reserve_key, ) try: for m in callAPI(self, 'objectdb', 'transact', { 'keys': keys, 'updater': _updater, 'withtime': True }): yield m except RetryUpdateException: continue else: env.outputjson({'Address': rets[0], 'Data': {}}) break
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)
def parse_ip4_address(address): return ip4_addr(address)
def addrouterinterface(keys, values): rkeys = keys[0:len(routerkeys)] robjs = values[0:len(routerkeys)] snkeys = keys[len(routerkeys):len(routerkeys) + len(subnetkeys)] snobjs = values[len(routerkeys):len(routerkeys) + len(subnetkeys)] snmkeys = keys[len(routerkeys) + len(subnetkeys):len(routerkeys) + len(subnetkeys) + len(subnetmapkeys)] snmobjs = values[len(routerkeys) + len(subnetkeys):len(routerkeys) + len(subnetkeys) + len(subnetmapkeys)] rpkeys = keys[len(routerkeys) + len(subnetkeys) + len(subnetmapkeys):] rpobjs = values[len(routerkeys) + len(subnetkeys) + len(subnetmapkeys):] rdict = dict(zip(rkeys, robjs)) sndict = dict(zip(snkeys, zip(snobjs, snmobjs))) rpdict = dict(zip(rpkeys, rpobjs)) for i, interface in enumerate(newinterfaces): routerport = interface['id'] router = interface['router'] subnet = interface['subnet'] routerobj = rdict.get(VRouter.default_key(router)) subnetobj, subnetmapobj = sndict.get( SubNet.default_key(subnet)) newrouterport = newrouterportdict.get( RouterPort.default_key(routerport)) routerport = rpdict.get(RouterPort.default_key(routerport)) if routerobj and subnetobj and subnetmapobj: # now subnet only have one router ,,so check it if not hasattr(subnetobj, 'router'): # new router port special ip address , we check it in subnetmap if hasattr(newrouterport, "ip_address"): ipaddress = ip4_addr(newrouterport.ip_address) n, p = parse_ip4_network(subnetobj.cidr) if not ip_in_network(ipaddress, n, p): raise ValueError( " special ip address not in subnet cidr") if str(ipaddress ) not in subnetmapobj.allocated_ips: subnetmapobj.allocated_ips[str( ipaddress )] = newrouterport.create_weakreference() else: raise ValueError( " ip address have used in subnet " + newrouterport.ip_address) else: # not have special ip address, special gateway to this only router port # gateway in subnet existed be sure # # when this case , special subnet gateway as ip_address # but we do not set ip_address attr , when subnet gateway change , # we do not need to change router port attr #setattr(newrouterport,"ip_address",subnetobj.gateway) # it may be subnet not have gateway, checkout it if not hasattr(subnetobj, "gateway"): raise ValueError( " interface not special ip_address and subnet has no gateway" ) #routerport = set_new(routerport,newrouterport) values[len(routerkeys) + len(subnetkeys) + len(subnetmapkeys) + i] = set_new( values[len(routerkeys) + len(subnetkeys) + len(subnetmapkeys) + i], routerportobjects[i]) subnetobj.router = newrouterport.create_weakreference() routerobj.interfaces.dataset().add( newrouterport.create_weakreference()) else: raise ValueError(" subnet " + subnet + " have router port " + subnetobj.router.getkey()) else: raise ValueError(" routerobj " + router + "or subnetobj " + subnet + " not existed ") return keys, values
def createendpoint(self, env, params): lognet_id = 'docker-' + params['NetworkID'] + '-lognet' subnet_id = 'docker-' + params['NetworkID'] + '-subnet' logport_id = 'docker-' + params['EndpointID'] logport_params = {} if 'Options' in params: logport_params.update(params['Options']) logport_params['id'] = logport_id logport_params['logicalnetwork'] = lognet_id logport_params['subnet'] = subnet_id mac_address = None if 'Interface' in params: interface = params['Interface'] if 'Address' in interface and interface['Address']: ip, f, prefix = interface['Address'].rpartition('/') logport_params['ip_address'] = ip else: ip = None if 'MacAddress' in interface and interface['MacAddress']: logport_params['mac_address'] = interface['MacAddress'] mac_address = interface['MacAddress'] if mac_address is None: # Generate a MAC address if ip: # Generate MAC address based on IP address mac_num = self._macbase mac_num ^= ((hash(subnet_id) & 0xffffffff) << 8) mac_num ^= ip4_addr(ip) else: # Generate MAC address based on Port ID and random number mac_num = self._macbase mac_num ^= ((hash(logport_id) & 0xffffffff) << 8) mac_num ^= randint(0, 0xffffffff) mac_address = mac_addr_bytes.formatter(create_binary(mac_num, 6)) logport_params['mac_address'] = mac_address for m in callAPI(self, 'viperflow', 'createlogicalport', logport_params): yield m ip_address = self.retvalue[0]['ip_address'] subnet_cidr = self.retvalue[0]['subnet']['cidr'] mtu = self.retvalue[0]['network'].get('mtu', self._parent.mtu) _, _, prefix = subnet_cidr.partition('/') port_created = False try: for m in self._parent.taskpool.runTask( self, lambda: _create_veth(self._parent.ipcommand, self._parent. vethprefix, mac_address, mtu)): yield m port_created = True device_name, _ = self.retvalue info = DockerInfo.create_instance(logport_id) info.docker_port = device_name @updater def _updater(dockerinfo): dockerinfo = set_new(dockerinfo, info) return (dockerinfo, ) for m in callAPI(self, 'objectdb', 'transact', { 'keys': (info.getkey(), ), 'updater': _updater }): yield m for m in self._parent.taskpool.runTask( self, lambda: _plug_ovs(self._parent.ovscommand, self._parent. ovsbridge, device_name, logport_id)): yield m result = {'Interface': {'MacAddress': mac_address}} if 'Address' not in interface: result['Interface']['Address'] = ip_address + '/' + prefix env.outputjson(result) except Exception as exc: try: if port_created: for m in self._parent.taskpool.runTask( self, lambda: _delete_veth(self._parent.ipcommand, device_name)): yield m except Exception: pass try: for m in callAPI(self, 'viperflow', 'deletelogicalport', {'id': logport_id}): yield m except Exception: pass raise exc
def walker(walk, write, timestamp): with suppress(WalkKeyNotRetrieved): pool = walk(reserve_key) if pool is None: raise ValueError('PoolID %r does not exist' % (poolid, )) self._remove_staled_ips(pool, timestamp) if hasattr(pool, 'subnetmap'): subnetmap_key = pool.subnetmap.getkey() subnet_key = SubNetMap._subnet.rightkey(subnetmap_key) ensure_keys(walk, subnet_key, subnetmap_key) subnetmap = walk(subnetmap_key) subnet = walk(subnet_key) else: subnetmap = None subnet = None if address: # check ip_address in cidr if address in pool.reserved_ips: raise ValueError("IP address " + address + " has been reserved") if pool.subpool: cidr = pool.subpool else: cidr = pool.pool network, mask = parse_ip4_network(cidr) addr_num = ip4_addr(address) if not ip_in_network(addr_num, network, mask): raise ValueError('IP address ' + address + " is not in the network CIDR") if subnetmap is not None: start = ip4_addr(subnet.allocated_start) end = ip4_addr(subnet.allocated_end) try: assert start <= addr_num <= end if hasattr(subnet, 'gateway'): assert addr_num != ip4_addr(subnet.gateway) except Exception: raise ValueError("specified IP address " + address + " is not valid") if str(addr_num) in subnetmap.allocated_ips: raise ValueError("IP address " + address + " has been used") new_address = address else: # allocated ip_address from cidr gateway = None cidr = pool.pool if pool.subpool: cidr = pool.subpool network, prefix = parse_ip4_network(cidr) start = network_first(network, prefix) end = network_last(network, prefix) if subnetmap is not None: start = max(start, ip4_addr(subnet.allocated_start)) end = min(end, ip4_addr(subnet.allocated_end)) if hasattr(subnet, "gateway"): gateway = ip4_addr(subnet.gateway) for ip_address in range(start, end): new_address = ip4_addr.formatter(ip_address) if ip_address != gateway and \ (subnetmap is None or str(ip_address) not in subnetmap.allocated_ips) and \ new_address not in pool.reserved_ips: break else: raise ValueError("No available IP address can be used") pool.reserved_ips[ new_address] = timestamp + self.iptimeout * 1000000 _, mask = parse_ip4_network(pool.pool) rets[:] = [new_address + '/' + str(mask)] write(pool.getkey(), pool)