blob: d506a7e4965e8690c04533dedf647abbc03524d0 [file] [log] [blame]
/*
* Copyright 2017-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.simplefabric;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceService;
import org.onosproject.net.neighbour.NeighbourMessageContext;
import org.onosproject.net.neighbour.NeighbourMessageHandler;
import org.onosproject.net.neighbour.NeighbourResolutionService;
import org.onosproject.net.Host;
import org.onosproject.net.host.HostService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
/**
* Handles neighbour messages for on behalf of the L2 Network application. Handlers
* will be changed automatically by interface or network configuration events.
*/
@Component(immediate = true, enabled = false)
public class SimpleFabricNeighbour {
private final Logger log = LoggerFactory.getLogger(getClass());
protected ApplicationId appId;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected InterfaceService interfaceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected NeighbourResolutionService neighbourService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected SimpleFabricService simpleFabric;
private final InternalSimpleFabricListener simpleFabricListener =
new InternalSimpleFabricListener();
private L2NetworkNeighbourMessageHandler neighbourHandler =
new L2NetworkNeighbourMessageHandler();
private Set<Interface> monitoredInterfaces = new HashSet<>();
@Activate
public void activate() {
appId = simpleFabric.getAppId();
simpleFabric.addListener(simpleFabricListener);
refresh();
log.info("simple fabric neighbour started");
}
@Deactivate
public void deactivate() {
simpleFabric.removeListener(simpleFabricListener);
unregister();
monitoredInterfaces.clear();
log.info("simple fabric neighbour stoped");
}
/**
* Registers neighbour handler to all available interfaces.
*/
protected void refresh() {
Set<Interface> interfaces = interfaceService.getInterfaces();
// check for new interfaces
for (Interface intf : interfaces) {
if (!monitoredInterfaces.contains(intf) && simpleFabric.isL2NetworkInterface(intf)) {
log.info("simple fabric neighbour register handler: {}", intf);
neighbourService.registerNeighbourHandler(intf, neighbourHandler, appId);
monitoredInterfaces.add(intf);
} else {
log.debug("simple fabric neighobur unknown interface: {}", intf);
}
}
// check for removed interfaces
Set<Interface> monitoredInterfacesToBeRemoved = new HashSet<>();
for (Interface intf : monitoredInterfaces) {
if (!interfaces.contains(intf)) {
log.info("simple fabric neighbour unregister handler: {}", intf);
neighbourService.unregisterNeighbourHandler(intf, neighbourHandler, appId);
monitoredInterfacesToBeRemoved.add(intf);
}
}
for (Interface intf : monitoredInterfacesToBeRemoved) {
monitoredInterfaces.remove(intf);
}
}
/**
* Unregisters neighbour handler to all available interfaces.
*/
protected void unregister() {
log.info("simple fabric neighbour unregister handler");
neighbourService.unregisterNeighbourHandlers(appId);
}
/**
* Handles request messages.
*
* @param context the message context
*/
protected void handleRequest(NeighbourMessageContext context) {
MacAddress mac = simpleFabric.findVMacForIp(context.target());
if (mac != null) {
log.trace("simple fabric neightbour request on virtualGatewayAddress {}; response to {} {} mac={}",
context.target(), context.inPort(), context.vlan(), mac);
context.reply(mac);
return;
}
// else forward to corresponding host
L2Network l2Network = simpleFabric.findL2Network(context.inPort(), context.vlan());
if (l2Network != null) {
int numForwards = 0;
if (!context.dstMac().isBroadcast() && !context.dstMac().isMulticast()) {
for (Host host : hostService.getHostsByMac(context.dstMac())) {
log.trace("simple fabric neightbour request forward unicast to {}", host.location());
context.forward(host.location()); // ASSUME: vlan is same
// TODO: may need to check host.location().time()
numForwards++;
}
if (numForwards > 0) {
return;
}
}
// else do broadcast to all host in the same l2 network
log.trace("simple fabric neightbour request forward broadcast: {} {}",
context.inPort(), context.vlan());
for (Interface iface : l2Network.interfaces()) {
if (!context.inPort().equals(iface.connectPoint())) {
log.trace("simple fabric forward neighbour request broadcast to {}", iface);
context.forward(iface);
}
}
} else {
log.warn("simple fabric neightbour request drop: {} {}",
context.inPort(), context.vlan());
context.drop();
}
}
/**
* Handles reply messages between VLAN tagged interfaces.
*
* @param context the message context
* @param hostService the host service
*/
protected void handleReply(NeighbourMessageContext context,
HostService hostService) {
// Find target L2 Network, then reply to the host
L2Network l2Network = simpleFabric.findL2Network(context.inPort(), context.vlan());
if (l2Network != null) {
// TODO: need to check and update simpleFabric.L2Network
MacAddress mac = simpleFabric.findVMacForIp(context.target());
if (mac != null) {
log.trace("simple fabric neightbour response message to virtual gateway; drop: {} {} target={}",
context.inPort(), context.vlan(), context.target());
context.drop();
} else {
// forward reply to the hosts of the dstMac
Set<Host> hosts = hostService.getHostsByMac(context.dstMac());
log.trace("simple fabric neightbour response message forward: {} {} target={} -> {}",
context.inPort(), context.vlan(), context.target(), hosts);
hosts.stream()
.map(host -> simpleFabric.findHostInterface(host))
.filter(Objects::nonNull)
.forEach(context::forward);
}
} else {
// this might be happened when we remove an interface from L2 Network
// just ignore this message
log.warn("simple fabric neightbour response message drop for unknown l2Network: {} {}",
context.inPort(), context.vlan());
context.drop();
}
}
private class L2NetworkNeighbourMessageHandler implements NeighbourMessageHandler {
@Override
public void handleMessage(NeighbourMessageContext context,
HostService hostService) {
switch (context.type()) {
case REQUEST:
handleRequest(context);
break;
case REPLY:
handleReply(context, hostService);
break;
default:
log.warn("simple fabric neightor unknown context type: {}", context.type());
break;
}
}
}
private class InternalSimpleFabricListener implements SimpleFabricListener {
@Override
public void event(SimpleFabricEvent event) {
switch (event.type()) {
case SIMPLE_FABRIC_UPDATED:
refresh();
break;
default:
break;
}
}
}
}