+/**
+ * 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.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+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.openflow.md.ModelDrivenSwitch;
-import org.opendaylight.openflowplugin.openflow.md.SwitchInventory;
-import org.opendaylight.openflowplugin.openflow.md.core.SwitchConnectionDistinguisher;
+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.openflow.md.core.session.SessionContext;
-import org.opendaylight.openflowplugin.openflow.md.core.session.SessionListener;
-import org.opendaylight.openflowplugin.openflow.md.core.session.SessionManager;
+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.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.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class SalRegistrationManager implements SessionListener, SwitchInventory {
+/**
+ * session and inventory listener implementation
+ */
+public class SalRegistrationManager implements SessionListener, AutoCloseable {
private final static Logger LOG = LoggerFactory.getLogger(SalRegistrationManager.class);
- Map<InstanceIdentifier<Node>, ModelDrivenSwitch> salSwitches = new ConcurrentHashMap<>();
-
private ProviderContext providerContext;
private NotificationProviderService publishService;
+ private DataBroker dataService;
+
+ private SwitchFeaturesUtil swFeaturesUtil;
+
+ private ListenerRegistration<SessionListener> sessionListenerRegistration;
+
+ public SalRegistrationManager() {
+ swFeaturesUtil = SwitchFeaturesUtil.getInstance();
+ }
+
public NotificationProviderService getPublishService() {
return publishService;
}
}
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);
- LOG.info("SalRegistrationManager initialized");
-
+ sessionListenerRegistration = getSessionManager().registerSessionListener(this);
+ getSessionManager().setNotificationProviderService(publishService);
+ getSessionManager().setDataBroker(dataService);
+ LOG.debug("SalRegistrationManager initialized");
}
@Override
- public void onSessionAdded(SwitchConnectionDistinguisher sessionKey, SessionContext context) {
+ public void onSessionAdded(SwitchSessionKeyOF sessionKey, SessionContext context) {
GetFeaturesOutput features = context.getFeatures();
BigInteger datapathId = features.getDatapathId();
InstanceIdentifier<Node> identifier = identifierFromDatapathId(datapathId);
-
+ NodeRef nodeRef = new NodeRef(identifier);
NodeId nodeId = nodeIdFromDatapathId(datapathId);
ModelDrivenSwitchImpl ofSwitch = new ModelDrivenSwitchImpl(nodeId, identifier, context);
- salSwitches.put(identifier, ofSwitch);
- ofSwitch.register(providerContext);
+ CompositeObjectRegistration<ModelDrivenSwitch> registration = ofSwitch.register(providerContext);
+ context.setProviderRegistration(registration);
- LOG.info("ModelDrivenSwitch for {} registered to MD-SAL.", datapathId.toString());
+ LOG.debug("ModelDrivenSwitch for {} registered to MD-SAL.", datapathId.toString());
- publishService.publish(nodeAdded(ofSwitch, features));
+ NotificationQueueWrapper wrappedNotification = new NotificationQueueWrapper(
+ nodeAdded(ofSwitch, features, nodeRef),
+ context.getFeatures().getVersion());
+ context.getNotificationEnqueuer().enqueueNotification(wrappedNotification);
}
- private NodeUpdated nodeAdded(ModelDrivenSwitch sw, GetFeaturesOutput features) {
+ @Override
+ public void onSessionRemoved(SessionContext context) {
+ GetFeaturesOutput features = context.getFeatures();
+ BigInteger datapathId = features.getDatapathId();
+ InstanceIdentifier<Node> identifier = identifierFromDatapathId(datapathId);
+ NodeRef nodeRef = new NodeRef(identifier);
+ NodeRemoved nodeRemoved = nodeRemoved(nodeRef);
+ if (context.isValid()) {
+ CompositeObjectRegistration<ModelDrivenSwitch> 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(new NodeRef(InstanceIdentifier.builder()
- .node(Nodes.class)
- .node(Node.class, new NodeKey(builder.getId()))
- .toInstance()));
+ 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();
}
- @Override
- public ModelDrivenSwitch getSwitch(NodeRef node) {
- return salSwitches.get(node.getValue());
+ 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());
}
- public static InstanceIdentifier<Node> identifierFromDatapathId(BigInteger datapathId) {
- InstanceIdentifierBuilder<?> builder = InstanceIdentifier.builder().node(Nodes.class);
+ 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<Node> identifierFromDatapathId(BigInteger datapathId) {
NodeKey nodeKey = nodeKeyFromDatapathId(datapathId);
- return builder.node(Node.class, nodeKey).toInstance();
+ InstanceIdentifierBuilder<Node> builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey);
+ return builder.toInstance();
}
public static NodeKey nodeKeyFromDatapathId(BigInteger datapathId) {
public SessionManager getSessionManager() {
return OFSessionUtil.getSessionManager();
}
+
+ @Override
+ public void close() {
+ LOG.debug("close");
+ dataService = null;
+ providerContext = null;
+ publishService = null;
+ if (sessionListenerRegistration != null) {
+ sessionListenerRegistration.close();
+ }
+ }
}