import string #untrusted meminfo size is taken from xenstore key, thus its size is limited #so splits do not require excessive memory def parse_meminfo(untrusted_meminfo): untrusted_dict = {} #split meminfo contents into lines untrusted_lines = string.split(untrusted_meminfo,"\n") for untrusted_lines_iterator in untrusted_lines: #split a single meminfo line into words untrusted_words = string.split(untrusted_lines_iterator) if len(untrusted_words) >= 2: untrusted_dict[string.rstrip(untrusted_words[0], ":")] = untrusted_words[1] return untrusted_dict def is_meminfo_suspicious(domain, untrusted_meminfo): ret = False #check whether the required keys exist and are not negative try: for i in ('MemTotal', 'MemFree', 'Buffers', 'Cached', 'SwapTotal', 'SwapFree'): val = int(untrusted_meminfo[i])*1024 if (val < 0): ret = True untrusted_meminfo[i] = val except: ret = True if not ret and untrusted_meminfo['SwapTotal'] < untrusted_meminfo['SwapFree']: ret = True if not ret and untrusted_meminfo['MemTotal'] < untrusted_meminfo['MemFree'] + untrusted_meminfo['Cached'] + untrusted_meminfo['Buffers']: ret = True #we could also impose some limits on all the above values #but it has little purpose - all the domain can gain by passing e.g. #very large SwapTotal is that it will be assigned all free Xen memory #it can be achieved with legal values, too, and it will not allow to #starve existing domains, by design if ret: print 'suspicious meminfo for domain', domain.id, 'mem actual', domain.memory_actual, untrusted_meminfo return ret #called when a domain updates its 'meminfo' xenstore key def refresh_meminfo_for_domain(domain, untrusted_xenstore_key): untrusted_meminfo = parse_meminfo(untrusted_xenstore_key) if untrusted_meminfo is None: domain.meminfo = None return #sanitize start if is_meminfo_suspicious(domain, untrusted_meminfo): #sanitize end domain.meminfo = None domain.mem_used = None else: #sanitized, can assign domain.meminfo = untrusted_meminfo domain.mem_used = domain.meminfo['MemTotal'] - domain.meminfo['MemFree'] - domain.meminfo['Cached'] - domain.meminfo['Buffers'] + domain.meminfo['SwapTotal'] - domain.meminfo['SwapFree'] def prefmem(domain): CACHE_FACTOR = 1.3 #dom0 is special, as it must have large cache, for vbds. Thus, give it a special boost if domain.id == '0': return domain.mem_used*CACHE_FACTOR + 350*1024*1024 return domain.mem_used*CACHE_FACTOR def memory_needed(domain): #do not change #in balance(), "distribute total_available_memory proportionally to mempref" relies on this exact formula ret = prefmem(domain) - domain.memory_actual return ret #prepare list of (domain, memory_target) pairs that need to be passed #to "xm memset" equivalent in order to obtain "memsize" of memory #return empty list when the request cannot be satisfied def balloon(memsize, domain_dictionary): REQ_SAFETY_NET_FACTOR = 1.05 donors = list() request = list() available = 0 for i in domain_dictionary.keys(): if domain_dictionary[i].meminfo is None: continue if domain_dictionary[i].no_progress: continue need = memory_needed(domain_dictionary[i]) if need < 0: print 'balloon: dom' , i, 'has actual memory', domain_dictionary[i].memory_actual donors.append((i,-need)) available-=need print 'req=', memsize, 'avail=', available, 'donors', donors if available