Package net.floodlightcontroller.staticflowentry

Source Code of net.floodlightcontroller.staticflowentry.StaticFlowTests

/**
*    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.staticflowentry;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;


import org.easymock.Capture;
import org.easymock.CaptureType;
import org.junit.Test;
import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFMatch;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPort;
import org.openflow.protocol.action.OFAction;
import org.openflow.protocol.action.OFActionOutput;
import org.openflow.protocol.action.OFActionStripVirtualLan;
import org.openflow.util.HexString;


import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.test.MockFloodlightProvider;
import net.floodlightcontroller.test.FloodlightTestCase;
import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.restserver.RestApiServer;
import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher;
import net.floodlightcontroller.storage.IStorageSourceService;
import net.floodlightcontroller.storage.memory.MemoryStorageSource;
import static net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher.*;
import static org.easymock.EasyMock.*;

public class StaticFlowTests extends FloodlightTestCase {

    static String TestSwitch1DPID = "00:00:00:00:00:00:00:01";
    static int TotalTestRules = 3;

    /***
     * Create TestRuleXXX and the corresponding FlowModXXX
     * for X = 1..3
     */
    static Map<String,Object> TestRule1;
    static OFFlowMod FlowMod1;
    static {
        FlowMod1 = new OFFlowMod();
        TestRule1 = new HashMap<String,Object>();
        TestRule1.put(COLUMN_NAME, "TestRule1");
        TestRule1.put(COLUMN_SWITCH, TestSwitch1DPID);
        // setup match
        OFMatch match = new OFMatch();
        TestRule1.put(COLUMN_DL_DST, "00:20:30:40:50:60");
        match.fromString("dl_dst=00:20:30:40:50:60");
        // setup actions
        List<OFAction> actions = new LinkedList<OFAction>();
        TestRule1.put(COLUMN_ACTIONS, "output=1");
        actions.add(new OFActionOutput((short)1, Short.MAX_VALUE));
        // done
        FlowMod1.setMatch(match);
        FlowMod1.setActions(actions);
        FlowMod1.setBufferId(-1);
        FlowMod1.setOutPort(OFPort.OFPP_NONE.getValue());
        FlowMod1.setPriority(Short.MAX_VALUE);
        FlowMod1.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8)// 8 bytes of actions
    }

    static Map<String,Object> TestRule2;
    static OFFlowMod FlowMod2;

    static {
        FlowMod2 = new OFFlowMod();
        TestRule2 = new HashMap<String,Object>();
        TestRule2.put(COLUMN_NAME, "TestRule2");
        TestRule2.put(COLUMN_SWITCH, TestSwitch1DPID);
        // setup match
        OFMatch match = new OFMatch();
        TestRule2.put(COLUMN_NW_DST, "192.168.1.0/24");
        match.fromString("nw_dst=192.168.1.0/24");
        // setup actions
        List<OFAction> actions = new LinkedList<OFAction>();
        TestRule2.put(COLUMN_ACTIONS, "output=1");
        actions.add(new OFActionOutput((short)1, Short.MAX_VALUE));
        // done
        FlowMod2.setMatch(match);
        FlowMod2.setActions(actions);
        FlowMod2.setBufferId(-1);
        FlowMod2.setOutPort(OFPort.OFPP_NONE.getValue());
        FlowMod2.setPriority(Short.MAX_VALUE);
        FlowMod2.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8)// 8 bytes of actions

    }


    static Map<String,Object> TestRule3;
    static OFFlowMod FlowMod3;
    private StaticFlowEntryPusher staticFlowEntryPusher;
    private IOFSwitch mockSwitch;
    private Capture<OFMessage> writeCapture;
    private Capture<FloodlightContext> contextCapture;
    private Capture<List<OFMessage>> writeCaptureList;
    private long dpid;
    private IStorageSourceService storage;
    static {
        FlowMod3 = new OFFlowMod();
        TestRule3 = new HashMap<String,Object>();
        TestRule3.put(COLUMN_NAME, "TestRule3");
        TestRule3.put(COLUMN_SWITCH, TestSwitch1DPID);
        // setup match
        OFMatch match = new OFMatch();
        TestRule3.put(COLUMN_DL_DST, "00:20:30:40:50:60");
        TestRule3.put(COLUMN_DL_VLAN, 4096);
        match.fromString("dl_dst=00:20:30:40:50:60,dl_vlan=4096");
        // setup actions
        TestRule3.put(COLUMN_ACTIONS, "output=controller");
        List<OFAction> actions = new LinkedList<OFAction>();
        actions.add(new OFActionOutput(OFPort.OFPP_CONTROLLER.getValue(), Short.MAX_VALUE));
        // done
        FlowMod3.setMatch(match);
        FlowMod3.setActions(actions);
        FlowMod3.setBufferId(-1);
        FlowMod3.setOutPort(OFPort.OFPP_NONE.getValue());
        FlowMod3.setPriority(Short.MAX_VALUE);
        FlowMod3.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8)// 8 bytes of actions

    }

    private void verifyFlowMod(OFFlowMod testFlowMod,
            OFFlowMod goodFlowMod) {
        verifyMatch(testFlowMod, goodFlowMod);
        verifyActions(testFlowMod, goodFlowMod);
        // dont' bother testing the cookie; just copy it over
        goodFlowMod.setCookie(testFlowMod.getCookie());
        // .. so we can continue to use .equals()
        assertEquals(goodFlowMod, testFlowMod);
    }


    private void verifyMatch(OFFlowMod testFlowMod, OFFlowMod goodFlowMod) {
        assertEquals(goodFlowMod.getMatch(), testFlowMod.getMatch());
    }


    private void verifyActions(OFFlowMod testFlowMod, OFFlowMod goodFlowMod) {
        List<OFAction> goodActions = goodFlowMod.getActions();
        List<OFAction> testActions = testFlowMod.getActions();
        assertNotNull(goodActions);
        assertNotNull(testActions);
        assertEquals(goodActions.size(), testActions.size());
        // assumes actions are marshalled in same order; should be safe
        for(int i = 0; i < goodActions.size(); i++) {
            assertEquals(goodActions.get(i), testActions.get(i));
        }

    }


    @Override
    public void setUp() throws Exception {
        super.setUp();
        staticFlowEntryPusher = new StaticFlowEntryPusher();
        storage = createStorageWithFlowEntries();
        dpid = HexString.toLong(TestSwitch1DPID);

        mockSwitch = createNiceMock(IOFSwitch.class);
        writeCapture = new Capture<OFMessage>(CaptureType.ALL);
        contextCapture = new Capture<FloodlightContext>(CaptureType.ALL);
        writeCaptureList = new Capture<List<OFMessage>>(CaptureType.ALL);

        //OFMessageSafeOutStream mockOutStream = createNiceMock(OFMessageSafeOutStream.class);
        mockSwitch.write(capture(writeCapture), capture(contextCapture));
        expectLastCall().anyTimes();
        mockSwitch.write(capture(writeCaptureList), capture(contextCapture));
        expectLastCall().anyTimes();
        mockSwitch.flush();
        expectLastCall().anyTimes();


        FloodlightModuleContext fmc = new FloodlightModuleContext();
        fmc.addService(IStorageSourceService.class, storage);

        MockFloodlightProvider mockFloodlightProvider = getMockFloodlightProvider();
        Map<Long, IOFSwitch> switchMap = new HashMap<Long, IOFSwitch>();
        switchMap.put(dpid, mockSwitch);
        // NO ! expect(mockFloodlightProvider.getSwitches()).andReturn(switchMap).anyTimes();
        mockFloodlightProvider.setSwitches(switchMap);
        fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider);
        RestApiServer restApi = new RestApiServer();
        fmc.addService(IRestApiService.class, restApi);
        restApi.init(fmc);
        staticFlowEntryPusher.init(fmc);
        staticFlowEntryPusher.startUp(fmc);    // again, to hack unittest
    }

    @Test
    public void testStaticFlowPush() throws Exception {

        // verify that flowpusher read all three entries from storage
        assertEquals(TotalTestRules, staticFlowEntryPusher.countEntries());

        // if someone calls mockSwitch.getOutputStream(), return mockOutStream instead
        //expect(mockSwitch.getOutputStream()).andReturn(mockOutStream).anyTimes();

        // if someone calls getId(), return this dpid instead
        expect(mockSwitch.getId()).andReturn(dpid).anyTimes();
        expect(mockSwitch.getStringId()).andReturn(TestSwitch1DPID).anyTimes();
        replay(mockSwitch);

        // hook the static pusher up to the fake switch
        staticFlowEntryPusher.switchAdded(dpid);

        verify(mockSwitch);

        // Verify that the switch has gotten some flow_mods
        assertEquals(true, writeCapture.hasCaptured());
        assertEquals(TotalTestRules, writeCapture.getValues().size());

        // Order assumes how things are stored in hash bucket;
        // should be fixed because OFMessage.hashCode() is deterministic
        OFFlowMod firstFlowMod = (OFFlowMod) writeCapture.getValues().get(2);
        verifyFlowMod(firstFlowMod, FlowMod1);
        OFFlowMod secondFlowMod = (OFFlowMod) writeCapture.getValues().get(1);
        verifyFlowMod(secondFlowMod, FlowMod2);
        OFFlowMod thirdFlowMod = (OFFlowMod) writeCapture.getValues().get(0);
        verifyFlowMod(thirdFlowMod, FlowMod3);

        writeCapture.reset();
        contextCapture.reset();


        // delete two rules and verify they've been removed
        // this should invoke staticFlowPusher.rowsDeleted()
        storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule1");
        storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule2");

        assertEquals(1, staticFlowEntryPusher.countEntries());
        assertEquals(2, writeCapture.getValues().size());

        OFFlowMod firstDelete = (OFFlowMod) writeCapture.getValues().get(0);
        FlowMod1.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
        verifyFlowMod(firstDelete, FlowMod1);

        OFFlowMod secondDelete = (OFFlowMod) writeCapture.getValues().get(1);
        FlowMod2.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
        verifyFlowMod(secondDelete, FlowMod2);

        // add rules back to make sure that staticFlowPusher.rowsInserted() works
        writeCapture.reset();
        FlowMod2.setCommand(OFFlowMod.OFPFC_ADD);
        storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule2);
        assertEquals(2, staticFlowEntryPusher.countEntries());
        assertEquals(1, writeCaptureList.getValues().size());
        List<OFMessage> outList =
            writeCaptureList.getValues().get(0);
        assertEquals(1, outList.size());
        OFFlowMod firstAdd = (OFFlowMod) outList.get(0);
        verifyFlowMod(firstAdd, FlowMod2);
        writeCapture.reset();
        contextCapture.reset();
        writeCaptureList.reset();

        // now try an overwriting update, calling staticFlowPusher.rowUpdated()
        TestRule3.put(COLUMN_DL_VLAN, 333);
        storage.updateRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3);
        assertEquals(2, staticFlowEntryPusher.countEntries());
        assertEquals(1, writeCaptureList.getValues().size());

        outList = writeCaptureList.getValues().get(0);
        assertEquals(2, outList.size());
        OFFlowMod removeFlowMod = (OFFlowMod) outList.get(0);
        FlowMod3.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
        verifyFlowMod(removeFlowMod, FlowMod3);
        FlowMod3.setCommand(OFFlowMod.OFPFC_ADD);
        FlowMod3.getMatch().fromString("dl_dst=00:20:30:40:50:60,dl_vlan=333");
        OFFlowMod updateFlowMod = (OFFlowMod) outList.get(1);
        verifyFlowMod(updateFlowMod, FlowMod3);
        writeCaptureList.reset();

        // now try an action modifying update, calling staticFlowPusher.rowUpdated()
        TestRule3.put(COLUMN_ACTIONS, "output=controller,strip-vlan"); // added strip-vlan
        storage.updateRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3);
        assertEquals(2, staticFlowEntryPusher.countEntries());
        assertEquals(1, writeCaptureList.getValues().size());

        outList = writeCaptureList.getValues().get(0);
        assertEquals(1, outList.size());
        OFFlowMod modifyFlowMod = (OFFlowMod) outList.get(0);
        FlowMod3.setCommand(OFFlowMod.OFPFC_MODIFY_STRICT);
        List<OFAction> modifiedActions = FlowMod3.getActions();
        modifiedActions.add(new OFActionStripVirtualLan()); // add the new action to what we should expect
        FlowMod3.setActions(modifiedActions);
        FlowMod3.setLengthU(OFFlowMod.MINIMUM_LENGTH + 16); // accommodate the addition of new actions
        verifyFlowMod(modifyFlowMod, FlowMod3);

    }


    IStorageSourceService createStorageWithFlowEntries() {
        return populateStorageWithFlowEntries(new MemoryStorageSource());
    }

    IStorageSourceService populateStorageWithFlowEntries(IStorageSourceService storage) {
        Set<String> indexedColumns = new HashSet<String>();
        indexedColumns.add(COLUMN_NAME);
        storage.createTable(StaticFlowEntryPusher.TABLE_NAME, indexedColumns);
        storage.setTablePrimaryKeyName(StaticFlowEntryPusher.TABLE_NAME, COLUMN_NAME);

        storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule1);
        storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule2);
        storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3);

        return storage;
    }

    @Test
    public void testHARoleChanged() throws IOException {

        assert(staticFlowEntryPusher.entry2dpid.containsValue(TestSwitch1DPID));
        assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod1));
        assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod2));
        assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod3));

        /* FIXME: what's the right behavior here ??
        // Send a notification that we've changed to slave
        mfp.dispatchRoleChanged(Role.SLAVE);
        // Make sure we've removed all our entries
        assert(staticFlowEntryPusher.entry2dpid.isEmpty());
        assert(staticFlowEntryPusher.entriesFromStorage.isEmpty());

        // Send a notification that we've changed to master
        mfp.dispatchRoleChanged(Role.MASTER);
        // Make sure we've learned the entries
        assert(staticFlowEntryPusher.entry2dpid.containsValue(TestSwitch1DPID));
        assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod1));
        assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod2));
        assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod3));
        */
    }
}
TOP

Related Classes of net.floodlightcontroller.staticflowentry.StaticFlowTests

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.