• No results found

Host-based Execution-graph Construction (HEC) Algorithm

CHAPTER 4 ARTICLE 1: "VIRTFLOW: GUEST INDEPENDENT EXECUTION

5.5 VM Analysis Algorithms

5.5.3 Host-based Execution-graph Construction (HEC) Algorithm

We compute the critical path of an execution using the Host-based Execution-graph Con- struction (HEC) Algorithm. The input to the algorithm is the trace events and the output is the processes dependency graph. In addition, the algorithm outputs the critical path of the process executions, characterized by process id, starting timestamp, ending time-stamp, and segments status. The status could be running (at a certain level of code execution), preempted (in different levels), and wait for OS (block device, network or timer).

The HEC algorithm is presented in Algorithm 8. Here again, error handling is not shown and the data structures are shown for one VM per host. However, the algorithm can detect and find processes dependencies for any number of VMs per host. The execution graph data structure is a two-dimensional doubly linked list, where the horizontal links are the start and end of task states, and the vertical edges represent wake-up signals between processes. The algorithm first initializes the state of running processes by creating a vertex for the process with a time-stamp for the beginning of the trace (Line 7). Then, the algorithm iterates over the events and generates new vertices according to their types. The sched_switch event adds one more new edges for previous processes, as running in the host hypervisor level, to the graph (Line 13). Then, the algorithm checks if the last exit for the previous process is hlt or not (Line 16). In the case where hlt was the last exit state, the process was blocked for reasons other than preemption. If the process was preempted, the vm_entry event adds

one new edge for the process as preempted to the graph (Line 22). Otherwise, a new edge is added for the process as running in the host hypervisor level. When receiving a vm_exit event, a new horizontal link is added to the previous process based on the code execution level. The sched_ttwu event sets the waker and wakee processes to be used later when processing a inj_virq event (Line 34). The inj_virq event adds vertical and horizontal edges based on the IRQ number. If the IRQ number matches IPI, a vertical edge would be added from waker to wakee (Line 42). In addition, it adds two new horizontal edges to the graph, one for the waker that is blocked (Line 40), and the other for the wakee that is running (Line 41). When the IRQ number is equal to Timer interrupt, Disk interrupt, or Network interrupt, an horizontal edge is added as Timer (Line 44), and Disk (Line 46), respectively. When receiving inet_sock_local_in and inet_sock_local_out events, the algorithm finds the matched packet and adds a vertical link between the sender and receiver of the packet(Line 47-52). The complexity of the HEC algorithm is O(n), where n is the number of events in the trace.

To find the active path of execution for a process inside the VM, all blocking edges are replaced by their corresponding processes. We use the Active Path Computation algorithm proposed in [87] to compute the active path of execution. The Active Path of Execution (APE) algorithm starts with the start vertex and traverses the graph recursively .

To get a better understanding of how the HEC algorithm works, a simple example is provided. Figure 5.5-a presents the execution graph of processes inside a VM, based on events from Table 5.1. It shows the horizontal links between different states of the processes. In order to find the active path of each process, we use the APE algorithm. Figure 5.5-a depicts the full dependency graph for all the processes in different VMs. Figure 5.5-b shows the active path for process #1. As shown, the process waits for the timer during interval [12-94] and then it executes again. The active path for process #4 is presented in Figure 5.5-c. As shown, process #4 waits for disk and then runs from time 15 to 22. Then, it waits for a timer to fire. The first interesting active path is shown in Figure 5.5-d for process #2 where it waits for process #3 during interval [0-50]. As a result, the active path of process #2 includes process #3. Actually, it is shown that process #3 was blocked for a network packet. When receiving the packet, it wakes up process #2. The active path for process #3 is presented in 5.5-e. Process #3 waits for a network packet and executes for time interval [23-45]. Then, it waits for a timer to be fired. Finally, the second interesting active path is depicted in Figure 5.5-f where VM2 process #1 waits for Nested-VM1,→process #2 and Nested-VM1,→ process #3.

Algorithm 8: Host-based Execution-graph Construction (HEC) Algorithm

Input : Trace T

Output: Execution Graph G

1 Initialization

2 PROCESS ←− {inital CR3}

3 for all process p ∈ P ROCESS do

4 if p.state is running then

5 vcpu = get_vcpu(p.tid); 6 set_vcpu(vcpu, p.cr3);

7 Create initial vertex of process p with timestamp T .begin

8 hec:sock:out Main Procedure

9 for all event e ∈ T do

10 if (e.type is sched_switch) then

11 j = getVMvCPU(e.prev_tid); 12 pCR3 = getLastCR3(vCP Uj); 13 LINK_HORIZONTAL(pCR3, e.ts, L0); 14 k = getVMvCPU(e.next_tid); 15 lExit = getLastExit(vCP Uk); 16 if lExit != hlt then 17 updateCR3Status(pCR3, preempted);

18 else if (e.type is vm_entry) then

19 j = getVMvCPU(e.tid);

20 pCR3 = getLastCR3(vCP Uj);

21 if (queryCR3Status(e.cr3) == preempted) then

22 LINK_HORIZONTAL(e.cr3, e.ts, PREEMPTED);

23 else

24 LINK_HORIZONTAL(e.cr3, e.ts, L0);

25 else if (e.type is vm_exit) then 26 j = getVMvCPU(e.tid);

27 pCR3 = getLastCR3(vCP Uj);

28 levelState = queryLastLevel(vCP Uj);

29 LINK_HORIZONTAL(pCR3, e.ts, levelState);

30 else if (e.type is sched_ttwu) then

31 j = getVMvCPU(e.wakee_tid);

32 k = getVMvCPU(e.waker_tid); 33 wakerCR3= getLastCR3(vCP Uk);

34 updateWaker(vCP Uj, wakerCR3);

35 else if (e.type is inj_virq) then 36 j = getVMvCPU(e.tid);

37 pCR3 = getVMvCPU(vCP Uj);

38 if (e.irq is IPI) then

39 wakerCR3 = queryWaker(vCP Uj);

40 V1←− LINK_HORIZONTAL (wakerCR3, e.ts, BLOCKED);

41 V2←− LINK_HORIZONTAL (pCR3, e.ts, L0);

42 LINK_VERTICAL(V1, V2, TASK);

43 else if (e.irq is timer) then

44 LINK_HORIZONTAL (pCR3, e.ts, TIMER);

45 else if (e.irq is disk) then

46 LINK_HORIZONTAL (pCR3, e.ts, DISK);

47 else if (e.type is inet_sock_local_in) then

48 tx ←− LINK_HORIZONTAL (pCR3, e.ts, L0);

49 else if (e.type is inet_sock_local_out) then

50 if (packet match found) then

51 rx ←− LINK_HORIZONTAL (pCR3, e.ts, L0);

Figure 5.5 Example of Execution Graph based on events from Table 5.1