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