ed8edd0cd4189a9681aeb2dd3fc6a74e47d242ce
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / intervpnlink / InterVpnLinkNodeAddTask.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.netvirt.vpnmanager.intervpnlink;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.CheckedFuture;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
17 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
18 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.FirstEndpointState;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.FirstEndpointStateBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.SecondEndpointState;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.SecondEndpointStateBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
27
28 import java.math.BigInteger;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.concurrent.Callable;
32
33 public class InterVpnLinkNodeAddTask implements Callable<List<ListenableFuture<Void>>> {
34     private static final String NBR_OF_DPNS_PROPERTY_NAME = "vpnservice.intervpnlink.number.dpns";
35
36     private DataBroker broker;
37     private BigInteger dpnId;
38     final IMdsalApiManager mdsalManager;
39
40     public InterVpnLinkNodeAddTask(final DataBroker broker, final IMdsalApiManager mdsalMgr, final BigInteger dpnId) {
41         this.broker = broker;
42         this.dpnId = dpnId;
43         this.mdsalManager = mdsalMgr;
44     }
45
46     @Override
47     public List<ListenableFuture<Void>> call() throws Exception {
48         List<ListenableFuture<Void>> result = new ArrayList<ListenableFuture<Void>>();
49         // check if there is any inter-vpn-link in with erroneous state
50         List<InterVpnLinkState> allInterVpnLinkState = InterVpnLinkUtil.getAllInterVpnLinkState(broker);
51         int numberOfDpns = Integer.getInteger(NBR_OF_DPNS_PROPERTY_NAME, 1);
52
53         List<BigInteger> firstDpnList = new ArrayList<BigInteger>();
54         List<BigInteger> secondDpnList = new ArrayList<BigInteger>();
55         for (InterVpnLinkState interVpnLinkState : allInterVpnLinkState) {
56             // if the inter-vpn-link is erroneous and any of its endPoints has no dpns associated
57             if (shouldConfigureLinkIntoDpn(interVpnLinkState, this.dpnId, numberOfDpns)) {
58                 firstDpnList.add(dpnId);
59                 secondDpnList = firstDpnList;
60                 // TODO: Limitation to be solved later
61                 // List<BigInteger> secondDpnList = VpnUtil.pickRandomDPNs(broker, numberOfDpns, firstDpnList);
62                 secondDpnList = firstDpnList;
63                 installLPortDispatcherTable(interVpnLinkState, firstDpnList, secondDpnList);
64                 CheckedFuture<Void, TransactionCommitFailedException> futures =
65                         updateInterVpnLinkState(interVpnLinkState, firstDpnList, secondDpnList, numberOfDpns);
66                 result.add(futures);
67             }
68         }
69         return result;
70     }
71
72     private boolean shouldConfigureLinkIntoDpn(InterVpnLinkState interVpnLinkState, BigInteger dpnId, int numberOfDpns) {
73
74         if (interVpnLinkState.getState().equals(InterVpnLinkState.State.Error)) {
75             if ((interVpnLinkState.getFirstEndpointState().getDpId() == null
76                || interVpnLinkState.getFirstEndpointState().getDpId().isEmpty())
77                || (interVpnLinkState.getSecondEndpointState().getDpId() == null
78                || interVpnLinkState.getSecondEndpointState().getDpId().isEmpty())) {
79                 return true;
80             } else if (!interVpnLinkState.getFirstEndpointState().getDpId().contains(dpnId)
81                     && !interVpnLinkState.getSecondEndpointState().getDpId().contains(dpnId)
82                     && (interVpnLinkState.getFirstEndpointState().getDpId().size() < numberOfDpns)) {
83                 return true;
84             }
85         }
86
87         return false;
88     }
89
90     private CheckedFuture<Void, TransactionCommitFailedException>
91                 updateInterVpnLinkState(InterVpnLinkState interVpnLinkState, List<BigInteger> firstDpnList,
92                                         List<BigInteger> secondDpnList, int numberOfDpns) {
93         FirstEndpointState firstEndPointState =
94                 new FirstEndpointStateBuilder(interVpnLinkState.getFirstEndpointState())
95                                                                .setDpId(firstDpnList).build();
96         SecondEndpointState secondEndPointState =
97                 new SecondEndpointStateBuilder(interVpnLinkState.getSecondEndpointState())
98                                                                 .setDpId(secondDpnList).build();
99         InterVpnLinkState newInterVpnLinkState = new InterVpnLinkStateBuilder(interVpnLinkState)
100                                                                 .setState(InterVpnLinkState.State.Active)
101                                                                 .setFirstEndpointState(firstEndPointState)
102                                                                 .setSecondEndpointState(secondEndPointState)
103                                                                 .build();
104         WriteTransaction tx = broker.newWriteOnlyTransaction();
105         tx.merge(LogicalDatastoreType.CONFIGURATION,
106                  VpnUtil.getInterVpnLinkStateIid(interVpnLinkState.getInterVpnLinkName()), newInterVpnLinkState, true);
107         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
108         return futures;
109     }
110
111     private void installLPortDispatcherTable(InterVpnLinkState interVpnLinkState, List<BigInteger> firstDpnList,
112                                              List<BigInteger> secondDpnList) {
113         Optional<InterVpnLink> vpnLink = InterVpnLinkUtil.getInterVpnLinkByName(broker, interVpnLinkState.getKey().getInterVpnLinkName());
114         if (vpnLink.isPresent()) {
115             Uuid firstEndpointVpnUuid = vpnLink.get().getFirstEndpoint().getVpnUuid();
116             Uuid secondEndpointVpnUuid = vpnLink.get().getSecondEndpoint().getVpnUuid();
117             // Note that in the DPN of the firstEndpoint we install the lportTag of the secondEndpoint and viceversa
118             InterVpnLinkUtil.installLPortDispatcherTableFlow(broker, mdsalManager, vpnLink.get(), firstDpnList,
119                                                     secondEndpointVpnUuid,
120                                                     interVpnLinkState.getSecondEndpointState().getLportTag());
121             InterVpnLinkUtil.installLPortDispatcherTableFlow(broker, mdsalManager, vpnLink.get(), secondDpnList,
122                                                     firstEndpointVpnUuid,
123                                                     interVpnLinkState.getFirstEndpointState().getLportTag());
124             // Update the VPN -> DPNs Map.
125             // Note: when a set of DPNs is calculated for Vpn1, these DPNs are added to the VpnToDpn map of Vpn2. Why?
126             // because we do the handover from Vpn1 to Vpn2 in those DPNs, so in those DPNs we must know how to reach
127             // to Vpn2 targets. If new Vpn2 targets are added later, the Fib will be maintained in these DPNs even if
128             // Vpn2 is not physically present there.
129             InterVpnLinkUtil.updateVpnToDpnMap(broker, firstDpnList, secondEndpointVpnUuid);
130             InterVpnLinkUtil.updateVpnToDpnMap(broker, secondDpnList, firstEndpointVpnUuid);
131         }
132     }
133
134 }