def walker(walk, write): for key, parameters in parameter_dict.items(): with suppress(WalkKeyNotRetrieved): value = walk(key) value = create_new(RouterPort, value, parameters['id']) subnet = walk(SubNet.default_key(parameters['subnet'])) if subnet is None: raise ValueError("Subnet " + parameters['subnet'] + " not exists") subnet_map = walk(SubNetMap.default_key(parameters['subnet'])) router = walk(VRouter.default_key(parameters['router'])) if router is None: raise ValueError("Virtual router " + parameters['router'] + " not exists") if hasattr(subnet, 'router'): # normal subnet can only have one router _, (rid,) = VRouter._getIndices(subnet.router.getkey()) raise ValueError("Subnet %r is already in virtual router %r", parameters['subnet'], rid) if hasattr(subnet_map, 'routers'): if router.create_weakreference() in subnet_map.routers.dataset(): raise ValueError("Subnet %r is already in virtual router %r", parameters['subnet'], parameters['router']) if 'ip_address' in parameters: if getattr(subnet, 'isexternal', False): raise ValueError("Cannot specify IP address when add external subnet to virtual router") # Check IP address in CIDR nip = parse_ip4_address(parameters['ip_address']) cidr, prefix = parse_ip4_network(subnet.cidr) if not ip_in_network(nip, cidr, prefix): raise ValueError("IP address " + parameters['ip_address'] + " not in subnet CIDR") # Check IP not allocated if str(nip) in subnet_map.allocated_ips: raise ValueError("IP address " + parameters['ip_address'] + " has been used") else: # Save to allocated map subnet_map.allocated_ips[str(nip)] = (value.create_weakreference(), router.create_weakreference()) write(subnet_map.getkey(), subnet_map) else: # Use gateway if not hasattr(subnet, 'gateway'): raise ValueError("Subnet " + subnet.id + " does not have a gateway, IP address on router port must be specified explicitly") if not hasattr(subnet_map, 'routers'): subnet_map.routers = DataObjectSet() subnet_map.routers.dataset().add(router.create_weakreference()) if not hasattr(subnet_map, 'routerports'): subnet_map.routerports = {} subnet_map.routerports[router.id] = value.create_weakreference() write(subnet_map.getkey(), subnet_map) if not getattr(subnet, 'isexternal', False): subnet.router = value.create_weakreference() write(subnet.getkey(), subnet) # Save port to router router.interfaces.dataset().add(value.create_weakreference()) write(router.getkey(), router) value.router = router.create_reference() value.subnet = subnet.create_reference() for k, v in parameters.items(): if k not in ('router', 'subnet', 'id'): setattr(value, k, v) write(key, value)
def updatevirtualrouters(self, routers): "Update multiple virtual routers" idset = set() for router in routers: if 'id' not in router: raise ValueError(" must specify id") else: if router['id'] in idset: raise ValueError(" id repeat " + router['id']) else: idset.add(router['id']) # if routers updating ,, check format if 'routes' in router: for r in router['routes']: ip_prefix = r[0] nexthop = r[1] if ip_prefix and nexthop: ip_prefix = parse_ip4_network(ip_prefix) nexthop = check_ip_address(nexthop) else: raise ValueError("routes format error " + r) routerkeys = [VRouter.default_key(r['id']) for r in routers] def updaterouter(keys, values): for i in range(0, len(routers)): if values[i]: for k, v in routers[i].items(): if k == 'routes': # update routers accord new static routes values[i].routes = [] for pn in v: values[i].routes.append(pn) else: setattr(values[i], k, v) else: raise ValueError("router object not exists " + routers[i]['id']) return keys, values try: for m in callAPI(self.app_routine, 'objectdb', 'transact', { 'keys': routerkeys, 'updater': updaterouter }): yield m except: raise else: for m in self._dumpkeys(routerkeys): yield m
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))
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 _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_requestpool(self, env, params): if params['AddressSpace'] != _GLOBAL_SPACE: raise ValueError( 'Unsupported address space: must use this IPAM driver together with network driver' ) if params['V6']: raise ValueError('IPv6 is not supported') new_pool = IPAMReserve.create_instance(uuid1().hex) new_pool.pool = params['Pool'] if new_pool.pool: subnet, mask = parse_ip4_network(new_pool.pool) new_pool.pool = ip4_addr.formatter(subnet) + '/' + str(mask) new_pool.subpool = params['SubPool'] if new_pool.subpool: subnet, mask = parse_ip4_network(new_pool.subpool) new_pool.subpool = ip4_addr.formatter(subnet) + '/' + str(mask) new_pool.options = params['Options'] if new_pool.pool: l = Lock(('dockerplugin_ipam_request_pool', new_pool.pool), self.scheduler) for m in l.lock(self): yield m else: l = None try: while True: fail = 0 rets = [] def _updater(keys, values, timestamp): reservepool = values[0] reserve_new_pool = set_new(values[1], new_pool) remove_keys = self._remove_staled_pools( reservepool, timestamp) used_cidrs = set( cidr for _, (cidr, _) in reservepool.reserved_pools.items()) if not reserve_new_pool.pool: # pool is not specified for _ in range(0, self.cidrrange_end): reservepool.nextalloc += 1 if reservepool.nextalloc >= self.cidrrange_end: reservepool.nextalloc = 0 new_subnet = self.cidrrange_subnet | ( reservepool.nextalloc << 8) new_cidr = ip4_addr.formatter(new_subnet) + '/24' if new_cidr not in used_cidrs: break reserve_new_pool.pool = new_cidr reserve_new_pool.subpool = '' rets[:] = [reserve_new_pool.pool] if reserve_new_pool.pool in used_cidrs: # We must wait until this CIDR is released raise IPAMUsingException reservepool.reserved_pools[reserve_new_pool.id] = \ [reserve_new_pool.pool, timestamp + self.pooltimeout * 1000000] marker = IPAMReserveMarker.create_instance( reserve_new_pool.pool) if marker.getkey() in remove_keys: remove_keys.remove(marker.getkey()) return (tuple(keys[0:2]) + tuple(remove_keys), (reservepool, reserve_new_pool) + (None, ) * len(remove_keys)) else: return (tuple(keys[0:2]) + (marker.getkey(), ) + tuple(remove_keys), (reservepool, reserve_new_pool, marker) + (None, ) * len(remove_keys)) try: for m in callAPI( self, 'objectdb', 'transact', { 'keys': (IPAMPoolReserve.default_key(), new_pool.getkey()), 'updater': _updater, 'withtime': True }): yield m except IPAMUsingException: # Wait for the CIDR to be released self._reqid += 1 fail += 1 reqid = ('dockerplugin_ipam', self._reqid) marker_key = IPAMReserveMarker.default_key(rets[0]) for m in callAPI(self, 'objectdb', 'get', { 'key': marker_key, 'requestid': reqid, 'nostale': True }): yield m retvalue = self.retvalue with watch_context([marker_key], [retvalue], reqid, self): if retvalue is not None and not retvalue.isdeleted(): for m in self.executeWithTimeout( self.pooltimeout, retvalue.waitif(self, lambda x: x.isdeleted())): yield m else: env.outputjson({ 'PoolID': new_pool.id, 'Pool': rets[0], 'Data': {} }) break finally: if l is not None: l.unlock()
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 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)
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)