67a06d67ac8501fb7d988ce0ae06f1a8f3b8caa5
[bgpcep.git] / pcep / server / server-provider / src / main / java / org / opendaylight / bgpcep / pcep / server / provider / PathManagerListener.java
1 /*
2  * Copyright (c) 2021 Orange. All rights reserved.
3  *
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
7  */
8 package org.opendaylight.bgpcep.pcep.server.provider;
9
10 import static java.util.Objects.requireNonNull;
11
12 import java.util.Collection;
13 import java.util.List;
14 import java.util.stream.Collectors;
15 import org.opendaylight.mdsal.binding.api.DataBroker;
16 import org.opendaylight.mdsal.binding.api.DataObjectModification;
17 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
18 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
19 import org.opendaylight.mdsal.binding.api.DataTreeModification;
20 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PcepNodeConfig;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLsp;
23 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
24 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
25 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
26 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
27 import org.opendaylight.yangtools.concepts.ListenerRegistration;
28 import org.opendaylight.yangtools.yang.binding.DataObject;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  * This Class Implements the DataStoreService interface providing the methods required to manage the path
36  * representation elements in the Data Store.
37  *
38  * @author Olivier Dugeon
39  */
40
41 public final class PathManagerListener implements DataTreeChangeListener<Node>, AutoCloseable {
42     private static final Logger LOG = LoggerFactory.getLogger(PathManagerListener.class);
43     private ListenerRegistration<PathManagerListener> listenerRegistration;
44
45     private final PathManagerProvider pathManager;
46
47     public PathManagerListener(final DataBroker dataBroker, KeyedInstanceIdentifier<Topology, TopologyKey> topology,
48             final PathManagerProvider pathManager) {
49         requireNonNull(dataBroker);
50         requireNonNull(topology);
51         this.pathManager = requireNonNull(pathManager);
52         final InstanceIdentifier<Node> nodeTopology = topology.child(Node.class);
53         this.listenerRegistration = dataBroker.registerDataTreeChangeListener(
54                 DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION, nodeTopology), this);
55         LOG.info("Registered listener for Managed TE Path on Topology {}",
56                 topology.getKey().getTopologyId().getValue());
57     }
58
59     /**
60      * Close this Listener.
61      */
62     @Override
63     public void close() {
64         if (this.listenerRegistration != null) {
65             LOG.debug("Unregistered listener {} for Managed TE Path", this);
66             this.listenerRegistration.close();
67             this.listenerRegistration = null;
68         }
69     }
70
71     /**
72      * Handle Configured LSP modifications.
73      *
74      * @param nodeId    Node Identifier to which the modified children belongs to.
75      * @param lspMod    List of Configured LSP modifications.
76      */
77     private void handleLspChange(NodeId nodeId, List<? extends DataObjectModification<? extends DataObject>> lspMod) {
78         for (DataObjectModification<? extends DataObject> lsp : lspMod) {
79             ConfiguredLsp cfgLsp;
80             switch (lsp.getModificationType()) {
81                 case DELETE:
82                     cfgLsp = (ConfiguredLsp) lsp.getDataBefore();
83                     LOG.debug("Delete Managed TE Path: {}", cfgLsp.getName());
84                     pathManager.deleteManagedTePath(nodeId, cfgLsp.key());
85                     break;
86                 case SUBTREE_MODIFIED:
87                 case WRITE:
88                     cfgLsp = (ConfiguredLsp) lsp.getDataAfter();
89                     LOG.debug("Update Managed TE Path {}", cfgLsp);
90                     pathManager.createManagedTePath(nodeId, cfgLsp);
91                     break;
92                 default:
93                     break;
94             }
95
96         }
97     }
98
99     /**
100      * Parse Sub Tree modification. Given list has been filtered to get only Path Computation Client1 modifications.
101      * This function first create, update or delete Managed TE Node that corresponds to the given NodeId. Then, it
102      * filter the children to retain only the Configured LSP modifications.
103      *
104      * @param nodeId    Node Identifier to which the modified children belongs to.
105      * @param pccMod    List of PCEP Node Configuration modifications.
106      */
107     private void handlePccChange(NodeId nodeId, List<? extends DataObjectModification<? extends DataObject>> pccMod) {
108         for (DataObjectModification<? extends DataObject> node : pccMod) {
109             /* First, process PCC modification */
110             switch (node.getModificationType()) {
111                 case DELETE:
112                     LOG.debug("Delete Managed TE Node: {}", nodeId);
113                     pathManager.deleteManagedTeNode(nodeId);
114                     break;
115                 case SUBTREE_MODIFIED:
116                 case WRITE:
117                     /* First look if the Managed TE Node belongs to this PCC was not already created */
118                     final PcepNodeConfig pccNode = (PcepNodeConfig) node.getDataAfter();
119                     if (!pathManager.checkManagedTeNode(nodeId)) {
120                         LOG.info("Create new Managed Node {}", nodeId);
121                         pathManager.createManagedTeNode(nodeId, pccNode);
122                     } else {
123                         /* Then, look to Configured LSP modification */
124                         final List<DataObjectModification<? extends DataObject>> lspMod = node.getModifiedChildren()
125                                 .stream().filter(mod -> mod.getDataType().equals(ConfiguredLsp.class))
126                                 .collect(Collectors.toList());
127                         if (!lspMod.isEmpty()) {
128                             handleLspChange(nodeId, lspMod);
129                         }
130                     }
131                     break;
132                 default:
133                     break;
134             }
135         }
136     }
137
138     @Override
139     public void onDataTreeChanged(final Collection<DataTreeModification<Node>> changes) {
140         for (DataTreeModification<Node> change : changes) {
141             DataObjectModification<Node> root = change.getRootNode();
142
143             final String nodeAddr = root.getModificationType() == DataObjectModification.ModificationType.DELETE
144                     ? root.getDataBefore().getNodeId().getValue()
145                     : root.getDataAfter().getNodeId().getValue();
146             NodeId nodeId;
147             if (nodeAddr.startsWith("pcc://")) {
148                 nodeId = new NodeId(nodeAddr);
149             } else {
150                 nodeId = new NodeId("pcc://" + nodeAddr);
151             }
152
153             /* Look only to PcepNodeConfig.class modification */
154             final List<DataObjectModification<? extends DataObject>> pccMod = root.getModifiedChildren().stream()
155                     .filter(mod -> mod.getDataType().equals(PcepNodeConfig.class)).collect(Collectors.toList());
156             if (!pccMod.isEmpty()) {
157                 handlePccChange(nodeId, pccMod);
158             }
159         }
160     }
161 }
162