mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-21 12:22:18 +02:00
CORD-416 Implemented ARP proxy for service IPs
Added ARP proxy which sends fake ARP reply for service IPs. Change-Id: I0583ee994def2a429701c0375af5203bdfaa39c5
This commit is contained in:
parent
68c4fc4862
commit
42c7b4e684
@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Deactivate;
|
|||||||
import org.apache.felix.scr.annotations.Reference;
|
import org.apache.felix.scr.annotations.Reference;
|
||||||
import org.apache.felix.scr.annotations.ReferenceCardinality;
|
import org.apache.felix.scr.annotations.ReferenceCardinality;
|
||||||
import org.apache.felix.scr.annotations.Service;
|
import org.apache.felix.scr.annotations.Service;
|
||||||
|
import org.onlab.packet.Ethernet;
|
||||||
import org.onlab.packet.Ip4Address;
|
import org.onlab.packet.Ip4Address;
|
||||||
import org.onlab.util.ItemNotFoundException;
|
import org.onlab.util.ItemNotFoundException;
|
||||||
import org.onlab.packet.IpAddress;
|
import org.onlab.packet.IpAddress;
|
||||||
@ -56,6 +57,9 @@ import org.onosproject.net.group.GroupService;
|
|||||||
import org.onosproject.net.host.HostEvent;
|
import org.onosproject.net.host.HostEvent;
|
||||||
import org.onosproject.net.host.HostListener;
|
import org.onosproject.net.host.HostListener;
|
||||||
import org.onosproject.net.host.HostService;
|
import org.onosproject.net.host.HostService;
|
||||||
|
import org.onosproject.net.packet.PacketContext;
|
||||||
|
import org.onosproject.net.packet.PacketProcessor;
|
||||||
|
import org.onosproject.net.packet.PacketService;
|
||||||
import org.onosproject.openstackswitching.OpenstackNetwork;
|
import org.onosproject.openstackswitching.OpenstackNetwork;
|
||||||
import org.onosproject.openstackswitching.OpenstackPort;
|
import org.onosproject.openstackswitching.OpenstackPort;
|
||||||
import org.onosproject.openstackswitching.OpenstackSubnet;
|
import org.onosproject.openstackswitching.OpenstackSubnet;
|
||||||
@ -134,6 +138,9 @@ public class CordVtn implements CordVtnService {
|
|||||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
protected FlowRuleService flowRuleService;
|
protected FlowRuleService flowRuleService;
|
||||||
|
|
||||||
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
|
protected PacketService packetService;
|
||||||
|
|
||||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
protected OvsdbController controller;
|
protected OvsdbController controller;
|
||||||
|
|
||||||
@ -154,6 +161,7 @@ public class CordVtn implements CordVtnService {
|
|||||||
|
|
||||||
private final DeviceListener deviceListener = new InternalDeviceListener();
|
private final DeviceListener deviceListener = new InternalDeviceListener();
|
||||||
private final HostListener hostListener = new InternalHostListener();
|
private final HostListener hostListener = new InternalHostListener();
|
||||||
|
private final PacketProcessor packetProcessor = new InternalPacketProcessor();
|
||||||
|
|
||||||
private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
|
private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
|
||||||
private final BridgeHandler bridgeHandler = new BridgeHandler();
|
private final BridgeHandler bridgeHandler = new BridgeHandler();
|
||||||
@ -163,6 +171,7 @@ public class CordVtn implements CordVtnService {
|
|||||||
private ConsistentMap<CordVtnNode, NodeState> nodeStore;
|
private ConsistentMap<CordVtnNode, NodeState> nodeStore;
|
||||||
private Map<HostId, OpenstackNetwork> hostNetMap = Maps.newHashMap();
|
private Map<HostId, OpenstackNetwork> hostNetMap = Maps.newHashMap();
|
||||||
private CordVtnRuleInstaller ruleInstaller;
|
private CordVtnRuleInstaller ruleInstaller;
|
||||||
|
private CordVtnArpProxy arpProxy;
|
||||||
|
|
||||||
private enum NodeState {
|
private enum NodeState {
|
||||||
|
|
||||||
@ -223,6 +232,10 @@ public class CordVtn implements CordVtnService {
|
|||||||
mastershipService,
|
mastershipService,
|
||||||
DEFAULT_TUNNEL);
|
DEFAULT_TUNNEL);
|
||||||
|
|
||||||
|
arpProxy = new CordVtnArpProxy(appId, packetService);
|
||||||
|
packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
|
||||||
|
arpProxy.requestPacket();
|
||||||
|
|
||||||
deviceService.addListener(deviceListener);
|
deviceService.addListener(deviceListener);
|
||||||
hostService.addListener(hostListener);
|
hostService.addListener(hostListener);
|
||||||
|
|
||||||
@ -233,6 +246,7 @@ public class CordVtn implements CordVtnService {
|
|||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
deviceService.removeListener(deviceListener);
|
deviceService.removeListener(deviceListener);
|
||||||
hostService.removeListener(hostListener);
|
hostService.removeListener(hostListener);
|
||||||
|
packetService.removeProcessor(packetProcessor);
|
||||||
|
|
||||||
eventExecutor.shutdown();
|
eventExecutor.shutdown();
|
||||||
nodeStore.clear();
|
nodeStore.clear();
|
||||||
@ -920,17 +934,18 @@ public class CordVtn implements CordVtnService {
|
|||||||
log.info("VM {} is detected", host.id());
|
log.info("VM {} is detected", host.id());
|
||||||
hostNetMap.put(host.id(), vNet);
|
hostNetMap.put(host.id(), vNet);
|
||||||
|
|
||||||
|
CordService service = getCordService(vNet);
|
||||||
|
if (service != null) {
|
||||||
|
// TODO check if the service needs an update on its group buckets after done CORD-433
|
||||||
|
ruleInstaller.updateServiceGroup(service);
|
||||||
|
arpProxy.addServiceIp(service.serviceIp());
|
||||||
|
}
|
||||||
|
|
||||||
ruleInstaller.populateBasicConnectionRules(
|
ruleInstaller.populateBasicConnectionRules(
|
||||||
host,
|
host,
|
||||||
hostIp,
|
hostIp,
|
||||||
checkNotNull(getRemoteIp(host.location().deviceId())).getIp4Address(),
|
checkNotNull(getRemoteIp(host.location().deviceId())).getIp4Address(),
|
||||||
vNet);
|
vNet);
|
||||||
|
|
||||||
CordService service = getCordService(vNet);
|
|
||||||
// TODO check if the service needs an update on its group buckets after done CORD-433
|
|
||||||
if (service != null) {
|
|
||||||
ruleInstaller.updateServiceGroup(service);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -950,12 +965,37 @@ public class CordVtn implements CordVtnService {
|
|||||||
ruleInstaller.removeBasicConnectionRules(host);
|
ruleInstaller.removeBasicConnectionRules(host);
|
||||||
|
|
||||||
CordService service = getCordService(vNet);
|
CordService service = getCordService(vNet);
|
||||||
// TODO check if the service needs an update on its group buckets after done CORD-433
|
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
|
// TODO check if the service needs an update on its group buckets after done CORD-433
|
||||||
ruleInstaller.updateServiceGroup(service);
|
ruleInstaller.updateServiceGroup(service);
|
||||||
|
|
||||||
|
if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
|
||||||
|
arpProxy.removeServiceIp(service.serviceIp());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hostNetMap.remove(host.id());
|
hostNetMap.remove(host.id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class InternalPacketProcessor implements PacketProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(PacketContext context) {
|
||||||
|
if (context.isHandled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ethernet ethPacket = context.inPacket().parsed();
|
||||||
|
if (ethPacket == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arpProxy.processArpPacket(context, ethPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2015 Open Networking Laboratory
|
||||||
|
*
|
||||||
|
* 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.cordvtn;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import org.onlab.packet.ARP;
|
||||||
|
import org.onlab.packet.EthType;
|
||||||
|
import org.onlab.packet.Ethernet;
|
||||||
|
import org.onlab.packet.Ip4Address;
|
||||||
|
import org.onlab.packet.IpAddress;
|
||||||
|
import org.onlab.packet.MacAddress;
|
||||||
|
import org.onosproject.core.ApplicationId;
|
||||||
|
import org.onosproject.net.flow.DefaultTrafficSelector;
|
||||||
|
import org.onosproject.net.flow.DefaultTrafficTreatment;
|
||||||
|
import org.onosproject.net.flow.TrafficSelector;
|
||||||
|
import org.onosproject.net.flow.TrafficTreatment;
|
||||||
|
import org.onosproject.net.packet.DefaultOutboundPacket;
|
||||||
|
import org.onosproject.net.packet.PacketContext;
|
||||||
|
import org.onosproject.net.packet.PacketPriority;
|
||||||
|
import org.onosproject.net.packet.PacketService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static org.slf4j.LoggerFactory.getLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles ARP requests for virtual network service IPs.
|
||||||
|
*/
|
||||||
|
public class CordVtnArpProxy {
|
||||||
|
protected final Logger log = getLogger(getClass());
|
||||||
|
// TODO make gateway MAC address configurable
|
||||||
|
private static final MacAddress DEFAULT_GATEWAY_MAC = MacAddress.valueOf("00:00:00:00:00:01");
|
||||||
|
|
||||||
|
private final ApplicationId appId;
|
||||||
|
private final PacketService packetService;
|
||||||
|
|
||||||
|
private Set<Ip4Address> serviceIPs = Sets.newHashSet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*
|
||||||
|
* @param appId application id
|
||||||
|
* @param packetService packet service
|
||||||
|
*/
|
||||||
|
public CordVtnArpProxy(ApplicationId appId, PacketService packetService) {
|
||||||
|
this.appId = appId;
|
||||||
|
this.packetService = packetService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests ARP packet.
|
||||||
|
*/
|
||||||
|
public void requestPacket() {
|
||||||
|
TrafficSelector selector = DefaultTrafficSelector.builder()
|
||||||
|
.matchEthType(EthType.EtherType.ARP.ethType().toShort())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
packetService.requestPackets(selector,
|
||||||
|
PacketPriority.CONTROL,
|
||||||
|
appId,
|
||||||
|
Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels ARP packet.
|
||||||
|
*/
|
||||||
|
public void cancelPacket() {
|
||||||
|
TrafficSelector selector = DefaultTrafficSelector.builder()
|
||||||
|
.matchEthType(EthType.EtherType.ARP.ethType().toShort())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
packetService.cancelPackets(selector,
|
||||||
|
PacketPriority.CONTROL,
|
||||||
|
appId,
|
||||||
|
Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a given service IP address to be served.
|
||||||
|
*
|
||||||
|
* @param serviceIp service ip
|
||||||
|
*/
|
||||||
|
public void addServiceIp(IpAddress serviceIp) {
|
||||||
|
checkNotNull(serviceIp);
|
||||||
|
serviceIPs.add(serviceIp.getIp4Address());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a given service IP address from this ARP proxy.
|
||||||
|
*
|
||||||
|
* @param serviceIp service ip
|
||||||
|
*/
|
||||||
|
public void removeServiceIp(IpAddress serviceIp) {
|
||||||
|
checkNotNull(serviceIp);
|
||||||
|
serviceIPs.remove(serviceIp.getIp4Address());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits ARP reply with fake MAC address for a given ARP request.
|
||||||
|
* It only handles requests for the registered service IPs, and the other
|
||||||
|
* requests can be handled by other ARP handlers like openstackSwitching or
|
||||||
|
* proxyArp, for example.
|
||||||
|
*
|
||||||
|
* @param context packet context
|
||||||
|
* @param ethPacket ethernet packet
|
||||||
|
*/
|
||||||
|
public void processArpPacket(PacketContext context, Ethernet ethPacket) {
|
||||||
|
ARP arpPacket = (ARP) ethPacket.getPayload();
|
||||||
|
Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
|
||||||
|
|
||||||
|
if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serviceIPs.contains(targetIp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ethernet ethReply = ARP.buildArpReply(
|
||||||
|
targetIp,
|
||||||
|
DEFAULT_GATEWAY_MAC,
|
||||||
|
ethPacket);
|
||||||
|
|
||||||
|
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
|
||||||
|
.setOutput(context.inPacket().receivedFrom().port())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
packetService.emit(new DefaultOutboundPacket(
|
||||||
|
context.inPacket().receivedFrom().deviceId(),
|
||||||
|
treatment,
|
||||||
|
ByteBuffer.wrap(ethReply.serialize())));
|
||||||
|
|
||||||
|
context.block();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user