1c78c343c5fd41dacd24bb31af70800feda0fd4e
[bgpcep.git] / pcep / topology-provider / src / main / java / org / opendaylight / bgpcep / pcep / topology / provider / Stateful07TopologySessionListener.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  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.topology.provider;
9
10 import java.net.InetAddress;
11 import java.nio.ByteBuffer;
12 import java.util.Collections;
13
14 import javax.annotation.concurrent.GuardedBy;
15
16 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
17 import org.opendaylight.protocol.pcep.PCEPSession;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.PcinitiateBuilder;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.pcinitiate.message.PcinitiateMessageBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.pcinitiate.message.pcinitiate.message.RequestsBuilder;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Arguments1;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Arguments2;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.OperationalStatus;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.PcrptMessage;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.PcupdBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.PlspId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.ReportedLsp1;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.ReportedLsp1Builder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.SrpIdNumber;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.StatefulTlv1;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.StatefulTlv1Builder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.SymbolicPathName;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Tlvs1;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.Lsp;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.LspBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.TlvsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.pcerr.pcerr.message.error.type.StatefulCase;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.pcerr.pcerr.message.error.type.stateful._case.stateful.Srps;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.pcrpt.message.pcrpt.message.Reports;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.pcupd.message.PcupdMessageBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.pcupd.message.pcupd.message.UpdatesBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.pcupd.message.pcupd.message.updates.PathBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.srp.object.Srp;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.srp.object.SrpBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.stateful.capability.tlv.Stateful;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.symbolic.path.name.tlv.SymbolicPathNameBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.PcerrMessage;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.open.Tlvs;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.AddLspArgs;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.EnsureLspOperationalInput;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.OperationResult;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.PccSyncState;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.RemoveLspArgs;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.UpdateLspArgs;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClientBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLsp;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.StatefulTlvBuilder;
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 import com.google.common.base.Charsets;
65 import com.google.common.base.Preconditions;
66 import com.google.common.collect.ImmutableList;
67 import com.google.common.util.concurrent.ListenableFuture;
68
69 final class Stateful07TopologySessionListener extends AbstractTopologySessionListener<SrpIdNumber, PlspId> {
70         private static final Logger LOG = LoggerFactory.getLogger(Stateful07TopologySessionListener.class);
71
72         /**
73          * @param serverSessionManager
74          */
75         Stateful07TopologySessionListener(final ServerSessionManager serverSessionManager) {
76                 super(serverSessionManager);
77         }
78
79         @GuardedBy("this")
80         private long requestId = 1;
81
82         @Override
83         protected void onSessionUp(final PCEPSession session, final PathComputationClientBuilder pccBuilder) {
84                 final InetAddress peerAddress = session.getRemoteAddress();
85
86                 final Tlvs tlvs = session.getRemoteTlvs();
87                 if (tlvs != null && tlvs.getAugmentation(Tlvs1.class) != null) {
88                         final Stateful stateful = tlvs.getAugmentation(Tlvs1.class).getStateful();
89                         if (stateful != null) {
90                                 pccBuilder.setReportedLsp(Collections.<ReportedLsp> emptyList());
91                                 pccBuilder.setStateSync(PccSyncState.InitialResync);
92                                 pccBuilder.setStatefulTlv(new StatefulTlvBuilder().addAugmentation(StatefulTlv1.class,
93                                                 new StatefulTlv1Builder(tlvs.getAugmentation(Tlvs1.class)).build()).build());
94                         } else {
95                                 LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
96                         }
97                 } else {
98                         LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
99                 }
100         }
101
102         @Override
103         protected synchronized boolean onMessage(final DataModificationTransaction trans, final Message message) {
104                 if (message instanceof PcerrMessage) {
105                         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcerr.message.PcerrMessage errMsg = ((PcerrMessage) message).getPcerrMessage();
106                         if (errMsg.getErrorType() instanceof StatefulCase) {
107                                 StatefulCase stat = (StatefulCase)errMsg.getErrorType();
108                                 for (Srps srps : stat.getStateful().getSrps()) {
109                                         SrpIdNumber id = srps.getSrp().getOperationId();
110                                         if (id.getValue() != 0) {
111                                                 final PCEPRequest req = removeRequest(id);
112                                                 if (req != null) {
113                                                         req.setResult(OperationResults.SUCCESS);
114                                                 } else {
115                                                         LOG.warn("Request ID {} not found in outstanding DB", id);
116                                                 }
117                                         }
118                                 }
119                         } else {
120                                 LOG.warn("Unhandled PCErr message {}.", errMsg);
121                                 return true;
122                         }
123                         return false;
124                 }
125                 if (!(message instanceof PcrptMessage)) {
126                         return true;
127                 }
128
129                 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.pcrpt.message.PcrptMessage rpt = ((PcrptMessage) message).getPcrptMessage();
130                 for (final Reports r : rpt.getReports()) {
131                         final Lsp lsp = r.getLsp();
132
133                         if (!lsp.isSync() && (lsp.getPlspId() == null || lsp.getPlspId().getValue() == 0)) {
134                                 stateSynchronizationAchieved(trans);
135                                 continue;
136                         }
137
138                         final ReportedLspBuilder rlb = new ReportedLspBuilder();
139                         rlb.addAugmentation(ReportedLsp1.class, new ReportedLsp1Builder(r).build());
140                         if (r.getPath() != null) {
141                                 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.reported.lsp.PathBuilder pb = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.reported.lsp.PathBuilder();
142                                 pb.fieldsFrom(r.getPath());
143                                 rlb.setPath(pb.build());
144                         }
145                         boolean solicited = false;
146
147                         final Srp srp = r.getSrp();
148                         if (srp != null) {
149                                 final SrpIdNumber id = srp.getOperationId();
150                                 if (id.getValue() != 0) {
151                                         solicited = true;
152
153                                         switch (lsp.getOperational()) {
154                                         case Active:
155                                         case Down:
156                                         case Up:
157                                                 final PCEPRequest req = removeRequest(id);
158                                                 if (req != null) {
159                                                         LOG.debug("Request {} resulted in LSP operational state {}", id, lsp.getOperational());
160                                                         rlb.setMetadata(req.getMetadata());
161                                                         req.setResult(OperationResults.SUCCESS);
162                                                 } else {
163                                                         LOG.warn("Request ID {} not found in outstanding DB", id);
164                                                 }
165                                                 break;
166                                         case GoingDown:
167                                         case GoingUp:
168                                                 // These are transitive states, so we don't have to do anything, as they will be followed
169                                                 // up...
170                                                 break;
171                                         }
172                                 }
173                         }
174
175                         final PlspId id = lsp.getPlspId();
176                         if (!lsp.isRemove()) {
177                                 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.lsp.Tlvs tlvs = r.getLsp().getTlvs();
178                                 final String name;
179                                 if (tlvs != null && tlvs.getSymbolicPathName() != null) {
180                                         name = Charsets.UTF_8.decode(ByteBuffer.wrap(tlvs.getSymbolicPathName().getPathName().getValue())).toString();
181                                 } else {
182                                         name = null;
183                                 }
184
185                                 updateLsp(trans, id, name, rlb, solicited);
186                                 LOG.debug("LSP {} updated", lsp);
187                         } else {
188                                 removeLsp(trans, id);
189                                 LOG.debug("LSP {} removed", lsp);
190                         }
191                 }
192
193                 return false;
194         }
195
196         @GuardedBy("this")
197         private SrpIdNumber nextRequest() {
198                 return new SrpIdNumber(this.requestId++);
199         }
200
201         @Override
202         public synchronized ListenableFuture<OperationResult> addLsp(final AddLspArgs input) {
203                 LOG.trace("AddLspArgs {}", input);
204                 // Make sure there is no such LSP
205                 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName()).build();
206                 if (readOperationalData(lsp) != null) {
207                         LOG.debug("Node {} already contains lsp {} at {}", input.getNode(), input.getName(), lsp);
208                         return OperationResults.UNSENT.future();
209                 }
210                 // Build the request
211                 final RequestsBuilder rb = new RequestsBuilder();
212                 Lsp inputLsp = input.getArguments().getAugmentation(Arguments2.class).getLsp();
213                 rb.fieldsFrom(input.getArguments());
214                 rb.setSrp(new SrpBuilder().setOperationId(nextRequest()).setProcessingRule(Boolean.TRUE).build());
215                 rb.setLsp(new LspBuilder().setAdministrative(inputLsp.isAdministrative()).setDelegate(inputLsp.isDelegate()).setPlspId(
216                                 new PlspId(0L)).setTlvs(
217                                                 new TlvsBuilder().setSymbolicPathName(
218                                                                 new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(input.getName().getBytes(Charsets.UTF_8))).build()).build()).build());
219
220                 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder(MESSAGE_HEADER);
221                 ib.setRequests(ImmutableList.of(rb.build()));
222
223                 // Send the message
224                 return sendMessage(new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build(), rb.getSrp().getOperationId(),
225                                 input.getArguments().getMetadata());
226         }
227
228         @Override
229         public synchronized ListenableFuture<OperationResult> removeLsp(final RemoveLspArgs input) {
230                 // Make sure the LSP exists, we need it for PLSP-ID
231                 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName()).build();
232                 final ReportedLsp rep = readOperationalData(lsp);
233                 if (rep == null) {
234                         LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
235                         return OperationResults.UNSENT.future();
236                 }
237
238                 final ReportedLsp1 ra = rep.getAugmentation(ReportedLsp1.class);
239                 Preconditions.checkState(ra != null);
240
241                 // Build the request and send it
242                 final RequestsBuilder rb = new RequestsBuilder();
243                 rb.setSrp(new SrpBuilder().setOperationId(nextRequest()).setProcessingRule(Boolean.TRUE).build());
244                 rb.setLsp(new LspBuilder().setRemove(Boolean.TRUE).setPlspId(ra.getLsp().getPlspId()).setDelegate(ra.getLsp().isDelegate()).build());
245
246                 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder(MESSAGE_HEADER);
247                 ib.setRequests(ImmutableList.of(rb.build()));
248                 return sendMessage(new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build(), rb.getSrp().getOperationId(), null);
249         }
250
251         @Override
252         public synchronized ListenableFuture<OperationResult> updateLsp(final UpdateLspArgs input) {
253                 // Make sure the LSP exists
254                 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName()).build();
255                 final ReportedLsp rep = readOperationalData(lsp);
256                 if (rep == null) {
257                         LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
258                         return OperationResults.UNSENT.future();
259                 }
260
261                 final ReportedLsp1 ra = rep.getAugmentation(ReportedLsp1.class);
262                 Preconditions.checkState(ra != null);
263
264                 // Build the PCUpd request and send it
265                 final UpdatesBuilder rb = new UpdatesBuilder();
266                 rb.setSrp(new SrpBuilder().setOperationId(nextRequest()).setProcessingRule(Boolean.TRUE).build());
267                 rb.setLsp(new LspBuilder().setPlspId(ra.getLsp().getPlspId()).setDelegate(ra.getLsp().isDelegate()).build());
268                 final PathBuilder pb = new PathBuilder();
269                 rb.setPath(pb.setEro(input.getArguments().getEro()).build());
270                 pb.fieldsFrom(input.getArguments());
271                 rb.setPath(pb.build());
272                 final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
273                 ub.setUpdates(ImmutableList.of(rb.build()));
274                 return sendMessage(new PcupdBuilder().setPcupdMessage(ub.build()).build(), rb.getSrp().getOperationId(),
275                                 input.getArguments().getMetadata());
276         }
277
278         @Override
279         public synchronized ListenableFuture<OperationResult> ensureLspOperational(final EnsureLspOperationalInput input) {
280                 OperationalStatus op = null;
281                 final Arguments1 aa = input.getArguments().getAugmentation(Arguments1.class);
282                 if (aa != null) {
283                         op = aa.getOperational();
284                 }
285
286                 // Make sure the LSP exists
287                 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName()).build();
288                 LOG.debug("Checking if LSP {} has operational state {}", lsp, op);
289                 final ReportedLsp rep = readOperationalData(lsp);
290                 if (rep == null) {
291                         LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
292                         return OperationResults.UNSENT.future();
293                 }
294
295                 final ReportedLsp1 ra = rep.getAugmentation(ReportedLsp1.class);
296                 if (ra == null) {
297                         LOG.warn("Node {} LSP {} does not contain data", input.getNode(), input.getName());
298                         return OperationResults.UNSENT.future();
299                 }
300
301                 if (ra.getLsp().getOperational().equals(op)) {
302                         return OperationResults.SUCCESS.future();
303                 } else {
304                         return OperationResults.UNSENT.future();
305                 }
306         }
307 }