2 * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
9 package org.opendaylight.netvirt.bgpmanager.oam;
11 import java.io.BufferedReader;
12 import java.io.BufferedWriter;
14 import java.io.FileNotFoundException;
15 import java.io.FileWriter;
16 import java.io.IOException;
17 import java.io.InputStreamReader;
18 import java.io.PrintWriter;
19 import java.lang.management.ManagementFactory;
20 import java.net.Inet4Address;
21 import java.net.Inet6Address;
22 import java.net.InetAddress;
23 import java.net.Socket;
24 import java.net.SocketTimeoutException;
25 import java.net.UnknownHostException;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.Scanner;
31 import java.util.TimerTask;
33 import javax.annotation.Nonnull;
34 import javax.management.JMException;
35 import javax.management.MBeanServer;
36 import javax.management.ObjectName;
38 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_afi;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 public class BgpCounters extends TimerTask {
45 private static final Logger LOG = LoggerFactory.getLogger(BgpCounters.class);
46 private static BgpCountersBroadcaster bgpStatsBroadcaster = null;
47 private MBeanServer bgpStatsServer = null;
48 private Map<String, String> countersMap = new HashMap<>();
49 private String bgpSdncMip = "127.0.0.1";
50 public static final String BGP_VPNV6_FILE = "cmd_ip_bgp_vpnv6_all.txt";
51 public static final String BGP_VPNV4_FILE = "cmd_ip_bgp_vpnv4_all.txt";
52 public static final String BGP_VPNV6_SUMMARY_FILE = "cmd_ip_bgp_vpnv6_all_summary.txt";
53 public static final String BGP_VPNV4_SUMMARY_FILE = "cmd_ip_bgp_vpnv4_all_summary.txt";
55 public BgpCounters(String mipAddress) {
56 bgpSdncMip = mipAddress;
62 LOG.debug("Fetching counters from BGP");
64 fetchCmdOutputs("cmd_ip_bgp_summary.txt", "show ip bgp summary");
65 fetchCmdOutputs("cmd_bgp_ipv4_unicast_statistics.txt", "show bgp ipv4 unicast statistics");
66 fetchCmdOutputs(BGP_VPNV4_FILE, "show ip bgp vpnv4 all");
67 fetchCmdOutputs(BGP_VPNV6_FILE, "show ip bgp vpnv6 all");
71 if (LOG.isDebugEnabled()) {
74 if (bgpStatsBroadcaster == null) {
75 //First time execution
77 bgpStatsBroadcaster = new BgpCountersBroadcaster();
78 bgpStatsServer = ManagementFactory.getPlatformMBeanServer();
79 ObjectName bgpStatsObj = new ObjectName("SDNC.PM:type=BgpCountersBroadcaster");
80 bgpStatsServer.registerMBean(bgpStatsBroadcaster, bgpStatsObj);
81 LOG.info("BGP Counters MBean Registered :::");
82 } catch (JMException e) {
83 LOG.error("Adding a NotificationBroadcaster failed.", e);
87 bgpStatsBroadcaster.setBgpCountersMap(countersMap);
88 LOG.debug("Finished updating the counters from BGP");
89 } catch (IOException e) {
90 LOG.error("Failed to publish bgp counters ", e);
94 private void dumpCounters() {
95 for (Map.Entry<String, String> entry : countersMap.entrySet()) {
96 LOG.debug("{}, Value = {}", entry.getKey(), entry.getValue());
100 void fetchCmdOutputs(String filename, String cmdName) throws IOException {
101 try (Socket socket = new Socket(bgpSdncMip, 2605);
102 PrintWriter toRouter = new PrintWriter(socket.getOutputStream(), true);
103 BufferedReader fromRouter = new BufferedReader(new InputStreamReader(socket.getInputStream()));
104 BufferedWriter toFile = new BufferedWriter(new FileWriter(filename, true))) {
105 socket.setSoTimeout(2 * 1000);
107 // Wait for the password prompt
108 StringBuilder sb = new StringBuilder();
110 char[] cbuf = new char[10];
111 while (!sb.toString().contains("Password:")) {
112 if ((read = fromRouter.read(cbuf)) == -1) {
113 LOG.error("Connection closed by BGPd.");
116 sb.append(cbuf, 0, read);
120 toRouter.println(BgpConstants.QBGP_VTY_PASSWORD);
122 // Wait for the prompt (ending with '>' or '#')
123 sb = new StringBuilder();
124 String prompt = null;
125 while (prompt == null) {
126 switch (read = fromRouter.read()) {
128 LOG.error("Connection closed by BGPd, read {}", sb.toString());
133 sb.append((char) read);
134 prompt = sb.toString().trim();
137 sb.append((char) read);
143 toRouter.println("en");
146 while ((read = fromRouter.read()) != '#') {
148 LOG.error("Connection closed by BGPd, read {}", sb.toString());
154 toRouter.println(cmdName);
156 // Read all the router's output
157 sb = new StringBuilder();
158 cbuf = new char[1024];
159 while ((read = fromRouter.read(cbuf)) != -1) {
160 sb.append(cbuf, 0, read);
161 if (sb.toString().trim().endsWith(prompt)) {
166 // Only keep output up to the last prompt
167 int lastPromptIndex = sb.lastIndexOf(prompt);
168 if (lastPromptIndex >= 0) {
169 sb.delete(lastPromptIndex, sb.length());
173 toFile.write(sb.toString().trim());
174 } catch (UnknownHostException e) {
175 LOG.error("Unknown host {}", bgpSdncMip, e);
176 } catch (SocketTimeoutException e) {
177 LOG.error("Socket timeout", e);
178 } catch (IOException e) {
179 LOG.error("I/O error", e);
183 private static boolean validate(@Nonnull final String ip, af_afi afi) {
187 int identifiedAFI = 0;
189 InetAddress address = InetAddress.getByName(ip);
190 if (address instanceof Inet6Address) {
191 identifiedAFI = af_afi.AFI_IPV6.getValue();
192 } else if (address instanceof Inet4Address) {
193 identifiedAFI = af_afi.AFI_IP.getValue();
195 } catch (java.net.UnknownHostException e) {
196 /*if exception is catched then the prefix is not an IPv6 and IPv4*/
197 LOG.error("Unrecognized ip address ipAddress: {}", ip);
199 return (identifiedAFI == afi.getValue() ? true : false);
203 * The below function parses the output of "show ip bgp summary" saved in a file.
204 * Below is the snippet for the same :-
206 BGP router identifier 10.183.254.53, local AS number 101
208 Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
209 10.183.254.76 4 100 3 4 0 0 0 00:01:27 0
211 Total number of neighbors 1
215 private void parseIpBgpSummary() {
216 File file = new File("cmd_ip_bgp_summary.txt");
218 try (Scanner scanner = new Scanner(file)) {
219 boolean startEntries = false;
220 while (scanner.hasNextLine()) {
221 String str = scanner.nextLine();
222 if (str.contains("State/PfxRcd")) {
224 } else if (startEntries) {
225 String[] result = str.split("\\s+");
226 if (result.length < 5) {
229 String strIp = result[0].trim();
230 if (!validate(strIp, af_afi.AFI_IP)) {
233 final String as = result[2];
234 final String rx = result[3];
235 final String tx = result[4];
238 BgpConstants.BGP_COUNTER_NBR_PKTS_RX + ":BGP_Nbr_IP_" + strIp + "_AS_" + as
242 BgpConstants.BGP_COUNTER_NBR_PKTS_TX + ":BGP_Nbr_IP_" + strIp + "_AS_" + as + "_PktsSent",
246 } catch (IOException e) {
247 LOG.error("Could not process the file {}", file.getAbsolutePath());
251 * The below function parses the output of "show bgp ipv4 unicast statistics" saved in a file.
252 * Below is the sample output for the same :-
254 BGP IPv4 Unicast RIB statistics
261 private void parseBgpIpv4UnicastStatistics() {
262 File file = new File("cmd_bgp_ipv4_unicast_statistics.txt");
264 try (Scanner scanner = new Scanner(file)) {
265 while (scanner.hasNextLine()) {
266 String instr = scanner.nextLine();
267 if (instr.contains("Total Prefixes")) {
268 String[] result = instr.split(":");
269 if (result.length > 1) {
270 totPfx = result[1].trim();
277 } catch (IOException e) {
278 LOG.error("Could not process the file {}", file.getAbsolutePath());
281 countersMap.put(BgpConstants.BGP_COUNTER_TOTAL_PFX, totPfx);
285 * The below function parses the output of "show ip bgp vpnv4 all" saved in a file.
286 * Below is the sample output for the same :-
287 * show ip bgp vpnv4 all
289 BGP table version is 0, local router ID is 10.183.181.21
291 Route Distinguisher: 100:1
292 *>i15.15.15.15/32 10.183.181.25 0 100 0 ?
293 *>i17.18.17.17/32 10.183.181.25 0 100 0 ?
294 *>i17.18.17.17/32 10.183.181.25 0 100 0 ?
295 *>i17.18.17.17/32 10.183.181.25 0 100 0 ?
296 Route Distinguisher: 100:2
297 *>i16.16.16.16/32 10.183.181.25 0 100 0 ?
298 *>i18.18.18.18/32 10.183.181.25 0 100 0 ?
299 *>i17.18.17.17/32 10.183.181.25 0 100 0 ?
302 private void parseIpBgpVpnv4All() {
303 File file = new File(BGP_VPNV4_FILE);
304 List<String> inputStrs = new ArrayList<>();
306 try (Scanner scanner = new Scanner(file)) {
307 while (scanner.hasNextLine()) {
308 inputStrs.add(scanner.nextLine());
310 } catch (IOException e) {
311 LOG.error("Could not process the file {}", file.getAbsolutePath());
314 for (int i = 0; i < inputStrs.size(); i++) {
315 String instr = inputStrs.get(i);
316 if (instr.contains("Route Distinguisher")) {
317 String[] result = instr.split(":");
318 String rd = result[1].trim() + "_" + result[2].trim();
319 i = processRouteCount(rd, i + 1, inputStrs);
322 /*populate the "BgpTotalPrefixes" counter by combining
323 the prefixes that are calculated per RD basis*/
324 int bgpTotalPfxs = calculateBgpTotalPrefixes();
325 LOG.trace("BGP Total Prefixes:{}",bgpTotalPfxs);
326 countersMap.put(BgpConstants.BGP_COUNTER_TOTAL_PFX,String.valueOf(bgpTotalPfxs));
330 * The below function parses the output of "show ip bgp vpnv6 all" saved in a file.
331 * Below is the sample output for the same :-
332 * show ip bgp vpnv6 all
334 BGP table version is 0, local router ID is 10.183.181.21
336 Route Distinguisher: 100:1
337 *>i2001:db8:0:2::/128 10.183.181.25 0 100 0 ?
338 *>i2001:db8:0:2::/128 10.183.181.25 0 100 0 ?
339 *>i2001:db8:0:2::/128 10.183.181.25 0 100 0 ?
340 *>i2001:db8:0:2::/128 10.183.181.25 0 100 0 ?
341 Route Distinguisher: 100:2
342 *>i2001:db9:0:3::/128 10.183.181.25 0 100 0 ?
343 *>i2001:db9:0:3::/128 10.183.181.25 0 100 0 ?
344 *>i2001:db9:0:3::/128 10.183.181.25 0 100 0 ?
347 private void parseIpBgpVpnv6All() {
348 File file = new File(BGP_VPNV6_FILE);
349 List<String> inputStrs = new ArrayList<>();
351 try (Scanner scanner = new Scanner(file)) {
352 while (scanner.hasNextLine()) {
353 inputStrs.add(scanner.nextLine());
355 } catch (IOException e) {
356 LOG.error("Could not process the file {}", file.getAbsolutePath());
359 for (int i = 0; i < inputStrs.size(); i++) {
360 String instr = inputStrs.get(i);
361 if (instr.contains("Route Distinguisher")) {
362 String[] result = instr.split(":");
363 String rd = result[1].trim() + "_" + result[2].trim();
364 i = processRouteCount(rd, i + 1, inputStrs);
369 private int processRouteCount(String rd, int startIndex, List<String> inputStrs) {
370 int num = startIndex;
372 String key = BgpConstants.BGP_COUNTER_RD_ROUTE_COUNT + ":BGP_RD_" + rd + "_route_count";
374 for (String str = inputStrs.get(num); str != null && !str.trim().equals("") && num < inputStrs.size();
375 str = inputStrs.get(num)) {
376 if (str.contains("Route Distinguisher")) {
377 countersMap.put(key, Integer.toString(routeCount));
382 if (num == inputStrs.size()) {
386 if (routeCount == 0) {
387 // Erroneous condition, should never happen.
388 // Implies that the file contains marker for RD without routes.
389 // will form an infinite loop if not broken
390 // by sending a big number back.
391 return Integer.MAX_VALUE;
393 countersMap.put(key, Integer.toString(routeCount));
397 private int calculateBgpTotalPrefixes() {
398 return countersMap.entrySet().stream().filter(entry -> entry.getKey().contains(BgpConstants
399 .BGP_COUNTER_RD_ROUTE_COUNT)).map(Map.Entry::getValue).mapToInt(Integer::parseInt).sum();
402 private void resetCounters() {
404 resetFile("cmd_ip_bgp_summary.txt");
405 resetFile("cmd_bgp_ipv4_unicast_statistics.txt");
406 resetFile(BGP_VPNV4_FILE);
407 resetFile(BGP_VPNV6_FILE);
410 static void resetFile(String fileName) {
411 File file = (new File(fileName));
412 if (!file.delete()) {
413 try (PrintWriter pw = new PrintWriter(file)) {
415 } catch (FileNotFoundException e) {
421 static Map<String, String> parseIpBgpVpnAllSummary(Map<String, String> countMap,
424 File file = new File(cmdFile);
426 try (Scanner scanner = new Scanner(file)) {
427 boolean startEntries = false;
428 while (scanner.hasNextLine()) {
429 String str = scanner.nextLine();
430 LOG.trace("str is:: {}", str);
431 if (str.contains("State/PfxRcd")) {
433 } else if (startEntries) {
434 String[] result = str.split("\\s+");
435 if (result.length > 9) {
436 String strIp = result[0].trim();
437 LOG.trace("strIp " + strIp);
439 if (!validate(strIp, afi)) {
442 String statePfxRcvd = result[9];
443 countMap.put(strIp, statePfxRcvd);
447 } catch (IOException e) {
448 LOG.trace("Could not process the file {}", file.getAbsolutePath());
455 static Map<String, String> parseIpBgpVpnv4AllSummary(Map<String, String> countMap) {
456 return BgpCounters.parseIpBgpVpnAllSummary(countMap,
457 BGP_VPNV4_SUMMARY_FILE,
461 static Map<String, String> parseIpBgpVpnv6AllSummary(Map<String, String> countMap) {
462 return BgpCounters.parseIpBgpVpnAllSummary(countMap,
463 BGP_VPNV6_SUMMARY_FILE,