Package net.floodlightcontroller.flowcache

Source Code of net.floodlightcontroller.flowcache.FlowReconcileMgrTest$FlowReconcileWorker

/**
*    Copyright 2013, Big Switch Networks, Inc.
*
*    Licensed under the Apache License, Version 2.0 (the "License"); you may
*    not use this file except in compliance with the License. You may obtain
*    a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
*    Unless required by applicable law or agreed to in writing, software
*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
*    License for the specific language governing permissions and limitations
*    under the License.
**/

package net.floodlightcontroller.flowcache;

import static org.easymock.EasyMock.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.ListIterator;

import net.floodlightcontroller.core.IListener.Command;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.test.MockThreadPoolService;
import net.floodlightcontroller.counter.ICounterStoreService;
import net.floodlightcontroller.counter.SimpleCounter;
import net.floodlightcontroller.counter.CounterValue.CounterType;
import net.floodlightcontroller.flowcache.IFlowReconcileListener;
import net.floodlightcontroller.flowcache.OFMatchReconcile;
import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority;
import net.floodlightcontroller.test.FloodlightTestCase;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import org.junit.Before;
import org.junit.Test;
import org.openflow.protocol.OFStatisticsRequest;
import org.openflow.protocol.OFType;

public class FlowReconcileMgrTest extends FloodlightTestCase {

    protected FlowReconcileManager flowReconcileMgr;
    protected MockThreadPoolService threadPool;
    protected ICounterStoreService counterStore;
    protected FloodlightModuleContext fmc;
   
    OFStatisticsRequest ofStatsRequest;

    protected int NUM_FLOWS_PER_THREAD = 100;
    protected int NUM_THREADS = 20;
   
    @Before
    public void setUp() throws Exception {
        super.setUp();

        fmc = new FloodlightModuleContext();
        flowReconcileMgr = new FlowReconcileManager();
        threadPool = new MockThreadPoolService();
        counterStore = createMock(ICounterStoreService.class);
       
        fmc.addService(ICounterStoreService.class, counterStore);
        fmc.addService(IThreadPoolService.class, threadPool);
       
        threadPool.init(fmc);
        flowReconcileMgr.init(fmc);

        threadPool.startUp(fmc);
        flowReconcileMgr.startUp(fmc);
    }

