BgpManager commit for:
[vpnservice.git] / bgpmanager / bgpmanager-impl / src / main / java / org / opendaylight / bgpmanager / BgpManager.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.bgpmanager;
9
10
11 import java.net.SocketTimeoutException;
12 import java.util.*;
13 import java.util.concurrent.ConcurrentMap;
14 import java.util.concurrent.CountDownLatch;
15
16 import org.apache.thrift.TException;
17 import org.opendaylight.bgpmanager.thrift.client.globals.Route;
18 import org.opendaylight.bgpmanager.thrift.client.implementation.BgpRouter;
19 import org.opendaylight.bgpmanager.thrift.server.implementation.BgpThriftService;
20 import org.opendaylight.bgpmanager.thrift.exceptions.BgpRouterException;
21 import org.opendaylight.bgpmanager.api.IBgpManager;
22 import org.opendaylight.bgpmanager.globals.BgpConfiguration;
23 import org.opendaylight.bgpmanager.globals.BgpConstants;
24
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
27 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
28 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
29
30 import org.osgi.framework.Bundle;
31 import org.osgi.framework.BundleContext;
32 import org.osgi.framework.FrameworkUtil;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 public class BgpManager implements BindingAwareProvider, AutoCloseable, IBgpManager {
37
38     private static final Logger s_logger = LoggerFactory.getLogger(BgpManager.class);
39     private BgpConfigurationManager bgpConfigurationMgr;
40     private FibDSWriter fibDSWriter;
41     private BgpConfiguration    bgpConfiguration = new BgpConfiguration();
42     private BgpRouter           bgpThriftClient;
43     private BgpThriftService    bgpThriftService;
44     private boolean             isBgpInitialized = false;
45     private boolean             hasBgpServiceStarted = false;
46     private String                              bgpHost;
47     private int                                 bgpPort;
48
49
50     private String getCustomConfig(String var, String def) {
51         Bundle b = FrameworkUtil.getBundle(this.getClass());
52         BundleContext context = null;
53         if (b != null) {
54             context = b.getBundleContext();
55         }
56         if (context != null)
57             return context.getProperty(var);
58         else
59             return def;
60
61     }
62
63     private void initializeBGPCommunication() {
64         //start our side of thrift server
65         bgpThriftService = new BgpThriftService(this, fibDSWriter);
66         bgpThriftService.start();
67
68         //start bgp thrift client connection
69         bgpThriftClient = new BgpRouter();
70
71         bgpHost = getCustomConfig(BgpConstants.BGP_SPEAKER_HOST_NAME, BgpConstants.DEFAULT_BGP_HOST_NAME);
72         bgpPort = BgpConstants.DEFAULT_BGP_THRIFT_PORT;
73
74         configureBgpServer(bgpHost, bgpPort);
75         try {
76             connectToServer(bgpHost, bgpPort);
77         } catch (Exception e) {
78             return;
79         }
80
81         isBgpInitialized = true;
82         //notify();       //notify all threads waiting for bgp init
83
84     }
85
86     public synchronized void waitForBgpInit() {
87         if(!isBgpInitialized) {
88             try {
89                 wait();
90             } catch (InterruptedException e) {
91                 s_logger.error("InterruptedException while waiting for Bgp connection to initialize");
92                 return;
93             }
94         }
95     }
96
97     public void startBgpService() throws TException {
98         if(bgpThriftClient == null) {
99             s_logger.info("Start Bgp Service - bgpThriftClient is null. Unable to start BGP service.");
100             return;
101         }
102
103         // Now try start bgp - if bgp is already Active, it will tell us, nothing to do then
104         try {
105             bgpThriftClient.startBgp((int)bgpConfiguration.getAsNum(), bgpConfiguration.getRouterId());
106             s_logger.info("Started BGP with AS number " + (int)bgpConfiguration.getAsNum() + " and router id " + bgpConfiguration.getRouterId());
107         } catch (BgpRouterException be) {
108             if(be.getErrorCode() == BgpRouterException.BGP_ERR_ACTIVE) {
109                 s_logger.info("bgp server already active");
110                 return;
111             }
112             else if(be.getErrorCode() == BgpRouterException.BGP_ERR_NOT_INITED) {
113                 s_logger.error("bgp server connection not initialized.");
114                 reInitConn();
115                 return;
116             }
117             else {
118                 s_logger.error("application error while starting bgp server " + be.getErrorCode());
119                 return;
120             }
121
122         }  catch (TException t) {
123             //s_logger.error("Transport error while starting bgp server ", t);
124             s_logger.error("Could not set up thrift connection with bgp server");
125             reInitConn();
126             throw t;
127         } catch (Exception e) {
128             s_logger.error("Error while starting bgp server", e);
129             return;
130         }
131
132         hasBgpServiceStarted = true;
133
134     }
135
136     @Override
137     public void onSessionInitiated(ProviderContext session) {
138         s_logger.info("BgpManager Session Initiated");
139         try {
140             final DataBroker dataBroker = session.getSALService(DataBroker.class);
141             bgpConfigurationMgr = new BgpConfigurationManager(dataBroker, bgpConfiguration, this);
142             fibDSWriter = new FibDSWriter(dataBroker);
143         } catch (Exception e) {
144             s_logger.error("Error initializing services", e);
145         }
146
147         initializeBGPCommunication();
148     }
149
150
151    @Override
152     public void close() throws Exception {
153         s_logger.info("BgpManager Closed");
154
155        //close the client and server ends of the thrift communication
156        if(bgpThriftClient != null)
157            bgpThriftClient.disconnect();
158        bgpThriftService.stop();
159
160
161    }
162
163     private void setBgpServerDetails() {
164         if(bgpThriftClient != null)
165             bgpThriftClient.setBgpServer(bgpHost, bgpPort);
166     }
167
168     private void configureBgpServer(String bgpServer, int bgpPort) {
169         bgpConfiguration.setBgpServer(bgpServer);
170         bgpConfiguration.setBgpPort(bgpPort);
171         setBgpServerDetails();
172     }
173
174     protected void addNeighbor(String ipAddress, long asNum) throws TException {
175         if(bgpThriftClient == null) {
176             s_logger.info("Add BGP Neighbor - bgpThriftClient is null. Unable to add BGP Neighbor.");
177             return;
178         }
179
180         try {
181             bgpThriftClient.addNeighbor(ipAddress, (int) asNum);
182         } catch (BgpRouterException b) {
183             s_logger.error("Failed to add BGP neighbor " + ipAddress + "due to BgpRouter Exception number " + b.getErrorCode());
184             s_logger.error("BgpRouterException trace ", b);
185         } catch (TException t) {
186             s_logger.error(String.format("Failed adding neighbor %s due to Transport error", ipAddress));
187             reInitConn();
188             throw t;
189         } catch (Exception e) {
190             s_logger.error(String.format("Failed adding neighbor %s", ipAddress));
191         }
192     }
193
194
195     protected void deleteNeighbor(String ipAddress) throws TException {
196         if(bgpThriftClient == null) {
197             s_logger.info("Delete BGP Neighbor - bgpThriftClient is null. Unable to delete BGP Neighbor.");
198             return;
199         }
200
201         try {
202             bgpThriftClient.delNeighbor(ipAddress);
203         } catch (BgpRouterException b) {
204             s_logger.error("Failed to delete BGP neighbor " + ipAddress + "due to BgpRouter Exception number " + b.getErrorCode());
205             s_logger.error("BgpRouterException trace ", b);
206         }catch (TException t) {
207             s_logger.error(String.format("Failed deleting neighbor %s due to Transport error", ipAddress));
208             reInitConn();
209             throw t;
210         } catch (Exception e) {
211             s_logger.error(String.format("Failed deleting neighbor %s", ipAddress));
212         }
213     }
214
215
216     @Override
217     public void addVrf(String rd, Collection<String> importRts, Collection<String> exportRts) throws Exception {
218         if(bgpThriftClient == null) {
219             s_logger.info("Add BGP vrf - bgpThriftClient is null. Unable to add BGP vrf.");
220             return;
221         }
222         try {
223             bgpThriftClient.addVrf(rd, new ArrayList<>(importRts), new ArrayList<>(exportRts));
224         } catch (BgpRouterException b) {
225             s_logger.error("Failed to add BGP vrf " + rd + "due to BgpRouter Exception number " + b.getErrorCode());
226             s_logger.error("BgpRouterException trace ", b);
227             throw b;
228         } catch (TException t) {
229             s_logger.error(String.format("Failed adding vrf %s due to Transport error", rd));
230             reInitConn();
231             throw t;
232         } catch (Exception e) {
233             s_logger.error(String.format("Failed adding vrf %s", rd));
234             throw e;
235         }
236     }
237
238     @Override
239     public void deleteVrf(String rd) throws Exception {
240         if(bgpThriftClient == null) {
241             s_logger.info("Delete BGP vrf - bgpThriftClient is null. Unable to delete BGP vrf.");
242             return;
243         }
244         try {
245             bgpThriftClient.delVrf(rd);
246         } catch (BgpRouterException b) {
247             s_logger.error("Failed to delete BGP vrf " + rd + "due to BgpRouter Exception number " + b.getErrorCode());
248             s_logger.error("BgpRouterException trace ", b);
249             throw b;
250         } catch (TException t) {
251             s_logger.error(String.format("Failed deleting vrf %s due to Transport error", rd));
252             reInitConn();
253             throw t;
254         } catch (Exception e) {
255             s_logger.error(String.format("Failed deleting vrf %s", rd));
256             throw e;
257         }
258     }
259
260     @Override
261     public void addPrefix(String rd, String prefix, String nextHop, int vpnLabel) throws Exception {
262         if(bgpThriftClient == null) {
263             s_logger.info("Add BGP prefix - bgpThriftClient is null. Unable to add BGP prefix.");
264             return;
265         }
266         if(!hasBgpServiceStarted) {
267             fibDSWriter.addFibEntryToDS(rd, prefix, nextHop, vpnLabel);
268         }
269         try {
270             bgpThriftClient.addPrefix(rd, prefix, nextHop, vpnLabel);
271         } catch (BgpRouterException b) {
272             s_logger.error("Failed to add BGP prefix " + prefix + "due to BgpRouter Exception number " + b.getErrorCode());
273             s_logger.error("BgpRouterException trace ", b);
274             throw b;
275         } catch (TException t) {
276             s_logger.error(String.format("Failed adding prefix entry <vrf:prefix:nexthop:vpnlabel> %s:%s:%s:%d due to Transport error",
277                 rd, prefix, nextHop, vpnLabel));
278             reInitConn();
279             throw t;
280         } catch (Exception e) {
281             s_logger.error(String.format("Failed adding prefix entry <vrf:prefix:nexthop:vpnlabel> %s:%s:%s:%d",
282                 rd, prefix, nextHop, vpnLabel));
283             throw e;
284         }
285     }
286
287
288     @Override
289     public void deletePrefix(String rd, String prefix) throws Exception {
290         if(bgpThriftClient == null) {
291             s_logger.info("Delete BGP prefix - bgpThriftClient is null. Unable to delete BGP prefix.");
292             return;
293         }
294         if(!hasBgpServiceStarted) {
295             fibDSWriter.removeFibEntryFromDS(rd, prefix);
296         }
297         try {
298             bgpThriftClient.delPrefix(rd, prefix);
299         } catch (BgpRouterException b) {
300             s_logger.error("Failed to delete BGP prefix " + prefix + "due to BgpRouter Exception number " + b.getErrorCode());
301             s_logger.error("BgpRouterException trace ", b);
302             throw b;
303         } catch (TException t) {
304             s_logger.error(String.format("Failed deleting prefix entry <vrf:prefix> %s:%s due to Transport error",
305                 rd, prefix));
306             reInitConn();
307             throw t;
308         } catch (Exception e) {
309             s_logger.error(String.format("Failed deleting prefix entry <vrf:prefix> %s:%s",
310                 rd, prefix));
311             throw e;
312         }
313     }
314
315     private void connectToServer(String host, int port) throws Exception {
316
317         bgpHost = host;
318         bgpPort = port;
319
320         if(bgpThriftClient == null) {
321             s_logger.error("Failed to connect to BGP server since Bgp Thrift Client is not initialized yet.");
322             return;
323         }
324         try {
325             bgpThriftClient.connect(host, port);
326             s_logger.info("Connected to BGP server " + host + " on port " + port);
327         } catch (BgpRouterException b) {
328             s_logger.error("Failed to connect to BGP server " + host + " on port " + port + " due to BgpRouter Exception number " + b.getErrorCode());
329             s_logger.error("BgpRouterException trace ", b);
330             throw b;
331         } catch (TException t) {
332             s_logger.error("Failed to initialize BGP Connection due to Transport error ", t);
333             throw t;
334         }
335         catch (Exception e) {
336             s_logger.error("Failed to initialize BGP Connection ", e);
337             throw e;
338         }
339     }
340
341     public void configureBgp(long asNum, String routerId) {
342         try {
343             bgpConfiguration.setAsNum(asNum);
344             bgpConfiguration.setRouterId(routerId);
345         } catch(Throwable e) {
346             s_logger.error("failed configuring bgp ",e);
347         }
348     }
349
350     public synchronized void reInitConn() {
351
352         try {
353             bgpThriftClient.reInit();
354             s_logger.info("Reinitialized connection to BGP Server " + bgpHost);
355         } catch (BgpRouterException b) {
356             s_logger.error("Failed to reinitialize connection to BGP server " + bgpHost + " on port " + bgpPort + " due to BgpRouter Exception number " + b.getErrorCode());
357             s_logger.error("BgpRouterException trace ", b);
358         } catch (TException t) {
359             s_logger.error("Failed to reinitialize BGP Connection due to Transport error.");
360         }
361         catch (Exception e) {
362             s_logger.error("Failed to reinitialize BGP Connection.", e);
363         }
364     }
365
366     /*public synchronized void startBgpSync() {
367         boolean getRoutes = true;
368         readBgpConfiguration();
369         try {
370             pushConfigurationToBgp();
371
372         } catch (BgpRouterException b) {
373             s_logger.error("Failed to push configuration to BGP due to BgpRouter Exception number " + b.getErrorCode());
374             s_logger.error("BgpRouterException trace ", b);
375             if(b.getErrorCode() == BgpRouterException.BGP_ERR_INACTIVE)
376                 getRoutes = false;
377         } catch (Exception e) {
378             s_logger.error("Failed to push configuration to bgp ", e);
379         }
380         if(getRoutes == true)
381             pullConfigurationFromBgp();
382         //controllerResyncLatch.countDown();
383     }*/
384
385     /*public void waitForControllerBgpResync() {
386         try {
387             controllerResyncLatch.await();
388         } catch (InterruptedException e) {
389         }
390     }*/
391
392     /*private void pullConfigurationFromBgp() {
393         //get routes from bgp server
394         s_logger.info("Starting bgp route sync");
395         try {
396             bgpThriftClient.doRouteSync();
397         } catch (BgpRouterException b) {
398             s_logger.error("Failed BGP Route sync due to BgpRouter Exception number " + b.getErrorCode());
399             s_logger.error("BgpRouterException trace ", b);
400         } catch (Exception e) {
401             s_logger.error("Failed to pull configuration from bgp ", e);
402         }
403     }*/
404
405     /*private BgpConfiguration readBgpConfiguration() {
406         if (cache != null) {
407             bgpConfiguration = cache.get("bgpConfiguration");
408             if (bgpConfiguration == null) {
409                 s_logger.info("Created bgp configuration cache");
410                 bgpConfiguration = new BgpConfiguration();
411                 cache.put("bgpConfiguration", bgpConfiguration);
412             } else {
413                 s_logger.info("Using bgp configuration cache");
414             }
415         }
416         return bgpConfiguration;
417     }*/
418
419     /*public synchronized void pushConfigurationToBgp() throws Exception {
420         if (bgpConfiguration.getAsNum() == 0) {
421             s_logger.error("No as num configured, Skipping the push configuration to bgp ");
422             throw new BgpRouterException(BgpRouterException.BGP_ERR_INACTIVE);
423             //return;
424         }
425         if(bgpThriftClient == null) {
426             s_logger.error("bgpThriftClient is null. Skipping the push configuration to bgp.");
427             throw new BgpRouterException(BgpRouterException.BGP_ERR_INACTIVE);
428             //return;
429         }
430
431         try {
432             bgpThriftClient.startBgp((int)bgpConfiguration.getAsNum(), bgpConfiguration.getRouterId());
433             s_logger.info("Started BGP with AS number " + (int)bgpConfiguration.getAsNum() + " and router id " + bgpConfiguration.getRouterId());
434         } catch (BgpRouterException be) {
435             if(be.getErrorCode() == BgpRouterException.BGP_ERR_ACTIVE) {
436                 s_logger.info("bgp server already active");
437                 return;         //the assumption here is that bgp server is configured already with neighbor, vrfs and routes as well
438             } if(be.getErrorCode() == BgpRouterException.BGP_ERR_INACTIVE) {
439                 s_logger.info("bgp server inactive");
440                 throw be;
441             }
442
443             else {
444                 s_logger.error("application error while starting bgp server %d", be.getErrorCode());
445                 return;
446             }
447
448         } catch (SocketTimeoutException to) {
449             s_logger.error("Socket Timeout error while starting bgp server", to);
450             return;
451         } catch (TException t) {
452             s_logger.error("Transport error while starting bgp server ", t);
453             return;
454         } catch (Exception e) {
455             s_logger.error("Error while starting bgp server", e);
456         }
457
458         if (bgpConfiguration.getNeighbourIp().trim().length() > 0) {
459             try {
460                 bgpThriftClient.addNeighbor(bgpConfiguration.getNeighbourIp(), bgpConfiguration.getNeighbourAsNum());
461             } catch (TException t) {
462                 s_logger.error("Failed to push vrf to bgp due to Transport error" );
463                 //retry connection
464                 reInitConn();
465                 addNeighbor(bgpConfiguration.getNeighbourIp(), bgpConfiguration.getNeighbourAsNum());
466             } catch (Exception e) {
467                 s_logger.error("Error while starting bgp server", e);
468             }
469         }
470
471         Tenant tenant;
472         try {
473             tenant = tenantManager.getTenant("NEUTRON");
474         } catch (TenantNotFoundException e) {
475             s_logger.error("Tenant not found. Skipping push configuration to bgp.");
476             return;
477         }
478         if (tenant != null) {
479             int tenantId = tenant.getTenantId();
480
481             Set<VpnInstanceInfo> vpnInfos = l3Manager.getVpnInstanceManager().getVpnsForTenant(tenantId);
482             s_logger.info("Number of vpns to configure is "+vpnInfos.size());
483             for (VpnInstanceInfo vpnInfo: vpnInfos) {
484                 try {
485                     bgpThriftClient.addVrf(vpnInfo.getRouteDistinguisher(),
486                         new ArrayList<>(vpnInfo.getRtImportList()),
487                         new ArrayList<>(vpnInfo.getRtExportList()));
488                 } catch (TException t) {
489                     s_logger.error("Failed to push vrf to bgp due to Transport error" );
490                     //retry connection
491                     reInitConn();
492                     addVrf(vpnInfo.getRouteDistinguisher(), new ArrayList<>(vpnInfo.getRtImportList()),
493                         new ArrayList<>(vpnInfo.getRtExportList()));
494                 } catch (Exception e) {
495                     s_logger.error("Failed to push vrf to bgp ", e);
496                 }
497             }
498             for (VpnInstanceInfo vpnInfo: vpnInfos) {
499                 ConcurrentMap<FibInfo, Object>  fibInfos = l3Manager.getVpnInstanceManager().
500                     getLocalFibInfosForRdCache(vpnInfo.getRouteDistinguisher());
501                 s_logger.info("Number of fib infos to configure is "+fibInfos.size());
502                 for (FibInfo fibInfo : fibInfos.keySet()) {
503                     try {
504                         bgpThriftClient.addPrefix(vpnInfo.getRouteDistinguisher(), fibInfo.getDestinationPrefix(),
505                             fibInfo.getNextHopPrefix(), (int) fibInfo.getLabel());
506                     } catch (TException t) {
507                         s_logger.error("Failed to push route to bgp due to Transport error" );
508                         reInitConn();
509                         addPrefix(vpnInfo.getRouteDistinguisher(), fibInfo.getDestinationPrefix(),
510                             fibInfo.getNextHopPrefix(), (int) fibInfo.getLabel());
511                     } catch (Exception e) {
512                         s_logger.error("Failed to push route to bgp ", e);
513                     }
514                 }
515             }
516         }
517
518     }
519     */
520
521     public void disconnect() {
522         bgpThriftClient.disconnect();
523     }
524 /*
525     public void setRoute(Route r) {
526         s_logger.info("Setting route in VPN Manager");
527         //l3Manager.getVpnInstanceManager().addRoute(r.getRd(), r.getPrefix(), r.getNexthop(), r.getLabel());
528     }*/
529
530     /* For testing purposes */
531     /*public String ribGet() {
532         String family = "ipv4";
533         String format = "json";
534
535         try {
536             List<Route> routeList = bgpThriftClient.getRoutes();
537             Iterator<Route> iter = routeList.iterator();
538             while(iter.hasNext()) {
539                 Route r = iter.next();
540                 System.out.println("Route:: vrf:" + r.getRd() + " Prefix: " + r.getPrefix() + " Nexthop: " + r.getNexthop() + "Label: " + r.getLabel());
541             }
542         } catch (Exception e) {
543             s_logger.error("Failed getting bgp routes ", e);
544         }
545         return null;
546     }*/
547
548
549 }