/** * 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); }
@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; }
/** 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); }
/** * Sends an ARP or Neighbor Discovery Protocol request for the given IP address. * * @param targetIp IP address to send the request for */ private void sendArpNdpRequest(IpAddress targetIp) { Interface intf = interfaceService.getMatchingInterface(targetIp); if (intf == null) { return; } for (InterfaceIpAddress ia : intf.ipAddresses()) { if (ia.subnetAddress().contains(targetIp)) { sendArpNdpProbe(intf.connectPoint(), targetIp, ia.ipAddress(), intf.mac(), intf.vlan()); } } }
private void handle(Ethernet eth) { checkNotNull(eth); if (!(eth.getEtherType() == EthType.EtherType.IPV4.ethType().toShort())) { return; } IPv4 ipv4 = (IPv4) eth.getPayload().clone(); Ip4Address dstIp = Ip4Address.valueOf(ipv4.getDestinationAddress()); Interface egressInterface = interfaceService.getMatchingInterface(dstIp); if (egressInterface == null) { log.info("No egress interface found for {}", dstIp); return; } Optional<Host> host = hostService .getHostsByIp(dstIp) .stream() .filter(h -> h.location().equals(egressInterface.connectPoint())) .filter(h -> h.vlan().equals(egressInterface.vlan())) .findAny(); if (host.isPresent()) { transformAndSend(ipv4, egressInterface, host.get().mac()); } else { hostService.startMonitoringIp(dstIp); ipPacketCache .asMap() .compute( dstIp, (ip, queue) -> { if (queue == null) { queue = new ConcurrentLinkedQueue(); } queue.add(ipv4); return queue; }); } }
@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(); }
private void sendQueued(IpAddress ipAddress, MacAddress macAddress) { log.debug("Sending queued packets for {} ({})", ipAddress, macAddress); ipPacketCache .asMap() .computeIfPresent( ipAddress, (ip, packets) -> { packets.forEach( ipv4 -> { Interface egressInterface = interfaceService.getMatchingInterface(ipAddress); if (egressInterface == null) { log.info("No egress interface found for {}", ipAddress); return; } transformAndSend(ipv4, egressInterface, macAddress); }); return null; }); }
/** * Generates a route intent for a prefix, the next hop IP address, and the next hop MAC address. * * <p>This method will find the egress interface for the intent. Intent will match dst IP prefix * and rewrite dst MAC address at all other border switches, then forward packets according to dst * MAC address. * * @param prefix IP prefix of the route to add * @param nextHopIpAddress IP address of the next hop * @param nextHopMacAddress MAC address of the next hop * @return the generated intent, or null if no intent should be submitted */ private MultiPointToSinglePointIntent generateRouteIntent( IpPrefix prefix, IpAddress nextHopIpAddress, MacAddress nextHopMacAddress) { // Find the attachment point (egress interface) of the next hop Interface egressInterface = interfaceService.getMatchingInterface(nextHopIpAddress); if (egressInterface == null) { log.warn("No outgoing interface found for {}", nextHopIpAddress); return null; } // Generate the intent itself Set<ConnectPoint> ingressPorts = new HashSet<>(); ConnectPoint egressPort = egressInterface.connectPoint(); log.debug("Generating intent for prefix {}, next hop mac {}", prefix, nextHopMacAddress); for (Interface intf : interfaceService.getInterfaces()) { // TODO this should be only peering interfaces if (!intf.connectPoint().equals(egressInterface.connectPoint())) { ConnectPoint srcPort = intf.connectPoint(); ingressPorts.add(srcPort); } } // Match the destination IP prefix at the first hop TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); if (prefix.isIp4()) { selector.matchEthType(Ethernet.TYPE_IPV4); // if it is default route, then we do not need match destination // IP address if (prefix.prefixLength() != 0) { selector.matchIPDst(prefix); } } else { selector.matchEthType(Ethernet.TYPE_IPV6); // if it is default route, then we do not need match destination // IP address if (prefix.prefixLength() != 0) { selector.matchIPv6Dst(prefix); } } // Rewrite the destination MAC address TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder().setEthDst(nextHopMacAddress); if (!egressInterface.vlan().equals(VlanId.NONE)) { treatment.setVlanId(egressInterface.vlan()); // If we set VLAN ID, we have to make sure a VLAN tag exists. // TODO support no VLAN -> VLAN routing selector.matchVlanId(VlanId.ANY); } int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET; Key key = Key.of(prefix.toString(), appId); return MultiPointToSinglePointIntent.builder() .appId(appId) .key(key) .selector(selector.build()) .treatment(treatment.build()) .ingressPoints(ingressPorts) .egressPoint(egressPort) .priority(priority) .constraints(CONSTRAINTS) .build(); }
/** 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); }
/** * 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; }