BFD logging
[netvirt.git] / bgpmanager / impl / src / main / java / org / opendaylight / netvirt / bgpmanager / ConfigureBgpCli.java
1 /*
2  * Copyright © 2015, 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;
10
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.List;
14 import org.apache.karaf.shell.commands.Command;
15 import org.apache.karaf.shell.commands.Option;
16 import org.apache.karaf.shell.console.OsgiCommandSupport;
17 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_afi;
18 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_safi;
19 import org.opendaylight.netvirt.bgpmanager.thrift.gen.protocol_type;
20 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.Bgp;
21 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.TcpMd5SignaturePasswordType;
22 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.Neighbors;
23 import org.opendaylight.yangtools.yang.common.Uint32;
24
25 @Command(scope = "odl", name = "configure-bgp", description = "")
26 public class ConfigureBgpCli extends OsgiCommandSupport {
27     private static final long AS_MIN = 0;
28     private static final long AS_MAX = 4294967295L;//2^32-1
29
30     @Option(name = "-op", aliases = {"--operation", "--op"}, description = "[start-bgp-server, stop-bgp-server, "
31             + "add-neighbor, delete-neighbor, add-route, delete-route,graceful-restart, enable-log ]",
32             required = false, multiValued = false)
33     String op;
34
35     //exec configure-bgp  add-neighbor --ip <neighbor-ip> --as-num <as-num> --address-family <af> --use-source-ip
36     // <sip> --ebgp-multihops <em> --next-hop <nh>
37     //exec configure-bgp --op add-route/delete-route --rd <rd> --prefix <prefix> --nexthop <nexthop>
38     // --mac <mac> --l2vni <l2vni> --l3vni <l3vni>
39
40     @Option(name = "--as-num", description = "as number of the bgp neighbor", required = false, multiValued = false)
41     String asNumber = null;
42
43     @Option(name = "--ip", description = "ip of the bgp neighbor", required = false, multiValued = false)
44     String ip = null;
45
46     @Option(name = "--tcp-md5-password", description = "RFC2385 TCP MD5 Signature Option shared secret",
47             required = false, multiValued = false)
48     String md5passwordOption = null;
49
50     @Option(name = "--address-family", description = "address family of the bgp neighbor "
51             + "lu|evpn|vpnv4|vpnv6",
52             required = false, multiValued = false)
53     String addressFamily = null;
54
55     @Option(name = "--use-source-ip", description = "source ip to be used for neighborship connection establishment",
56             required = false, multiValued = false)
57     String sourceIp = null;
58
59     @Option(name = "--ebgp-multihops", description = "ebgp multihops of the bgp neighbor",
60             required = false, multiValued = false)
61     String ebgpMultihops = null;
62
63     @Option(name = "--router-id", description = "router id of the bgp instance",
64             required = false, multiValued = false)
65     String routerId = null;
66
67     @Option(name = "--rd", description = "rd of the route",
68             required = false, multiValued = false)
69     String rd = null;
70
71     @Option(name = "--prefix", description = "prefix of the route",
72             required = false, multiValued = false)
73     String prefix = null;
74
75     @Option(name = "--nexthop", description = "nexthop of the route",
76             required = false, multiValued = false)
77     String nexthop = null;
78
79     @Option(name = "--mac", description = "mac of the route",
80             required = false, multiValued = false)
81     String mac = null;
82
83     @Option(name = "--l2vni", description = "l2vni of the route",
84             required = false, multiValued = false)
85     Uint32 l2vni = Uint32.ZERO;
86
87     @Option(name = "--l3vni", description = "l3vni",
88             required = false, multiValued = false)
89     Uint32 l3vni = Uint32.ZERO;
90
91     @Option(name = "--stalepath-time", description = "the time delay after bgp restart stalepaths are cleaned",
92             required = false, multiValued = false)
93     String stalePathTime = null;
94
95     @Option(name = "--log-file-path", description = "bgp log file path",
96             required = false, multiValued = false)
97     String logFile = null;
98
99     @Option(name = "--log-level", description = "log level emergencies,alerts,critical,errors,warnings,notifications,"
100             + "informational,debugging",
101             required = false, multiValued = false)
102     String logLevel = null;
103
104     enum LogLevels {
105         emergencies, alerts, critical, errors, warnings, notifications, informational, debugging
106     }
107
108     private final BgpConfigurationManager bgpConfigurationManager;
109
110     public ConfigureBgpCli(BgpConfigurationManager bgpConfigurationManager) {
111         this.bgpConfigurationManager = bgpConfigurationManager;
112     }
113
114     @Override
115     protected Object doExecute() {
116         if (op == null) {
117             session.getConsole().println("Please provide valid operation");
118             usage();
119             session.getConsole().println(
120                     "exec configure-bgp -op [start-bgp-server | stop-bgp-server | add-neighbor | delete-neighbor|"
121                             + " add-route | delete-route | graceful-restart| enable-log ]");
122             return null;
123         }
124         switch (op) {
125             case "start-bgp-server":
126                 startBgp();
127                 break;
128             case "stop-bgp-server":
129                 stopBgp();
130                 break;
131             case "add-neighbor":
132                 addNeighbor();
133                 break;
134             case "delete-neighbor":
135                 deleteNeighbor();
136                 break;
137             case "add-route":
138                 addRoute();
139                 break;
140             case "delete-route":
141                 deleteRoute();
142                 break;
143             case "graceful-restart":
144                 configureGR();
145                 break;
146             case "enable-log":
147                 enableBgpLogLevel();
148                 break;
149             default:
150                 session.getConsole().println("invalid operation");
151                 usage();
152                 session.getConsole().println(
153                         "exec configure-bgp -op [start-bgp-server | stop-bgp-server | add-neighbor | "
154                                 + "delete-neighbor| graceful-restart| enable-log ]");
155         }
156         return null;
157     }
158
159     public boolean validateStalepathTime() {
160         try {
161             int time = Integer.parseInt(stalePathTime);
162             if (time < 30 || time > 3600) {
163                 session.getConsole().println("invalid stale path time valid range [30-3600]");
164                 printGracefulRestartHelp();
165                 return false;
166             }
167         } catch (NumberFormatException e) {
168             session.getConsole().println("invalid stale path time");
169             printGracefulRestartHelp();
170             return false;
171         }
172         return true;
173     }
174
175     private void configureGR() {
176         boolean validStalepathTime = validateStalepathTime();
177         if (!validStalepathTime) {
178             return;
179         }
180         bgpConfigurationManager.addGracefulRestart(Integer.parseInt(stalePathTime));
181     }
182
183     private void deleteNeighbor() {
184         if (ip == null || !validateIp(ip)) {
185             session.getConsole().println("invalid neighbor ip");
186             printDeleteNeighborHelp();
187             return;
188         }
189         long asNo = getAsNumber(ip);
190         if (asNo < 0) {
191             session.getConsole().println("neighbor does not exist");
192             printDeleteNeighborHelp();
193             return;
194         }
195         bgpConfigurationManager.delNeighbor(ip);
196     }
197
198     public long getAsNumber(String nbrIp) {
199         Bgp conf = bgpConfigurationManager.getConfig();
200         if (conf == null) {
201             return -1;
202         }
203         List<Neighbors> nbrs = conf.getNeighbors();
204         if (nbrs == null) {
205             return -1;
206         }
207         for (Neighbors nbr : nbrs) {
208             if (nbrIp.equals(nbr.getAddress().getValue())) {
209                 return nbr.getRemoteAs().toJava();
210             }
211         }
212         return -1;
213     }
214
215     private void stopBgp() {
216         Bgp conf = bgpConfigurationManager.getConfig();
217         if (conf == null) {
218             return;
219         }
220         List<Neighbors> nbrs = conf.getNeighbors();
221         if (nbrs != null && nbrs.size() > 0) {
222             session.getConsole().println(
223                     "error: all BGP congiguration must be deleted before stopping the router instance");
224             return;
225         }
226         bgpConfigurationManager.stopBgp();
227     }
228
229     private void usage() {
230         session.getConsole().println("usage:");
231     }
232
233     private void printStartBgpHelp() {
234         usage();
235         session.getConsole().println(
236                 "exec configure-bgp -op start-bgp-server --as-num <asnum> --router-id <routerid> [--stalepath-time "
237                         + "<time>]");
238     }
239
240     private void printAddNeighborHelp() {
241         usage();
242         session.getConsole().println(
243                 "exec configure-bgp -op add-neighbor --ip <neighbor-ip> --as-num <as-num> [--address-family <af>] "
244                         + "[--tcp-md5-password <password>] "
245                         + "[--use-source-ip <sip>] [--ebgp-multihops <em> ]");
246     }
247
248     private void printDeleteNeighborHelp() {
249         usage();
250         session.getConsole().println("exec configure-bgp -op delete-neighbor --ip <neighbor-ip>");
251     }
252
253     void printEnableLogHelp() {
254         usage();
255         session.getConsole().println(
256                 "exec configure-bgp -op enable-logging --filename <filename> --log-level "
257                         + "[emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]");
258     }
259
260     private void printGracefulRestartHelp() {
261         usage();
262         session.getConsole().println("exec configure-bgp -op graceful-restart --stalepath-time <30-3600>");
263     }
264
265     private void startBgp() {
266         boolean validRouterId = false;
267
268         if (bgpConfigurationManager.getConfig() != null && bgpConfigurationManager.getConfig().getAsId() != null) {
269             session.getConsole().println("bgp is already started please use stop-bgp-server and start again");
270             return;
271         }
272         if (!validateAsNumber(asNumber)) {
273             printStartBgpHelp();
274             return;
275         }
276         validRouterId = validateIp(routerId);
277         if (!validRouterId) {
278             session.getConsole().println("invalid router id please supply valid ip address");
279             printStartBgpHelp();
280             return;
281         }
282
283         if (stalePathTime != null) {
284             boolean validStalepathTime = validateStalepathTime();
285             if (!validStalepathTime) {
286                 return;
287             }
288         }
289         bgpConfigurationManager.startBgp(Long.parseLong(asNumber), routerId,
290                 stalePathTime == null ? 0 : Integer.parseInt(stalePathTime), false);
291     }
292
293     protected void addNeighbor() {
294         if (!validateAsNumber(asNumber)) {
295             printAddNeighborHelp();
296             return;
297         }
298
299         boolean validIp = validateIp(ip);
300         if (!validIp) {
301             session.getConsole().println("invalid neighbor ip");
302             printAddNeighborHelp();
303             return;
304         }
305
306         TcpMd5SignaturePasswordType md5secret = null;
307         if (md5passwordOption != null) {
308             try {
309                 md5secret = new TcpMd5SignaturePasswordType(md5passwordOption);
310             } catch (IllegalArgumentException e) {
311                 session.getConsole().println(
312                         new StringBuilder("invalid MD5 password: ").append(e.getMessage()).toString());
313                 printAddNeighborHelp();
314                 return;
315             }
316         }
317
318         if (sourceIp != null) {
319             validIp = validateIp(sourceIp);
320             if (!validIp) {
321                 session.getConsole().println("invalid source ip");
322                 printAddNeighborHelp();
323                 return;
324             }
325         }
326
327         if (ebgpMultihops != null) {
328             try {
329                 long val = Long.parseLong(ebgpMultihops);
330                 if (val < 1 || val > 255) {
331                     session.getConsole().println("invalid ebgpMultihops number , valid range [1,255] ");
332                     printAddNeighborHelp();
333                     return;
334                 }
335             } catch (NumberFormatException e) {
336                 session.getConsole().println("invalid ebgpMultihops number, valid range [1-255]");
337                 printAddNeighborHelp();
338                 return;
339             }
340         }
341         if (addressFamily != null) {
342             if (!addressFamily.equals("lu") && !addressFamily.equals("vpnv4")
343                     && !addressFamily.equals("vpnv6")
344                     && !addressFamily.equals("evpn")) {
345                 session.getConsole().println("error: Address family must be lu/evpn/vpnv4/vpnv6 ");
346                 return;
347             }
348
349             int afi ;
350             int safi ;
351             if (addressFamily.equals("vpnv6")) {
352                 afi = 2;
353                 safi = 5;
354             } else if (addressFamily.equals("evpn")) {
355                 afi = 3;
356                 safi = 6;
357             } else if (addressFamily.equals("lu")) {
358                 afi = 1;
359                 safi = 4;
360             } else if  (addressFamily.equals("vpnv4")) {
361                 afi = 1;
362                 safi = 5;
363             } else {
364                 session.getConsole().println(
365                         "invalid addressFamily valid values SAFI_IPV4_LABELED_UNICAST | SAFI_MPLS_VPN");
366                 printAddNeighborHelp();
367                 return;
368             }
369             bgpConfigurationManager.addAddressFamily(ip, afi, safi);
370
371         }
372         if (getAsNumber(ip) != -1) {
373             session.getConsole().println("neighbor with ip " + ip + " already exists");
374             return;
375         }
376         bgpConfigurationManager.addNeighbor(ip, Long.parseLong(asNumber), md5secret);
377         if (addressFamily != null) {
378             bgpConfigurationManager.addAddressFamily(ip, af_afi.AFI_IP.getValue(),
379                     af_safi.valueOf(addressFamily).getValue());
380         }
381         if (ebgpMultihops != null) {
382             bgpConfigurationManager.addEbgpMultihop(ip, Integer.parseInt(ebgpMultihops));
383         }
384         if (sourceIp != null) {
385             bgpConfigurationManager.addUpdateSource(ip, sourceIp);
386         }
387     }
388
389     protected void addRoute() {
390         bgpConfigurationManager.onUpdatePushRoute(protocol_type.PROTOCOL_EVPN, rd, prefix,
391                 0, nexthop, mac, l3vni, l2vni, null, null);
392     }
393
394     protected void deleteRoute() {
395         bgpConfigurationManager.onUpdateWithdrawRoute(protocol_type.PROTOCOL_EVPN, rd, prefix,
396                 0, nexthop, mac);
397     }
398
399     private boolean validateIp(String inputIp) {
400         boolean validIp = false;
401         try {
402             if (inputIp != null) {
403                 InetAddress addr = InetAddress.getByName(inputIp);
404                 if (addr.isMulticastAddress()) {
405                     session.getConsole().println("ip cannot be multicast address");
406                     return false;
407                 }
408                 if (addr.isLoopbackAddress()) {
409                     session.getConsole().println("ip cannot be loopback address");
410                     return false;
411                 }
412                 byte[] addrBytes = addr.getAddress();
413                 int lastPart = addrBytes[3] & 0xFF;
414                 int firstPart = addrBytes[0] & 0xFF;
415                 if (firstPart == 0) {
416                     return false;//cannot start with 0 "0.1.2.3"
417                 }
418                 if (lastPart == 0 || lastPart == 255) {
419                     return false;
420                 }
421                 validIp = true;
422             }
423         } catch (UnknownHostException e) {
424             // Ignored?
425         }
426         return validIp;
427     }
428
429     private void enableBgpLogLevel() {
430         if (logFile == null) {
431             session.getConsole().println("Please provide log file name ");
432             usage();
433             session.getConsole().println(
434                     "exec configure-bgp -op enable-log --log-file-path <logfile> --log-level <level>");
435             return;
436         }
437         boolean validLoglevel = false;
438         try {
439             LogLevels.valueOf(logLevel);
440             validLoglevel = true;
441         } catch (IllegalArgumentException e) {
442             // Ignored?
443         }
444         if (!validLoglevel) {
445             session.getConsole().println(
446                     "Please provide valid log level "
447                             + "emergencies|alerts|critical|errors|warnings|notifications|informational|debugging");
448             usage();
449             session.getConsole().println(
450                     "exec configure-bgp -op enable-log --log-file-path <logfile> --log-level <level>");
451             return;
452         }
453         bgpConfigurationManager.addLogging(logFile, logLevel);
454     }
455
456     private boolean validateAsNumber(String strAsnum) {
457
458         try {
459             long asNum = Long.parseLong(strAsnum);
460             if (asNum == 0L || asNum == 65535L || asNum == 23456L) {
461                 session.getConsole().println("reserved AS Number supplied ");
462                 return false;
463             }
464             if (asNum <= AS_MIN || asNum > AS_MAX) {
465                 session.getConsole().println("invalid AS Number , supported range [1," + AS_MAX + "]");
466                 return false;
467             }
468         } catch (NumberFormatException e) {
469             session.getConsole().println("invalid AS Number ");
470             return false;
471         }
472         return true;
473     }
474 }