/* * Copyright (c) 2015 - 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.netvirt.fibmanager.shell; import java.io.PrintStream; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; import java.util.Locale; import java.util.Map; import org.apache.karaf.shell.commands.Argument; import org.apache.karaf.shell.commands.Command; import org.apache.karaf.shell.commands.Option; import org.apache.karaf.shell.console.OsgiCommandSupport; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.genius.datastoreutils.ExpectedDataObjectNotFoundException; import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker; import org.opendaylight.mdsal.binding.api.DataBroker; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.mdsal.common.api.ReadFailedException; import org.opendaylight.netvirt.fibmanager.api.FibHelper; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.VrfEntryBase.EncapType; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePathsKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Command(scope = "vpnservice", name = "fib-show", description = "Displays fib entries.\t" + "To get more help use cli fib-show fullHelp") public class ShowFibCommand extends OsgiCommandSupport { private static final Logger LOG = LoggerFactory.getLogger(ShowFibCommand.class); private static final String TABULAR_FORMAT = " %-7s %-20s %-20s %-7s %-7s"; private static final String HEADER = String.format(TABULAR_FORMAT, "RD", "Prefix", "NextHop", "Label", "Origin") + "\n -------------------------------------------------------------------"; private static final String ADDRFAMILY = "--addr-family"; private static final String SUBNET = "--subnet"; @Argument(name = "addFam|fullHelp", description = "type of address families to show, or full help cli", required = false, multiValued = false) private final String options = null; @Option(name = ADDRFAMILY, aliases = {"-af"}, description = "show address family ipv4 and/or ipv6 and/or l2vpn", required = false, multiValued = true) private final List addrFamList = null; @Option(name = SUBNET, aliases = {"-sub"}, description = "show only one IP or subnet sorted by mask ex \"x.x.x.x/32\" or \"2001::1/128\"", required = false, multiValued = true) private final String prefixOrSubnetOption = null; private String prefixOrSubnet = null; private SingleTransactionDataBroker singleTxDb; public void setDataBroker(DataBroker dataBroker) { this.singleTxDb = new SingleTransactionDataBroker(dataBroker); } @Override @Nullable protected Object doExecute() { PrintStream console = session.getConsole(); if (prefixOrSubnetOption != null && prefixOrSubnetOption.length() > 0) { prefixOrSubnet = prefixOrSubnetOption.replace("[", ""); prefixOrSubnet = prefixOrSubnet.replace("]", ""); if (!prefixOrSubnet.contains("/")) { String maskFull = null; try { Inet4Address tempAdd = (Inet4Address) InetAddress.getByName(prefixOrSubnet); maskFull = "/32"; } catch (SecurityException | UnknownHostException | ClassCastException e) { maskFull = null; } if (maskFull == null) { try { Inet6Address tempAdd = (Inet6Address) InetAddress.getByName(prefixOrSubnet); maskFull = "/128"; } catch (SecurityException | UnknownHostException | ClassCastException e) { maskFull = null; } } if (maskFull == null) { console.println("a part of cli " + SUBNET + " is wrong => " + prefixOrSubnet); return usage(console); } prefixOrSubnet += maskFull; } } console.println(HEADER); if (options == null && prefixOrSubnet == null && (addrFamList == null || addrFamList.isEmpty())) { InstanceIdentifier id = InstanceIdentifier.create(FibEntries.class); try { FibEntries fibEntries = singleTxDb.syncRead(LogicalDatastoreType.CONFIGURATION, id); Map keyVrfTablesMap = fibEntries.getVrfTables(); if (keyVrfTablesMap == null || keyVrfTablesMap.isEmpty()) { console.println(" No Fib entries found"); return null; } for (VrfTables vrfTable : keyVrfTablesMap.values()) { printVrfTable(vrfTable, console); } } catch (ExpectedDataObjectNotFoundException e404) { /* This is always thrown the first time FIB DS is accessed, and no route have yet been configured in it. So, no need to print FATAL on the console. */ String errMsg = "FATAL: fib-entries container is missing from MD-SAL"; LOG.error(errMsg, e404); } catch (ReadFailedException rfe) { String errMsg = "Internal Error occurred while processing vpnservice:fib-show command"; console.println("\n" + errMsg); LOG.error(errMsg, rfe); } return null; } else { String optionsLowerCase = options != null ? options.toLowerCase(Locale.getDefault()) : ""; switch (optionsLowerCase) { case "fullhelp": return usage(console); default : } if ((addrFamList == null || addrFamList.isEmpty()) && (prefixOrSubnet == null || prefixOrSubnet.indexOf("/") < 5)) { console.println("any address family is requiered or " + SUBNET + " is wrong"); usage(console); } else { boolean isIpv4 = false; boolean isIpv6 = false; boolean isL2vpn = false; if (addrFamList != null && addrFamList.size() > 0) { for (String addF : addrFamList) { switch (addF.toLowerCase(Locale.getDefault())) { case "ipv4": isIpv4 = true; break; case "ipv6": isIpv6 = true; break; case "l2vpn": isL2vpn = true; break; default : } } } InstanceIdentifier id = InstanceIdentifier.create(FibEntries.class); try { FibEntries fibEntries = singleTxDb.syncRead(LogicalDatastoreType.CONFIGURATION, id); Map keyVrfTablesMap = fibEntries.getVrfTables(); if (keyVrfTablesMap == null || keyVrfTablesMap.isEmpty()) { console.println(" No Fib entries found"); return null; } for (VrfTables vrfTable : keyVrfTablesMap.values()) { printVrfTable(vrfTable, console, isIpv4, isIpv6, isL2vpn, prefixOrSubnet); } } catch (ExpectedDataObjectNotFoundException e404) { String errMsg = "FATAL: fib-entries container is missing from MD-SAL"; console.println("\n" + errMsg); LOG.error(errMsg, e404); } catch (ReadFailedException rfe) { String errMsg = "Internal Error occurred while processing vpnservice:fib-show command"; console.println("\n" + errMsg); LOG.error(errMsg, rfe); } return null; } } return null; } private void printVrfTable(VrfTables vrfTable, PrintStream console) { printVrfTable(vrfTable, console, true, true, true, null); } private void printVrfTable(VrfTables vrfTable, PrintStream console, boolean isIpv4, boolean isIpv6, boolean isL2vpn, @Nullable String inputPrefixOrSubnet) { Map keyVrfEntryMap = vrfTable.getVrfEntry(); if (keyVrfEntryMap == null) { LOG.warn("Null keyVrfEntryMap found for VPN with rd={}", vrfTable.getRouteDistinguisher()); return; } for (VrfEntry vrfEntry : keyVrfEntryMap.values()) { boolean showIt = false; if (isIpv4 && isIpv6 && isL2vpn) { showIt = true; } if (!showIt && isIpv4) { LOG.debug("is ipv4 address family=> vrfEntry.getDestPrefix() = {}", vrfEntry.getDestPrefix()); showIt = FibHelper.isIpv4Prefix(vrfEntry.getDestPrefix()); } if (!showIt && isIpv6) { LOG.debug("is ipv6 address family=> vrfEntry.getDestPrefix() = {}", vrfEntry.getDestPrefix()); showIt = FibHelper.isIpv6Prefix(vrfEntry.getDestPrefix()); } if (!showIt && isL2vpn) { if (vrfEntry.getEncapType() != null && !EncapType.Mplsgre.equals(vrfEntry.getEncapType())) { LOG.debug("is l2vpn address family=> vrfEntry.getEncapType() = {}", vrfEntry.getEncapType()); showIt = true; } } if (!showIt && inputPrefixOrSubnet != null) { showIt = FibHelper.isBelongingPrefix(vrfEntry.getDestPrefix(), inputPrefixOrSubnet); } if (!showIt) { continue; } Map routePathsMap = vrfEntry.getRoutePaths(); if (routePathsMap == null || routePathsMap.isEmpty()) { console.println(String.format(TABULAR_FORMAT, vrfTable.getRouteDistinguisher(), vrfEntry.getDestPrefix(), "local", routePathsMap == null ? "" : "", vrfEntry.getOrigin())); continue; } for (RoutePaths routePath : routePathsMap.values()) { console.println(String.format(TABULAR_FORMAT, vrfTable.getRouteDistinguisher(), vrfEntry.getDestPrefix(), routePath.getNexthopAddress(), routePath.getLabel(), vrfEntry.getOrigin())); } } } @Nullable private Object usage(PrintStream console) { String nl = System.getProperty("line.separator"); console.println("==================================================="); console.println("usage cli =>" + nl); console.println("fib-show --help => to get the current help"); console.println("fib-show fullHelp => to get the FULL help" + nl); console.println("fib-show -af ipv4 => to get ipv4 address family"); console.println("fib-show -af ipv4 -af ipv6 => to get ipv4 and ipv6 address family"); console.println("fib-show -af ipv4 -af ipv6 -af l2vpn => to get ipv4 and ipv6 and l2vpn address family"); console.println("---------------------------------------------------"); console.println("fib-show -sub 40.1.1.0/24 => to get all IPv4 from fib belonging to this subnet"); console.println("fib-show -sub 40.1.1.1/32 => to get the IPv4 from fib"); console.println("---------------------------------------------------"); console.println("fib-show -sub 2001::1/64 => to get all IPv6 from fib belonging to this subnet"); console.println("fib-show -sub 2001::1/128 => to get all IPv6 from fib"); console.println("==================================================="); return null; } }