2 * Copyright (c) 2015 NEC 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.vtn.manager.internal.routing;
11 import java.util.ArrayList;
12 import java.util.HashSet;
13 import java.util.List;
15 import java.util.concurrent.ConcurrentSkipListSet;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
20 import org.opendaylight.vtn.manager.PathPolicy;
21 import org.opendaylight.vtn.manager.VTNException;
23 import org.opendaylight.vtn.manager.internal.TxContext;
24 import org.opendaylight.vtn.manager.internal.TxTask;
25 import org.opendaylight.vtn.manager.internal.VTNManagerProvider;
26 import org.opendaylight.vtn.manager.internal.util.ChangedData;
27 import org.opendaylight.vtn.manager.internal.util.DataStoreListener;
28 import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
29 import org.opendaylight.vtn.manager.internal.util.IdentifiedData;
30 import org.opendaylight.vtn.manager.internal.util.MiscUtils;
31 import org.opendaylight.vtn.manager.internal.util.XmlConfigFile;
32 import org.opendaylight.vtn.manager.internal.util.concurrent.VTNFuture;
33 import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathPolicyConfigBuilder;
34 import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathPolicyUtils;
35 import org.opendaylight.vtn.manager.internal.util.rpc.RpcException;
36 import org.opendaylight.vtn.manager.internal.util.tx.AbstractTxTask;
38 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
39 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
40 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
41 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
43 import org.opendaylight.yangtools.yang.binding.DataObject;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.VtnPathPolicies;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.VtnPathPoliciesBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.vtn.path.policies.VtnPathPolicy;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.vtn.path.policies.VtnPathPolicyKey;
52 * A data change listener that listens change of path policy configuration.
54 final class PathPolicyListener
55 extends DataStoreListener<VtnPathPolicy, PathPolicyChange> {
59 private static final Logger LOG =
60 LoggerFactory.getLogger(PathPolicyListener.class);
63 * A graph that keeps network topology.
65 private final TopologyGraph topology;
68 * A set of path policy IDs laoded by {@link PathPolicyLoadTask}.
70 private Set<Integer> loadedPolicies;
73 * MD-SAL transaction task to load path policy configuration.
76 * This task returns current {@link VtnPathPolicies} instance.
79 private class PathPolicyLoadTask extends AbstractTxTask<VtnPathPolicies> {
81 * Resume the configuration for the given path policy.
83 * @param vlist A list of {@link VtnPathPolicy} instance to store
84 * resumed configuration.
85 * @param loaded A set of loaded path policy IDs.
86 * @param key A string representation of the policy ID.
87 * @param pp A {@link PathPolicy} instance.
89 private void resume(List<VtnPathPolicy> vlist, Set<Integer> loaded,
90 String key, PathPolicy pp) {
91 Integer pid = pp.getPolicyId();
93 if (!key.equals(String.valueOf(pid))) {
94 String msg = new StringBuilder("Unexpected ID: ").
95 append(pid).append(": expected=").append(key).
97 throw new IllegalArgumentException(msg);
99 VtnPathPolicy vpp = new PathPolicyConfigBuilder.Data().
100 set(pp).getBuilder().build();
103 } catch (RpcException | RuntimeException e) {
104 String msg = MiscUtils.joinColon(
105 "Ignore invalid path policy configuration",
115 public VtnPathPolicies execute(TxContext ctx) throws VTNException {
116 loadedPolicies = null;
117 Set<Integer> loaded = new ConcurrentSkipListSet<>();
119 // Load configuration from file.
120 XmlConfigFile.Type ftype = XmlConfigFile.Type.PATHPOLICY;
121 List<VtnPathPolicy> vlist = new ArrayList<>();
122 for (String key: XmlConfigFile.getKeys(ftype)) {
123 PathPolicy pp = XmlConfigFile.load(
124 ftype, key, PathPolicy.class);
126 resume(vlist, loaded, key, pp);
130 VtnPathPoliciesBuilder builder = new VtnPathPoliciesBuilder();
131 if (!vlist.isEmpty()) {
132 builder.setVtnPathPolicy(vlist);
134 InstanceIdentifier<VtnPathPolicies> path =
135 InstanceIdentifier.create(VtnPathPolicies.class);
137 // Remove old configuration, and install loaded configuration.
138 LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
139 ReadWriteTransaction tx = ctx.getReadWriteTransaction();
140 DataStoreUtils.delete(tx, oper, path);
142 VtnPathPolicies policies = builder.build();
143 tx.put(oper, path, policies, true);
144 if (!loaded.isEmpty()) {
145 loadedPolicies = loaded;
155 public void onSuccess(VTNManagerProvider provider,
156 VtnPathPolicies result) {
157 List<VtnPathPolicy> vlist = result.getVtnPathPolicy();
159 // Create route resolvers for path policies.
160 for (VtnPathPolicy vpp: vlist) {
161 Integer id = vpp.getId();
162 LOG.info("{}: Path policy has been loaded.", id);
163 topology.updateResolver(id);
170 * MD-SAL transaction task to save current path policy configuration.
173 * This task returns current {@link VtnPathPolicies} instance.
176 private static class PathPolicySaveTask
177 extends AbstractTxTask<VtnPathPolicies> {
179 * Set {@code true} if the root container has been created.
181 private boolean created;
187 public VtnPathPolicies execute(TxContext ctx) throws VTNException {
190 // Load current configuration.
191 InstanceIdentifier<VtnPathPolicies> path =
192 InstanceIdentifier.create(VtnPathPolicies.class);
193 LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
194 ReadWriteTransaction tx = ctx.getReadWriteTransaction();
195 VtnPathPolicies policies =
196 DataStoreUtils.read(tx, oper, path).orNull();
197 if (policies == null) {
198 // Initialize the path policy container.
199 VtnPathPoliciesBuilder builder = new VtnPathPoliciesBuilder();
200 policies = builder.build();
201 tx.put(oper, path, builder.build(), true);
212 public void onSuccess(VTNManagerProvider provider,
213 VtnPathPolicies result) {
216 "An empty path policy container has been created.");
219 XmlConfigFile.Type ftype = XmlConfigFile.Type.PATHPOLICY;
220 Set<String> names = new HashSet<>();
221 List<VtnPathPolicy> vlist = result.getVtnPathPolicy();
223 for (VtnPathPolicy vpp: vlist) {
224 // Save configuration into a file.
225 PathPolicy pp = PathPolicyUtils.toPathPolicy(vpp);
226 String key = pp.getPolicyId().toString();
227 XmlConfigFile.save(ftype, key, pp);
232 // Remove obsolete configuration files.
233 XmlConfigFile.deleteAll(ftype, names);
238 * Construct a new instance.
240 * @param provider VTN Manager provider service.
241 * @param topo A {@link TopologyGraph} instance.
243 PathPolicyListener(VTNManagerProvider provider, TopologyGraph topo) {
244 super(VtnPathPolicy.class);
246 registerListener(provider.getDataBroker(),
247 LogicalDatastoreType.OPERATIONAL,
248 DataChangeScope.SUBTREE);
252 * Post a MD-SAL transaction task to initialize configuration.
254 * @param provider VTN Manager provider service.
255 * @param master {@code true} if the local node is the configuration
257 * @return A {@link VTNFuture} instance.
259 VTNFuture<?> initConfig(VTNManagerProvider provider, boolean master) {
260 TxTask<?> task = (master)
261 ? new PathPolicyLoadTask() : new PathPolicySaveTask();
262 return provider.post(task);
266 * Return the path policy identifier in the given instance identifier.
268 * @param path Path to the path policy configuration.
269 * @return An {@link Integer} instance which represents the path policy
270 * identifier. {@code null} on failure.
272 private Integer getIdentifier(InstanceIdentifier<VtnPathPolicy> path) {
273 VtnPathPolicyKey key =
274 path.firstKeyOf(VtnPathPolicy.class, VtnPathPolicyKey.class);
288 protected PathPolicyChange enterEvent(
289 AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> ev) {
290 return new PathPolicyChange(topology);
297 protected void exitEvent(PathPolicyChange ectx) {
305 protected void onCreated(PathPolicyChange ectx,
306 IdentifiedData<VtnPathPolicy> data) {
307 InstanceIdentifier<VtnPathPolicy> path = data.getIdentifier();
308 Integer id = getIdentifier(path);
310 LOG.warn("Ignore broken creation event: path={}, value={}",
311 path, data.getValue());
313 // Do nothing if the specified event was caused by the initial
315 Set<Integer> loaded = loadedPolicies;
316 if (loaded == null || !loaded.remove(id)) {
317 VtnPathPolicy vpp = data.getValue();
318 ectx.addUpdated(id, PathPolicyUtils.toPathPolicy(vpp));
319 } else if (loaded.isEmpty()) {
320 LOG.debug("All loaded path policies have been notified.");
321 loadedPolicies = null;
330 protected void onUpdated(PathPolicyChange ectx,
331 ChangedData<VtnPathPolicy> data) {
332 InstanceIdentifier<VtnPathPolicy> path = data.getIdentifier();
333 VtnPathPolicy vpp = data.getValue();
334 Integer id = getIdentifier(path);
336 LOG.warn("Ignore broken update event: path={}, old={}, new={}",
337 path, vpp, data.getOldValue());
339 ectx.addUpdated(id, PathPolicyUtils.toPathPolicy(vpp));
347 protected void onRemoved(PathPolicyChange ectx,
348 IdentifiedData<VtnPathPolicy> data) {
349 InstanceIdentifier<VtnPathPolicy> path = data.getIdentifier();
350 Integer id = getIdentifier(path);
352 LOG.warn("Ignore broken removal event: path={}, value={}",
353 path, data.getValue());
363 protected InstanceIdentifier<VtnPathPolicy> getWildcardPath() {
364 return InstanceIdentifier.builder(VtnPathPolicies.class).
365 child(VtnPathPolicy.class).build();
368 // CloseableContainer
374 protected Logger getLogger() {