/*
* Copyright (c) 2013 Big Switch Networks, Inc.
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html
*
* 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 org.sdnplatform.devicemanager.internal;
import static org.easymock.EasyMock.*;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.easymock.IAnswer;
import org.junit.Before;
import org.junit.Test;
import org.openflow.protocol.OFFeaturesReply;
import org.openflow.protocol.OFPhysicalPort;
import org.openflow.util.HexString;
import org.sdnplatform.core.IControllerService;
import org.sdnplatform.core.IOFSwitch;
import org.sdnplatform.core.module.ModuleContext;
import org.sdnplatform.core.test.MockThreadPoolService;
import org.sdnplatform.devicemanager.IDeviceService;
import org.sdnplatform.devicemanager.IEntityClass;
import org.sdnplatform.devicemanager.IEntityClassifierService;
import org.sdnplatform.devicemanager.internal.BetterDeviceManagerImpl;
import org.sdnplatform.devicemanager.internal.DefaultEntityClassifier;
import org.sdnplatform.devicemanager.internal.Entity;
import org.sdnplatform.devicemanager.internal.EntityConfig;
import org.sdnplatform.flowcache.FlowReconcileManager;
import org.sdnplatform.flowcache.IFlowReconcileService;
import org.sdnplatform.packet.Ethernet;
import org.sdnplatform.packet.IPv4;
import org.sdnplatform.restserver.IRestApiService;
import org.sdnplatform.restserver.RestApiServer;
import org.sdnplatform.storage.IResultSet;
import org.sdnplatform.storage.IStorageSourceService;
import org.sdnplatform.storage.OperatorPredicate;
import org.sdnplatform.storage.memory.MemoryStorageSource;
import org.sdnplatform.tagmanager.ITagListener;
import org.sdnplatform.tagmanager.Tag;
import org.sdnplatform.tagmanager.TagDoesNotExistException;
import org.sdnplatform.tagmanager.TagManagerException;
import org.sdnplatform.test.PlatformTestCase;
import org.sdnplatform.threadpool.IThreadPoolService;
import org.sdnplatform.topology.ITopologyService;
@SuppressWarnings("unchecked")
public class BetterDeviceManagerTest extends PlatformTestCase {
private BetterDeviceManagerImpl betterDeviceManager;
ITopologyService topology;
MemoryStorageSource storageSource;
FlowReconcileManager flowReconcileMgr;
private static class TagManagerTest {
ArrayList<Map<String, Object>> m_tags =
new ArrayList<Map<String, Object>>();
ArrayList<Map<String, Object>> m_tagEntityMappings =
new ArrayList<Map<String, Object>>();
public void addTag(Map<String, Object>... tags) {
for (Map<String, Object> tag : tags) {
m_tags.add(tag);
}
}
public void addEntityTagMappings(Map<String, Object>... tagMappings) {
for (Map<String, Object> mapping : tagMappings) {
m_tagEntityMappings.add(mapping);
}
}
public void writeToStorageTags(IStorageSourceService storageSource) {
for (Map<String, Object> row : m_tags) {
storageSource.insertRow(BetterDeviceManagerImpl.TAG_TABLE_NAME,
row);
}
}
public void writeToStorageEntityMappings(
IStorageSourceService storageSource) {
for (Map<String, Object> row : m_tagEntityMappings) {
storageSource.insertRow(
BetterDeviceManagerImpl.TAGMAPPING_TABLE_NAME,
row);
}
}
}
// in our service insertion OUI
protected static byte[] vMAC = Ethernet.toMACAddress("5C:16:C7:01:DE:AD");
protected static int vIP = IPv4.toIPv4Address("192.168.1.3");
protected static byte[] snMAC = Ethernet.toMACAddress("00:44:44:22:11:00");
protected static int snIP = IPv4.toIPv4Address("192.168.1.11");
private static final Map<String, Object> tag1;
static {
tag1 = new HashMap<String, Object>();
tag1.put(BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME,
"sdnplatform.org|tag1Name|tag1Value");
tag1.put(BetterDeviceManagerImpl.TAG_NAMESPACE_COLUMN_NAME,
"sdnplatform.org");
tag1.put(BetterDeviceManagerImpl.TAG_NAME_COLUMN_NAME, "tag1Name");
tag1.put(BetterDeviceManagerImpl.TAG_VALUE_COLUMN_NAME, "tag1Value");
}
private static final Map<String, Object> tag1Mapping;
static {
tag1Mapping = new HashMap<String, Object>();
tag1Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME,
"sdnplatform.org|tag1Name|tag1Value|00:00:00:00:00:01|10|" +
"00:00:00:00:00:00:00:01|eth1");
tag1Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_TAG_COLUMN_NAME,
"sdnplatform.org|tag1Name|tag1Value");
tag1Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_MAC_COLUMN_NAME,
"00:00:00:00:00:01");
tag1Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_VLAN_COLUMN_NAME,
"10");
tag1Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_SWITCH_COLUMN_NAME,
"00:00:00:00:00:00:00:01");
tag1Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_INTERFACE_COLUMN_NAME,
"eth1");
}
private static final Map<String, Object> tag2;
static {
tag2 = new HashMap<String, Object>();
tag2.put(BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME,
"sdnplatform.org|tag2Name|tag2Value");
tag2.put(BetterDeviceManagerImpl.TAG_NAMESPACE_COLUMN_NAME,
"sdnplatform.org");
tag2.put(BetterDeviceManagerImpl.TAG_NAME_COLUMN_NAME, "tag2Name");
tag2.put(BetterDeviceManagerImpl.TAG_VALUE_COLUMN_NAME, "tag2Value");
}
private static final Map<String, Object> tag2Mapping;
static {
tag2Mapping = new HashMap<String, Object>();
tag2Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME,
"sdnplatform.org|tag2Name|tag2Value|00:00:00:00:00:02|null|null|null");
tag2Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_TAG_COLUMN_NAME,
"sdnplatform.org|tag2Name|tag2Value");
tag2Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_MAC_COLUMN_NAME,
"00:00:00:00:00:02");
tag2Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_VLAN_COLUMN_NAME, null);
tag2Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_SWITCH_COLUMN_NAME,
null);
tag2Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_INTERFACE_COLUMN_NAME,
null);
}
private static final Map<String, Object> tag3;
static {
tag3 = new HashMap<String, Object>();
tag3.put(BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME,
"sdnplatform.org|tag3Name|tag3Value");
tag3.put(BetterDeviceManagerImpl.TAG_NAMESPACE_COLUMN_NAME,
"sdnplatform.org");
tag3.put(BetterDeviceManagerImpl.TAG_NAME_COLUMN_NAME, "tag3Name");
tag3.put(BetterDeviceManagerImpl.TAG_VALUE_COLUMN_NAME, "tag3Value");
}
private static final Map<String, Object> tag3Mapping;
static {
tag3Mapping = new HashMap<String, Object>();
tag3Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME,
"sdnplatform.org|tag3Name|tag3Value|null|15|null|null");
tag3Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_TAG_COLUMN_NAME,
"sdnplatform.org|tag3Name|tag3Value");
tag3Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_MAC_COLUMN_NAME, null);
tag3Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_VLAN_COLUMN_NAME, "15");
tag3Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_SWITCH_COLUMN_NAME,
null);
tag3Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_INTERFACE_COLUMN_NAME,
null);
}
private static final Map<String, Object> tag4;
static {
tag4 = new HashMap<String, Object>();
tag4.put(BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME,
"sdnplatform.org|tag4Name|tag4Value");
tag4.put(BetterDeviceManagerImpl.TAG_NAMESPACE_COLUMN_NAME,
"sdnplatform.org");
tag4.put(BetterDeviceManagerImpl.TAG_NAME_COLUMN_NAME, "tag4Name");
tag4.put(BetterDeviceManagerImpl.TAG_VALUE_COLUMN_NAME, "tag4Value");
}
private static final Map<String, Object> tag4Mapping;
static {
tag4Mapping = new HashMap<String, Object>();
tag4Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME,
"sdnplatform.org|tag4Name|tag4Value|null|null|00:00:00:00:00:00:00:02|null");
tag4Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_TAG_COLUMN_NAME,
"sdnplatform.org|tag4Name|tag4Value");
tag4Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_MAC_COLUMN_NAME, null);
tag4Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_VLAN_COLUMN_NAME, null);
tag4Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_SWITCH_COLUMN_NAME,
"00:00:00:00:00:00:00:02");
tag4Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_INTERFACE_COLUMN_NAME,
null);
}
private static final Map<String, Object> tag5;
static {
tag5 = new HashMap<String, Object>();
tag5.put(BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME,
"sdnplatform.org|tag5Name|tag5Value");
tag5.put(BetterDeviceManagerImpl.TAG_NAMESPACE_COLUMN_NAME,
"sdnplatform.org");
tag5.put(BetterDeviceManagerImpl.TAG_NAME_COLUMN_NAME, "tag5Name");
tag5.put(BetterDeviceManagerImpl.TAG_VALUE_COLUMN_NAME, "tag5Value");
}
private static final Map<String, Object> tag5Mapping;
static {
tag5Mapping = new HashMap<String, Object>();
tag5Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME,
"sdnplatform.org|tag5Name|tag5Value|null|null|00:00:00:00:00:00:00:03|eth2");
tag5Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_TAG_COLUMN_NAME,
"sdnplatform.org|tag5Name|tag5Value");
tag5Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_MAC_COLUMN_NAME, null);
tag5Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_VLAN_COLUMN_NAME, null);
tag5Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_SWITCH_COLUMN_NAME,
"00:00:00:00:00:00:00:03");
tag5Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_INTERFACE_COLUMN_NAME,
"eth2");
}
private static final Map<String, Object> tag6;
static {
tag6 = new HashMap<String, Object>();
tag6.put(BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME,
"sdnplatform.org|tag6Name|tag6Value");
tag6.put(BetterDeviceManagerImpl.TAG_NAMESPACE_COLUMN_NAME,
"sdnplatform.org");
tag6.put(BetterDeviceManagerImpl.TAG_NAME_COLUMN_NAME, "tag6Name");
tag6.put(BetterDeviceManagerImpl.TAG_VALUE_COLUMN_NAME, "tag6Value");
}
private static final Map<String, Object> tag6Mapping;
static {
tag6Mapping = new HashMap<String, Object>();
tag6Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME,
"sdnplatform.org|tag6Name|tag6Value|null|20|00:00:00:00:00:00:00:04|eth3");
tag6Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_TAG_COLUMN_NAME,
"sdnplatform.org|tag6Name|tag6Value");
tag6Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_MAC_COLUMN_NAME, null);
tag6Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_VLAN_COLUMN_NAME, "20");
tag6Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_SWITCH_COLUMN_NAME,
"00:00:00:00:00:00:00:04");
tag6Mapping.put(BetterDeviceManagerImpl.TAGMAPPING_INTERFACE_COLUMN_NAME,
"eth3");
}
private static final TagManagerTest oneTagTest;
static {
oneTagTest = new TagManagerTest();
oneTagTest.addTag(tag1);
oneTagTest.addEntityTagMappings(tag1Mapping);
}
private static final TagManagerTest twoTagTest;
static {
twoTagTest = new TagManagerTest();
twoTagTest.addTag(tag1, tag2);
twoTagTest.addEntityTagMappings(tag1Mapping, tag2Mapping);
}
private static final TagManagerTest threeTagTest;
static {
threeTagTest = new TagManagerTest();
threeTagTest.addTag(tag1, tag2, tag3);
threeTagTest.addEntityTagMappings(tag1Mapping,
tag2Mapping,
tag3Mapping);
}
private static final TagManagerTest vlanTagTest;
static {
vlanTagTest = new TagManagerTest();
vlanTagTest.addTag(tag4);
vlanTagTest.addEntityTagMappings(tag4Mapping);
}
private static final TagManagerTest switchTagTest;
static {
switchTagTest = new TagManagerTest();
switchTagTest.addTag(tag5);
switchTagTest.addEntityTagMappings(tag5Mapping);
}
private static final TagManagerTest switchInterfaceTagTest;
static {
switchInterfaceTagTest = new TagManagerTest();
switchInterfaceTagTest.addTag(tag6);
switchInterfaceTagTest.addEntityTagMappings(tag6Mapping);
}
@Override
@Before
public void setUp() throws Exception {
super.setUp();
ModuleContext fmc = new ModuleContext();
RestApiServer restApi = new RestApiServer();
MockThreadPoolService tp = new MockThreadPoolService();
topology = createMock(ITopologyService.class);
fmc.addService(IThreadPoolService.class, tp);
mockControllerProvider = getMockControllerProvider();
flowReconcileMgr = new FlowReconcileManager();
storageSource = new MemoryStorageSource();
fmc.addService(IStorageSourceService.class, storageSource);
fmc.addService(IControllerService.class,
mockControllerProvider);
fmc.addService(IRestApiService.class, restApi);
fmc.addService(IFlowReconcileService.class, flowReconcileMgr);
fmc.addService(ITopologyService.class, topology);
DefaultEntityClassifier entityClassifier =
new DefaultEntityClassifier();
fmc.addService(IEntityClassifierService.class, entityClassifier);
tp.init(fmc);
entityClassifier.init(fmc);
restApi.init(fmc);
storageSource.init(fmc);
flowReconcileMgr.init(fmc);
storageSource.startUp(fmc);
flowReconcileMgr.startUp(fmc);
tp.startUp(fmc);
betterDeviceManager = new BetterDeviceManagerImpl();
betterDeviceManager.init(fmc);
betterDeviceManager.startUp(fmc);
clearTagTable();
}
private void clearTagTable() {
IStorageSourceService storageSource = getStorageSource();
// Clear tag table
IResultSet rSet = storageSource.executeQuery(
BetterDeviceManagerImpl.TAG_TABLE_NAME,
new String[]{BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME},
null, null);
while (rSet.next()) {
String id = rSet.getString(BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME);
storageSource.deleteRow(BetterDeviceManagerImpl.TAG_TABLE_NAME, id);
}
// Clear tag_Host_Mapping table
rSet = storageSource.executeQuery(
BetterDeviceManagerImpl.TAGMAPPING_TABLE_NAME,
new String[]{BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME},
null, null);
while (rSet.next()) {
String id = rSet.getString(
BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME);
storageSource.deleteRow(BetterDeviceManagerImpl.TAGMAPPING_TABLE_NAME,
id);
}
BetterDeviceManagerImpl tagManager = getTagManager();
tagManager.loadTagsFromStorage();
}
private void setupTest(TagManagerTest test) {
clearTagTable();
IStorageSourceService storageSource = getStorageSource();
test.writeToStorageTags(storageSource);
test.writeToStorageEntityMappings(storageSource);
BetterDeviceManagerImpl tagManager = getTagManager();
tagManager.loadTagsFromStorage();
}
private void checkTag(Set<Tag> checkTags, Tag referenceTag) {
assertTrue(checkTags.contains(referenceTag));
}
private void checkTag(Tag checkTag, Tag referenceTag) {
assertTrue(checkTag.equals(referenceTag));
}
private String getTagDBId(Tag tag) {
return tag.getNamespace() + Tag.KEY_SEPARATOR +
tag.getName() + Tag.KEY_SEPARATOR +
tag.getValue();
}
private void checkTagInStorage(Tag tag) {
IStorageSourceService storageSource = getStorageSource();
String id = getTagDBId(tag);
IResultSet rset =
storageSource.executeQuery(BetterDeviceManagerImpl.TAG_TABLE_NAME,
new String[]{BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME,
BetterDeviceManagerImpl.TAG_NAMESPACE_COLUMN_NAME,
BetterDeviceManagerImpl.TAG_NAME_COLUMN_NAME,
BetterDeviceManagerImpl.TAG_VALUE_COLUMN_NAME},
new OperatorPredicate(BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME,
OperatorPredicate.Operator.EQ,
id), null);
int count = 0;
while (rset.next()) {
count += 1;
assertEquals(id, rset.getString(
BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME));
assertEquals(tag.getNamespace(), rset.getString(
BetterDeviceManagerImpl.TAG_NAMESPACE_COLUMN_NAME));
assertEquals(tag.getName(), rset.getString(
BetterDeviceManagerImpl.TAG_NAME_COLUMN_NAME));
assertEquals(tag.getValue(), rset.getString(
BetterDeviceManagerImpl.TAG_VALUE_COLUMN_NAME));
}
assertEquals(1, count);
}
private void checkNoTagInStorage(Tag tag) {
IStorageSourceService storageSource = getStorageSource();
String id = getTagDBId(tag);
IResultSet rset =
storageSource.executeQuery(BetterDeviceManagerImpl.TAG_TABLE_NAME,
new String[]{BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME,
BetterDeviceManagerImpl.TAG_NAMESPACE_COLUMN_NAME,
BetterDeviceManagerImpl.TAG_NAME_COLUMN_NAME,
BetterDeviceManagerImpl.TAG_VALUE_COLUMN_NAME},
new OperatorPredicate(BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME,
OperatorPredicate.Operator.EQ,
id), null);
while (rset.next()) {
assertFalse((id.equals(rset.getString(
BetterDeviceManagerImpl.TAG_ID_COLUMN_NAME))) &&
(tag.getNamespace().equals(rset.getString(
BetterDeviceManagerImpl.TAG_NAMESPACE_COLUMN_NAME))) &&
(tag.getName().equals(rset.getString(
BetterDeviceManagerImpl.TAG_NAME_COLUMN_NAME))) &&
(tag.getValue().equals(rset.getString(
BetterDeviceManagerImpl.TAG_VALUE_COLUMN_NAME))));
}
}
private void checkTagMappingInStorage(Tag tag, String host, Integer vlan,
String dpid, String interfaceName) {
IStorageSourceService storageSource = getStorageSource();
String id = getTagDBId(tag) + Tag.KEY_SEPARATOR + host +
Tag.KEY_SEPARATOR + vlan.toString() + Tag.KEY_SEPARATOR + dpid +
Tag.KEY_SEPARATOR + interfaceName;
IResultSet rset =
storageSource.executeQuery(
BetterDeviceManagerImpl.TAGMAPPING_TABLE_NAME,
new String[]{BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME,
BetterDeviceManagerImpl.TAGMAPPING_TAG_COLUMN_NAME,
BetterDeviceManagerImpl.TAGMAPPING_MAC_COLUMN_NAME,
BetterDeviceManagerImpl.TAGMAPPING_VLAN_COLUMN_NAME,
BetterDeviceManagerImpl.TAGMAPPING_SWITCH_COLUMN_NAME,
BetterDeviceManagerImpl.TAGMAPPING_INTERFACE_COLUMN_NAME},
new OperatorPredicate(
BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME,
OperatorPredicate.Operator.EQ,
id), null);
int count = 0;
while (rset.next()) {
count += 1;
assertEquals(getTagDBId(tag), rset.getString(
BetterDeviceManagerImpl.TAGMAPPING_TAG_COLUMN_NAME));
assertEquals(host, rset.getString(
BetterDeviceManagerImpl.TAGMAPPING_MAC_COLUMN_NAME));
}
assertEquals(1, count);
}
private void checkNoTagMappingInStorage(Tag tag, String host, Integer vlan,
String dpid, String interfaceName) {
IStorageSourceService storageSource = getStorageSource();
String vlanStr = null;
if (vlan != null)
vlanStr = new String(vlan.toString());
String id = getTagDBId(tag) + Tag.KEY_SEPARATOR + host +
Tag.KEY_SEPARATOR + vlanStr + Tag.KEY_SEPARATOR + dpid +
Tag.KEY_SEPARATOR + interfaceName;
IResultSet rset =
storageSource.executeQuery(
BetterDeviceManagerImpl.TAGMAPPING_TABLE_NAME,
new String[]{BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME,
BetterDeviceManagerImpl.TAGMAPPING_TAG_COLUMN_NAME,
BetterDeviceManagerImpl.TAGMAPPING_MAC_COLUMN_NAME,
BetterDeviceManagerImpl.TAGMAPPING_VLAN_COLUMN_NAME,
BetterDeviceManagerImpl.TAGMAPPING_SWITCH_COLUMN_NAME,
BetterDeviceManagerImpl.TAGMAPPING_INTERFACE_COLUMN_NAME},
new OperatorPredicate(
BetterDeviceManagerImpl.TAGMAPPING_ID_COLUMN_NAME,
OperatorPredicate.Operator.EQ,
id), null);
assertFalse(rset.next());
}
@Test
public void testInitialLoad() {
setupTest(threeTagTest);
BetterDeviceManagerImpl tagManager = getTagManager();
String host1 = "00:00:00:00:00:01";
String dpid = "00:00:00:00:00:00:00:01";
String interfaceName = "eth1";
Short vlan = new Short((short)10);
EntityConfig entity = new EntityConfig(host1, vlan.toString(), dpid,
interfaceName);
Set<Tag> tags = tagManager.getTagsByNamespace("sdnplatform.org");
assertEquals(3, tags.size());
Set<Tag> myTag1s = tagManager.getTags("sdnplatform.org", "tag1Name");
Tag referenceTag1 = new Tag("sdnplatform.org", "tag1Name", "tag1Value");
checkTag(myTag1s, referenceTag1);
Set<Tag> myTag2s = tagManager.getTags("sdnplatform.org", "tag2Name");
Tag referenceTag2 = new Tag("sdnplatform.org", "tag2Name", "tag2Value");
checkTag(myTag2s, referenceTag2);
tags = tagManager.getTagsByEntityConfig(entity);
assertEquals(1, tags.size());
checkTag(tags, referenceTag1);
//Tag referenceTag3 = new Tag("sdnplatform.org", "tag3Name", "tag3Value");
checkTag(tags, referenceTag1);
}
@Test
public void testAddTag() {
BetterDeviceManagerImpl tagManager = getTagManager();
clearTagTable();
String host1 = "00:00:00:00:00:01";
String dpid = "00:00:00:00:00:00:00:01";
String interfaceName = "eth1";
Short vlan = new Short((short)10);
EntityConfig entity1 = new EntityConfig(host1, vlan.toString(), dpid,
interfaceName);
String host2 = "00:00:00:00:00:02";
EntityConfig entity2 = new EntityConfig(host2, null, null, null);
Tag newTag1 = new Tag("sdnplatform.org", "tag1Name", "tag1Value");
tagManager.addTag(newTag1);
Set<Tag> tags = tagManager.getTags("sdnplatform.org", "tag1Name");
assertEquals(1, tags.size());
Tag myTag = tags.iterator().next();
checkTag(myTag, newTag1);
checkTagInStorage(newTag1);
tags = tagManager.getTagsByEntityConfig(entity1);
assertTrue(tags.isEmpty());
checkNoTagMappingInStorage(newTag1, host1, new Integer(vlan), dpid,
interfaceName);
checkNoTagMappingInStorage(newTag1, host2, null, null, null);
try {
tagManager.mapTagToHost(newTag1, host1, new Short((short)10),
"00:00:00:00:00:00:00:01", "eth1");
} catch (TagManagerException e){
e.printStackTrace();
}
tags = tagManager.getTagsByEntityConfig(entity1);
assertEquals(1, tags.size());
checkTag(tags, newTag1);
checkTagMappingInStorage(newTag1, host1, 10, "00:00:00:00:00:00:00:01",
"eth1");
//checkNoTagMappingInStorage(newTag1, host2);
try {
tagManager.mapTagToHost(newTag1, host2, null, null, null);
} catch (TagManagerException e){}
tags = tagManager.getTagsByEntityConfig(entity2);
assertEquals(1, tags.size());
checkTag(tags, newTag1);
//checkTagMappingInStorage(newTag1, host2);
//tags = tagManager.getTagsByEntity(entity2);
//assertEquals(1, tags.size());
checkTag(tags, newTag1);
}
@Test
public void testAddTagToDBDirect() {
clearTagTable();
BetterDeviceManagerImpl tagManager = getTagManager();
TagManagerTest oneTagTest = new TagManagerTest();
oneTagTest.addTag(tag1);
oneTagTest.addEntityTagMappings(tag1Mapping);
oneTagTest.writeToStorageTags(getStorageSource());
oneTagTest.writeToStorageEntityMappings(getStorageSource());
Set<Tag> tags = tagManager.getTagsByNamespace("sdnplatform.org");
assertEquals(1, tags.size());
tags = tagManager.getTags("sdnplatform.org", "tag1Name");
assertEquals(1, tags.size());
Tag myTag = tags.iterator().next();
Tag referenceTag = new Tag("sdnplatform.org", "tag1Name", "tag1Value");
checkTag(myTag, referenceTag);
tags = tagManager.getTagsByEntityConfig(
new EntityConfig("00:00:00:00:00:01", "10",
"00:00:00:00:00:00:00:01", "eth1"));
assertEquals(1, tags.size());
checkTag(tags, referenceTag);
}
@Test
public void testAddVlanToDBDirect() {
clearTagTable();
BetterDeviceManagerImpl tagManager = getTagManager();
TagManagerTest oneTagTest = new TagManagerTest();
oneTagTest.addTag(tag3);
oneTagTest.addEntityTagMappings(tag3Mapping);
oneTagTest.writeToStorageTags(getStorageSource());
oneTagTest.writeToStorageEntityMappings(getStorageSource());
Set<Tag> tags = tagManager.getTagsByNamespace("sdnplatform.org");
assertEquals(1, tags.size());
tags = tagManager.getTags("sdnplatform.org", "tag3Name");
assertEquals(1, tags.size());
Tag myTag = tags.iterator().next();
Tag referenceTag = new Tag("sdnplatform.org", "tag3Name", "tag3Value");
checkTag(myTag, referenceTag);
tags = tagManager.getTagsByEntityConfig(new EntityConfig(null,
"15", null, null));
assertEquals(1, tags.size());
checkTag(tags, referenceTag);
}
@Test
public void testAddSwitchToDBDirect() {
clearTagTable();
BetterDeviceManagerImpl tagManager = getTagManager();
TagManagerTest oneTagTest = new TagManagerTest();
oneTagTest.addTag(tag4);
oneTagTest.addEntityTagMappings(tag4Mapping);
oneTagTest.writeToStorageTags(getStorageSource());
oneTagTest.writeToStorageEntityMappings(getStorageSource());
Set<Tag> tags = tagManager.getTagsByNamespace("sdnplatform.org");
assertEquals(1, tags.size());
tags = tagManager.getTags("sdnplatform.org", "tag4Name");
assertEquals(1, tags.size());
Tag myTag = tags.iterator().next();
Tag referenceTag = new Tag("sdnplatform.org", "tag4Name", "tag4Value");
checkTag(myTag, referenceTag);
tags = tagManager.getTagsByEntityConfig(new EntityConfig(null, null,
"00:00:00:00:00:00:00:02",
null));
assertEquals(1, tags.size());
checkTag(tags, referenceTag);
}
@Test
public void testAddSwitchInterfaceToDBDirect() {
clearTagTable();
BetterDeviceManagerImpl tagManager = getTagManager();
TagManagerTest oneTagTest = new TagManagerTest();
OFFeaturesReply reply = new OFFeaturesReply();
List<OFPhysicalPort> ports = new ArrayList<OFPhysicalPort>();
reply.setPorts(ports);
OFPhysicalPort port1 = new OFPhysicalPort();
port1.setName("eth1");
port1.setPortNumber((short) 1);
ports.add(port1);
OFPhysicalPort port2 = new OFPhysicalPort();
port2.setName("eth2");
port2.setPortNumber((short) 2);
ports.add(port2);
OFPhysicalPort port3 = new OFPhysicalPort();
port2.setName("eth3");
port2.setPortNumber((short) 3);
ports.add(port3);
IOFSwitch mockSwitch = createMock(IOFSwitch.class);
for (OFPhysicalPort p: ports) {
expect(mockSwitch.getPort(p.getName())).andReturn(p).anyTimes();
expect(mockSwitch.getPort(p.getPortNumber()))
.andReturn(p).anyTimes();
}
expect(mockSwitch.getId()).andReturn(4L).anyTimes();
//expect(mockSwitch.getFeaturesReply()).andReturn(reply).anyTimes();
HashMap<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, mockSwitch);
mockControllerProvider.setSwitches(switches);
replay(mockSwitch);
oneTagTest.addTag(tag6);
oneTagTest.addEntityTagMappings(tag6Mapping);
oneTagTest.writeToStorageTags(getStorageSource());
oneTagTest.writeToStorageEntityMappings(getStorageSource());
Set<Tag> tags = tagManager.getTagsByNamespace("sdnplatform.org");
assertEquals(1, tags.size());
tags = tagManager.getTags("sdnplatform.org", "tag6Name");
assertEquals(1, tags.size());
Tag myTag = tags.iterator().next();
Tag referenceTag = new Tag("sdnplatform.org", "tag6Name", "tag6Value");
checkTag(myTag, referenceTag);
tags =
tagManager.getTagsByEntityConfig(new EntityConfig(null,
"20",
"00:00:00:00:00:00:00:04","eth3"));
assertEquals(1, tags.size());
checkTag(tags, referenceTag);
}
@Test
public void testRemoveTag1() {
setupTest(twoTagTest);
String host1 = "00:00:00:00:00:01";
String dpid = "00:00:00:00:00:00:00:01";
String interfaceName = "eth1";
Short vlan = new Short((short)10);
EntityConfig entity1 = new EntityConfig(host1, vlan.toString(), dpid,
interfaceName);
String host2 = "00:00:00:00:00:02";
new EntityConfig(host2, null, null, null);
BetterDeviceManagerImpl tagManager = getTagManager();
Tag myTag = new Tag("sdnplatform.org", "tag1Name", "tag1Value");
try {
tagManager.unmapTagToHost(myTag, host1, vlan, dpid, interfaceName);
} catch (TagManagerException e) {
fail("Failed to unmap tag " + myTag + " and host " + host1);
}
checkNoTagMappingInStorage(myTag, host1, new Integer(vlan), dpid,
interfaceName);
Set<Tag> tags = tagManager.getTagsByEntityConfig(entity1);
assertTrue(tags.isEmpty());
try {
tagManager.deleteTag(myTag);
} catch (TagDoesNotExistException e) {
fail("Failed to delete tag " + myTag);
}
Set<Tag> tags1 = tagManager.getTags("sdnplatform.org", "tag1Name");
assertNull(tags1);
checkNoTagInStorage(myTag);
}
@Test
public void testRemoveTag2() {
setupTest(threeTagTest);
BetterDeviceManagerImpl tagManager = getTagManager();
String host1 = "00:00:00:00:00:01";
String dpid = "00:00:00:00:00:00:00:01";
String interfaceName = "eth1";
Short vlan = new Short((short)10);
EntityConfig entity1 = new EntityConfig(host1, vlan.toString(), dpid,
interfaceName);
Tag myTag1 = new Tag("sdnplatform.org", "tag1Name", "tag1Value");
new Tag("sdnplatform.org", "tag3Name", "tag3Value");
try {
tagManager.unmapTagToHost(myTag1, host1, vlan, dpid, interfaceName);
} catch (TagManagerException e) {
fail("Failed to unmap tag " + myTag1 + " and host " + host1);
}
checkNoTagMappingInStorage(myTag1, host1, new Integer(vlan), dpid,
interfaceName);
//checkTagMappingInStorage(myTag3, host1);
Set<Tag> tags = tagManager.getTagsByEntityConfig(entity1);
assertEquals(0, tags.size());
}
@Test
public void testRemoveTagFromDBDirect() {
setupTest(twoTagTest);
BetterDeviceManagerImpl tagManager = getTagManager();
Tag myTag = new Tag("sdnplatform.org", "tag1Name", "tag1Value");
String host1 = "00:00:00:00:00:01";
String dpid = "00:00:00:00:00:00:00:01";
String interfaceName = "eth1";
Short vlan = new Short((short)10);
EntityConfig entity1 = new EntityConfig(host1, vlan.toString(), dpid,
interfaceName);
String tagId = "sdnplatform.org|tag1Name|tag1Value";
String tagMappingId = tagId + Tag.KEY_SEPARATOR + host1 +
Tag.KEY_SEPARATOR + vlan.toString() + Tag.KEY_SEPARATOR + dpid
+ Tag.KEY_SEPARATOR + interfaceName;
checkTagInStorage(myTag);
checkTagMappingInStorage(myTag, host1, new Integer(vlan), dpid,
interfaceName);
getStorageSource().deleteRow(BetterDeviceManagerImpl.TAG_TABLE_NAME, tagId);
Set<Tag> tags = tagManager.getTags("sdnplatform.org", "tag1Name");
assertNull(tags);
checkNoTagInStorage(myTag);
getStorageSource().deleteRow(BetterDeviceManagerImpl.TAGMAPPING_TABLE_NAME,
tagMappingId);
tags = tagManager.getTagsByEntityConfig(entity1);
assertTrue(tags.isEmpty());
checkNoTagMappingInStorage(myTag, host1, new Integer(vlan), dpid,
interfaceName);
}
@Test
public void testAddTagListener() {
setupTest(oneTagTest);
BetterDeviceManagerImpl tagManager = getTagManager();
String host1 = "00:00:00:00:00:01";
// Set up the listeners and record the expected notification
ITagListener listener1 = createNiceMock(ITagListener.class);
ITagListener listener2 = createNiceMock(ITagListener.class);
Tag myTag = new Tag("sdnplatform.org", "tag2Name", "tag2Value");
listener1.tagAdded(myTag);
listener2.tagAdded(myTag);
//listener1.tagHostMappingAdded(myTag, host1);
//listener2.tagHostMappingAdded(myTag, host1);
/*
listener1.tagDevicesReMapped(
tagManager.queryDevices(HexString.toLong(host1),
null, null, null, null));
listener2.tagDevicesReMapped(
tagManager.queryDevices(HexString.toLong(host1),
null, null, null, null));
*/
replay(listener1, listener2);
// Now try it for real
tagManager.addListener(listener1);
tagManager.addListener(listener2);
// Update a new tag
tagManager.addTag(myTag);
try {
tagManager.mapTagToHost(myTag, host1, null, null, null);
} catch (TagManagerException e) {}
verify(listener1);
verify(listener2);
tagManager.removeAllListeners();
}
@Test
public void testRemoveTagListener() {
setupTest(twoTagTest);
BetterDeviceManagerImpl tagManager = getTagManager();
String host1 = "00:00:00:00:00:02";
// Set up the listeners and record the expected notification
ITagListener listener1 = createNiceMock(ITagListener.class);
//ITagListener listener2 = createNiceMock(ITagListener.class);
Tag myTag = new Tag("sdnplatform.org", "tag1Name", "tag1Value");
listener1.tagDeleted(myTag);
//listener2.tagDeleted(myTag);
/*
Iterator<? extends IDevice> devices =
tagManager.queryDevices(new Long(HexString.toLong(host1)), null,
null, null, null);
listener1.tagDevicesReMapped(devices);
*/
replay(listener1);
// Now try it for real
tagManager.addListener(listener1);
//tagManager.addListener(listener2);
// Delete a tag
try {
tagManager.unmapTagToHost(myTag, host1, null, null, null);
tagManager.deleteTag(myTag);
} catch (TagManagerException e) {
fail("deleteTag failed with exception " + e);
}
verify(listener1);
//verify(listener2);
}
/* A shim class to represent an HostSecurityAttachmentPoint row with helpers
* to add/remove a row from storage.
*/
protected static class HostSecurityAttachmentPointRow {
public HostSecurityAttachmentPointRow() {
super();
}
public HostSecurityAttachmentPointRow(String addressSpace, Short vlan,
Long mac, Long dpid,
String iface) {
super();
this.addressSpace = addressSpace;
this.vlan = vlan;
this.mac = mac;
this.dpid = dpid;
this.iface = iface;
}
public String addressSpace;
public Long mac;
public Short vlan;
public Long dpid;
public String iface;
public void writeToStorage(IStorageSourceService storageSource) {
ConcurrentHashMap<String, Object> row =
new ConcurrentHashMap<String, Object>();
String vlanString = (vlan==null) ? "" : vlan.toString();
String hostConfig = addressSpace + "|" + vlanString + "|" +
HexString.toHexString(mac, 6);
String dpidString =
(dpid != null) ? HexString.toHexString(dpid, 8) : "\010";
String id = hostConfig + "|" + dpidString + "|" + iface;
row.put(BetterDeviceManagerImpl
.HOSTSECURITYATTACHMENTPOINT_ID_COLUMN_NAME,
id);
row.put(BetterDeviceManagerImpl
.HOSTSECURITYATTACHMENTPOINT_HOSTCONFIG_COLUMN_NAME,
hostConfig);
storageSource.insertRow(
BetterDeviceManagerImpl.HOSTSECURITYATTACHMENTPOINT_TABLE_NAME,
row);
}
public void removeFromStorage(IStorageSourceService storageSource) {
String vlanString = (vlan==null) ? "" : vlan.toString();
String hostConfig = addressSpace + "|" + vlanString + "|" +
HexString.toHexString(mac, 6);
String dpidString =
(dpid != null) ? HexString.toHexString(dpid, 8) : "\010";
String id = hostConfig + "|" + dpidString + "|" + iface;
storageSource.deleteRow(
BetterDeviceManagerImpl.HOSTSECURITYATTACHMENTPOINT_TABLE_NAME,
id);
}
}
/* A shim class to represent an HostSecurityIpAddressRow with helpers
* to add/remove a row from storage.
*/
protected static class HostSecurityIpAddressRow {
public HostSecurityIpAddressRow() {
super();
}
public HostSecurityIpAddressRow(String addressSpace, Short vlan,
Long mac, Integer ip) {
super();
this.addressSpace = addressSpace;
this.vlan = vlan;
this.mac = mac;
this.ip = ip;
}
public String addressSpace;
public Short vlan;
public Long mac;
public Integer ip;
public void writeToStorage(IStorageSourceService storageSource) {
ConcurrentHashMap<String, Object> row =
new ConcurrentHashMap<String, Object>();
String vlanString = (vlan==null) ? "" : vlan.toString();
String hostConfig = addressSpace + "|" + vlanString + "|" +
HexString.toHexString(mac, 6);
String ipString = IPv4.fromIPv4Address(ip);
String id = hostConfig + "|" + ipString;
row.put(BetterDeviceManagerImpl.HOSTSECURITYIPADDRESS_ID_COLUMN_NAME,
id);
row.put(BetterDeviceManagerImpl
.HOSTSECURITYIPADDRESS_HOSTCONFIG_COLUMN_NAME,
hostConfig);
row.put(BetterDeviceManagerImpl.HOSTSECURITYIPADDRESS_IP_COLUMN_NAME,
ipString);
storageSource.insertRow(
BetterDeviceManagerImpl.HOSTSECURITYIPADDRESS_TABLE_NAME,
row);
}
public void removeFromStorage(IStorageSourceService storageSource) {
String vlanString = (vlan==null) ? "" : vlan.toString();
String hostConfig = addressSpace + "|" + vlanString + "|" +
HexString.toHexString(mac, 6);
String ipString = IPv4.fromIPv4Address(ip);
String id = hostConfig + "|" + ipString;
storageSource.deleteRow(
BetterDeviceManagerImpl.HOSTSECURITYIPADDRESS_TABLE_NAME, id);
}
}
/* an IAnswer for responding to topology.isConsistent() calls. We return
* true if both switch/ports are equal and false otherwise
*/
protected static class IsConsistentAnswer implements IAnswer<Boolean> {
@Override
public Boolean answer() throws Throwable {
Object[] args = getCurrentArguments();
if (args[0].equals(args[2]) && args[1].equals(args[3]))
return true;
else
return false;
}
}
/**
* Verify of the given entities are allowed or not. Calls isEntityAllowed
* for each entity that's passed in and verifies that it matches the
* expected value in the expected boolean array.
* "expecgted" is an array of expected values. We expect that
* isEntityAllowed(entities[i]) == expected[i] (in the given address space)
*
* @param expected
* @param entities
* @param entityClassName
*/
public void verifyEntityAllowed(boolean[] expected, Entity[] entities,
String entityClassName) {
assertEquals("test setup error", expected.length, entities.length);
for(int i = 0; i < expected.length; i++) {
assertEquals("testing entity idx " + i,
expected[i],
isEntityAllowed(entities[i], entityClassName));
}
}
public void setupTopology(IAnswer<Boolean> answer,
boolean switch1IsAttachmentPoint) {
reset(topology);
topology.isConsistent(anyLong(), anyShort(), anyLong(), anyShort());
expectLastCall().andAnswer(answer).anyTimes();
topology.isAttachmentPointPort(eq(1L), anyShort());
expectLastCall().andReturn(switch1IsAttachmentPoint).anyTimes();
topology.isAttachmentPointPort(anyLong(), anyShort());
expectLastCall().andReturn(true).anyTimes();
replay(topology);
}
/**
* A wrapper around BetterDeviceManager.isEntityAllowed (the method under
* test). This method just mocks an IEnityClass and its key fields according
* to the current controller semantics (default AS has VLAN+MAC as key
* field, others have just MAC as key fields).
*
* @param entity
* @param entityClassName
* @return
*/
public boolean isEntityAllowed(Entity entity, String entityClassName) {
IEntityClass ec = createMock(IEntityClass.class);
expect(ec.getName()).andReturn(entityClassName).anyTimes();
EnumSet<IDeviceService.DeviceField> keyFields;
if (entityClassName.equals("default")) {
keyFields = EnumSet.of(IDeviceService.DeviceField.VLAN,
IDeviceService.DeviceField.MAC);
} else {
keyFields = EnumSet.of(IDeviceService.DeviceField.MAC);
}
expect(ec.getKeyFields()).andReturn(keyFields).anyTimes();
replay(ec);
boolean rv = betterDeviceManager.isEntityAllowed(entity, ec);
verify(ec);
return rv;
}
/*
* Test anti-spoofing protecting using only IP based rules. The test
* successively adds (and potentially) removes IP based anti-spoofing
* rules.
*
* We test against a set of three entities.
*/
@Test
public void testIsEntityAllowedIpOnly() {
expect(topology.isAttachmentPointPort(anyLong(), anyShort()))
.andReturn(true).anyTimes();
replay(topology);
Entity e1 = new Entity(1L, null, 1, 1L, 1, null);
Entity e2 = new Entity(1L, null, null, 1L, 1, null);
Entity e3 = new Entity(2L, null, 1, 1L, 1, null);
Entity[] entities = new Entity[] { e1, e2, e3 };
// no rules. all entities allowed in all address-spaces.
verifyEntityAllowed(new boolean[] { true, true, true},
entities, "foobar");
verifyEntityAllowed(new boolean[] { true, true, true},
entities, "AS1");
// progressively populate ip to mac anti-spoofing rules for AS1.
// we check address-space foobar to ensure it's unaffected by the rules.
// lock IP2 to Mac 3 in AS1. Doesn't affect our entities
HostSecurityIpAddressRow r3 =
new HostSecurityIpAddressRow("AS1", null, 3L, 2);
r3.writeToStorage(storageSource);
verifyEntityAllowed(new boolean[] { true, true, true},
entities, "foobar");
verifyEntityAllowed(new boolean[] { true, true, true},
entities, "AS1");
// lock IP1 to Mac 1 in AS1. Entity e3 violates this rule and
// should thus be disallowed.
HostSecurityIpAddressRow r4 =
new HostSecurityIpAddressRow("AS1", null, 1L, 1);
r4.writeToStorage(storageSource);
verifyEntityAllowed(new boolean[] { true, true, true},
entities, "foobar");
verifyEntityAllowed(new boolean[] { true, true, false},
entities, "AS1");
r4.removeFromStorage(storageSource);
// Lock Ip1 to Mac 3 in AS1. Not both e1 and e3 violate this rule.
HostSecurityIpAddressRow r5 =
new HostSecurityIpAddressRow("AS1", null, 3L, 1);
r5.writeToStorage(storageSource);
verifyEntityAllowed(new boolean[] { true, true, true},
entities, "foobar");
verifyEntityAllowed(new boolean[] { false, true, false},
entities, "AS1");
// previous rule still in force. Now we also allow IP1 on Mac 1.
// e1 becomes valid again
HostSecurityIpAddressRow r6 =
new HostSecurityIpAddressRow("AS1", null, 1L, 1);
r6.writeToStorage(storageSource);
verifyEntityAllowed(new boolean[] { true, true, true},
entities, "foobar");
verifyEntityAllowed(new boolean[] { true, true, false},
entities, "AS1");
// previous rules still in force. Now we also allow IP1 on Mac 2.
// e3 is valid again (i.e., all entities are now allowed)
HostSecurityIpAddressRow r7 =
new HostSecurityIpAddressRow("AS1", null, 2L, 1);
r7.writeToStorage(storageSource);
verifyEntityAllowed(new boolean[] { true, true, true},
entities, "foobar");
verifyEntityAllowed(new boolean[] { true, true, true},
entities, "AS1");
}
@Test
public void testIsEntityAllowedHost2SwitchPort() {
IAnswer<Boolean> isConsistentAnswer = new IsConsistentAnswer();
IOFSwitch sw1 = createMock(IOFSwitch.class);
IOFSwitch sw2 = createMock(IOFSwitch.class);
ArrayList<OFPhysicalPort> sw1ports = new ArrayList<OFPhysicalPort>();
ArrayList<OFPhysicalPort> sw2ports = new ArrayList<OFPhysicalPort>();
for(int i=1; i<=2; i++) {
OFPhysicalPort p = new OFPhysicalPort();
p.setName("eth" + i);
p.setPortNumber((short)i);
expect(sw1.getPort(p.getName())).andReturn(p).anyTimes();
sw1ports.add(p);
p = new OFPhysicalPort();
p.setName("port" + i);
p.setPortNumber((short)(i));
expect(sw2.getPort(p.getName())).andReturn(p).anyTimes();
sw2ports.add(p);
}
// catch-all for ports we haven't specified
expect(sw1.getPort(anyObject(String.class))).andStubReturn(null);
expect(sw2.getPort(anyObject(String.class))).andStubReturn(null);
expect(sw1.getEnabledPorts()).andReturn(sw1ports).anyTimes();
expect(sw2.getEnabledPorts()).andReturn(sw2ports).anyTimes();
expect(sw1.getId()).andReturn(1L).anyTimes();
expect(sw2.getId()).andReturn(2L).anyTimes();
ConcurrentHashMap<Long, IOFSwitch> switches =
new ConcurrentHashMap<Long, IOFSwitch>();
switches.put(1L, sw1);
switches.put(2L, sw2);
mockControllerProvider.setSwitches(switches);
replay(sw1, sw2);
// host1 switch1 port1
Entity h1s1p1 = new Entity(1L, null, null, 1L, 1, null);
// host1 switch1 port2
Entity h1s1p2 = new Entity(1L, null, null, 1L, 2, null);
// host1 switch2 port1
Entity h1s2p1 = new Entity(1L, null, null, 2L, 1, null);
// host2 switch2 port2
Entity h2s2p2 = new Entity(2L, null, null, 2L, 2, null);
Entity[] entities = new Entity[] { h1s1p1, h1s1p2, h1s2p1, h2s2p2 };
// Test 0
// no config. All should be allowed
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {true, true, true, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, true, true, true},
entities, "foobar");
// Test 1
// In address-space "foobar" allow MAC 1 on the following switch ports:
// sw1,p1(eth1), sw2,p2(port2)
HostSecurityAttachmentPointRow r =
new HostSecurityAttachmentPointRow("foobar", null, 1L, 1L, "eth1");
r.writeToStorage(storageSource);
r = new HostSecurityAttachmentPointRow("foobar", null, 1L, 2L, "port1");
r.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {true, true, true, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "foobar");
verify(topology);
// Test 2a
// foobar is same as Test1
// In address-space "AS1" allow MAC 2 on a non-existing switch
r = new HostSecurityAttachmentPointRow("AS1", null, 2L, 10L, "eth1");
r.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {true, true, true, false},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "foobar");
verify(topology);
r.removeFromStorage(storageSource);
// Test 2b
// foobar is same as Test1
// same as 2a but allow MAC 2 on existing switch 1 but on a
// non-existing port (we use a port name what would be valid on sw 2
// though)
// We just reuse and modify switchPorts !
r = new HostSecurityAttachmentPointRow("AS1", null, 2L, 1L, "port1");
r.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {true, true, true, false},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "foobar");
verify(topology);
// Test 2c
// foobar is same as Test1
// same as 2b but we finally allow MAC 2 on sw2/p2
HostSecurityAttachmentPointRow r2;
r2 = new HostSecurityAttachmentPointRow("AS1", null, 2L, 2L, "port2");
r2.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {true, true, true, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "foobar");
verify(topology);
r.removeFromStorage(storageSource);
r2.removeFromStorage(storageSource);
// Test 4a
// foobar is same as in Test1
// AS1: Only allow MAC1 on sw1/eth1
r = new HostSecurityAttachmentPointRow("AS1", null, 1L, 1L, "eth1");
r.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {true, false, false, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "foobar");
verify(topology);
r.removeFromStorage(storageSource);
// Test 4b
// same as 2a but also allow MAC 1 on sw2/port1
r = new HostSecurityAttachmentPointRow("AS1", null, 1L, 1L, "eth1");
r.writeToStorage(storageSource);
r2 = new HostSecurityAttachmentPointRow("AS1", null, 1L, 2L, "port1");
r2.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "foobar");
verify(topology);
r.removeFromStorage(storageSource);
r2.removeFromStorage(storageSource);
// Test 5
// foobar is same as in Test1
// AS1: Only allow MAC1 on sw1/eth1. However, we declare all ports
// on switch 1 as non-attachment point ports
r = new HostSecurityAttachmentPointRow("AS1", null, 1L, 1L, "eth1");
r.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, false);
verifyEntityAllowed(new boolean[] {true, true, false, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, true, true, true},
entities, "foobar");
r.removeFromStorage(storageSource);
verify(topology);
// Test 6: regex on switch1: match all ports
r = new HostSecurityAttachmentPointRow("AS1", null, 1L, 1L, "eth.*");
r.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {true, true, false, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "foobar");
r.removeFromStorage(storageSource);
verifyEntityAllowed(new boolean[] {true, true, true, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "foobar");
// r is already removed
verify(topology);
// Test 7: regex all switches
r = new HostSecurityAttachmentPointRow("AS1", null, 1L, null, ".*1");
r.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "foobar");
r.removeFromStorage(storageSource);
verifyEntityAllowed(new boolean[] {true, true, true, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, true, true},
entities, "foobar");
// r is already removed
verify(topology);
verify(sw1, sw2);
}
/*
* Test spoofing protection in default address space with different VLANs
*/
@Test
public void testIsEntityAllowedVlan() {
IAnswer<Boolean> isConsistentAnswer = new IsConsistentAnswer();
IOFSwitch sw1 = createMock(IOFSwitch.class);
IOFSwitch sw2 = createMock(IOFSwitch.class);
ArrayList<OFPhysicalPort> sw1ports = new ArrayList<OFPhysicalPort>();
ArrayList<OFPhysicalPort> sw2ports = new ArrayList<OFPhysicalPort>();
for(int i=1; i<=2; i++) {
OFPhysicalPort p = new OFPhysicalPort();
p.setName("eth" + i);
p.setPortNumber((short)i);
expect(sw1.getPort(p.getName())).andReturn(p).anyTimes();
sw1ports.add(p);
p = new OFPhysicalPort();
p.setName("eth" + i);
p.setPortNumber((short)(i));
expect(sw2.getPort(p.getName())).andReturn(p).anyTimes();
sw2ports.add(p);
}
// catch-all for ports we haven't specified
expect(sw1.getPort(anyObject(String.class))).andStubReturn(null);
expect(sw2.getPort(anyObject(String.class))).andStubReturn(null);
expect(sw1.getEnabledPorts()).andReturn(sw1ports).anyTimes();
expect(sw2.getEnabledPorts()).andReturn(sw2ports).anyTimes();
expect(sw1.getId()).andReturn(1L).anyTimes();
expect(sw2.getId()).andReturn(2L).anyTimes();
ConcurrentHashMap<Long, IOFSwitch> switches =
new ConcurrentHashMap<Long, IOFSwitch>();
switches.put(1L, sw1);
switches.put(2L, sw2);
mockControllerProvider.setSwitches(switches);
replay(sw1, sw2);
Entity h1 = new Entity(1L, null, 1, 1L, 1, null);
Entity h1vlan2 = new Entity(1L, (short)2, 1, 1L, 1, null);
Entity h1vlan2sw2 = new Entity(1L, (short)2, 1, 2L, 1, null);
Entity h2vlan2 = new Entity(2L, (short)2, 1, 1L, 1, null);
Entity[] entities = new Entity[] { h1, h1vlan2, h1vlan2sw2, h2vlan2 };
// Test 0
// no config. All should be allowed
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {true, true, true, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, true, true, true},
entities, "default");
verify(topology);
// Test 1
// Lock MAC 1 to nonexisting switch/port in AS1 and default. VLAN
// should be ignored in AS1
HostSecurityAttachmentPointRow r1 =
new HostSecurityAttachmentPointRow("AS1", null, 1L,
0xffL, "eth1");
HostSecurityAttachmentPointRow r2 =
new HostSecurityAttachmentPointRow("default", null, 1L,
0xffL, "eth1");
r1.writeToStorage(storageSource);
r2.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {false, false, false, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {false, true, true, true},
entities, "default");
verify(topology);
// Test 2: now lock MAC 1 to sw1-port1
HostSecurityAttachmentPointRow r3 =
new HostSecurityAttachmentPointRow("AS1", (short)2, 1L,
0x1L, "eth1");
HostSecurityAttachmentPointRow r4 =
new HostSecurityAttachmentPointRow("default", (short)2, 1L,
0x1L, "eth1");
r3.writeToStorage(storageSource);
r4.writeToStorage(storageSource);
setupTopology(isConsistentAnswer, true);
verifyEntityAllowed(new boolean[] {false, false, false, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {false, true, false, true},
entities, "default");
verify(topology);
// Clear storage
r1.removeFromStorage(storageSource);
r2.removeFromStorage(storageSource);
r3.removeFromStorage(storageSource);
r4.removeFromStorage(storageSource);
// Test 3: Lock IP1 to MAC 2
HostSecurityIpAddressRow ipRow1 =
new HostSecurityIpAddressRow("AS1", null, 2L, 1);
HostSecurityIpAddressRow ipRow2 =
new HostSecurityIpAddressRow("default", null, 2L, 1);
ipRow1.writeToStorage(storageSource);
ipRow2.writeToStorage(storageSource);
verifyEntityAllowed(new boolean[] {false, false, false, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {false, false, false, false},
entities, "default");
verify(topology);
// Test 4: same as Test3 plus add: Lock IP1 to MAC 2, VLAN 2
// Not setting for AS1 since using non-default AS + vlan is illegal
HostSecurityIpAddressRow ipRow3 =
new HostSecurityIpAddressRow("default", (short)2, 2L, 1);
ipRow3.writeToStorage(storageSource);
verifyEntityAllowed(new boolean[] {false, false, false, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {false, false, false, true},
entities, "default");
verify(topology);
// Test 5: Same as Test 4: add: Lock IP1 to MAC 1
HostSecurityIpAddressRow ipRow4 =
new HostSecurityIpAddressRow("AS1", null, 1L, 1);
HostSecurityIpAddressRow ipRow5 =
new HostSecurityIpAddressRow("default", null, 1L, 1);
ipRow4.writeToStorage(storageSource);
ipRow5.writeToStorage(storageSource);
verifyEntityAllowed(new boolean[] {true, true, true, true},
entities, "AS1");
verifyEntityAllowed(new boolean[] {true, false, false, true},
entities, "default");
verify(topology);
verify(sw1, sw2);
}
/**
* Add the specified HostSecurityAttachmentPointRow to the storage source
* and then verify how many rules betterDeviceManager has read into its
* matching structure (hostSecurityInterfaceRegexMap). This method is used
* to check if out-of-bounds values are ignored when reading from storage.
* Will also remove the row after we are done.
* @param r row to write to storage
* @param expectedEntries number of expected entries in matching structure
* after row is added.
*/
public void doTestHostSecurityIpAddressRow(HostSecurityIpAddressRow r,
int expectedEntries) {
r.writeToStorage(storageSource);
assertEquals(expectedEntries, betterDeviceManager.hostSecurityIpMap.size());
r.removeFromStorage(storageSource);
}
/* Valid range check when reading HostSecurityIpAddress config
* from storage. Valid vlans are 1--4095. Macs must be at most 6 bytes.
*/
@Test
public void testHostSecurityIpAddressVlanMacRange() {
HostSecurityIpAddressRow ipRow;
// vlan 0: invalid. ignored.
ipRow = new HostSecurityIpAddressRow("default", (short)0, 1L, 1);
doTestHostSecurityIpAddressRow(ipRow, 0);
// vlan 1: ok
ipRow = new HostSecurityIpAddressRow("default", (short)1, 1L, 1);
doTestHostSecurityIpAddressRow(ipRow, 1);
// vlan 4095: ok
ipRow = new HostSecurityIpAddressRow("default", (short)4095, 1L, 1);
doTestHostSecurityIpAddressRow(ipRow, 1);
// vlan 4096: invalid. ignored.
ipRow = new HostSecurityIpAddressRow("default", (short)4096, 1L, 1);
doTestHostSecurityIpAddressRow(ipRow, 0);
// MAC is all "1". largest valid mac.
ipRow = new HostSecurityIpAddressRow("default", (short)1,
0xffffffffffffL, 1);
doTestHostSecurityIpAddressRow(ipRow, 1);
// MAC is more then 48 bit. Invalid and ignored.
ipRow = new HostSecurityIpAddressRow("default", (short)1,
0x1000000000000L, 1);
doTestHostSecurityIpAddressRow(ipRow, 0);
}
/**
* Add the specified HostSecurityAttachmentPointRow to the storage source
* and then verify how many rules betterDeviceManager has read into its
* matching structure (hostSecurityInterfaceRegexMap). This method is used
* to check if out-of-bounds values are ignored when reading from storage.
* Will also remove the row after we are done.
* @param r row to write to storage
* @param expectedEntries number of expected entries in matching structure
* after row is added.
*/
public void doTestHostSecurityAttachmentPointRow(
HostSecurityAttachmentPointRow r, int expectedEntries) {
r.writeToStorage(storageSource);
assertEquals(expectedEntries,
betterDeviceManager.hostSecurityInterfaceRegexMap.size());
r.removeFromStorage(storageSource);
}
/* Valid range check when reading HostSecurityAttachmentPoint config
* from storage. Valid vlans are 1--4095. Macs must be at most 6 bytes.
*/
@Test
public void testHostSecurityAttachmentPointVlanMacRange() {
HostSecurityAttachmentPointRow apRow;
// vlan 0: invalid. ignored
apRow = new HostSecurityAttachmentPointRow("default", (short)0, 1L,
1L, "eth1");
doTestHostSecurityAttachmentPointRow(apRow, 0);
// vlan 1: ok
apRow = new HostSecurityAttachmentPointRow("default", (short)1, 1L,
1L, "eth1");
doTestHostSecurityAttachmentPointRow(apRow, 1);
// vlan 4095: ok
apRow = new HostSecurityAttachmentPointRow("default", (short)4095, 1L,
1L, "eth1");
doTestHostSecurityAttachmentPointRow(apRow, 1);
// vlan 4096: invalid. ignored
apRow = new HostSecurityAttachmentPointRow("default", (short)4096, 1L,
1L, "eth1");
doTestHostSecurityAttachmentPointRow(apRow, 0);
// MAC is all "1". Still allowed.
apRow = new HostSecurityAttachmentPointRow("default", (short)1,
0xffffffffffffL,
1L, "eth1");
doTestHostSecurityAttachmentPointRow(apRow, 1);
// MAC has more then 48 bits. Ignored.
apRow = new HostSecurityAttachmentPointRow("default", (short)1,
0x1000000000000L,
1L, "eth1");
doTestHostSecurityAttachmentPointRow(apRow, 0);
}
protected BetterDeviceManagerImpl getTagManager() {
return betterDeviceManager;
}
protected IStorageSourceService getStorageSource() {
return betterDeviceManager.getStorageSource();
}
}