blob: 70ade23a0e1339a51ffeeab6bb22ec46fcdcf667 [file] [log] [blame]
/*
* Copyright 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.pim.impl;
import org.jboss.netty.util.Timeout;
import org.jboss.netty.util.TimerTask;
import org.onosproject.incubator.net.config.basics.ConfigException;
import org.onosproject.incubator.net.config.basics.InterfaceConfig;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* PIMInterfaces is a collection of all neighbors we have received
* PIM hello messages from. The main structure is a HashMap indexed
* by ConnectPoint with another HashMap indexed on the PIM neighbors
* IPAddress, it contains all PIM neighbors attached on that ConnectPoint.
*/
public final class PIMInterfaces {
private Logger log = LoggerFactory.getLogger("PIMInterfaces");
private static PIMInterfaces instance = null;
// Used to listen to network configuration changes
private NetworkConfigService configService;
// Used to access IP Interface definitions for our segment
private InterfaceService interfaceService;
// Internal class used to listen for network configuration changes
private InternalConfigListener configListener = new InternalConfigListener();
// This is the global container for all PIM Interfaces indexed by ConnectPoints.
private Map<ConnectPoint, PIMInterface> interfaces = new HashMap<>();
// Default hello message interval
private int helloMessageInterval = 60;
// Timer used to send hello messages on this interface
private Timeout helloTimer;
// Required by a utility class
private PIMInterfaces() {}
/**
* Get the instance of PIMInterfaces. Create the instance if needed.
*
* @return PIMInterface instance
*/
public static PIMInterfaces getInstance() {
if (null == instance) {
instance = new PIMInterfaces();
}
return instance;
}
// Initialize the services
public void initialize(NetworkConfigService cs, InterfaceService is) {
configService = cs;
interfaceService = is;
// Initialize interfaces if they already exist
initInterfaces();
// Listen for network config changes
configService.addListener(configListener);
}
/**
* Listener for network config events.
*/
private class InternalConfigListener implements NetworkConfigListener {
private void updateInterfaces(InterfaceConfig config) {
Set<Interface> intfs;
try {
intfs = config.getInterfaces();
} catch (ConfigException e) {
log.error(e.toString());
return;
}
for (Interface intf : intfs) {
addInterface(intf);
}
}
/**
* Remove the PIMInterface represented by the ConnectPoint. If the
* PIMInterface does not exist this function is a no-op.
*
* @param cp The connectPoint representing the PIMInterface to be removed.
*/
private void removeInterface(ConnectPoint cp) {
PIMInterfaces.this.removeInterface(cp);
}
@Override
public void event(NetworkConfigEvent event) {
switch (event.type()) {
case CONFIG_ADDED:
case CONFIG_UPDATED:
log.debug("Config updated: " + event.toString() + "\n");
if (event.configClass() == InterfaceConfig.class) {
InterfaceConfig config =
configService.getConfig((ConnectPoint) event.subject(), InterfaceConfig.class);
updateInterfaces(config);
}
break;
case CONFIG_REMOVED:
if (event.configClass() == InterfaceConfig.class) {
removeInterface((ConnectPoint) event.subject());
}
break;
case CONFIG_REGISTERED:
case CONFIG_UNREGISTERED:
default:
break;
}
}
}
// Configure interfaces if they already exist.
private void initInterfaces() {
Set<Interface> intfs = interfaceService.getInterfaces();
for (Interface intf : intfs) {
log.debug("Adding interface: " + intf.toString() + "\n");
addInterface(intf);
}
}
/**
* Create a PIM Interface and add to our interfaces list.
*
* @param intf the interface to add
* @return the PIMInterface
*/
public PIMInterface addInterface(Interface intf) {
PIMInterface pif = new PIMInterface(intf);
interfaces.put(intf.connectPoint(), pif);
// If we have added our first interface start the hello timer.
if (interfaces.size() == 1) {
startHelloTimer();
}
// Return this interface
return pif;
}
/**
* Remove the PIMInterface from the given ConnectPoint.
*
* @param cp the ConnectPoint indexing the PIMInterface to be removed.
*/
public void removeInterface(ConnectPoint cp) {
if (interfaces.containsKey(cp)) {
interfaces.remove(cp);
}
if (interfaces.size() == 0) {
PIMTimer.stop();
}
}
/**
* Return a collection of PIMInterfaces for use by the PIM Interface codec.
*
* @return the collection of PIMInterfaces
*/
public Collection<PIMInterface> getInterfaces() {
return interfaces.values();
}
/**
* Get the PIM Interface indexed by the given ConnectPoint.
*
* @param cp the connect point
* @return the PIMInterface if it exists, NULL if not
*/
public PIMInterface getInterface(ConnectPoint cp) {
return interfaces.get(cp);
}
/**
* Return a string of PIMInterfaces for the cli command.
*
* @return a string representing PIM interfaces
*/
public String printInterfaces() {
String str = "";
for (PIMInterface pi : interfaces.values()) {
str += pi.toString();
}
return str;
}
/* ---------------------------------- PIM Hello Timer ----------------------------------- */
/**
* Start a new hello timer for this interface.
*/
private void startHelloTimer() {
helloTimer = PIMTimer.getTimer().newTimeout(
new HelloTimer(),
helloMessageInterval,
TimeUnit.SECONDS);
log.debug("Started Hello Timer");
}
/**
* This inner class handles transmitting a PIM hello message on this ConnectPoint.
*/
private final class HelloTimer implements TimerTask {
HelloTimer() {
}
@Override
public void run(Timeout timeout) throws Exception {
log.debug("Running Hello Timer\n");
// Technically we should not send all hello's in synch..
for (PIMInterface pi : interfaces.values()) {
pi.sendHello();
}
// restart the hello timer
if (interfaces.size() > 0) {
startHelloTimer();
}
}
}
}