org.xerela.provider.telemetry.TelemetryProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.xerela.provider.telemetry.TelemetryProvider.java

Source

/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 */
package org.xerela.provider.telemetry;

import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.ScrollMode;
import org.hibernate.classic.Session;
import org.xerela.addressing.IPAddress;
import org.xerela.addressing.MACAddress;
import org.xerela.addressing.NetworkAddressElf;
import org.xerela.provider.devices.ZDeviceCore;
import org.xerela.zap.jta.TransactionElf;

/**
 * TelemetryProvider
 */
public class TelemetryProvider implements ITelemetryProvider {

    /** {@inheritDoc} */
    public SwitchPortResult findSwitchPort(String host) {
        SwitchPortResult result = new SwitchPortResult();
        MACAddress targetMacAddress = null;
        boolean ownTransaction = TransactionElf.beginOrJoinTransaction();
        try {
            if (NetworkAddressElf.isValidMacAddress(host)) {
                targetMacAddress = new MACAddress(host);
            } else {
                try {
                    IPAddress ipAddress = new IPAddress(InetAddress.getByName(host));
                    result.setHostIpAddress(ipAddress.getIPAddress());
                    DeviceArpTableEntry entry = null;
                    if (ipAddress.isVersion6()) {
                        entry = findNdpEntry(ipAddress);

                    } else {
                        entry = findArpEntry(ipAddress);
                    }

                    if (entry != null) {
                        result.setArpEntry(entry);
                        String mac = entry.getMacAddress();
                        targetMacAddress = new MACAddress(mac);
                    } else {
                        result.setError(SwitchPortResult.NO_ARP_ENTRY);
                        return result;
                    }
                } catch (UnknownHostException e) {
                    result.setError(SwitchPortResult.UNABLE_TO_RESOLVE_HOST);
                    return result;
                }
            }
            result.setMacEntry(findMacTableEntry(targetMacAddress));
            result.setHostMacAddress(targetMacAddress.getMACAddress());
            if (result.getMacEntry() == null) {
                result.setError(SwitchPortResult.NO_MAC_ENTRY);
            }
            return result;
        } finally {
            if (ownTransaction) {
                TransactionElf.commit();
            }
        }

    }

    /** {@inheritDoc} */
    @SuppressWarnings({ "unchecked", "nls" })
    public MacPageData getMacTable(MacPageData pageData, String ipAddress, String managedNetwork) {
        ZDeviceCore device = getDevice(ipAddress, managedNetwork);
        if (device == null) {
            pageData.setMacEntries(new MacTableEntry[0]);
            pageData.setTotal(0);
            return pageData;
        }

        boolean ownTransaction = TransactionElf.beginOrJoinTransaction();
        try {
            Session session = TelemetryActivator.getSessionFactory().getCurrentSession();
            String fromClause = "FROM discovery_mac WHERE device_id = " + device.getDeviceId();
            SQLQuery query = session
                    .createSQLQuery("SELECT mac_address, interface, vlan " + fromClause + " ORDER BY interface");
            query.addScalar("mac_address", Hibernate.LONG);
            query.addScalar("interface", Hibernate.STRING);
            query.addScalar("vlan", Hibernate.STRING);
            query.setFirstResult(pageData.getOffset()).setMaxResults(pageData.getPageSize());
            query.scroll(ScrollMode.SCROLL_INSENSITIVE);
            List<Object[]> resultList = (List<Object[]>) query.list();
            if (resultList == null || resultList.isEmpty()) {
                pageData.setMacEntries(new MacTableEntry[0]);
                pageData.setTotal(0);
                return pageData;
            } else {
                if (pageData.getOffset() == 0) {
                    // Set the total result size into the page data.
                    query = session.createSQLQuery("SELECT count(mac_address) " + fromClause);
                    pageData.setTotal(getCount(query));
                }

                List<MacTableEntry> macTable = new ArrayList<MacTableEntry>();
                for (Object[] resultEntry : resultList) {
                    MacTableEntry entry = new MacTableEntry();
                    entry.setMacAddress((Long) resultEntry[0]);
                    entry.setPort((String) resultEntry[1]);
                    entry.setVlan((String) resultEntry[2]);
                    macTable.add(entry);
                }
                pageData.setMacEntries(macTable.toArray(new MacTableEntry[0]));
                return pageData;
            }
        } finally {
            if (ownTransaction) {
                TransactionElf.commit();
            }
        }
    }

