/** * 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 transformAndSend(IPv4 ipv4, Interface egressInterface, MacAddress macAddress) { Ethernet eth = new Ethernet(); eth.setDestinationMACAddress(macAddress); eth.setSourceMACAddress(egressInterface.mac()); eth.setEtherType(EthType.EtherType.IPV4.ethType().toShort()); eth.setPayload(ipv4); if (!egressInterface.vlan().equals(VlanId.NONE)) { eth.setVlanID(egressInterface.vlan().toShort()); } ipv4.setTtl((byte) (ipv4.getTtl() - 1)); ipv4.setChecksum((short) 0); send(eth, egressInterface.connectPoint()); }
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; }); } }
/** * 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(); }