    /** Verify pipeline listener registration and ordering
     *
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    @Test
    public void testFlowReconcilePipeLine() throws Exception {
        flowReconcileMgr.flowReconcileEnabled = true;
   
        IFlowReconcileListener r1 =
            EasyMock.createNiceMock(IFlowReconcileListener.class);
        IFlowReconcileListener r2 =
            EasyMock.createNiceMock(IFlowReconcileListener.class);
        IFlowReconcileListener r3 =
            EasyMock.createNiceMock(IFlowReconcileListener.class);
       
        expect(r1.getName()).andReturn("r1").anyTimes();
        expect(r2.getName()).andReturn("r2").anyTimes();
        expect(r3.getName()).andReturn("r3").anyTimes();
       
        // Set the listeners' order: r1 -> r2 -> r3
        expect(r1.isCallbackOrderingPrereq((OFType)anyObject(),
            (String)anyObject())).andReturn(false).anyTimes();
        expect(r1.isCallbackOrderingPostreq((OFType)anyObject(),
            (String)anyObject())).andReturn(false).anyTimes();
        expect(r2.isCallbackOrderingPrereq((OFType)anyObject(),
            eq("r1"))).andReturn(true).anyTimes();
        expect(r2.isCallbackOrderingPrereq((OFType)anyObject(),
            eq("r3"))).andReturn(false).anyTimes();
        expect(r2.isCallbackOrderingPostreq((OFType)anyObject(),
            eq("r1"))).andReturn(false).anyTimes();
        expect(r2.isCallbackOrderingPostreq((OFType)anyObject(),
            eq("r3"))).andReturn(true).anyTimes();
        expect(r3.isCallbackOrderingPrereq((OFType)anyObject(),
            eq("r1"))).andReturn(false).anyTimes();
        expect(r3.isCallbackOrderingPrereq((OFType)anyObject(),
            eq("r2"))).andReturn(true).anyTimes();
        expect(r3.isCallbackOrderingPostreq((OFType)anyObject(),
            (String)anyObject())).andReturn(false).anyTimes();
       
        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).
                  andThrow(new RuntimeException("This is NOT an error! " +
                            "We are testing exception catching."));
       
        SimpleCounter cnt = (SimpleCounter)SimpleCounter.createCounter(
                            new Date(),
                            CounterType.LONG);
        cnt.increment();
        expect(counterStore.getCounter(
                flowReconcileMgr.controllerPktInCounterName))
                .andReturn(cnt)
                .anyTimes();
       
        replay(r1, r2, r3, counterStore);
        flowReconcileMgr.clearFlowReconcileListeners();
        flowReconcileMgr.addFlowReconcileListener(r1);
        flowReconcileMgr.addFlowReconcileListener(r2);
        flowReconcileMgr.addFlowReconcileListener(r3);
       
        int pre_flowReconcileThreadRunCount =
                flowReconcileMgr.flowReconcileThreadRunCount.get();
        Date startTime = new Date();
        OFMatchReconcile ofmRcIn = new OFMatchReconcile();
        try {
            flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH);
            flowReconcileMgr.doReconcile();
        } catch (RuntimeException e) {
            assertEquals(e.getMessage()
                .startsWith("This is NOT an error!"), true);
        }
       
        verify(r1, r2, r3);

        // verify STOP works
        reset(r1, r2, r3);
       
        // restart reconcileThread since it exited due to previous runtime
        // exception.
        flowReconcileMgr.startUp(fmc);
        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
        .andReturn(Command.STOP).times(1);
        expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()));
        expectLastCall().andAnswer(new IAnswer<Object>() {
            public Object answer() {
                fail("Unexpected call");
                return Command.STOP;
            }
        }).anyTimes();
       
        pre_flowReconcileThreadRunCount =
            flowReconcileMgr.flowReconcileThreadRunCount.get();
        startTime = new Date();
        replay(r1, r2, r3);
        flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH);
        while (flowReconcileMgr.flowReconcileThreadRunCount.get() <=
                pre_flowReconcileThreadRunCount) {
            Thread.sleep(10);
            Date currTime = new Date();
            assertTrue((currTime.getTime() - startTime.getTime()) < 1000);
        }
        verify(r1, r2, r3);
       
        // verify CONTINUE works
        reset(r1, r2, r3);
        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
        .andReturn(Command.CONTINUE).times(1);
        expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
        .andReturn(Command.STOP).times(1);
        expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()));
        expectLastCall().andAnswer(new IAnswer<Object>() {
            public Object answer() {
                fail("Unexpected call");
                return Command.STOP;
            }
        }).anyTimes();
       
        pre_flowReconcileThreadRunCount =
            flowReconcileMgr.flowReconcileThreadRunCount.get();
        startTime = new Date();
       
        replay(r1, r2, r3);
        flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH);
        while (flowReconcileMgr.flowReconcileThreadRunCount.get() <=
                pre_flowReconcileThreadRunCount) {
            Thread.sleep(10);
            Date currTime = new Date();
            assertTrue((currTime.getTime() - startTime.getTime()) < 1000);
        }
        verify(r1, r2, r3);
       
        // verify CONTINUE works
        reset(r1, r2, r3);
        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
        .andReturn(Command.CONTINUE).times(1);
        expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
        .andReturn(Command.CONTINUE).times(1);
        expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
        .andReturn(Command.STOP).times(1);
       
        pre_flowReconcileThreadRunCount =
            flowReconcileMgr.flowReconcileThreadRunCount.get();
        startTime = new Date();
       
        replay(r1, r2, r3);
        flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH);
        while (flowReconcileMgr.flowReconcileThreadRunCount.get() <=
                pre_flowReconcileThreadRunCount) {
            Thread.sleep(10);
            Date currTime = new Date();
            assertTrue((currTime.getTime() - startTime.getTime()) < 1000);
        }
        verify(r1, r2, r3);
       
        // Verify removeFlowReconcileListener
        flowReconcileMgr.removeFlowReconcileListener(r1);
        reset(r1, r2, r3);
        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()));
        expectLastCall().andAnswer(new IAnswer<Object>() {
            public Object answer() {
                fail("Unexpected call to a listener that is " +
                        "removed from the chain.");
                return Command.STOP;
            }
        }).anyTimes();
        expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
        .andReturn(Command.CONTINUE).times(1);
        expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
        .andReturn(Command.STOP).times(1);
       
        pre_flowReconcileThreadRunCount =
            flowReconcileMgr.flowReconcileThreadRunCount.get();
        startTime = new Date();
        replay(r1, r2, r3);
        flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH);
        while (flowReconcileMgr.flowReconcileThreadRunCount.get() <=
                pre_flowReconcileThreadRunCount) {
            Thread.sleep(10);
            Date currTime = new Date();
            assertTrue((currTime.getTime() - startTime.getTime()) < 1000);
        }
        verify(r1, r2, r3);
    }
   
    @Test
    public void testGetPktInRate() {
        internalTestGetPktInRate(CounterType.LONG);
        internalTestGetPktInRate(CounterType.DOUBLE);
    }
   
    protected void internalTestGetPktInRate(CounterType type) {
        Date currentTime = new Date();
        SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter(
                                currentTime, type);
        newCnt.increment(currentTime, 1);
   
        // Set the lastCounter time in the future of the current time
        Date lastCounterTime = new Date(currentTime.getTime() + 1000);
        flowReconcileMgr.lastPacketInCounter =
                (SimpleCounter)SimpleCounter.createCounter(
                    lastCounterTime, type);
        flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1);
   
        assertEquals(FlowReconcileManager.MAX_SYSTEM_LOAD_PER_SECOND,
                flowReconcileMgr.getPktInRate(newCnt, new Date()));
   
        // Verify the rate == 0 time difference is zero.
        lastCounterTime = new Date(currentTime.getTime() - 1000);
        flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1);
        assertEquals(0, flowReconcileMgr.getPktInRate(newCnt, lastCounterTime));
   
        /** verify the computation is correct.
         *  new = 2000, old = 1000, Tdiff = 1 second.
         *  rate should be 1000/second
         */
        newCnt = (SimpleCounter)SimpleCounter.createCounter(
                currentTime, type);
        newCnt.increment(currentTime, 2000);
   
