/** * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.openflowplugin.openflow.md.core.sal; import java.math.BigInteger; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.openflowplugin.api.openflow.md.ModelDrivenSwitch; import org.opendaylight.openflowplugin.api.openflow.md.core.NotificationQueueWrapper; import org.opendaylight.openflowplugin.openflow.md.core.session.OFSessionUtil; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionListener; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionManager; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SwitchSessionKeyOF; import org.opendaylight.openflowplugin.openflow.md.lldp.LLDPSpeaker; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdatedBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput; import org.opendaylight.yangtools.concepts.CompositeObjectRegistration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * session and inventory listener implementation */ public class SalRegistrationManager implements SessionListener, AutoCloseable { private final static Logger LOG = LoggerFactory.getLogger(SalRegistrationManager.class); private ProviderContext providerContext; private NotificationProviderService publishService; private DataBroker dataService; private SwitchFeaturesUtil swFeaturesUtil; public SalRegistrationManager() { swFeaturesUtil = SwitchFeaturesUtil.getInstance(); } public NotificationProviderService getPublishService() { return publishService; } public void setPublishService(NotificationProviderService publishService) { this.publishService = publishService; } public ProviderContext getProviderContext() { return providerContext; } public void onSessionInitiated(ProviderContext session) { LOG.debug("onSessionInitiated"); this.providerContext = session; this.publishService = session.getSALService(NotificationProviderService.class); this.dataService = session.getSALService(DataBroker.class); // We register as listener for Session Manager getSessionManager().registerSessionListener(this); getSessionManager().setNotificationProviderService(publishService); getSessionManager().setDataBroker(dataService); LOG.debug("SalRegistrationManager initialized"); } @Override public void onSessionAdded(SwitchSessionKeyOF sessionKey, SessionContext context) { GetFeaturesOutput features = context.getFeatures(); BigInteger datapathId = features.getDatapathId(); InstanceIdentifier identifier = identifierFromDatapathId(datapathId); NodeRef nodeRef = new NodeRef(identifier); NodeId nodeId = nodeIdFromDatapathId(datapathId); ModelDrivenSwitchImpl ofSwitch = new ModelDrivenSwitchImpl(nodeId, identifier, context); LLDPSpeaker.getInstance().addModelDrivenSwitch(identifier, ofSwitch); CompositeObjectRegistration registration = ofSwitch.register(providerContext); context.setProviderRegistration(registration); LOG.debug("ModelDrivenSwitch for {} registered to MD-SAL.", datapathId.toString()); NotificationQueueWrapper wrappedNotification = new NotificationQueueWrapper( nodeAdded(ofSwitch, features, nodeRef), context.getFeatures().getVersion()); context.getNotificationEnqueuer().enqueueNotification(wrappedNotification); } @Override public void onSessionRemoved(SessionContext context) { GetFeaturesOutput features = context.getFeatures(); BigInteger datapathId = features.getDatapathId(); InstanceIdentifier identifier = identifierFromDatapathId(datapathId); NodeRef nodeRef = new NodeRef(identifier); NodeRemoved nodeRemoved = nodeRemoved(nodeRef); LLDPSpeaker.getInstance().removeModelDrivenSwitch(identifier); if (context.isValid()) { CompositeObjectRegistration registration = context.getProviderRegistration(); registration.close(); } LOG.debug("ModelDrivenSwitch for {} unregistered from MD-SAL.", datapathId.toString()); NotificationQueueWrapper wrappedNotification = new NotificationQueueWrapper( nodeRemoved, context.getFeatures().getVersion()); context.getNotificationEnqueuer().enqueueNotification(wrappedNotification); } private NodeUpdated nodeAdded(ModelDrivenSwitch sw, GetFeaturesOutput features, NodeRef nodeRef) { NodeUpdatedBuilder builder = new NodeUpdatedBuilder(); builder.setId(sw.getNodeId()); builder.setNodeRef(nodeRef); FlowCapableNodeUpdatedBuilder builder2 = new FlowCapableNodeUpdatedBuilder(); builder2.setIpAddress(getIpAddressOf(sw)); builder2.setSwitchFeatures(swFeaturesUtil.buildSwitchFeatures(features)); builder.addAugmentation(FlowCapableNodeUpdated.class, builder2.build()); return builder.build(); } private IpAddress getIpAddressOf(ModelDrivenSwitch sw) { SessionContext sessionContext = sw.getSessionContext(); if (!sessionContext.isValid()) { LOG.warn("IP address of the node {} cannot be obtained. Session is not valid.", sw.getNodeId()); return null; } InetSocketAddress remoteAddress = sessionContext.getPrimaryConductor().getConnectionAdapter() .getRemoteAddress(); if (remoteAddress == null) { LOG.warn("IP address of the node {} cannot be obtained. No connection with switch.", sw.getNodeId()); return null; } return resolveIpAddress(remoteAddress.getAddress()); } private static IpAddress resolveIpAddress(InetAddress address) { String hostAddress = address.getHostAddress(); if (address instanceof Inet4Address) { return new IpAddress(new Ipv4Address(hostAddress)); } if (address instanceof Inet6Address) { return new IpAddress(new Ipv6Address(hostAddress)); } throw new IllegalArgumentException("Unsupported IP address type!"); } private NodeRemoved nodeRemoved(NodeRef nodeRef) { NodeRemovedBuilder builder = new NodeRemovedBuilder(); builder.setNodeRef(nodeRef); return builder.build(); } public static InstanceIdentifier identifierFromDatapathId(BigInteger datapathId) { NodeKey nodeKey = nodeKeyFromDatapathId(datapathId); InstanceIdentifierBuilder builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey); return builder.toInstance(); } public static NodeKey nodeKeyFromDatapathId(BigInteger datapathId) { return new NodeKey(nodeIdFromDatapathId(datapathId)); } public static NodeId nodeIdFromDatapathId(BigInteger datapathId) { // FIXME: Convert to textual representation of datapathID String current = datapathId.toString(); return new NodeId("openflow:" + current); } public SessionManager getSessionManager() { return OFSessionUtil.getSessionManager(); } @Override public void close() { LOG.debug("close"); dataService = null; providerContext = null; publishService = null; } }