/** Tests for the {@link Vpls} class. */ public class VplsTest { private static final int NUM_DEVICES = 7; private static final MacAddress MAC1 = MacAddress.valueOf("00:00:00:00:00:01"); private static final MacAddress MAC2 = MacAddress.valueOf("00:00:00:00:00:02"); private static final MacAddress MAC3 = MacAddress.valueOf("00:00:00:00:00:03"); private static final MacAddress MAC4 = MacAddress.valueOf("00:00:00:00:00:04"); private static final MacAddress MAC5 = MacAddress.valueOf("00:00:00:00:00:05"); private static final MacAddress MAC6 = MacAddress.valueOf("00:00:00:00:00:06"); private static final MacAddress MAC7 = MacAddress.valueOf("00:00:00:00:00:07"); private static final Ip4Address IP1 = Ip4Address.valueOf("192.168.1.1"); private static final Ip4Address IP2 = Ip4Address.valueOf("192.168.1.2"); private static final PortNumber P1 = PortNumber.portNumber(1); private static final VlanId VLAN1 = VlanId.vlanId((short) 1); private static final VlanId VLAN2 = VlanId.vlanId((short) 2); private static final int PRIORITY_OFFSET = 1000; private static final String PREFIX_BROADCAST = "brc"; private static final String PREFIX_UNICAST = "uni"; private static final DeviceId DID1 = getDeviceId(1); private static final DeviceId DID2 = getDeviceId(2); private static final DeviceId DID3 = getDeviceId(3); private static final DeviceId DID4 = getDeviceId(4); private static final DeviceId DID5 = getDeviceId(5); private static final DeviceId DID6 = getDeviceId(6); private static final ConnectPoint C1 = new ConnectPoint(DID1, P1); private static final ConnectPoint C2 = new ConnectPoint(DID2, P1); private static final ConnectPoint C3 = new ConnectPoint(DID3, P1); private static final ConnectPoint C4 = new ConnectPoint(DID4, P1); private static final ConnectPoint C5 = new ConnectPoint(DID5, P1); private static final ConnectPoint C6 = new ConnectPoint(DID6, P1); private static final HostId HID1 = HostId.hostId(MAC1, VLAN1); private static final HostId HID2 = HostId.hostId(MAC2, VLAN1); private static final HostId HID3 = HostId.hostId(MAC3, VLAN1); private static final HostId HID4 = HostId.hostId(MAC4, VLAN2); private static final HostId HID5 = HostId.hostId(MAC5, VLAN2); private static final HostId HID6 = HostId.hostId(MAC6, VLAN2); private static final HostId HID7 = HostId.hostId(MAC7, VlanId.NONE); private ApplicationService applicationService; private CoreService coreService; private HostListener hostListener; private Set<Host> hostsAvailable; private HostService hostService; private IntentService intentService; private InterfaceService interfaceService; private Vpls vpls; private static final String APP_NAME = "org.onosproject.vpls"; private static final ApplicationId APPID = TestApplicationId.create(APP_NAME); private static final ProviderId PID = new ProviderId("of", "foo"); private static IdGenerator idGenerator; @Before public void setUp() throws Exception { idGenerator = new TestIdGenerator(); Intent.bindIdGenerator(idGenerator); applicationService = createMock(ApplicationService.class); coreService = createMock(CoreService.class); expect(coreService.registerApplication(APP_NAME)).andReturn(APPID); replay(coreService); hostsAvailable = Sets.newHashSet(); hostService = new TestHostService(hostsAvailable); intentService = new TestIntentService(); TestIntentSynchronizer intentSynchronizer = new TestIntentSynchronizer(intentService); interfaceService = createMock(InterfaceService.class); interfaceService.addListener(anyObject(InterfaceListener.class)); expectLastCall().anyTimes(); addIntfConfig(); vpls = new Vpls(); vpls.applicationService = applicationService; vpls.coreService = coreService; vpls.hostService = hostService; vpls.intentService = intentService; vpls.interfaceService = interfaceService; vpls.intentSynchronizer = intentSynchronizer; } @After public void tearDown() { Intent.unbindIdGenerator(idGenerator); } /** * Creates the interface configuration. On devices 1, 2 and 3 is configured an interface on port 1 * with vlan 1. On devices 4, 5 and 6 is configured an interface on port 1 with vlan 2. On device * 5 no interfaces are configured. */ private void addIntfConfig() { Set<Interface> interfaces = Sets.newHashSet(); Set<Interface> vlanOneSet = Sets.newHashSet(); Set<Interface> vlanTwoSet = Sets.newHashSet(); for (int i = 1; i <= NUM_DEVICES - 1; i++) { ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1); Interface intf = new Interface("intfOne", cp, Collections.emptyList(), null, VlanId.NONE); if (i <= 3) { intf = new Interface("intfTwo", cp, Collections.emptyList(), null, VLAN1); interfaces.add(intf); vlanOneSet.add(intf); } else if (i > 3 && i <= 6) { intf = new Interface("intfThree", cp, Collections.emptyList(), null, VLAN2); interfaces.add(intf); vlanTwoSet.add(intf); } expect(interfaceService.getInterfacesByPort(cp)).andReturn(Sets.newHashSet(intf)).anyTimes(); } expect(interfaceService.getInterfacesByVlan(VLAN1)).andReturn(vlanOneSet).anyTimes(); expect(interfaceService.getInterfacesByVlan(VLAN2)).andReturn(vlanTwoSet).anyTimes(); expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes(); replay(interfaceService); } /** * Checks the case in which six ports are configured with VLANs but no hosts are registered by the * HostService. The first three ports have an interface configured on VLAN1, the other three on * VLAN2. The number of intents expected is six: three for VLAN1, three for VLAN2. three sp2mp * intents, three mp2sp intents. */ @Test public void testActivateNoHosts() { vpls.activate(); List<Intent> expectedIntents = Lists.newArrayList(); expectedIntents.addAll(generateVlanOneBrc()); expectedIntents.addAll(generateVlanTwoBrc()); checkIntents(expectedIntents); } /** * Checks the case in which six ports are configured with VLANs and four hosts are registered by * the HostService. The first three ports have an interface configured on VLAN1, the other three * on VLAN2. The number of intents expected is twelve: six for VLAN1, six for VLAN2. six sp2mp * intents, six mp2sp intents. For VLAN1 IPs are added to demonstrate it doesn't influence the * number of intents created. */ @Test public void testFourInterfacesConfiguredHostsPresent() { Host h1 = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(1), Collections.singleton(IP1)); Host h2 = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(2), Collections.singleton(IP2)); Host h3 = new DefaultHost(PID, HID3, MAC3, VLAN1, getLocation(3), Collections.EMPTY_SET); Host h4 = new DefaultHost(PID, HID4, MAC4, VLAN2, getLocation(4), Collections.EMPTY_SET); Host h5 = new DefaultHost(PID, HID5, MAC5, VLAN2, getLocation(5), Collections.EMPTY_SET); Host h6 = new DefaultHost(PID, HID6, MAC6, VLAN2, getLocation(6), Collections.EMPTY_SET); hostsAvailable.addAll(Sets.newHashSet(h1, h2, h3, h4, h5, h6)); vpls.activate(); List<Intent> expectedIntents = Lists.newArrayList(); expectedIntents.addAll(generateVlanOneBrc()); expectedIntents.addAll(generateVlanOneUni()); expectedIntents.addAll(generateVlanTwoBrc()); expectedIntents.addAll(generateVlanTwoUni()); checkIntents(expectedIntents); } /** * Checks the case in which six ports are configured with VLANs and initially no hosts are * registered by the HostService. The first three ports have an interface configured on VLAN1, the * other three have an interface configured on VLAN2. When the module starts up, three hosts - on * device one, two and three - port 1 (both on VLAN1), are registered by the HostService and * events are sent to the application. sp2mp intents are created for all interfaces configured and * mp2sp intents are created only for the hosts attached. The number of intents expected is nine: * six for VLAN1, three for VLAN2. Six sp2mp intents, three mp2sp intents. IPs are added on the * first two hosts only to demonstrate it doesn't influence the number of intents created. An * additional host is added on device seven, port one to demonstrate that, even if it's on the * same VLAN of other interfaces configured in the system, it doesn't let the application generate * intents, since it's not connected to the interface configured. */ @Test public void testFourInterfacesThreeHostEventsSameVlan() { vpls.activate(); Host h1 = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(1), Collections.singleton(IP1)); Host h2 = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(2), Collections.singleton(IP2)); Host h3 = new DefaultHost(PID, HID3, MAC3, VLAN1, getLocation(3), Collections.EMPTY_SET); Host h7 = new DefaultHost(PID, HID7, MAC7, VLAN1, getLocation(7), Collections.EMPTY_SET); hostsAvailable.addAll(Sets.newHashSet(h1, h2, h3, h7)); hostsAvailable.forEach( host -> hostListener.event(new HostEvent(HostEvent.Type.HOST_ADDED, host))); List<Intent> expectedIntents = Lists.newArrayList(); expectedIntents.addAll(generateVlanOneBrc()); expectedIntents.addAll(generateVlanOneUni()); expectedIntents.addAll(generateVlanTwoBrc()); checkIntents(expectedIntents); } /** * Checks the case in which six ports are configured with VLANs and initially no hosts are * registered by the HostService. The first three ports have an interface configured on VLAN1, the * other three have an interface configured on VLAN2. When the module starts up, two hosts - on * device one and four - port 1 (VLAN 1 and VLAN 2), are registered by the HostService and events * are sent to the application. sp2mp intents are created for all interfaces configured and no * mp2sp intents are created at all, since the minimum number of hosts needed on the same vlan to * create mp2sp intents is 2. The number of intents expected is six: three for VLAN1, three for * VLAN2. six sp2mp intents, zero mp2sp intents. IPs are added on the first host only to * demonstrate it doesn't influence the number of intents created. */ @Test public void testFourInterfacesTwoHostEventsDifferentVlan() { vpls.activate(); Host h1 = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(1), Collections.singleton(IP1)); Host h4 = new DefaultHost(PID, HID4, MAC4, VLAN2, getLocation(4), Collections.EMPTY_SET); hostsAvailable.addAll(Sets.newHashSet(h1, h4)); hostsAvailable.forEach( host -> { hostListener.event(new HostEvent(HostEvent.Type.HOST_ADDED, host)); }); List<Intent> expectedIntents = Lists.newArrayList(); expectedIntents.addAll(generateVlanOneBrc()); expectedIntents.addAll(generateVlanTwoBrc()); checkIntents(expectedIntents); } /** * Checks both that the number of intents in submitted in the intent framework it's equal to the * number of intents expected and that all intents are equivalent. * * @param intents the list of intents expected */ private void checkIntents(List<Intent> intents) { assertEquals(intents.size(), intentService.getIntentCount()); for (Intent intentOne : intents) { boolean found = false; for (Intent intentTwo : intentService.getIntents()) { if (intentOne.key().equals(intentTwo.key())) { found = true; assertTrue( format("Comparing %s and %s", intentOne, intentTwo), IntentUtils.intentsAreEqual(intentOne, intentTwo)); break; } } assertTrue(found); } } /** * Generates the list of the expected sp2mp intents for VLAN 1. * * @return the list of expected sp2mp intents for VLAN 1 */ private List<SinglePointToMultiPointIntent> generateVlanOneBrc() { Key key = null; List<SinglePointToMultiPointIntent> intents = Lists.newArrayList(); // Building sp2mp intent for H1 - VLAN1 key = Key.of((PREFIX_BROADCAST + "-" + DID1 + "-" + P1 + "-" + VLAN1), APPID); intents.add(buildBrcIntent(key, C1, Sets.newHashSet(C2, C3), VLAN1)); // Building sp2mp intent for H2 - VLAN1 key = Key.of((PREFIX_BROADCAST + "-" + DID2 + "-" + P1 + "-" + VLAN1), APPID); intents.add(buildBrcIntent(key, C2, Sets.newHashSet(C1, C3), VLAN1)); // Building sp2mp intent for H3 - VLAN1 key = Key.of((PREFIX_BROADCAST + "-" + DID3 + "-" + P1 + "-" + VLAN1), APPID); intents.add(buildBrcIntent(key, C3, Sets.newHashSet(C1, C2), VLAN1)); return intents; } /** * Generates the list of the expected mp2sp intents for VLAN 1. * * @return the list of expected mp2sp intents for VLAN 1 */ private List<MultiPointToSinglePointIntent> generateVlanOneUni() { Key key = null; List<MultiPointToSinglePointIntent> intents = Lists.newArrayList(); // Building mp2sp intent for H1 - VLAN1 key = Key.of((PREFIX_UNICAST + "-" + DID1 + "-" + P1 + "-" + VLAN1), APPID); intents.add(buildUniIntent(key, Sets.newHashSet(C2, C3), C1, VLAN1, MAC1)); // Building mp2sp intent for H2 - VLAN1 key = Key.of((PREFIX_UNICAST + "-" + DID2 + "-" + P1 + "-" + VLAN1), APPID); intents.add(buildUniIntent(key, Sets.newHashSet(C1, C3), C2, VLAN1, MAC2)); // Building mp2sp intent for H3 - VLAN1 key = Key.of((PREFIX_UNICAST + "-" + DID3 + "-" + P1 + "-" + VLAN1), APPID); intents.add(buildUniIntent(key, Sets.newHashSet(C1, C2), C3, VLAN1, MAC3)); return intents; } /** * Generates the list of the expected sp2mp intents for VLAN 2. * * @return the list of expected sp2mp intents for VLAN 2 */ private List<SinglePointToMultiPointIntent> generateVlanTwoBrc() { Key key = null; List<SinglePointToMultiPointIntent> intents = Lists.newArrayList(); // Building sp2mp intent for H4 - VLAN2 key = Key.of((PREFIX_BROADCAST + "-" + DID4 + "-" + P1 + "-" + VLAN2), APPID); intents.add(buildBrcIntent(key, C4, Sets.newHashSet(C5, C6), VLAN2)); // Building sp2mp intent for H5 - VLAN2 key = Key.of((PREFIX_BROADCAST + "-" + DID5 + "-" + P1 + "-" + VLAN2), APPID); intents.add(buildBrcIntent(key, C5, Sets.newHashSet(C4, C6), VLAN2)); // Building sp2mp intent for H6 - VLAN2 key = Key.of((PREFIX_BROADCAST + "-" + DID6 + "-" + P1 + "-" + VLAN2), APPID); intents.add(buildBrcIntent(key, C6, Sets.newHashSet(C4, C5), VLAN2)); return intents; } /** * Generates the list of the expected mp2sp intents for VLAN 2. * * @return the list of expected mp2sp intents for VLAN 2 */ private List<MultiPointToSinglePointIntent> generateVlanTwoUni() { Key key = null; List<MultiPointToSinglePointIntent> intents = Lists.newArrayList(); // Building mp2sp intent for H4 - VLAN2 key = Key.of((PREFIX_UNICAST + "-" + DID4 + "-" + P1 + "-" + VLAN2), APPID); intents.add(buildUniIntent(key, Sets.newHashSet(C5, C6), C4, VLAN2, MAC4)); // Building mp2sp intent for H5 - VLAN2 key = Key.of((PREFIX_UNICAST + "-" + DID5 + "-" + P1 + "-" + VLAN2), APPID); intents.add(buildUniIntent(key, Sets.newHashSet(C4, C6), C5, VLAN2, MAC5)); // Building mp2sp intent for H6 - VLAN2 key = Key.of((PREFIX_UNICAST + "-" + DID6 + "-" + P1 + "-" + VLAN2), APPID); intents.add(buildUniIntent(key, Sets.newHashSet(C4, C5), C6, VLAN2, MAC6)); return intents; } /** * Builds a Single Point to Multi Point intent. * * @param key The intent key * @param src The source Connect Point * @param dsts The destination Connect Points * @return Single Point to Multi Point intent generated. */ private SinglePointToMultiPointIntent buildBrcIntent( Key key, ConnectPoint src, Set<ConnectPoint> dsts, VlanId vlanId) { SinglePointToMultiPointIntent intent; TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); TrafficSelector selector = DefaultTrafficSelector.builder() .matchEthDst(MacAddress.BROADCAST) .matchVlanId(vlanId) .build(); intent = SinglePointToMultiPointIntent.builder() .appId(APPID) .key(key) .selector(selector) .treatment(treatment) .ingressPoint(src) .egressPoints(dsts) .priority(PRIORITY_OFFSET) .build(); return intent; } /** * Builds a Multi Point to Single Point intent. * * @param key The intent key * @param srcs The source Connect Points * @param dst The destination Connect Point * @return Multi Point to Single Point intent generated. */ private MultiPointToSinglePointIntent buildUniIntent( Key key, Set<ConnectPoint> srcs, ConnectPoint dst, VlanId vlanId, MacAddress mac) { MultiPointToSinglePointIntent intent; TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); TrafficSelector.Builder builder = DefaultTrafficSelector.builder().matchEthDst(mac).matchVlanId(vlanId); TrafficSelector selector = builder.build(); intent = MultiPointToSinglePointIntent.builder() .appId(APPID) .key(key) .selector(selector) .treatment(treatment) .ingressPoints(srcs) .egressPoint(dst) .priority(PRIORITY_OFFSET) .build(); return intent; } /** * Returns the device ID of the ith device. * * @param i device to get the ID of * @return the device ID */ private static DeviceId getDeviceId(int i) { return DeviceId.deviceId("" + i); } private static HostLocation getLocation(int i) { return new HostLocation(new ConnectPoint(getDeviceId(i), P1), 123L); } /** * Represents a fake IntentService class that easily allows to store and retrieve intents without * implementing the IntentService logic. */ private class TestIntentService extends IntentServiceAdapter { private Set<Intent> intents; public TestIntentService() { intents = Sets.newHashSet(); } @Override public void submit(Intent intent) { intents.add(intent); } @Override public long getIntentCount() { return intents.size(); } @Override public Iterable<Intent> getIntents() { return intents; } @Override public Intent getIntent(Key intentKey) { for (Intent intent : intents) { if (intent.key().equals(intentKey)) { return intent; } } return null; } } /** * Represents a fake HostService class which allows to add hosts manually in each test, when * needed. */ private class TestHostService extends HostServiceAdapter { private Set<Host> hosts; public TestHostService(Set<Host> hosts) { this.hosts = hosts; } @Override public void addListener(HostListener listener) { VplsTest.this.hostListener = listener; } @Override public Set<Host> getConnectedHosts(ConnectPoint connectPoint) { return hosts .stream() .filter( h -> h.location().elementId().equals(connectPoint.elementId()) && h.location().port().equals(connectPoint.port())) .collect(Collectors.toSet()); } } private static class TestIdGenerator implements IdGenerator { private final AtomicLong id = new AtomicLong(0); @Override public long getNewId() { return id.getAndIncrement(); } } /** Test IntentSynchronizer that passes all intents straight through to the intent service. */ private class TestIntentSynchronizer implements IntentSynchronizationService, IntentSynchronizationAdminService { private final IntentService intentService; /** * Creates a new test intent synchronizer. * * @param intentService intent service */ public TestIntentSynchronizer(IntentService intentService) { this.intentService = intentService; } @Override public void submit(Intent intent) { intentService.submit(intent); } @Override public void withdraw(Intent intent) { intentService.withdraw(intent); } @Override public void modifyPrimary(boolean isPrimary) {} @Override public void removeIntents() {} @Override public void removeIntentsByAppId(ApplicationId applicationId) {} } }
/** Unit tests for PeerConnectivityManager. */ public class PeerConnectivityManagerTest extends AbstractIntentTest { private static final ApplicationId APPID = TestApplicationId.create("foo"); private static final ApplicationId CONFIG_APP_ID = APPID; private PeerConnectivityManager peerConnectivityManager; private IntentSynchronizationService intentSynchronizer; private InterfaceService interfaceService; private NetworkConfigService networkConfigService; private Set<BgpConfig.BgpSpeakerConfig> bgpSpeakers; private Map<String, Interface> interfaces; private BgpConfig bgpConfig; private List<PointToPointIntent> intentList; private final DeviceId deviceId1 = DeviceId.deviceId("of:0000000000000001"); private final DeviceId deviceId2 = DeviceId.deviceId("of:0000000000000002"); private final DeviceId deviceId3 = DeviceId.deviceId("of:0000000000000003"); // Interfaces connected to BGP speakers private final ConnectPoint s1Eth100 = new ConnectPoint(deviceId1, PortNumber.portNumber(100)); private final ConnectPoint s2Eth100 = new ConnectPoint(deviceId2, PortNumber.portNumber(100)); private final ConnectPoint s3Eth100 = new ConnectPoint(deviceId3, PortNumber.portNumber(100)); // Interfaces connected to BGP peers private final ConnectPoint s1Eth1 = new ConnectPoint(deviceId1, PortNumber.portNumber(1)); private final ConnectPoint s2Eth1 = new ConnectPoint(deviceId2, PortNumber.portNumber(1)); private final ConnectPoint s3Eth1 = new ConnectPoint(deviceId3, PortNumber.portNumber(1)); private static final VlanId NO_VLAN = VlanId.NONE; private static final VlanId VLAN10 = VlanId.vlanId(Short.valueOf("10")); private static final VlanId VLAN20 = VlanId.vlanId(Short.valueOf("20")); private static final VlanId VLAN30 = VlanId.vlanId(Short.valueOf("30")); @Before public void setUp() throws Exception { super.setUp(); interfaceService = createMock(InterfaceService.class); interfaceService.addListener(anyObject(InterfaceListener.class)); expectLastCall().anyTimes(); networkConfigService = createMock(NetworkConfigService.class); networkConfigService.addListener(anyObject(NetworkConfigListener.class)); expectLastCall().anyTimes(); bgpConfig = createMock(BgpConfig.class); // These will set expectations on routingConfig and interfaceService bgpSpeakers = setUpBgpSpeakers(); interfaces = Collections.unmodifiableMap(setUpInterfaces()); initPeerConnectivity(); intentList = setUpIntentList(); } /** * Sets up BGP speakers. * * @return configured BGP speakers as a map from speaker name to speaker */ private Set<BgpConfig.BgpSpeakerConfig> setUpBgpSpeakers() { BgpConfig.BgpSpeakerConfig speaker1 = new BgpConfig.BgpSpeakerConfig( Optional.empty(), NO_VLAN, s1Eth100, Collections.singleton(IpAddress.valueOf("192.168.10.1"))); BgpConfig.BgpSpeakerConfig speaker2 = new BgpConfig.BgpSpeakerConfig( Optional.empty(), NO_VLAN, s1Eth100, Sets.newHashSet(IpAddress.valueOf("192.168.20.1"), IpAddress.valueOf("192.168.30.1"))); BgpConfig.BgpSpeakerConfig speaker3 = new BgpConfig.BgpSpeakerConfig( Optional.empty(), VLAN30, s3Eth100, Sets.newHashSet(IpAddress.valueOf("192.168.40.1"), IpAddress.valueOf("192.168.50.1"))); Set<BgpConfig.BgpSpeakerConfig> bgpSpeakers = Sets.newHashSet(); bgpSpeakers.add(speaker1); bgpSpeakers.add(speaker2); bgpSpeakers.add(speaker3); return bgpSpeakers; } /** * Sets up logical interfaces, which emulate the configured interfaces in SDN-IP application. * * @return configured interfaces as a map from interface name to Interface */ private Map<String, Interface> setUpInterfaces() { Map<String, Interface> configuredInterfaces = new HashMap<>(); String interfaceSw1Eth1 = "s1-eth1"; InterfaceIpAddress ia1 = new InterfaceIpAddress( IpAddress.valueOf("192.168.10.101"), IpPrefix.valueOf("192.168.10.0/24")); Interface intfsw1eth1 = new Interface( interfaceSw1Eth1, s1Eth1, Collections.singletonList(ia1), MacAddress.valueOf("00:00:00:00:00:01"), VlanId.NONE); configuredInterfaces.put(interfaceSw1Eth1, intfsw1eth1); String interfaceSw2Eth1 = "s2-eth1"; InterfaceIpAddress ia2 = new InterfaceIpAddress( IpAddress.valueOf("192.168.20.101"), IpPrefix.valueOf("192.168.20.0/24")); Interface intfsw2eth1 = new Interface( interfaceSw2Eth1, s2Eth1, Collections.singletonList(ia2), MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE); configuredInterfaces.put(interfaceSw2Eth1, intfsw2eth1); String interfaceSw2Eth1intf2 = "s2-eth1_2"; InterfaceIpAddress ia3 = new InterfaceIpAddress( IpAddress.valueOf("192.168.30.101"), IpPrefix.valueOf("192.168.30.0/24")); Interface intfsw2eth1intf2 = new Interface( interfaceSw2Eth1intf2, s2Eth1, Collections.singletonList(ia3), MacAddress.valueOf("00:00:00:00:00:03"), VlanId.NONE); configuredInterfaces.put(interfaceSw2Eth1intf2, intfsw2eth1intf2); String interfaceSw3Eth1 = "s3-eth1"; InterfaceIpAddress ia4 = new InterfaceIpAddress( IpAddress.valueOf("192.168.40.101"), IpPrefix.valueOf("192.168.40.0/24")); Interface intfsw3eth1 = new Interface( Interface.NO_INTERFACE_NAME, s3Eth1, ImmutableList.of(ia4), MacAddress.valueOf("00:00:00:00:00:04"), VLAN10); configuredInterfaces.put(interfaceSw3Eth1, intfsw3eth1); String interfaceSw3Eth1intf2 = "s3-eth1_2"; InterfaceIpAddress ia5 = new InterfaceIpAddress( IpAddress.valueOf("192.168.50.101"), IpPrefix.valueOf("192.168.50.0/24")); Interface intfsw3eth1intf2 = new Interface( Interface.NO_INTERFACE_NAME, s3Eth1, ImmutableList.of(ia5), MacAddress.valueOf("00:00:00:00:00:05"), VLAN20); configuredInterfaces.put(interfaceSw3Eth1intf2, intfsw3eth1intf2); expect(interfaceService.getInterfacesByPort(s1Eth1)) .andReturn(Collections.singleton(intfsw1eth1)) .anyTimes(); expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.10.101"))) .andReturn(Collections.singleton(intfsw1eth1)) .anyTimes(); expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.10.1"))) .andReturn(intfsw1eth1) .anyTimes(); expect(interfaceService.getInterfacesByPort(s2Eth1)) .andReturn(Collections.singleton(intfsw2eth1)) .anyTimes(); expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.20.101"))) .andReturn(Collections.singleton(intfsw2eth1)) .anyTimes(); expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.20.1"))) .andReturn(intfsw2eth1) .anyTimes(); expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.30.101"))) .andReturn(Collections.singleton(intfsw2eth1intf2)) .anyTimes(); expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.30.1"))) .andReturn(intfsw2eth1intf2) .anyTimes(); expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.40.101"))) .andReturn(Collections.singleton(intfsw3eth1)) .anyTimes(); expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.40.1"))) .andReturn(intfsw3eth1) .anyTimes(); expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.50.101"))) .andReturn(Collections.singleton(intfsw3eth1intf2)) .anyTimes(); expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.50.1"))) .andReturn(intfsw3eth1intf2) .anyTimes(); // Non-existent interface used during one of the tests expect( interfaceService.getInterfacesByPort( new ConnectPoint( DeviceId.deviceId("of:0000000000000100"), PortNumber.portNumber(1)))) .andReturn(null) .anyTimes(); expect(interfaceService.getInterfaces()) .andReturn(Sets.newHashSet(configuredInterfaces.values())) .anyTimes(); return configuredInterfaces; } /** * Sets up expected point to point intent list. * * @return point to point intent list */ private List<PointToPointIntent> setUpIntentList() { intentList = new ArrayList<>(); setUpBgpIntents(); setUpIcmpIntents(); return intentList; } /** * Constructs a BGP intent and put it into the intentList. * * <p>The purpose of this method is too simplify the setUpBgpIntents() method, and to make the * setUpBgpIntents() easy to read. * * @param srcVlanId ingress VlanId * @param dstVlanId egress VlanId * @param srcPrefix source IP prefix to match * @param dstPrefix destination IP prefix to match * @param srcTcpPort source TCP port to match * @param dstTcpPort destination TCP port to match * @param srcConnectPoint source connect point for PointToPointIntent * @param dstConnectPoint destination connect point for PointToPointIntent */ private void bgpPathintentConstructor( VlanId srcVlanId, VlanId dstVlanId, String srcPrefix, String dstPrefix, Short srcTcpPort, Short dstTcpPort, ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) { TrafficSelector.Builder builder = DefaultTrafficSelector.builder() .matchEthType(Ethernet.TYPE_IPV4) .matchIPProtocol(IPv4.PROTOCOL_TCP) .matchIPSrc(IpPrefix.valueOf(srcPrefix)) .matchIPDst(IpPrefix.valueOf(dstPrefix)); if (!srcVlanId.equals(VlanId.NONE)) { builder.matchVlanId(srcVlanId); } TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); if (!dstVlanId.equals(VlanId.NONE)) { treatment.setVlanId(dstVlanId); } if (srcTcpPort != null) { builder.matchTcpSrc(TpPort.tpPort(srcTcpPort)); } if (dstTcpPort != null) { builder.matchTcpDst(TpPort.tpPort(dstTcpPort)); } Key key = Key.of( srcPrefix.split("/")[0] + "-" + dstPrefix.split("/")[0] + "-" + ((srcTcpPort == null) ? "dst" : "src"), APPID); PointToPointIntent intent = PointToPointIntent.builder() .appId(APPID) .key(key) .selector(builder.build()) .treatment(treatment.build()) .ingressPoint(srcConnectPoint) .egressPoint(dstConnectPoint) .build(); intentList.add(intent); } /** Sets up intents for BGP paths. */ private void setUpBgpIntents() { Short bgpPort = 179; // Start to build intents between BGP speaker1 and BGP peer1 bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.10.101/32", "192.168.10.1/32", null, bgpPort, s1Eth100, s1Eth1); bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.10.101/32", "192.168.10.1/32", bgpPort, null, s1Eth100, s1Eth1); bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.10.1/32", "192.168.10.101/32", null, bgpPort, s1Eth1, s1Eth100); bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.10.1/32", "192.168.10.101/32", bgpPort, null, s1Eth1, s1Eth100); // Start to build intents between BGP speaker1 and BGP peer2 bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.20.101/32", "192.168.20.1/32", null, bgpPort, s1Eth100, s2Eth1); bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.20.101/32", "192.168.20.1/32", bgpPort, null, s1Eth100, s2Eth1); bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.20.1/32", "192.168.20.101/32", null, bgpPort, s2Eth1, s1Eth100); bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.20.1/32", "192.168.20.101/32", bgpPort, null, s2Eth1, s1Eth100); // Start to build intents between BGP speaker2 and BGP peer1 bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.30.101/32", "192.168.30.1/32", null, bgpPort, s1Eth100, s2Eth1); bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.30.101/32", "192.168.30.1/32", bgpPort, null, s1Eth100, s2Eth1); bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.30.1/32", "192.168.30.101/32", null, bgpPort, s2Eth1, s1Eth100); bgpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.30.1/32", "192.168.30.101/32", bgpPort, null, s2Eth1, s1Eth100); // Start to build intents between BGP speaker3 and BGP peer4 bgpPathintentConstructor( VLAN30, VLAN10, "192.168.40.101/32", "192.168.40.1/32", null, bgpPort, s3Eth100, s3Eth1); bgpPathintentConstructor( VLAN30, VLAN10, "192.168.40.101/32", "192.168.40.1/32", bgpPort, null, s3Eth100, s3Eth1); bgpPathintentConstructor( VLAN10, VLAN30, "192.168.40.1/32", "192.168.40.101/32", null, bgpPort, s3Eth1, s3Eth100); bgpPathintentConstructor( VLAN10, VLAN30, "192.168.40.1/32", "192.168.40.101/32", bgpPort, null, s3Eth1, s3Eth100); // Start to build intents between BGP speaker3 and BGP peer5 bgpPathintentConstructor( VLAN30, VLAN20, "192.168.50.101/32", "192.168.50.1/32", null, bgpPort, s3Eth100, s3Eth1); bgpPathintentConstructor( VLAN30, VLAN20, "192.168.50.101/32", "192.168.50.1/32", bgpPort, null, s3Eth100, s3Eth1); bgpPathintentConstructor( VLAN20, VLAN30, "192.168.50.1/32", "192.168.50.101/32", null, bgpPort, s3Eth1, s3Eth100); bgpPathintentConstructor( VLAN20, VLAN30, "192.168.50.1/32", "192.168.50.101/32", bgpPort, null, s3Eth1, s3Eth100); } /** * Constructs a BGP intent and put it into the intentList. * * <p>The purpose of this method is too simplify the setUpBgpIntents() method, and to make the * setUpBgpIntents() easy to read. * * @param srcVlanId ingress VlanId * @param dstVlanId egress VlanId * @param srcPrefix source IP prefix to match * @param dstPrefix destination IP prefix to match * @param srcConnectPoint source connect point for PointToPointIntent * @param dstConnectPoint destination connect point for PointToPointIntent */ private void icmpPathintentConstructor( VlanId srcVlanId, VlanId dstVlanId, String srcPrefix, String dstPrefix, ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) { TrafficSelector.Builder builder = DefaultTrafficSelector.builder() .matchEthType(Ethernet.TYPE_IPV4) .matchIPProtocol(IPv4.PROTOCOL_ICMP) .matchIPSrc(IpPrefix.valueOf(srcPrefix)) .matchIPDst(IpPrefix.valueOf(dstPrefix)); if (!srcVlanId.equals(VlanId.NONE)) { builder.matchVlanId(srcVlanId); } TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); if (!dstVlanId.equals(VlanId.NONE)) { treatment.setVlanId(dstVlanId); } Key key = Key.of(srcPrefix.split("/")[0] + "-" + dstPrefix.split("/")[0] + "-" + "icmp", APPID); PointToPointIntent intent = PointToPointIntent.builder() .appId(APPID) .key(key) .selector(builder.build()) .treatment(treatment.build()) .ingressPoint(srcConnectPoint) .egressPoint(dstConnectPoint) .build(); intentList.add(intent); } /** Sets up intents for ICMP paths. */ private void setUpIcmpIntents() { // Start to build intents between BGP speaker1 and BGP peer1 icmpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.10.101/32", "192.168.10.1/32", s1Eth100, s1Eth1); icmpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.10.1/32", "192.168.10.101/32", s1Eth1, s1Eth100); // Start to build intents between BGP speaker1 and BGP peer2 icmpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.20.101/32", "192.168.20.1/32", s1Eth100, s2Eth1); icmpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.20.1/32", "192.168.20.101/32", s2Eth1, s1Eth100); icmpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.30.101/32", "192.168.30.1/32", s1Eth100, s2Eth1); icmpPathintentConstructor( NO_VLAN, NO_VLAN, "192.168.30.1/32", "192.168.30.101/32", s2Eth1, s1Eth100); // Start to build intents between BGP speaker3 and BGP peer 4 icmpPathintentConstructor( VLAN10, VLAN30, "192.168.40.1/32", "192.168.40.101/32", s3Eth1, s3Eth100); icmpPathintentConstructor( VLAN30, VLAN10, "192.168.40.101/32", "192.168.40.1/32", s3Eth100, s3Eth1); // Start to build intents between BGP speaker3 and BGP peer 5 icmpPathintentConstructor( VLAN20, VLAN30, "192.168.50.1/32", "192.168.50.101/32", s3Eth1, s3Eth100); icmpPathintentConstructor( VLAN30, VLAN20, "192.168.50.101/32", "192.168.50.1/32", s3Eth100, s3Eth1); } /** Initializes peer connectivity testing environment. */ private void initPeerConnectivity() { expect(bgpConfig.bgpSpeakers()).andReturn(bgpSpeakers).anyTimes(); replay(bgpConfig); expect(networkConfigService.getConfig(APPID, BgpConfig.class)).andReturn(bgpConfig).anyTimes(); replay(networkConfigService); replay(interfaceService); intentSynchronizer = createMock(IntentSynchronizationService.class); replay(intentSynchronizer); peerConnectivityManager = new PeerConnectivityManager( APPID, intentSynchronizer, networkConfigService, CONFIG_APP_ID, interfaceService); } /** * Tests whether peer connectivity manager can set up correct BGP and ICMP intents according to * specific configuration. * * <p>Two tricky cases included in the configuration are: 2 peers on a same switch port, peer on * the same switch with BGPd. */ @Test public void testConnectionSetup() { reset(intentSynchronizer); // Setup the expected intents for (Intent intent : intentList) { intentSynchronizer.submit(eqExceptId(intent)); } replay(intentSynchronizer); // Running the interface to be tested. peerConnectivityManager.start(); verify(intentSynchronizer); } /** Tests a corner case, when there are no interfaces in the configuration. */ @Test public void testNullInterfaces() { reset(interfaceService); interfaceService.addListener(anyObject(InterfaceListener.class)); expectLastCall().anyTimes(); expect(interfaceService.getInterfaces()).andReturn(Sets.newHashSet()).anyTimes(); expect(interfaceService.getInterfacesByPort(s2Eth1)) .andReturn(Collections.emptySet()) .anyTimes(); expect(interfaceService.getInterfacesByPort(s1Eth1)) .andReturn(Collections.emptySet()) .anyTimes(); expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.10.101"))) .andReturn(Collections.emptySet()) .anyTimes(); expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.10.1"))) .andReturn(null) .anyTimes(); expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.20.101"))) .andReturn(Collections.emptySet()) .anyTimes(); expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.20.1"))) .andReturn(null) .anyTimes(); expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.30.101"))) .andReturn(Collections.emptySet()) .anyTimes(); expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.30.1"))) .andReturn(null) .anyTimes(); expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.40.101"))) .andReturn(Collections.emptySet()) .anyTimes(); expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.40.1"))) .andReturn(null) .anyTimes(); expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.50.101"))) .andReturn(Collections.emptySet()) .anyTimes(); expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.50.1"))) .andReturn(null) .anyTimes(); replay(interfaceService); reset(intentSynchronizer); replay(intentSynchronizer); peerConnectivityManager.start(); verify(intentSynchronizer); } /** Tests a corner case, when there is no BGP speakers in the configuration. */ @Test public void testNullBgpSpeakers() { reset(bgpConfig); expect(bgpConfig.bgpSpeakers()).andReturn(Collections.emptySet()).anyTimes(); replay(bgpConfig); // We don't expect any intents in this case reset(intentSynchronizer); replay(intentSynchronizer); peerConnectivityManager.start(); verify(intentSynchronizer); } /** Tests a corner case, when there is no Interface configured for one BGP peer. */ @Test public void testNoPeerInterface() { IpAddress ip = IpAddress.valueOf("1.1.1.1"); bgpSpeakers.clear(); bgpSpeakers.add( new BgpConfig.BgpSpeakerConfig( Optional.of("foo"), VlanId.NONE, s1Eth100, Collections.singleton(ip))); reset(interfaceService); interfaceService.addListener(anyObject(InterfaceListener.class)); expect(interfaceService.getMatchingInterface(ip)).andReturn(null).anyTimes(); replay(interfaceService); // We don't expect any intents in this case reset(intentSynchronizer); replay(intentSynchronizer); peerConnectivityManager.start(); verify(intentSynchronizer); } }