        lastCounterTime = new Date(currentTime.getTime() - 1000);
        flowReconcileMgr.lastPacketInCounter =
                (SimpleCounter)SimpleCounter.createCounter(
                    lastCounterTime, type);
        flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1000);
        assertEquals(1000, flowReconcileMgr.getPktInRate(newCnt, currentTime));
   
        /** verify the computation is correct.
         *  new = 2,000,000, old = 1,000,000, Tdiff = 2 second.
         *  rate should be 1000/second
         */
        newCnt = (SimpleCounter)SimpleCounter.createCounter(
                currentTime, type);
        newCnt.increment(currentTime, 2000000);
   
        lastCounterTime = new Date(currentTime.getTime() - 2000);
        flowReconcileMgr.lastPacketInCounter =
                (SimpleCounter)SimpleCounter.createCounter(
                    lastCounterTime, type);
        flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime,
                1000000);
        assertEquals(500000, flowReconcileMgr.getPktInRate(newCnt,
                    currentTime));
    }
   
    @Test
    public void testGetCurrentCapacity() throws Exception {
        // Disable the reconcile thread.
        flowReconcileMgr.flowReconcileEnabled = false;
   
        int minFlows = FlowReconcileManager.MIN_FLOW_RECONCILE_PER_SECOND *
                FlowReconcileManager.FLOW_RECONCILE_DELAY_MILLISEC / 1000;
   
        /** Verify the initial state, when packetIn counter has not
         *  been created.
         */
        expect(counterStore.getCounter(
                flowReconcileMgr.controllerPktInCounterName))
        .andReturn(null)
        .times(1);
   
        replay(counterStore);
        assertEquals(minFlows, flowReconcileMgr.getCurrentCapacity());
        verify(counterStore);
   
        /** Verify the initial state, when lastPacketInCounter is null */
        reset(counterStore);
        Date currentTime = new Date();
        SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter(
                        currentTime, CounterType.LONG);
   
        expect(counterStore.getCounter(
            flowReconcileMgr.controllerPktInCounterName))
        .andReturn(newCnt)
        .times(1);
        long initPktInCount = 1000;
        newCnt.increment(currentTime, initPktInCount);
   
        replay(counterStore);
        assertEquals(minFlows, flowReconcileMgr.getCurrentCapacity());
        verify(counterStore);
   
        /** Now the lastPacketInCounter has been set.
         *  lastCounter = 1,000 and newCounter = 3,000, t = 1 second
         *  packetInRate = 2,000/sec.
         *  capacity should be 10k - 2k = 8k
         */
        reset(counterStore);
        newCnt = (SimpleCounter)SimpleCounter.createCounter(
                    currentTime, CounterType.LONG);
        currentTime = new Date(currentTime.getTime() + 200);
        long nextPktInCount = 3000;
        newCnt.increment(currentTime, nextPktInCount);
   
        expect(counterStore.getCounter(
                flowReconcileMgr.controllerPktInCounterName))
        .andReturn(newCnt)
        .times(1);
   
        replay(counterStore);
        // Wait for 1 second so that enough elapsed time to compute capacity.
        Thread.sleep(1000);
        int capacity = flowReconcileMgr.getCurrentCapacity();
        verify(counterStore);
        long expectedCap = (FlowReconcileManager.MAX_SYSTEM_LOAD_PER_SECOND -
                (nextPktInCount - initPktInCount)) *
                FlowReconcileManager.FLOW_RECONCILE_DELAY_MILLISEC / 1000;
        assertEquals(expectedCap, capacity);
    }
   
    /** Verify the flows are sent to the reconcile pipeline in order.
     */
    @SuppressWarnings("unchecked")
    @Test
    public void testQueueFlowsOrder() {
        flowReconcileMgr.flowReconcileEnabled = false;
       
        IFlowReconcileListener r1 =
            EasyMock.createNiceMock(IFlowReconcileListener.class);
       
        expect(r1.getName()).andReturn("r1").anyTimes();
       
        // Set the listeners' order: r1 -> r2 -> r3
        expect(r1.isCallbackOrderingPrereq((OFType)anyObject(),
            (String)anyObject())).andReturn(false).anyTimes();
        expect(r1.isCallbackOrderingPostreq((OFType)anyObject(),
            (String)anyObject())).andReturn(false).anyTimes();
       
        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
        .andAnswer(new IAnswer<Command>() {
            @Override
            public Command answer() throws Throwable {
                ArrayList<OFMatchReconcile> ofmList =
                    (ArrayList<OFMatchReconcile>)EasyMock.
                        getCurrentArguments()[0];
                ListIterator<OFMatchReconcile> lit = ofmList.listIterator();
                int index = 0;
                while (lit.hasNext()) {
                    OFMatchReconcile ofm = lit.next();
                    assertEquals(index++, ofm.cookie);
                }
                return Command.STOP;
            }
        }).times(1);
       
        SimpleCounter cnt = (SimpleCounter)SimpleCounter.createCounter(
                            new Date(),
                            CounterType.LONG);
        cnt.increment();
        expect(counterStore.getCounter(
                flowReconcileMgr.controllerPktInCounterName))
                .andReturn(cnt)
                .anyTimes();
       
        replay(r1, counterStore);
        flowReconcileMgr.clearFlowReconcileListeners();
        flowReconcileMgr.addFlowReconcileListener(r1);
       
        OFMatchReconcile ofmRcIn = new OFMatchReconcile();
        int index = 0;
        for (index = 0; index < 10; index++) {
            ofmRcIn.cookie = index;
            flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH);
        }
        flowReconcileMgr.flowReconcileEnabled = true;
        flowReconcileMgr.doReconcile();
       
        verify(r1);
    }
   
    @SuppressWarnings("unchecked")
    @Test
    public void testQueueFlowsByManyThreads() {
        // Disable the reconcile thread so that the queue won't be emptied.
        flowQueueTest(false);
   
        // Enable the reconcile thread. The queue should be empty.
        Date currentTime = new Date();
        SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter(
                    currentTime, CounterType.LONG);
   
        expect(counterStore.getCounter(
                    flowReconcileMgr.controllerPktInCounterName))
        .andReturn(newCnt)
        .anyTimes();
        long initPktInCount = 10000;
        newCnt.increment(currentTime, initPktInCount);
   
        IFlowReconcileListener r1 =
                EasyMock.createNiceMock(IFlowReconcileListener.class);
       
        expect(r1.getName()).andReturn("r1").anyTimes();
       
        // Set the listeners' order: r1 -> r2 -> r3
        expect(r1.isCallbackOrderingPrereq((OFType)anyObject(),
                (String)anyObject())).andReturn(false).anyTimes();
        expect(r1.isCallbackOrderingPostreq((OFType)anyObject(),
                (String)anyObject())).andReturn(false).anyTimes();
       
        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
        .andReturn(Command.CONTINUE).anyTimes();
       
        flowReconcileMgr.clearFlowReconcileListeners();
        replay(r1, counterStore);
        flowQueueTest(true);
        verify(r1, counterStore);
    }
   
    protected void flowQueueTest(boolean enableReconcileThread) {
        flowReconcileMgr.flowReconcileEnabled = enableReconcileThread;
   
        // Simulate flow
        for (int i = 0; i < NUM_THREADS; i++) {
            Runnable worker = this.new FlowReconcileWorker();
            Thread t = new Thread(worker);
            t.start();
        }
   
        Date startTime = new Date();
        int totalFlows = NUM_THREADS * NUM_FLOWS_PER_THREAD;
        if (enableReconcileThread) {
            totalFlows = 0;
        }
        while (flowReconcileMgr.flowQueue.size() != totalFlows) {
            Date currTime = new Date();
            assertTrue((currTime.getTime() - startTime.getTime()) < 1000);
        }

        // Make sure all flows are in the queue.
        assertEquals(totalFlows, flowReconcileMgr.flowQueue.size());
    }
   
    private class FlowReconcileWorker implements Runnable {
    @Override
        public void run() {
            OFMatchReconcile ofmRc = new OFMatchReconcile();
            // push large number of flows to be reconciled.
            for (int i = 0; i < NUM_FLOWS_PER_THREAD; i++) {
                flowReconcileMgr.reconcileFlow(ofmRc,EventPriority.LOW);
            }
        }
    }
}
TOP

Related Classes of net.floodlightcontroller.flowcache.FlowReconcileMgrTest$FlowReconcileWorker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.