/* * 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 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 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 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 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(); } } } }