NETVIRT-1630 migrate to md-sal APIs
[netvirt.git] / bgpmanager / impl / src / main / java / org / opendaylight / netvirt / bgpmanager / FibDSWriter.java
1 /*
2  * Copyright (c) 2015 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.bgpmanager;
9
10 import com.google.common.base.Preconditions;
11
12 import java.util.ArrayList;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.stream.Collectors;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.apache.commons.lang3.StringUtils;
20 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
21 import org.opendaylight.mdsal.binding.api.DataBroker;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.mdsal.common.api.ReadFailedException;
24 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
25 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
26 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.AddressFamily;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.VrfEntryBase.EncapType;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.macvrfentries.MacVrfEntry;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.macvrfentries.MacVrfEntryBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.macvrfentries.MacVrfEntryKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
40 import org.opendaylight.yangtools.yang.common.Uint32;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 @Singleton
45 public class FibDSWriter {
46     private static final Logger LOG = LoggerFactory.getLogger(FibDSWriter.class);
47     private final SingleTransactionDataBroker singleTxDB;
48     private final BgpUtil bgpUtil;
49     private final Map<String, ArrayList<String>> fibMap = new HashMap<>();
50
51     @Inject
52     public FibDSWriter(final DataBroker dataBroker, final BgpUtil bgpUtil) {
53         this.bgpUtil = bgpUtil;
54         this.singleTxDB = new SingleTransactionDataBroker(dataBroker);
55     }
56
57     public synchronized void clearFibMap() {
58         fibMap.clear();
59     }
60
61     public synchronized void addEntryToFibMap(String rd, String prefix, String nextHop) {
62         ArrayList<String> temp = new ArrayList<String>();
63         if ((fibMap.get(appendrdtoprefix(rd, prefix)) != null)) {
64             temp.addAll(fibMap.get(appendrdtoprefix(rd, prefix)));
65         }
66         temp.add(nextHop);
67         fibMap.put(appendrdtoprefix(rd, prefix),temp);
68         LOG.debug("addEntryToFibMap rd {} prefix {} nexthop {}",
69                 rd, prefix, nextHop);
70
71     }
72
73     public synchronized void addFibEntryToDS(String rd, String prefix, List<String> nextHopList,
74                                              VrfEntry.EncapType encapType, Uint32 label, Uint32 l3vni,
75                                              String gatewayMacAddress, RouteOrigin origin) {
76         if (rd == null || rd.isEmpty()) {
77             LOG.error("Prefix {} not associated with vpn", prefix);
78             return;
79         }
80
81         Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
82         for (String nextHop : nextHopList) {
83             if (nextHop == null || nextHop.isEmpty()) {
84                 LOG.error("nextHop list contains null element");
85                 return;
86             }
87             LOG.debug("Created vrfEntry for {} nexthop {} label {}", prefix, nextHop, label);
88         }
89
90         LOG.debug("addFibEntryToDS rd {} prefix {} NH {}",
91                 rd, prefix, nextHopList.get(0));
92
93         ArrayList<String> temp = new ArrayList<String>();
94         if ((fibMap.get(appendrdtoprefix(rd, prefix)) != null)) {
95             temp.addAll(fibMap.get(appendrdtoprefix(rd, prefix)));
96         }
97         if (!temp.contains(nextHopList.get(0))) {
98             temp.addAll(nextHopList);
99             fibMap.put(appendrdtoprefix(rd, prefix), temp);
100         }
101
102         // Looking for existing prefix in MDSAL database
103         InstanceIdentifier<VrfEntry> vrfEntryId =
104                 InstanceIdentifier.builder(FibEntries.class)
105                         .child(VrfTables.class, new VrfTablesKey(rd))
106                         .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
107
108         VrfEntryBuilder vrfEntryBuilder = new VrfEntryBuilder().setDestPrefix(prefix).setOrigin(origin.getValue());
109         buildVpnEncapSpecificInfo(vrfEntryBuilder, encapType, label, l3vni,
110                 gatewayMacAddress, nextHopList);
111         bgpUtil.update(vrfEntryId, vrfEntryBuilder.build());
112     }
113
114     private String appendrdtoprefix(String rd, String prefix) {
115         return rd + "/" + prefix;
116     }
117
118     public void addMacEntryToDS(String rd, String macAddress, String prefix,
119                                 List<String> nextHopList, VrfEntry.EncapType encapType,
120                                 Uint32 l2vni, String gatewayMacAddress, RouteOrigin origin) {
121         if (StringUtils.isEmpty(rd)) {
122             LOG.error("Mac {} not associated with vpn", macAddress);
123             return;
124         }
125
126         Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
127         for (String nextHop : nextHopList) {
128             if (StringUtils.isEmpty(nextHop)) {
129                 LOG.error("nextHop list contains null element for macVrf");
130                 return;
131             }
132         }
133
134         MacVrfEntryBuilder macEntryBuilder = new MacVrfEntryBuilder().setOrigin(origin.getValue());
135         buildVpnEncapSpecificInfo(macEntryBuilder, encapType, l2vni,
136                 gatewayMacAddress, nextHopList);
137         macEntryBuilder.setMac(macAddress);
138         macEntryBuilder.setDestPrefix(prefix);
139         InstanceIdentifier<MacVrfEntry> macEntryId =
140                 InstanceIdentifier.builder(FibEntries.class)
141                         .child(VrfTables.class, new VrfTablesKey(rd))
142                         .child(MacVrfEntry.class, new MacVrfEntryKey(macAddress)).build();
143         bgpUtil.update(macEntryId, macEntryBuilder.build());
144     }
145
146     private static void buildVpnEncapSpecificInfo(VrfEntryBuilder builder,
147             VrfEntry.EncapType encapType, Uint32 label, Uint32 l3vni,
148             String gatewayMac, List<String> nextHopList) {
149         if (!encapType.equals(VrfEntry.EncapType.Mplsgre)) {
150             builder.setL3vni(l3vni);
151         }
152         builder.setEncapType(encapType);
153         builder.setGatewayMacAddress(gatewayMac);
154         Uint32 lbl = encapType.equals(VrfEntry.EncapType.Mplsgre) ? label : null;
155         List<RoutePaths> routePaths = nextHopList.stream()
156                         .filter(StringUtils::isNotEmpty)
157                         .map(nextHop -> FibHelper.buildRoutePath(nextHop, lbl)).collect(Collectors.toList());
158         builder.setRoutePaths(routePaths);
159     }
160
161     private static void buildVpnEncapSpecificInfo(MacVrfEntryBuilder builder,
162                                                   VrfEntry.EncapType encapType, Uint32 l2vni,
163                                                   String gatewayMac, List<String> nextHopList) {
164         builder.setEncapType(encapType);
165         builder.setGatewayMacAddress(gatewayMac);
166         builder.setL2vni(l2vni);
167         List<RoutePaths> routePaths = nextHopList.stream()
168                 .filter(StringUtils::isNotEmpty)
169                 .map(nextHop -> FibHelper.buildRoutePath(nextHop, null)).collect(Collectors.toList());
170         builder.setRoutePaths(routePaths);
171     }
172
173     public synchronized void removeFibEntryFromDS(String rd, String prefix) {
174
175         if (rd == null || rd.isEmpty()) {
176             LOG.error("Prefix {} not associated with vpn", prefix);
177             return;
178         }
179         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
180
181         InstanceIdentifierBuilder<VrfEntry> idBuilder =
182                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).child(
183                         VrfEntry.class, new VrfEntryKey(prefix));
184         InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
185         bgpUtil.delete(vrfEntryId);
186
187     }
188
189     public void removeMacEntryFromDS(String rd, String macAddress) {
190
191         if (StringUtils.isEmpty(rd)) {
192             LOG.error("Mac {} not associated with vpn", macAddress);
193             return;
194         }
195         LOG.debug("Removing Mac fib entry with Mac {} from vrf table for rd {}", macAddress, rd);
196
197         InstanceIdentifierBuilder<MacVrfEntry> idBuilder =
198                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).child(
199                         MacVrfEntry.class, new MacVrfEntryKey(macAddress));
200         InstanceIdentifier<MacVrfEntry> macEntryId = idBuilder.build();
201         bgpUtil.delete(macEntryId);
202
203     }
204
205     public synchronized void removeOrUpdateFibEntryFromDS(String rd, String prefix, String nextHop) {
206
207         if (rd == null || rd.isEmpty()) {
208             LOG.error("Prefix {} not associated with vpn", prefix);
209             return;
210         }
211         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {} and nextHop {}",
212                 prefix, rd, nextHop);
213
214
215         InstanceIdentifier<VrfEntry> vrfEntryId =
216                 InstanceIdentifier.builder(FibEntries.class)
217                         .child(VrfTables.class, new VrfTablesKey(rd))
218                         .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
219
220         LOG.debug("removeOrUpdateFibEntryFromDS rd {} prefix {} NH {}",
221                 rd, prefix, nextHop);
222
223         if (fibMap.get(appendrdtoprefix(rd,prefix)) != null) { //Key is there
224             // If nexthop is there, delete it from List
225             List<String> list = fibMap.get(appendrdtoprefix(rd,prefix));
226             list.remove(nextHop);
227             if (list.isEmpty()) {
228                 fibMap.remove(appendrdtoprefix(rd, prefix));
229                 bgpUtil.delete(vrfEntryId);
230             } else {
231                 InstanceIdentifier<RoutePaths> routePathId =
232                         FibHelper.buildRoutePathId(rd, prefix, nextHop);
233                 bgpUtil.delete(routePathId);
234             }
235         } else {
236             LOG.error("Invalid Delete from Quagga, RD {} Prefix {} Nexthop {}  ",
237                     rd,prefix,nextHop);
238         }
239     }
240
241
242     public synchronized void removeVrfSubFamilyFromDS(String rd, AddressFamily addressFamily) {
243
244         if (rd == null) {
245             return;
246         }
247         LOG.debug("removeVrfSubFamilyFromDS : addressFamily {} from vrf rd {}",
248                   addressFamily, rd);
249
250         InstanceIdentifier<VrfTables> id = InstanceIdentifier.create(FibEntries.class)
251             .child(VrfTables.class, new VrfTablesKey(rd));
252         try {
253             VrfTables vrfTable = singleTxDB.syncRead(LogicalDatastoreType.CONFIGURATION, id);
254             if (vrfTable != null) {
255                 List<VrfEntry> vrfEntries = vrfTable.getVrfEntry();
256                 if (vrfEntries == null) {
257                     LOG.error("removeVrfSubFamilyFromDS : VrfEntry not found for rd {}", rd);
258                     return;
259                 }
260                 for (VrfEntry vrfEntry : vrfEntries) {
261                     boolean found = false;
262                     if (vrfEntry.getEncapType() != null) {
263                         if (!vrfEntry.getEncapType().equals(EncapType.Mplsgre)
264                              && addressFamily == AddressFamily.L2VPN) {
265                             found = true;
266                         } else if (vrfEntry.getEncapType().equals(EncapType.Mplsgre)) {
267                             if (addressFamily == AddressFamily.IPV4
268                                 && FibHelper.isIpv4Prefix(vrfEntry.getDestPrefix())) {
269                                 found = true;
270                             } else if (addressFamily == AddressFamily.IPV6
271                                        && FibHelper.isIpv6Prefix(vrfEntry.getDestPrefix())) {
272                                 found = true;
273                             }
274                         }
275                     }
276                     if (found == false) {
277                         continue;
278                     }
279                     bgpUtil.removeVrfEntry(rd, vrfEntry);
280                 }
281             }
282         } catch (ReadFailedException rfe) {
283             LOG.error("removeVrfSubFamilyFromDS : Internal Error rd {}", rd, rfe);
284         }
285         return;
286     }
287
288     public synchronized void removeVrfFromDS(String rd) {
289         LOG.debug("Removing vrf table for  rd {}", rd);
290
291         InstanceIdentifierBuilder<VrfTables> idBuilder =
292                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
293         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
294
295         bgpUtil.delete(vrfTableId);
296
297     }
298 }