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(dom, 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', dom.id, 'mem actual', dom.memory_actual, untrusted_meminfo return ret def refresh_meminfo_for_domain(dom, untrusted_xenstore_key): untrusted_meminfo = parse_meminfo(untrusted_xenstore_key) if untrusted_meminfo is None: dom.meminfo = None return #sanitize start if is_meminfo_suspicious(dom, untrusted_meminfo): #sanitize end dom.meminfo = None dom.mem_used = None else: #sanitized, can assign dom.meminfo = untrusted_meminfo dom.mem_used = dom.meminfo['MemTotal'] - dom.meminfo['MemFree'] - dom.meminfo['Cached'] - dom.meminfo['Buffers'] + dom.meminfo['SwapTotal'] - dom.meminfo['SwapFree'] def prefmem(dom): CACHE_FACTOR = 1.3 #dom0 is special, as it must have large cache, for vbds. Thus, give it a special boost if dom.id == '0': return dom.mem_used*CACHE_FACTOR + 350*1024*1024 return dom.mem_used*CACHE_FACTOR def memneeded(dom): #do not change #in balance(), "distribute totalsum proportionally to mempref" relies on this exact formula ret = prefmem(dom) - dom.memory_actual return ret def balloon(memsize, domdict): REQ_SAFETY_NET_FACTOR = 1.05 donors = list() request = list() available = 0 for i in domdict.keys(): if domdict[i].meminfo is None: continue if domdict[i].no_progress: continue need = memneeded(domdict[i]) if need < 0: print 'balloon: dom' , i, 'has actual memory', domdict[i].memory_actual donors.append((i,-need)) available-=need print 'req=', memsize, 'avail=', available, 'donors', donors if available