| /* |
| * 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.apache.felix.scr.annotations.Activate; |
| import org.apache.felix.scr.annotations.Component; |
| import org.apache.felix.scr.annotations.Deactivate; |
| import org.apache.felix.scr.annotations.Reference; |
| import org.apache.felix.scr.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_UNARY) |
| protected CoreService coreService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected HostService hostService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected InterfaceService interfaceService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected NeighbourResolutionService neighbourService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 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; |
| } |
| } |
| } |
| |
| } |
| |