8a405d4f4a7836e5fd8f79e8387a4776fa82734b
[groupbasedpolicy.git] / sxp-integration / ip-sgt-distribution-service / src / main / java / org / opendaylight / groupbasedpolicy / ip / sgt / distribution / service / impl / IpSgtDistributionServiceImpl.java
1 /*
2  * Copyright (c) 2016 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
9 package org.opendaylight.groupbasedpolicy.ip.sgt.distribution.service.impl;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.ArrayListMultimap;
13 import com.google.common.collect.Multimap;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.SettableFuture;
18 import java.util.HashMap;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import java.util.concurrent.Future;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.sxp.util.time.TimeConv;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.IpSgtDistributionService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.RemoveIpSgtBindingFromPeerInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.SendIpSgtBindingToPeerInput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.rpc.fields.Binding;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.rpc.fields.binding.PeerNode;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.SxpControllerService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBinding;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBindingBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBindingKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.peer.sequence.fields.PeerSequenceBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.SxpNodeIdentity;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.SxpDomains;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomain;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomainKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.databases.fields.MasterDatabase;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.protocol.rev141002.NodeId;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.opendaylight.yangtools.yang.common.RpcResult;
57 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 public class IpSgtDistributionServiceImpl implements AutoCloseable, IpSgtDistributionService {
62
63     private static final Logger LOG = LoggerFactory.getLogger(IpSgtDistributionServiceImpl.class);
64     public static final String SXP_NODE_DESCRIPTION = "ODL-GBP SXP node";
65     public static final String SXP_TOPOLOGY_ID = "sxp";
66     private final String SXP_NODE_ID;
67     private DataBroker dataBroker;
68     private IpAddress sourceIp;
69     private SxpCapableNodeListener nodeCollector;
70
71     public IpSgtDistributionServiceImpl(DataBroker dataBroker, SxpControllerService sxpService, IpAddress sourceIp) {
72         this.dataBroker = Preconditions.checkNotNull(dataBroker);
73         this.sourceIp = Preconditions.checkNotNull(sourceIp);
74         Preconditions.checkNotNull(sxpService);
75
76         if (sourceIp.getIpv4Address() != null) {
77             SXP_NODE_ID = sourceIp.getIpv4Address().getValue();
78         } else {
79             SXP_NODE_ID = sourceIp.getIpv6Address().getValue();
80         }
81         createSxpNode(sxpService);
82         nodeCollector = new SxpCapableNodeListener(dataBroker, SXP_NODE_ID);
83
84     }
85
86     private void createSxpNode(SxpControllerService sxpService) {
87         AddNodeInput addNodeInput = new AddNodeInputBuilder().setNodeId(new NodeId(SXP_NODE_ID))
88                 .setSourceIp(sourceIp)
89                 .setDescription(SXP_NODE_DESCRIPTION)
90                 .build();
91         Future<RpcResult<AddNodeOutput>> addNodeResult = sxpService.addNode(addNodeInput);
92         try {
93             if (! addNodeResult.get().getResult().isResult()) {
94                 LOG.error("RPC add-node wasn't successfull");
95             }
96         } catch (Exception e) {
97             LOG.error("RPC add-node wasn't successfull");
98         }
99     }
100
101     @Override
102     public Future<RpcResult<Void>> sendIpSgtBindingToPeer(SendIpSgtBindingToPeerInput input) {
103         Map<String, Multimap<Sgt, IpPrefix>> bindingsMap = new HashMap<>();
104         boolean success = true;
105         for (Binding binding : input.getBinding()) {
106             success = transformChanges(binding, bindingsMap);
107             if (! success) {
108                 break;
109             }
110         }
111         if (! success) {
112             return Futures.immediateCheckedFuture(RpcResultBuilder.<Void>failed().build());
113         }
114         WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
115         bindingsMap.entrySet().forEach(bindingEntries -> {
116             String domainId = bindingEntries.getKey();
117             bindingEntries.getValue().entries().forEach(binding -> writeBinding(binding, domainId, wtx));
118         });
119         ListenableFuture<Void> submit = wtx.submit();
120         SettableFuture<RpcResult<Void>> future = SettableFuture.create();
121         Futures.addCallback(submit, new FutureCallback<Void>() {
122
123             @Override
124             public void onSuccess(Void result) {
125                 future.set(RpcResultBuilder.<Void>success().build());
126             }
127
128             @Override
129             public void onFailure(Throwable t) {
130                 future.set(RpcResultBuilder.<Void>failed().build());
131
132             }
133
134         });
135         return future;
136     }
137
138     private boolean transformChanges(Binding binding, Map<String, Multimap<Sgt, IpPrefix>> bindingsMap) {
139         Sgt sgt = binding.getSgt();
140         IpPrefix addr = binding.getIpPrefix();
141         for (PeerNode peer : binding.getPeerNode()) {
142             String domainId = nodeCollector.getDomainIdForPeer((InstanceIdentifier<Node>) peer.getNodeIid());
143             if (domainId == null) {
144                 LOG.debug("Node {} is not SXP capable", peer.getNodeIid());
145                 return false;
146             }
147             Multimap<Sgt, IpPrefix> domainBindingMap = bindingsMap.get(domainId);
148             if (domainBindingMap == null) {
149                 domainBindingMap = ArrayListMultimap.create();
150                 bindingsMap.put(domainId, domainBindingMap);
151             }
152             domainBindingMap.get(sgt).add(addr);
153         }
154         return true;
155     }
156
157     private void writeBinding(Entry<Sgt, IpPrefix> binding, String domainId, WriteTransaction wtx) {
158         IpPrefix addr = binding.getValue();
159         InstanceIdentifier<MasterDatabaseBinding> iid = bindingIid(domainId, addr);
160         MasterDatabaseBinding newBinding = createBinding(binding);
161         wtx.put(LogicalDatastoreType.CONFIGURATION, iid, newBinding);
162     }
163
164     private InstanceIdentifier<MasterDatabaseBinding> bindingIid(String domainId, IpPrefix prefix) {
165         return InstanceIdentifier.builder(NetworkTopology.class)
166                 .child(Topology.class, new TopologyKey(new TopologyId(SXP_TOPOLOGY_ID)))
167                 .child(Node.class,
168                         new NodeKey(
169                                 new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId(
170                                         SXP_NODE_ID)))
171                 .augmentation(SxpNodeIdentity.class)
172                 .child(SxpDomains.class)
173                 .child(SxpDomain.class, new SxpDomainKey(domainId))
174                 .child(MasterDatabase.class)
175                 .child(MasterDatabaseBinding.class, new MasterDatabaseBindingKey(prefix))
176                 .build();
177     }
178
179     private MasterDatabaseBinding createBinding(Entry<Sgt, IpPrefix> binding) {
180         final DateAndTime nowDateTime = TimeConv.toDt(System.currentTimeMillis());
181         return new MasterDatabaseBindingBuilder()
182                 .setIpPrefix(binding.getValue())
183                 .setSecurityGroupTag(binding.getKey())
184                 .setPeerSequence(new PeerSequenceBuilder().build())
185                 .setTimestamp(nowDateTime)
186                 .build();
187     }
188
189     @Override
190     public Future<RpcResult<Void>> removeIpSgtBindingFromPeer(RemoveIpSgtBindingFromPeerInput input) {
191         Map<String, Multimap<Sgt, IpPrefix>> bindingsMap = new HashMap<>();
192         boolean success = true;
193         for (Binding binding : input.getBinding()) {
194             success = transformChanges(binding, bindingsMap);
195             if (! success) {
196                 break;
197             }
198         }
199         if (! success) {
200             return Futures.immediateCheckedFuture(RpcResultBuilder.<Void>failed().build());
201         }
202         WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
203         bindingsMap.entrySet().forEach(bindingEntries -> {
204             String domainId = bindingEntries.getKey();
205             bindingEntries.getValue().entries().forEach(binding -> removeBinding(binding, domainId, wtx));
206         });
207         ListenableFuture<Void> submit = wtx.submit();
208         SettableFuture<RpcResult<Void>> future = SettableFuture.create();
209         Futures.addCallback(submit, new FutureCallback<Void>() {
210
211             @Override
212             public void onSuccess(Void result) {
213                 future.set(RpcResultBuilder.<Void>success().build());
214             }
215
216             @Override
217             public void onFailure(Throwable t) {
218                 future.set(RpcResultBuilder.<Void>failed().build());
219
220             }
221
222         });
223         return future;
224     }
225
226     private void removeBinding(Entry<Sgt, IpPrefix> binding, String domainId, WriteTransaction wtx) {
227         IpPrefix addr = binding.getValue();
228         InstanceIdentifier<MasterDatabaseBinding> iid = bindingIid(domainId, addr);
229         wtx.delete(LogicalDatastoreType.CONFIGURATION, iid);
230     }
231
232     @Override
233     public void close() throws Exception {
234         nodeCollector.close();
235     }
236
237 }