2 * Copyright (c) 2017 Intel Corporation. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.neutron.hostconfig.vpp;
11 import com.google.common.base.Preconditions;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.List;
16 import java.util.Locale;
18 import java.util.concurrent.ExecutorService;
19 import java.util.concurrent.Executors;
20 import java.util.stream.Collectors;
21 import javax.annotation.Nonnull;
22 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
25 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
26 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
27 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.neutron.hostconfig.utils.NeutronHostconfigUtils;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
39 import org.opendaylight.yangtools.concepts.ListenerRegistration;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.opendaylight.yangtools.yang.common.QName;
42 import org.opendaylight.yangtools.yang.common.Revision;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
46 public class NeutronHostconfigVppListener implements ClusteredDataTreeChangeListener<Node> {
48 private static final Logger LOG = LoggerFactory.getLogger(NeutronHostconfigVppListener.class);
49 private final DataBroker dataBroker;
50 private final NeutronHostconfigUtils neutronHostconfig;
51 private ListenerRegistration<DataTreeChangeListener<Node>> listenerRegistration;
52 private final ExecutorService executorService = Executors.newFixedThreadPool(1);
54 private static final TopologyId TOPOLOGY_NETCONF = new TopologyId("topology-netconf");
55 private static final QName V3PO_1704_CAPABILITY = QName.create(
56 URI.create("urn:opendaylight:params:xml:ns:yang:v3po"),
57 Revision.of("2017-03-15"), "v3po");
58 private static final QName V3PO_1701_CAPABILITY = QName.create(
59 URI.create("urn:opendaylight:params:xml:ns:yang:v3po"),
60 Revision.of("2016-12-14"), "v3po");
61 private static final QName INTERFACES_CAPABILITY =
62 QName.create(URI.create("urn:ietf:params:xml:ns:yang:ietf-interfaces"),
63 Revision.of("2014-05-08"), "ietf-interfaces");
64 private static final List<QName> REQUIRED_CAPABILITIES = new ArrayList<>();
65 private final SocketInfo socketInfo;
67 public NeutronHostconfigVppListener(final DataBroker dataBroker, String spath, String sname, String vhostMode) {
68 LOG.info("Initializing Neutron-Hostconfig-Vpp-Listener");
69 this.dataBroker = Preconditions.checkNotNull(dataBroker);
70 final String vhostModeChecked = Preconditions.checkNotNull(vhostMode).toLowerCase(Locale.ROOT);
71 Preconditions.checkArgument(vhostModeChecked.equals("server") || vhostModeChecked.equals("client"),
72 "Supported values for vhostuser-mode are client and server.");
74 new SocketInfo(Preconditions.checkNotNull(spath), Preconditions.checkNotNull(sname), vhostModeChecked);
75 this.neutronHostconfig = new NeutronHostconfigUtils(dataBroker);
76 REQUIRED_CAPABILITIES.add(V3PO_1704_CAPABILITY);
77 REQUIRED_CAPABILITIES.add(V3PO_1701_CAPABILITY);
78 REQUIRED_CAPABILITIES.add(INTERFACES_CAPABILITY);
82 public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Node>> changes) {
83 LOG.info("onDataTreeChanged: Received Data Tree Changed ...", changes);
84 executorService.execute(() -> {
86 for (DataTreeModification<Node> change : Preconditions.checkNotNull(changes,
87 "Changes may not be null!")) {
88 processDataTreeModification(change);
90 } catch (TransactionCommitFailedException e) {
91 LOG.error("Transaction commit failed; ignorining changes: ", changes, e);
96 private void processDataTreeModification(DataTreeModification<Node> change)
97 throws TransactionCommitFailedException {
98 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
99 final DataObjectModification<Node> mod = change.getRootNode();
100 LOG.info("onDataTreeChanged: Received Data Tree Changed Update of Type={} for Key={}",
101 mod.getModificationType(), key);
102 switch (mod.getModificationType()) {
103 case SUBTREE_MODIFIED:
104 if (validateVppNode(mod.getDataAfter())) {
105 updateHostConfig(mod.getDataAfter(), NeutronHostconfigUtils.Action.UPDATE);
107 updateHostConfig(mod.getDataBefore(), NeutronHostconfigUtils.Action.DELETE);
111 updateHostConfig(mod.getDataBefore(), NeutronHostconfigUtils.Action.DELETE);
114 if (validateVppNode(mod.getDataAfter())) {
115 updateHostConfig(mod.getDataAfter(), NeutronHostconfigUtils.Action.ADD);
123 LOG.info("Initializing {}", getClass().getSimpleName());
124 DataTreeIdentifier<Node> dataTreeIdentifier = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
125 InstanceIdentifier.builder(NetworkTopology.class)
126 .child(Topology.class, new TopologyKey(TOPOLOGY_NETCONF))
129 listenerRegistration =
130 dataBroker.registerDataTreeChangeListener(dataTreeIdentifier, NeutronHostconfigVppListener.this);
131 LOG.info("Registered listener to netconf nodes {}.", dataTreeIdentifier.getRootIdentifier());
134 private void updateHostConfig(Node node, NeutronHostconfigUtils.Action action)
135 throws TransactionCommitFailedException {
136 for (Map.Entry<String, String> entry : HostconfigUtil.createHostconfigsDataFor(node.getNodeId(), socketInfo)
138 LOG.info("Updating hostconfig for node {}. Action: {}.", node.key(), action);
139 neutronHostconfig.updateMdsal(neutronHostconfig.buildHostConfigInfo(node.getNodeId().getValue(),
140 entry.getKey(), entry.getValue()), action);
144 private boolean validateVppNode(Node node) {
145 LOG.info("Registering new node {}", node.getNodeId().getValue());
146 NetconfNode netconfNode = node.augmentation(NetconfNode.class);
147 if (netconfNode == null) {
148 LOG.warn("Node {} is not a netconf device", node.getNodeId().getValue());
151 NetconfNodeConnectionStatus.ConnectionStatus connectionStatus = netconfNode.getConnectionStatus();
152 switch (connectionStatus) {
154 LOG.info("Connecting device {} ...", node.getNodeId().getValue());
157 if (isCapabilitiesPresent(netconfNode)) {
158 LOG.warn("Node {} does not contain any capabilities", node.getNodeId().getValue());
161 if (!capabilityCheck(netconfNode.getAvailableCapabilities().getAvailableCapability())) {
162 LOG.warn("Node {} does not contain all capabilities required by vpp-renderer",
163 node.getNodeId().getValue());
166 LOG.info("VPP node connected {}", node.getNodeId().getValue());
168 case UnableToConnect:
169 LOG.warn("Unable to connect to node {}.", node.getNodeId().getValue());
176 private boolean isCapabilitiesPresent(final NetconfNode netconfNode) {
177 return netconfNode.getAvailableCapabilities() == null
178 || netconfNode.getAvailableCapabilities().getAvailableCapability() == null
179 || netconfNode.getAvailableCapabilities().getAvailableCapability().isEmpty();
182 private boolean capabilityCheck(final List<AvailableCapability> capabilities) {
183 final List<String> availableCapabilities =
184 capabilities.stream().map(AvailableCapability::getCapability).collect(Collectors.toList());
185 return REQUIRED_CAPABILITIES.stream().map(QName::toString).allMatch(availableCapabilities::contains);
188 public void close() throws Exception {
189 if (listenerRegistration != null) {
190 listenerRegistration.close();
191 LOG.info("HostConfig listener Closed");