blob: c5adcfb9ac666b7808cc214e2b5c9b90d5f5eef1 [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Foundation
*
* 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 org.onosproject.vpls;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.neighbour.NeighbourHandlerRegistration;
import org.onosproject.net.neighbour.NeighbourMessageContext;
import org.onosproject.net.neighbour.NeighbourMessageHandler;
import org.onosproject.net.neighbour.NeighbourMessageType;
import org.onosproject.net.neighbour.NeighbourProtocol;
import org.onosproject.net.neighbour.NeighbourResolutionService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Host;
import org.onosproject.net.host.HostService;
import org.onosproject.vpls.api.VplsData;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
/**
* Tests the the {@link VplsNeighbourHandler}.
*/
public class VplsNeighbourHandlerTest extends VplsTest {
private static final String IFACES_NOT_EXPECTED =
"The interfaces reached by the packet are not equal to the " +
"interfaces expected.";
private VplsNeighbourHandler vplsNeighbourHandler;
private HostService hostService;
/**
* Sets up 4 VPLS.
* VPLS 1 contains 3 hosts: v100h1, v200h1 and v300h1
* VPLS 2 contains 2 hosts: v100h2, v200h2
* VPLS 3 contains 2 hosts: vNoneh1, vNoneh2
* VPLS 4 contains 2 hosts: v400h1, vNoneh3
*/
@Before
public void setUp() {
vplsNeighbourHandler = new VplsNeighbourHandler();
hostService = new TestHostService();
vplsNeighbourHandler.vplsStore = new TestVplsStore();
vplsNeighbourHandler.interfaceService = new TestInterfaceService();
vplsNeighbourHandler.neighbourService = new TestNeighbourService();
vplsNeighbourHandler.coreService = new TestCoreService();
vplsNeighbourHandler.configService = new TestConfigService();
// Init VPLS store
VplsData vplsData = VplsData.of(VPLS1);
vplsData.addInterfaces(ImmutableSet.of(V100H1, V200H1, V300H1));
vplsNeighbourHandler.vplsStore.addVpls(vplsData);
vplsData = VplsData.of(VPLS2);
vplsData.addInterfaces(ImmutableSet.of(V100H2, V200H2));
vplsNeighbourHandler.vplsStore.addVpls(vplsData);
vplsData = VplsData.of(VPLS3);
vplsData.addInterfaces(ImmutableSet.of(VNONEH1, VNONEH2));
vplsNeighbourHandler.vplsStore.addVpls(vplsData);
vplsData = VplsData.of(VPLS4);
vplsData.addInterfaces(ImmutableSet.of(V400H1, VNONEH3));
vplsNeighbourHandler.vplsStore.addVpls(vplsData);
vplsNeighbourHandler.activate();
}
@After
public void tearDown() {
vplsNeighbourHandler.deactivate();
}
/**
* Registers neighbour handler to all available interfaces.
*/
@Test
public void testConfigNeighbourHandler() {
vplsNeighbourHandler.configNeighbourHandler();
assertEquals(9, vplsNeighbourHandler.neighbourService.getHandlerRegistrations().size());
}
/**
* Sends request messages to all hosts in VPLS 1.
* Request messages should be received from other hosts in VPLS 1.
*/
@Test
public void vpls1RequestMessage() {
// Request messages from v100h1 (VPLS 1) should be received by v200h1 and v300h1
TestMessageContext requestMessage =
makeBroadcastRequestContext(V100HOST1);
Set<Interface> expectInterfaces = ImmutableSet.of(V200H1, V300H1);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(requestMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, requestMessage.forwardResults);
// Request messages from v200h1 (VPLS 1) should be received by v100h1 and v300h1
requestMessage = makeBroadcastRequestContext(V200HOST1);
expectInterfaces = ImmutableSet.of(V100H1, V300H1);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(requestMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, requestMessage.forwardResults);
// Request from v300h1 (VPLS 1) should be received by v100h1 and v200h1
requestMessage = makeBroadcastRequestContext(V300HOST1);
expectInterfaces = ImmutableSet.of(V100H1, V200H1);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(requestMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, requestMessage.forwardResults);
}
/**
* Sends request messages to all hosts in VPLS 2.
* Request messages should be received from other hosts in VPLS 2.
*/
@Test
public void vpls2RequestMessage() {
// Request messages from v100h2 (VPLS 2) should be received by v200h2
TestMessageContext requestMessage =
makeBroadcastRequestContext(V100HOST2);
Set<Interface> expectInterfaces = ImmutableSet.of(V200H2);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(requestMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, requestMessage.forwardResults);
// Request messages from v200h2 (VPLS 2) should be received by v100h2
requestMessage = makeBroadcastRequestContext(V200HOST2);
expectInterfaces = ImmutableSet.of(V100H2);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(requestMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, requestMessage.forwardResults);
}
/**
* Tests correct connection between untagged interfaces.
*
* Sends request messages to all hosts in VPLS 3.
* Request messages should be received from other hosts in VPLS 3.
*/
@Test
public void vpls3RequestMessage() {
// Request messages from VNONEHOST1 (VPLS 3) should be received by VNONEHOST2
TestMessageContext requestMessage =
makeBroadcastRequestContext(VNONEHOST1);
Set<Interface> expectInterfaces = ImmutableSet.of(VNONEH2);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(requestMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, requestMessage.forwardResults);
// Request messages from vNoneh2 (VPLS 3) should be received by vNoneh1
requestMessage = makeBroadcastRequestContext(VNONEHOST2);
expectInterfaces = ImmutableSet.of(VNONEH1);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(requestMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, requestMessage.forwardResults);
}
/**
* Tests correct connection between tagged and untagged interfaces.
*
* Sends request messages to all hosts in VPLS 4.
* Request messages should be received from other hosts in VPLS 4.
*/
@Test
public void vpls4RequestMessage() {
// Request messages from V400HOST1 (VPLS 4) should be received by VNONEHOST3
TestMessageContext requestMessage =
makeBroadcastRequestContext(V400HOST1);
Set<Interface> expectInterfaces = ImmutableSet.of(VNONEH3);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(requestMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, requestMessage.forwardResults);
// Request messages from VNONEHOST3 (VPLS 4) should be received by V400HOST1
requestMessage = makeBroadcastRequestContext(VNONEHOST3);
expectInterfaces = ImmutableSet.of(V400H1);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(requestMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, requestMessage.forwardResults);
}
/**
* Sends reply messages to hosts in VPLS 1.
* Reply messages should be received by the host with MAC address equal to
* the dstMac of the message context.
*/
@Test
public void vpls1ReplyMessage() {
// Reply messages from v100h1 (VPLS 1) should be received by v200h1
TestMessageContext replyMessage =
makeReplyContext(V100HOST1, V200HOST1);
Set<Interface> expectInterfaces = ImmutableSet.of(V200H1);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
// Reply messages from v200h1 (VPLS 1) should be received by v300h1
replyMessage = makeReplyContext(V200HOST1, V300HOST1);
expectInterfaces = ImmutableSet.of(V300H1);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
// Reply messages from v300h1 (VPLS 1) should be received by v100h1
replyMessage = makeReplyContext(V300HOST1, V100HOST1);
expectInterfaces = ImmutableSet.of(V100H1);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
}
/**
* Sends reply messages to hosts in VPLS 2.
* Reply messages should be received by the host with MAC address equal to
* the dstMac of the message context.
*/
@Test
public void vpls2ReplyMessage() {
// Reply messages from v100h2 (VPLS 2) should be received by v200h2
TestMessageContext replyMessage =
makeReplyContext(V100HOST2, V200HOST2);
Set<Interface> expectInterfaces = ImmutableSet.of(V200H2);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
// Reply messages from v200h2 (VPLS 2) should be received by v100h2
replyMessage = makeReplyContext(V200HOST2, V100HOST2);
expectInterfaces = ImmutableSet.of(V100H2);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
}
/**
* Sends reply messages to hosts in VPLS 3.
* Reply messages should be received by the host with MAC address equal to
* the dstMac of the message context.
*/
@Test
public void vpls3ReplyMessage() {
// Reply messages from vNoneh1 (VPLS 3) should be received by vNoneh2
TestMessageContext replyMessage =
makeReplyContext(VNONEHOST1, VNONEHOST2);
Set<Interface> expectInterfaces = ImmutableSet.of(VNONEH2);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
// Reply messages from vNoneh2 (VPLS 3) should be received by vNoneh1
replyMessage = makeReplyContext(VNONEHOST2, VNONEHOST1);
expectInterfaces = ImmutableSet.of(VNONEH1);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
}
/**
* Sends reply messages to hosts in VPLS 4.
* Reply messages should be received by the host with MAC address equal to
* the dstMac of the message context.
*/
@Test
public void vpls4ReplyMessage() {
// Reply messages from v400h1 (VPLS 4) should be received by vNoneh3
TestMessageContext replyMessage =
makeReplyContext(V400HOST1, VNONEHOST3);
Set<Interface> expectInterfaces = ImmutableSet.of(VNONEH3);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
// Reply messages from vNoneh3 (VPLS 4) should be received by v400h1
replyMessage = makeReplyContext(VNONEHOST3, V400HOST1);
expectInterfaces = ImmutableSet.of(V400H1);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
}
/**
* Sends wrong reply messages to hosts.
* The source and the destination MAC addresses are not set on any host of the VPLS.
* The reply messages will not be received by any hosts.
*/
@Test
public void wrongReplyMessage() {
// Reply message from v100h1 (VPLS 1) to v100h2 (VPLS 2).
// Forward results should be empty
TestMessageContext replyMessage = makeReplyContext(V100HOST1, V100HOST2);
Set<Interface> expectInterfaces = ImmutableSet.of();
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
// Reply message from v200h2 (VPLS 2) to v300h1 (VPLS 1).
// Forward results should be empty
replyMessage = makeReplyContext(V200HOST2, V300HOST1);
expectInterfaces = ImmutableSet.of();
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
// Reply message from vNoneh1 (VPLS 3) to v400h1 (VPLS 4).
// Forward results should be empty
replyMessage = makeReplyContext(VNONEHOST1, V400HOST1);
expectInterfaces = ImmutableSet.of();
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
// Reply message from vNoneh3 (VPLS 4) to vNoneH2 (VPLS 3).
// Forward results should be empty
replyMessage = makeReplyContext(VNONEHOST3, VNONEHOST2);
expectInterfaces = ImmutableSet.of();
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
}
/**
* Sends reply and request message from a host which not related to any VPLS.
*/
@Test
public void testVplsNotfound() {
TestMessageContext replyMessage = makeReplyContext(V300HOST2, V100HOST1);
Set<Interface> expectInterfaces = ImmutableSet.of();
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(replyMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, replyMessage.forwardResults);
assertTrue(replyMessage.dropped());
TestMessageContext requestMessage = makeBroadcastRequestContext(V300HOST2);
((TestNeighbourService) vplsNeighbourHandler.neighbourService).sendNeighourMessage(requestMessage);
assertEquals(IFACES_NOT_EXPECTED, expectInterfaces, requestMessage.forwardResults);
assertTrue(requestMessage.dropped());
}
/**
* Generates broadcast request message context by given source host.
*
* @param host the source host
* @return the request message context
*/
private TestMessageContext makeBroadcastRequestContext(Host host) {
return new TestMessageContext(host.location(),
host.mac(),
MacAddress.BROADCAST,
host.vlan(),
NeighbourMessageType.REQUEST);
}
/**
* Generates reply message context by given source and destination host.
*
* @param src the source host
* @param dst the destination host
* @return the reply message context
*/
private TestMessageContext makeReplyContext(Host src, Host dst) {
return new TestMessageContext(src.location(),
src.mac(),
dst.mac(),
src.vlan(),
NeighbourMessageType.REPLY);
}
/**
* Test message context.
*/
private class TestMessageContext implements NeighbourMessageContext {
private final NeighbourMessageType type;
private final MacAddress srcMac;
private final MacAddress dstMac;
private final ConnectPoint inPort;
private final VlanId vlanId;
private boolean dropped = false;
public Set<Interface> forwardResults;
/**
* Creates new neighbour message context for test.
*
* @param inPort the input port
* @param srcMac the source Mac
* @param dstMac the destination Mac
* @param vlanId the VLAN Id
* @param type the message context type
*/
public TestMessageContext(
ConnectPoint inPort,
MacAddress srcMac,
MacAddress dstMac,
VlanId vlanId,
NeighbourMessageType type) {
this.inPort = inPort;
this.srcMac = srcMac;
this.dstMac = dstMac;
this.vlanId = vlanId;
this.type = type;
this.forwardResults = Sets.newHashSet();
this.dropped = false;
}
@Override
public ConnectPoint inPort() {
return inPort;
}
@Override
public NeighbourMessageType type() {
return type;
}
@Override
public VlanId vlan() {
return vlanId;
}
@Override
public MacAddress srcMac() {
return srcMac;
}
@Override
public MacAddress dstMac() {
return dstMac;
}
@Override
public IpAddress target() {
return null;
}
@Override
public IpAddress sender() {
return null;
}
@Override
public void forward(ConnectPoint outPort) {
}
/**
* Records all forward network interface information.
* @param outIntf output interface
*/
@Override
public void forward(Interface outIntf) {
forwardResults.add(outIntf);
}
@Override
public void reply(MacAddress targetMac) {
}
@Override
public void flood() {
}
@Override
public void drop() {
this.dropped = true;
}
@Override
public Ethernet packet() {
return null;
}
@Override
public NeighbourProtocol protocol() {
return null;
}
public boolean dropped() {
return dropped;
}
}
/**
* Test neighbour service; records all registrations between neighbour
* message handler and interfaces.
*/
private class TestNeighbourService implements NeighbourResolutionService {
private SetMultimap<ConnectPoint, NeighbourHandlerRegistration> handlerRegs;
public TestNeighbourService() {
handlerRegs = HashMultimap.create();
}
@Override
public void registerNeighbourHandler(ConnectPoint connectPoint,
NeighbourMessageHandler handler,
ApplicationId appId) {
Interface intf =
new Interface(null, connectPoint, null, null, null);
NeighbourHandlerRegistration reg =
new HandlerRegistration(handler, intf, appId);
handlerRegs.put(connectPoint, reg);
}
@Override
public void registerNeighbourHandler(Interface intf,
NeighbourMessageHandler handler,
ApplicationId appId) {
NeighbourHandlerRegistration reg =
new HandlerRegistration(handler, intf, appId);
handlerRegs.put(intf.connectPoint(), reg);
}
@Override
public void unregisterNeighbourHandler(ConnectPoint connectPoint,
NeighbourMessageHandler handler,
ApplicationId appId) {
handlerRegs.removeAll(connectPoint);
}
@Override
public void unregisterNeighbourHandler(Interface intf,
NeighbourMessageHandler handler,
ApplicationId appId) {
handlerRegs.removeAll(intf.connectPoint());
}
@Override
public void unregisterNeighbourHandlers(ApplicationId appId) {
handlerRegs.clear();
}
@Override
public Map<ConnectPoint, Collection<NeighbourHandlerRegistration>> getHandlerRegistrations() {
return handlerRegs.asMap();
}
/**
* Sends neighbour message context to all handler which related to the
* context.
*
* @param context the neighbour message context
*/
public void sendNeighourMessage(NeighbourMessageContext context) {
ConnectPoint connectPoint = context.inPort();
VlanId vlanId = context.vlan();
Collection<NeighbourHandlerRegistration> registrations = handlerRegs.get(connectPoint);
registrations.forEach(reg -> {
if (reg.intf().vlan().equals(vlanId)) {
reg.handler().handleMessage(context, hostService);
}
});
}
/**
* Test handler registration.
*/
private class HandlerRegistration implements NeighbourHandlerRegistration {
private final Interface intf;
private final NeighbourMessageHandler handler;
private final ApplicationId appId;
/**
* Creates a new registration handler.
*
* @param handler the neighbour message handler
* @param intf the interface
*/
public HandlerRegistration(NeighbourMessageHandler handler,
Interface intf,
ApplicationId appId) {
this.intf = intf;
this.handler = handler;
this.appId = appId;
}
@Override
public Interface intf() {
return intf;
}
@Override
public NeighbourMessageHandler handler() {
return handler;
}
@Override
public ApplicationId appId() {
return appId;
}
}
}
}