7d47d0150ba5e7d248cadd25d417ae53077cadb4
[netvirt.git] /
1 /*
2  * Copyright (c) 2016, 2017 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
9 package org.opendaylight.netvirt.bgpmanager.thrift.client;
10
11 import java.util.List;
12 import javax.annotation.Nullable;
13 import org.apache.thrift.TException;
14 import org.apache.thrift.protocol.TBinaryProtocol;
15 import org.apache.thrift.protocol.TProtocol;
16 import org.apache.thrift.transport.TSocket;
17 import org.apache.thrift.transport.TTransport;
18 import org.apache.thrift.transport.TTransportException;
19 import org.opendaylight.netvirt.bgpmanager.thrift.gen.BgpConfigurator;
20 import org.opendaylight.netvirt.bgpmanager.thrift.gen.Routes;
21 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_afi;
22 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_safi;
23 import org.opendaylight.netvirt.bgpmanager.thrift.gen.encap_type;
24 import org.opendaylight.netvirt.bgpmanager.thrift.gen.layer_type;
25 import org.opendaylight.netvirt.bgpmanager.thrift.gen.protocol_type;
26 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.LayerType;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 public class BgpRouter {
31     private static TTransport transport;
32     private static TProtocol protocol;
33     private static BgpConfigurator.Client bgpClient = null;
34     boolean isConnected = false;
35     private static final Logger LOGGER = LoggerFactory.getLogger(BgpRouter.class);
36     public int startBGPresult = Integer.MIN_VALUE;
37     public String bgpHost = null;
38     public int bgpHostPort = 0;
39     private long startTS = 0;
40     private long connectTS = 0;
41     private long lastConnectedTS = 0;
42
43     public long getLastConnectedTS() {
44         return lastConnectedTS;
45     }
46
47     public void setLastConnectedTS(long lastConnectedTS) {
48         this.lastConnectedTS = lastConnectedTS;
49     }
50
51     public long getConnectTS() {
52         return connectTS;
53     }
54
55     public void setConnectTS(long connectTS) {
56         this.connectTS = connectTS;
57     }
58
59     public long getStartTS() {
60         return startTS;
61     }
62
63     public void setStartTS(long startTS) {
64         this.startTS = startTS;
65     }
66
67
68     private enum Optype {
69         START, STOP, NBR, VRF, PFX, SRC, MHOP, LOG, AF, GR, MP, VRFMP
70     }
71
72     private static final int GET_RTS_INIT = 0;
73     private static final int GET_RTS_NEXT = 1;
74     private static final int CONNECTION_TIMEOUT = 60000;
75
76
77     private class BgpOp {
78
79         public Optype type;
80         public boolean add;
81         public String[] strs;
82         public int[] ints;
83         public List<String> irts;
84         public List<String> erts;
85         public long asNumber;
86         static final int IGNORE = 0;
87         public layer_type thriftLayerType;
88         public protocol_type thriftProtocolType;
89         public int ethernetTag;
90         public String esi;
91         public String macAddress;
92         public int l2label;
93         public int l3label;
94         public encap_type thriftEncapType;
95         public String routermac;
96         public af_afi afi;
97
98         BgpOp() {
99             strs = new String[3];
100             ints = new int[2];
101         }
102     }
103
104     private static BgpOp bop;
105
106     public synchronized void disconnect() {
107         bgpClient = null;
108         isConnected = false;
109         if (transport != null) {
110             transport.close();
111         }
112     }
113
114     public synchronized boolean connect(String bgpHost, int bgpPort) {
115         String msgPiece = "BGP config server at " + bgpHost + ":" + bgpPort;
116
117         this.bgpHost = bgpHost;
118         this.bgpHostPort = bgpPort;
119
120         disconnect();
121         setConnectTS(System.currentTimeMillis());
122         try {
123             TSocket ts = new TSocket(bgpHost, bgpPort, CONNECTION_TIMEOUT);
124             transport = ts;
125             transport.open();
126             ts.setTimeout(0);
127             isConnected = true;
128             setLastConnectedTS(System.currentTimeMillis());
129         } catch (TTransportException tte) {
130             LOGGER.error("Failed connecting to " + msgPiece + "; Exception: " + tte);
131             isConnected = false;
132             return false;
133         }
134         protocol = new TBinaryProtocol(transport);
135         bgpClient = new BgpConfigurator.Client(protocol);
136         LOGGER.info("Connected to " + msgPiece);
137         return true;
138     }
139
140     public boolean isBgpConnected() {
141         return isConnected;
142     }
143
144     private BgpRouter() {
145         bop = new BgpOp();
146     }
147
148     private BgpRouter(BgpConfigurator.Client bgpClient) { // FOR UNIT TESTS ONLY
149         this.bgpClient = bgpClient;
150         this.bop = new BgpOp();
151     } // private ctor FOR UNIT TESTS ONLY
152
153     static BgpRouter makeTestingRouter(BgpConfigurator.Client bgpClient) { // FOR UNIT TESTS ONLY
154         return new BgpRouter(bgpClient);
155     } // static factory makeTestingRouter
156
157     private static BgpRouter br = null;
158
159     public static synchronized BgpRouter getInstance() {
160         return (br == null ? br = new BgpRouter() : br);
161     }
162
163     private void dispatch(BgpOp op) throws TException, BgpRouterException {
164         int result = 1;
165
166         if (bgpClient == null) {
167             throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED);
168         }
169
170         af_afi afi = af_afi.findByValue(op.ints[0]);
171         af_safi safi = af_safi.findByValue(op.ints[1]);
172
173         switch (op.type) {
174             case START:
175                 setStartTS(System.currentTimeMillis());
176                 LOGGER.debug("startBgp thrift call for AsId {}", op.asNumber);
177                 result = bgpClient.startBgp(op.asNumber, op.strs[0],
178                         BgpOp.IGNORE, BgpOp.IGNORE, BgpOp.IGNORE, op.ints[0], op.add);
179                 LOGGER.debug("Result of startBgp thrift call for AsId {} : {}", op.asNumber, result);
180                 startBGPresult = result;
181                 break;
182             case STOP:
183                 result = bgpClient.stopBgp(op.asNumber);
184                 break;
185             case NBR:
186                 if (bop.add) {
187                     result = bgpClient.createPeer(op.strs[0], op.asNumber);
188                     if (result == 0 && op.strs[1] != null) { // createPeer worked and password is specified
189                         result = bgpClient.setPeerSecret(op.strs[0], op.strs[1]);
190                         if (result != 0) {
191                             throw new BgpRouterException(BgpRouterException.Function.SET_PEER_SECRET, result);
192                         }
193                     }
194                 } else { // delete
195                     result = bgpClient.deletePeer(op.strs[0]);
196                 }
197                 break;
198             case VRF:
199                 result = bop.add
200                         ? bgpClient.addVrf(op.thriftLayerType, op.strs[0], op.irts, op.erts)
201                         : bgpClient.delVrf(op.strs[0]);
202                 break;
203             case PFX:
204                 // order of args is different in addPrefix(), hence the
205                 // seeming out-of-order-ness of string indices
206                 afi = af_afi.findByValue(org.opendaylight.netvirt.bgpmanager.BgpUtil
207                         .getAFItranslatedfromPrefix(op.strs[1]));
208                 result = bop.add
209                         ? bgpClient.pushRoute(
210                                 op.thriftProtocolType,
211                                 op.strs[1],//prefix
212                                 op.strs[2],//nexthop
213                                 op.strs[0],//rd
214                                 op.ethernetTag,
215                                 op.esi,
216                                 op.macAddress,
217                                 op.l3label,
218                                 op.l2label,
219                                 op.thriftEncapType,
220                                 op.routermac,
221                                 op.afi)
222
223                         : bgpClient.withdrawRoute(
224                         op.thriftProtocolType,
225                         op.strs[1],//prefix
226                         op.strs[0],//rd
227                         op.ethernetTag,
228                         op.esi,
229                         op.macAddress,
230                         op.afi);
231                 break;
232             case LOG:
233                 result = bgpClient.setLogConfig(op.strs[0], op.strs[1]);
234                 break;
235             case MHOP:
236                 result = bop.add
237                         ? bgpClient.setEbgpMultihop(op.strs[0], op.ints[0])
238                         : bgpClient.unsetEbgpMultihop(op.strs[0]);
239                 break;
240             case SRC:
241                 result = bop.add
242                         ? bgpClient.setUpdateSource(op.strs[0], op.strs[1])
243                         : bgpClient.unsetUpdateSource(op.strs[0]);
244                 break;
245             case AF:
246                 result = bop.add
247                         ? bgpClient.enableAddressFamily(op.strs[0], afi, safi)
248                         : bgpClient.disableAddressFamily(op.strs[0], afi, safi);
249                 break;
250             case GR:
251                 result = bop.add
252                         ? bgpClient.enableGracefulRestart(op.ints[0])
253                         : bgpClient.disableGracefulRestart();
254                 break;
255             case MP:
256                 result = bop.add
257                         ? bgpClient.enableMultipath(afi, safi)
258                         : bgpClient.disableMultipath(afi, safi);
259                 break;
260             case VRFMP:
261                 result = bgpClient.multipaths(bop.strs[0], bop.ints[0]);
262                 break;
263             default:
264                 break;
265         }
266         if (result != 0) {
267             throw new BgpRouterException(result);
268         }
269     }
270
271     public synchronized void startBgp(long asNum, String rtrId, int stalepathTime, boolean announceFbit)
272             throws TException, BgpRouterException {
273         bop.type = Optype.START;
274         bop.add = announceFbit;
275         bop.asNumber = asNum;
276         bop.ints[0] = stalepathTime;
277         bop.strs[0] = rtrId;
278         LOGGER.debug("Starting BGP with as number {} and router ID {} StalePathTime: {}", asNum, rtrId, stalepathTime);
279         dispatch(bop);
280     }
281
282     public synchronized void stopBgp(long asNum)
283             throws TException, BgpRouterException {
284         bop.type = Optype.STOP;
285         bop.asNumber = asNum;
286         LOGGER.debug("Stopping BGP with as number {}", asNum);
287         dispatch(bop);
288     }
289
290     public synchronized void addNeighbor(String nbrIp, long nbrAsNum, @Nullable String md5Secret)
291             throws TException, BgpRouterException {
292         if (md5Secret == null) {
293             LOGGER.debug("Adding BGP Neighbor {} with as number {} ", nbrIp, nbrAsNum);
294         } else {
295             LOGGER.debug("Adding BGP Neighbor {} with as number {} and MD5 secret {}", nbrIp, nbrAsNum, md5Secret);
296         }
297         bop.type = Optype.NBR;
298         bop.add = true;
299         bop.strs[0] = nbrIp;
300         bop.asNumber = nbrAsNum;
301         bop.strs[1] = md5Secret;
302         dispatch(bop);
303     } // public addNeighbor( nbrIp, nbrAsNum, md5Secret )
304
305     public synchronized void delNeighbor(String nbrIp) throws TException, BgpRouterException {
306         bop.type = Optype.NBR;
307         bop.add = false;
308         bop.strs[0] = nbrIp;
309         LOGGER.debug("Deleting BGP Neighbor {} ", nbrIp);
310         dispatch(bop);
311     }
312
313     public synchronized void addVrf(LayerType layerType, String rd, List<String> irts, List<String> erts)
314             throws TException, BgpRouterException {
315         bop.thriftLayerType = layerType == LayerType.LAYER2 ? layer_type.LAYER_2 : layer_type.LAYER_3;
316         bop.type = Optype.VRF;
317         bop.add = true;
318         bop.strs[0] = rd;
319         bop.irts = irts;
320         bop.erts = erts;
321         LOGGER.debug("Adding BGP VRF rd: {} ", rd);
322         dispatch(bop);
323     }
324
325     public synchronized void delVrf(String rd) throws TException, BgpRouterException {
326         bop.type = Optype.VRF;
327         bop.add = false;
328         bop.strs[0] = rd;
329         LOGGER.debug("Deleting BGP VRF rd: {} " + rd);
330         dispatch(bop);
331     }
332
333     // bit of a mess-up: the order of arguments is different in
334     // the Thrift RPC: prefix-nexthop-rd-label.
335
336     public synchronized void addPrefix(String rd,
337                                        String prefix,
338                                        String nexthop,
339                                        int label,
340                                        int l3vni,
341                                        protocol_type protocolType,
342                                        int ethtag,
343                                        String esi,
344                                        String macaddress,
345                                        encap_type encapType,
346                                        String routermac)
347             throws TException, BgpRouterException {
348         bop.type = Optype.PFX;
349         bop.add = true;
350         bop.strs[0] = rd;
351         bop.strs[1] = prefix;
352         bop.strs[2] = nexthop;
353         // TODO: set label2 or label3 based on encapsulation type and protocol type once L2label is applicable
354         bop.ints[0] = label;
355         if (protocolType.equals(protocol_type.PROTOCOL_EVPN) && encapType.equals(encap_type.VXLAN)) {
356             bop.l3label = l3vni; //L3VPN Over VxLan
357         } else {
358             bop.l3label = label; // L3VPN Over MPLSGRE
359         }
360         bop.thriftProtocolType = protocolType;
361         bop.ethernetTag = ethtag;
362         bop.esi = esi;
363         bop.macAddress = macaddress;
364         bop.thriftEncapType = encapType;
365         bop.routermac = routermac;
366
367         LOGGER.debug("Adding BGP route - rd:{} prefix:{} nexthop:{} label:{} ", rd ,prefix, nexthop, label);
368         dispatch(bop);
369     }
370
371     public synchronized void delPrefix(String rd, String prefix) throws TException, BgpRouterException {
372         bop.type = Optype.PFX;
373         bop.add = false;
374         bop.strs[0] = rd;
375         bop.strs[1] = prefix;
376         LOGGER.debug("Deleting BGP route - rd:{} prefix:{} ", rd, prefix);
377         dispatch(bop);
378     }
379
380     public int initRibSync(BgpSyncHandle handle) throws TException, BgpRouterException {
381         if (bgpClient == null) {
382             throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED);
383         }
384         if (handle.getState() == BgpSyncHandle.ITERATING) {
385             return BgpRouterException.BGP_ERR_IN_ITER;
386         }
387         handle.setState(BgpSyncHandle.INITED);
388         handle.setMore(1);
389         return 0;
390     }
391
392     public int endRibSync(BgpSyncHandle handle) throws TException, BgpRouterException {
393         if (bgpClient == null) {
394             throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED);
395         }
396         int state = handle.getState();
397         switch (state) {
398             case BgpSyncHandle.INITED:
399             case BgpSyncHandle.ITERATING:
400                 handle.setState(BgpSyncHandle.ABORTED);
401                 break;
402             case BgpSyncHandle.DONE:
403                 break;
404             case BgpSyncHandle.NEVER_DONE:
405                 return BgpRouterException.BGP_ERR_NOT_ITER;
406             default:
407                 break;
408         }
409         return 0;
410     }
411
412     public Routes doRibSync(BgpSyncHandle handle, af_afi afi) throws TException, BgpRouterException {
413         if (bgpClient == null) {
414             throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED);
415         }
416         int state = handle.getState();
417         if (state != BgpSyncHandle.INITED && state != BgpSyncHandle.ITERATING) {
418             Routes routes = new Routes();
419             routes.setErrcode(BgpRouterException.BGP_ERR_NOT_ITER);
420             return routes;
421         }
422         int op = (state == BgpSyncHandle.INITED) ? GET_RTS_INIT : GET_RTS_NEXT;
423         handle.setState(BgpSyncHandle.ITERATING);
424         int winSize = handle.getMaxCount() * handle.getRouteSize();
425
426
427         // TODO: receive correct protocol_type here, currently populating with dummy protocol type
428         Routes outRoutes = bgpClient.getRoutes(protocol_type.PROTOCOL_ANY, op, winSize, afi);
429         if (outRoutes.errcode != 0) {
430             return outRoutes;
431         }
432         handle.setMore(outRoutes.more);
433         if (outRoutes.more == 0) {
434             handle.setState(BgpSyncHandle.DONE);
435         }
436         return outRoutes;
437     }
438
439     public synchronized void setLogging(String fileName, String debugLevel) throws TException, BgpRouterException {
440         bop.type = Optype.LOG;
441         bop.strs[0] = fileName;
442         bop.strs[1] = debugLevel;
443         LOGGER.debug("Setting Log file to BGP VRF rd: {} ", fileName, debugLevel);
444         dispatch(bop);
445     }
446
447     public synchronized void addEbgpMultihop(String nbrIp, int nhops) throws TException, BgpRouterException {
448         bop.type = Optype.MHOP;
449         bop.add = true;
450         bop.strs[0] = nbrIp;
451         bop.ints[0] = nhops;
452         LOGGER.debug("ebgp-multihop set for peer {}, num hops = {}",
453                 nbrIp, nhops);
454         dispatch(bop);
455     }
456
457     public synchronized void delEbgpMultihop(String nbrIp) throws TException, BgpRouterException {
458         bop.type = Optype.MHOP;
459         bop.add = false;
460         bop.strs[0] = nbrIp;
461         LOGGER.debug("ebgp-multihop deleted for peer {}", nbrIp);
462         dispatch(bop);
463     }
464
465     public synchronized void addUpdateSource(String nbrIp, String srcIp) throws TException, BgpRouterException {
466         bop.type = Optype.SRC;
467         bop.add = true;
468         bop.strs[0] = nbrIp;
469         bop.strs[1] = srcIp;
470         LOGGER.debug("update-source added for peer {}, src-ip = {}",
471                 nbrIp, srcIp);
472         dispatch(bop);
473     }
474
475     public synchronized void delUpdateSource(String nbrIp) throws TException, BgpRouterException {
476         bop.type = Optype.SRC;
477         bop.add = false;
478         bop.strs[0] = nbrIp;
479         LOGGER.debug("update-source deleted for peer {}", nbrIp);
480         dispatch(bop);
481     }
482
483     public synchronized void addAddressFamily(String nbrIp, af_afi afi, af_safi safi)
484             throws TException, BgpRouterException {
485         bop.type = Optype.AF;
486         bop.add = true;
487         bop.strs[0] = nbrIp;
488         bop.ints[0] = afi.getValue();
489         bop.ints[1] = safi.getValue();
490         LOGGER.debug("addr family added for peer {}, afi = {}, safi = {}",
491                 nbrIp, bop.ints[0], bop.ints[1]);
492         dispatch(bop);
493     }
494
495     public synchronized void delAddressFamily(String nbrIp, af_afi afi, af_safi safi)
496             throws TException, BgpRouterException {
497         bop.type = Optype.AF;
498         bop.add = false;
499         bop.strs[0] = nbrIp;
500         bop.ints[0] = afi.getValue();
501         bop.ints[1] = safi.getValue();
502         LOGGER.debug("addr family deleted for peer {}, afi = {}, safi = {}",
503                 nbrIp, bop.ints[0], bop.ints[1]);
504         dispatch(bop);
505     }
506
507     public synchronized void addGracefulRestart(int stalepathTime) throws TException, BgpRouterException {
508         bop.type = Optype.GR;
509         bop.add = true;
510         bop.ints[0] = stalepathTime;
511         LOGGER.debug("graceful restart added, stale-path-time = {}",
512                 stalepathTime);
513         dispatch(bop);
514     }
515
516     public synchronized void delGracefulRestart() throws TException, BgpRouterException {
517         bop.type = Optype.GR;
518         bop.add = false;
519         LOGGER.debug("graceful restart deleted");
520         dispatch(bop);
521     }
522
523     public synchronized void enableMultipath(af_afi afi, af_safi safi) throws TException, BgpRouterException {
524         bop.type = Optype.MP;
525         bop.add = true;
526         LOGGER.debug("Enabling multipath for afi: " + afi.getValue() + " safi: " + safi.getValue());
527         bop.ints[0] = afi.getValue();
528         bop.ints[1] = safi.getValue();
529         dispatch(bop);
530     }
531
532     public synchronized void disableMultipath(af_afi afi, af_safi safi) throws TException, BgpRouterException {
533         bop.type = Optype.MP;
534         bop.add = false;
535         LOGGER.debug("Disabling multipath for afi: " + afi.getValue() + " safi: " + safi.getValue());
536         bop.ints[0] = afi.getValue();
537         bop.ints[1] = safi.getValue();
538         dispatch(bop);
539     }
540
541     public synchronized void multipaths(String rd, int maxpath) throws TException, BgpRouterException {
542         bop.type = Optype.VRFMP;
543         bop.strs[0] = rd;
544         bop.ints[0] = maxpath;
545         dispatch(bop);
546     }
547 }
548