    /** {@inheritDoc} */
    @SuppressWarnings({ "unchecked", "nls" })
    public ArpPageData getArpTable(ArpPageData pageData, String ipAddress, String managedNetwork) {
        ZDeviceCore device = getDevice(ipAddress, managedNetwork);
        if (device == null) {
            pageData.setArpEntries(new ArpTableEntry[0]);
            pageData.setTotal(0);
            return pageData;
        }

        boolean ownTransaction = TransactionElf.beginOrJoinTransaction();
        try {
            Session session = TelemetryActivator.getSessionFactory().getCurrentSession();
            String fromClause = "FROM discovery_arp arp WHERE arp.device_id = " + device.getDeviceId();
            SQLQuery query = session.createSQLQuery(
                    "SELECT ip_address, mac_address, interface " + fromClause + " ORDER BY ip_address");
            query.addScalar("ip_address", Hibernate.STRING);
            query.addScalar("mac_address", Hibernate.LONG);
            query.addScalar("interface", Hibernate.STRING);
            query.setFirstResult(pageData.getOffset()).setMaxResults(pageData.getPageSize());
            query.scroll(ScrollMode.SCROLL_INSENSITIVE);
            List<Object[]> resultList = (List<Object[]>) query.list();
            if (resultList == null || resultList.isEmpty()) {
                pageData.setArpEntries(new ArpTableEntry[0]);
                pageData.setTotal(0);
                return pageData;
            } else {
                if (pageData.getOffset() == 0) {
                    // Set the total result size into the page data.
                    query = session.createSQLQuery("SELECT count(arp.ip_address) " + fromClause);
                    pageData.setTotal(getCount(query));
                }

                List<ArpTableEntry> arpTable = new ArrayList<ArpTableEntry>();
                for (Object[] resultEntry : resultList) {
                    ArpTableEntry entry = new ArpTableEntry();
                    entry.setIpAddress((String) resultEntry[0]);
                    entry.setMacAddress((Long) resultEntry[1]);
                    entry.setInterfaceName((String) resultEntry[2]);
                    arpTable.add(entry);
                }
                pageData.setArpEntries(arpTable.toArray(new ArpTableEntry[0]));
                return pageData;
            }
        } finally {
            if (ownTransaction) {
                TransactionElf.commit();
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings({ "unchecked", "nls" })
    public DeviceArpPageData getArpEntries(DeviceArpPageData pageData, String networkAddress, String sort,
            boolean descending) {
        StringBuilder selectClause = new StringBuilder(
                "SELECT d.ip_address as device, d.network as managedNetwork, arp.device_id as device_id, arp.ip_address as ipAddress, arp.mac_address as macAddress, arp.interface as interfaceName");
        StringBuilder fromClause = new StringBuilder(
                " FROM discovery_arp arp LEFT JOIN device d on arp.device_id = d.device_id");
        if (networkAddress.indexOf('/') > 0) {
            Long[] hiLoRange = NetworkAddressElf.getHiLoRange(networkAddress);
            if (hiLoRange[0] == null) {
                if (NetworkAddressElf.isIPv6AddressOrMask(networkAddress)) {
                    String[] ipAndCidr = networkAddress.split("/");
                    long[] hiLo = NetworkAddressElf.getHiLo(ipAndCidr[0]);
                    fromClause.append(String.format(" WHERE arp.ip_low BETWEEN %d AND %d AND arp.ip_high=%d",
                            hiLoRange[2], hiLoRange[1], hiLo[0]));
                } else {
                    fromClause.append(
                            String.format(" WHERE arp.ip_low BETWEEN %d AND %d", hiLoRange[2], hiLoRange[1]));
                }
            } else {
                fromClause
                        .append(String.format(" WHERE arp.ip_high BETWEEN %d AND %d", hiLoRange[1], hiLoRange[0]));
            }
        } else {
            long[] hiLo = NetworkAddressElf.getHiLo(networkAddress);
            fromClause.append(String.format(" WHERE arp.ip_high=%d AND arp.ip_low=%d", hiLo[0], hiLo[1]));
        }

        selectClause.append(fromClause);
        if (sort != null) {
            selectClause.append(" ORDER BY ").append(sort);
            if (descending) {
                selectClause.append(" DESC");
            }
        }

        boolean ownTransaction = TransactionElf.beginOrJoinTransaction();
        try {
            Session session = TelemetryActivator.getSessionFactory().getCurrentSession();
            SQLQuery query = session.createSQLQuery(selectClause.toString());
            query.addScalar("device", Hibernate.STRING);
            query.addScalar("managedNetwork", Hibernate.STRING);
            query.addScalar("device_id", Hibernate.INTEGER);
            query.addScalar("ipAddress", Hibernate.STRING);
            query.addScalar("macAddress", Hibernate.LONG);
            query.addScalar("interfaceName", Hibernate.STRING);

            query.setFirstResult(pageData.getOffset()).setMaxResults(pageData.getPageSize());
            query.scroll(ScrollMode.SCROLL_INSENSITIVE);
            List<Object[]> resultList = (List<Object[]>) query.list();
            if (resultList == null || resultList.isEmpty()) {
                pageData.setArpEntries(new DeviceArpTableEntry[0]);
                pageData.setTotal(0);
                return pageData;
            } else {
                if (pageData.getOffset() == 0) {
                    // Set the total result size into the page data.
                    query = session.createSQLQuery("SELECT count(arp.ip_address) " + fromClause.toString());
                    pageData.setTotal(getCount(query));
                }

                List<DeviceArpTableEntry> arpTable = new ArrayList<DeviceArpTableEntry>();
                for (Object[] resultEntry : resultList) {
                    DeviceArpTableEntry entry = new DeviceArpTableEntry();
                    entry.setDevice((String) resultEntry[0]);
                    entry.setManagedNetwork((String) resultEntry[1]);
                    entry.setDeviceId((Integer) resultEntry[2]);
                    entry.setIpAddress((String) resultEntry[3]);
                    entry.setMacAddress((Long) resultEntry[4]);
                    entry.setInterfaceName((String) resultEntry[5]);
                    arpTable.add(entry);
                }
                pageData.setArpEntries(arpTable.toArray(new DeviceArpTableEntry[0]));
                return pageData;
            }
        } finally {
            if (ownTransaction) {
                TransactionElf.commit();
            }
        }
    }

    /** {@inheritDoc} */
    public List<Neighbor> getNeighbors(String ipAddress, String managedNetwork) {
        ZDeviceCore device = getDevice(ipAddress, managedNetwork);
        List<Neighbor> neighborList = new ArrayList<Neighbor>();
        if (device != null) {
            boolean ownTransaction = TransactionElf.beginOrJoinTransaction();
            try {
                Session session = TelemetryActivator.getSessionFactory().getCurrentSession();
                addRoutingNeighbors(neighborList, session, device);
                addDiscoveryProtocolNeighbors(neighborList, session, device);
            } finally {
                if (ownTransaction) {
                    TransactionElf.commit();
                }
            }
        }
        return neighborList;
    }

    /**
     * Retrieve neighbors from the routing table
     * @param neighborList the list of neighbors so far
     * @param session
     * @param device 
     */
    @SuppressWarnings({ "unchecked", "nls" })
    private void addRoutingNeighbors(List<Neighbor> neighborList, Session session, ZDeviceCore device) {
        SQLQuery query = session.createSQLQuery(
                "SELECT protocol, remote_ip_address, router_id_ip_address, interface FROM discovery_routing WHERE device_id="
                        + device.getDeviceId() + " ORDER by remote_ip_address");
        query.addScalar("protocol", Hibernate.STRING);
        query.addScalar("remote_ip_address", Hibernate.STRING);
        query.addScalar("router_id_ip_address", Hibernate.STRING);
        query.addScalar("interface", Hibernate.STRING);
        List<Object[]> resultList = (List<Object[]>) query.list();
        for (Object[] resultEntry : resultList) {
            Neighbor neighbor = new Neighbor();
            neighbor.setProtocol((String) resultEntry[0]);
            neighbor.setIpAddress((String) resultEntry[1]);
            neighbor.setOtherId(NetworkAddressElf.fromDatabaseString((String) resultEntry[2]));
            neighbor.setLocalInterface((String) resultEntry[3]);
            neighborList.add(neighbor);
        }
    }

    /**
     * Add discovery protocol neighbors
     * @param neighborList
     * @param session
     * @param device
     */
    @SuppressWarnings({ "unchecked", "nls" })
    private void addDiscoveryProtocolNeighbors(List<Neighbor> neighborList, Session session, ZDeviceCore device) {
        SQLQuery query = session.createSQLQuery(
                "SELECT protocol, ip_address, local_interface, remote_interface, sys_name FROM discovery_xdp WHERE device_id="
                        + device.getDeviceId() + " ORDER by ip_address");
        query.addScalar("protocol", Hibernate.STRING);
        query.addScalar("ip_address", Hibernate.STRING);
        query.addScalar("local_interface", Hibernate.STRING);
        query.addScalar("remote_interface", Hibernate.STRING);
        query.addScalar("sys_name", Hibernate.STRING);
        List<Object[]> resultList = (List<Object[]>) query.list();
        for (Object[] resultEntry : resultList) {
            Neighbor neighbor = new Neighbor();
            neighbor.setProtocol((String) resultEntry[0]);
            neighbor.setIpAddress((String) resultEntry[1]);
            neighbor.setLocalInterface((String) resultEntry[2]);
            neighbor.setRemoteInterface((String) resultEntry[3]);
            neighbor.setOtherId((String) resultEntry[4]);
            neighborList.add(neighbor);
        }
    }

    /**
     * Find the best matching MAC forwarding entry for the provided MAC address
     * @param targetMacAddress what to look for
     * @return
     */
    @SuppressWarnings({ "unchecked", "nls" })
    private DeviceMacTableEntry findMacTableEntry(MACAddress targetMacAddress) {
        boolean ownTransaction = TransactionElf.beginOrJoinTransaction();
        try {
            Session session = TelemetryActivator.getSessionFactory().getCurrentSession();
            String queryString = "SELECT d.ip_address as device, d.network as net, m.device_id as device_id, m.mac_address as mac, m.interface as interface, m.vlan as vlan FROM discovery_mac m LEFT JOIN device d on m.device_id = d.device_id where m.mac_address="
                    + targetMacAddress.getMacLong();
            SQLQuery query = session.createSQLQuery(queryString);
            query.addScalar("device", Hibernate.STRING);
            query.addScalar("net", Hibernate.STRING);
            query.addScalar("device_id", Hibernate.INTEGER);
            query.addScalar("mac", Hibernate.LONG);
            query.addScalar("interface", Hibernate.STRING);
            query.addScalar("vlan", Hibernate.STRING);
            List<Object[]> resultList = (List<Object[]>) query.list();
            List<DeviceMacTableEntry> possibleMatches = new ArrayList<DeviceMacTableEntry>();
            for (Object[] resultEntry : resultList) {
                DeviceMacTableEntry entry = new DeviceMacTableEntry();
                entry.setDevice((String) resultEntry[0]);
                entry.setManagedNetwork((String) resultEntry[1]);
                entry.setDeviceId((Integer) resultEntry[2]);
                entry.setMacAddress((Long) resultEntry[3]);
                entry.setPort((String) resultEntry[4]);
                entry.setVlan((String) resultEntry[5]);
                possibleMatches.add(entry);
            }

            int portMacCount = 0;
            DeviceMacTableEntry leader = null;
            for (DeviceMacTableEntry macEntry : possibleMatches) {
                int frequency = getMacFrequency(macEntry);
                if (leader == null || portMacCount > frequency) {
                    portMacCount = frequency;
                    leader = macEntry;
                }
            }
            return leader;
        } finally {
            if (ownTransaction) {
                TransactionElf.commit();
            }
        }
    }

    /**
     * Tries to find the best MAC address for the IP Address provided.  This method looks at all 
     * ARP tables to determine the least used matching MAC address.
     * @param ipAddress find a mac mapped to this IP
     * @return the matching ARP entry
     */
    private DeviceArpTableEntry findArpEntry(IPAddress ipAddress) {
        DeviceArpPageData pageData = new DeviceArpPageData();
        pageData.setPageSize(500);
        List<DeviceArpTableEntry> arpEntries = new ArrayList<DeviceArpTableEntry>();
        do {
            pageData = getArpEntries(pageData, ipAddress.getIPAddress(), "ipAddress", false); //$NON-NLS-1$
            DeviceArpTableEntry[] entries = pageData.getArpEntries();
            for (int i = 0; i < entries.length; i++) {
                arpEntries.add(entries[i]);
            }
        } while (pageData.getTotal() >= pageData.getPageSize());

        int macUseCount = 0;
        DeviceArpTableEntry leader = null;

        for (DeviceArpTableEntry arpEntry : arpEntries) {
            int frequency = getArpFrequency(arpEntry);
            if (leader == null || macUseCount > frequency) {
                macUseCount = frequency;
                leader = arpEntry;
            }
        }
        return leader;
    }

    /**
     * Gives a count of how many times the MAC address on the provided 
     * {@link DeviceArpTableEntry} was seen on the device in the same entry.
     * @param arpEntry
     * @return
     */
    @SuppressWarnings("nls")
    private int getArpFrequency(DeviceArpTableEntry arpEntry) {
        String queryString = String.format(
                "SELECT count(*) FROM discovery_arp WHERE device_id=%d AND mac_address=%d", arpEntry.getDeviceId(),
                arpEntry.getRawMac().getMacLong());
        Session session = TelemetryActivator.getSessionFactory().getCurrentSession();
        SQLQuery query = session.createSQLQuery(queryString);
        return getCount(query);
    }

    /**
     * Gets the MAC address for the {@link IPAddress} provided using the discovery_xdp table.
     * This should be called when working with an IPv6 address as NDP neighbors can be in the X
     * @param ipAddress
     * @return
     */
    @SuppressWarnings({ "unchecked", "nls" })
    private DeviceArpTableEntry findNdpEntry(IPAddress ipAddress) {
        long[] hiLo = ipAddress.getHiLo();
        Session session = TelemetryActivator.getSessionFactory().getCurrentSession();
        String queryString = "SELECT d.ip_address as device, d.network as net, x.device_id as device_id, x.ip_address as ip, x.mac_address as mac, x.local_interface as interface";
        String fromClause = String.format(
                " FROM discovery_xdp x LEFT JOIN device d on x.device_id = d.device_id WHERE x.ip_high=%d AND x.ip_low=%d AND x.protocol='NDP'",
                hiLo[0], hiLo[1]);

        SQLQuery query = session.createSQLQuery(queryString + fromClause);
        query.addScalar("device", Hibernate.STRING);
        query.addScalar("net", Hibernate.STRING);
        query.addScalar("device_id", Hibernate.INTEGER);
        query.addScalar("ip", Hibernate.STRING);
        query.addScalar("mac", Hibernate.LONG);
        query.addScalar("interface", Hibernate.STRING);

        List<Object[]> resultList = (List<Object[]>) query.list();
        // pick the first one, which there should only be one anyways
        for (Object[] resultEntry : resultList) {
            DeviceArpTableEntry entry = new DeviceArpTableEntry();
            entry.setDevice((String) resultEntry[0]);
            entry.setManagedNetwork((String) resultEntry[1]);
            entry.setDeviceId((Integer) resultEntry[2]);
            entry.setIpAddress((String) resultEntry[3]);
            entry.setMacAddress((Long) resultEntry[4]);
            entry.setInterfaceName((String) resultEntry[5]);
            return entry;
        }
        return null;
    }

    /**
     * Counts the number of MAC addresses on a certain device's interface.  If an 
     * interface only has one MAC address in the MAC forwarding table, then the chances 
     * are good that it is the interface that the end host is directly plugged into.
     * @param macEntry
     * @return
     */
    @SuppressWarnings("nls")
    private int getMacFrequency(DeviceMacTableEntry macEntry) {
        String queryString = String.format(
                "SELECT count(*) FROM discovery_mac WHERE device_id=%d AND interface='%s'", macEntry.getDeviceId(),
                macEntry.getPort());
        Session session = TelemetryActivator.getSessionFactory().getCurrentSession();
        SQLQuery query = session.createSQLQuery(queryString);
        return getCount(query);
    }

    /**
     * Get a device by the IP
     * @param ip
     * @return
     */
    private ZDeviceCore getDevice(String ip, String managedNetwork) {
        boolean ownTransaction = TransactionElf.beginOrJoinTransaction();
        try {
            return TelemetryActivator.getDeviceProvider().getDevice(ip, managedNetwork);
        } finally {
            if (ownTransaction) {
                TransactionElf.commit();
            }
        }
    }

    private int getCount(Query query) {
        Object uniqueResult = query.uniqueResult();
        if (uniqueResult instanceof Integer) {
            return (Integer) uniqueResult;
        } else if (uniqueResult instanceof Long) {
            return ((Long) uniqueResult).intValue();
        } else {
            return ((BigInteger) uniqueResult).intValue();
        }
    }
}