Beispiel #1
0
    def _init_dfs(self, namespace, source, dest):
        """Initialize the dataframes used in this path hunt"""

        self._if_df = interfaces.IfObj(context=self.ctxt) \
                                .get(namespace=namespace)
        if self._if_df.empty:
            raise EmptyDataframeError(f"No interface found for {namespace}")

        self._lldp_df = lldp.LldpObj(context=self.ctxt).get(
            namespace=namespace, columns=self.columns)
        if self._lldp_df.empty:
            raise NoLLdpError(f"No LLDP information found for {namespace}")

        self._rdf = routes.RoutesObj(context=self.ctxt) \
                          .lpm(namespace=namespace, address=dest)
        if self._rdf.empty:
            raise EmptyDataframeError("No Routes information found for {}".
                                      format(dest))

        # We ignore the lack of ARPND for now
        self._arpnd_df = arpnd.ArpndObj(
            context=self.ctxt).get(namespace=namespace)

        self._macsobj = macs.MacsObj(context=self.ctxt, namespace=namespace)

        if ':' in source:
            self._src_df = self._if_df[self._if_df.ip6AddressList.astype(str)
                                       .str.contains(source + "/")]
        else:
            self._src_df = self._if_df[self._if_df.ipAddressList.astype(str)
                                       .str.contains(source + "/")]

        if self._src_df.empty:
            raise AttributeError(f"Invalid src {source}")

        if ':' in dest:
            self._dest_df = self._if_df[self._if_df.ip6AddressList.astype(str)
                                        .str.contains(dest + "/")]
        else:
            self._dest_df = self._if_df[self._if_df.ipAddressList.astype(str)
                                        .str.contains(dest + "/")]

        if self._dest_df.empty:
            raise AttributeError(f"Invalid dest {dest}")

        self.dest_device = self._dest_df["hostname"].unique()[0]
        self.src_device = self._src_df["hostname"].unique()[0]

        # Start with the source host and find its route to the destination
        if self._rdf[self._rdf["hostname"] == self.src_device].empty:
            raise EmptyDataframeError(f"No routes found for {self.src_device}")
Beispiel #2
0
    def _augment_arpnd_show(self, df):

        if not df.empty:
            # weed out entries that are not reachable
            df = df.query('state != "failed"').reset_index(drop=True)
            # Get the VRF
            df = df.merge(
                self._if_df[['namespace', 'hostname', 'ifname', 'master']],
                left_on=['namespace', 'hostname', 'oif'],
                right_on=['namespace', 'hostname', 'ifname'],
                suffixes=['', '_y'], how='outer') \
                .rename(columns={'master': 'vrf'}) \
                .dropna(subset=['ipAddress'])

            df['vrf'] = np.where(df['vrf'] == '', 'default', df['vrf'])
            df = df.drop(columns=[
                'vlan', 'oif', 'mackey', 'remoteVtepIp', 'timestamp_y'
            ],
                         errors='ignore')

            # address are where I find the neighbor, these own the mac
            addr = self.address_df[['namespace', 'hostname', 'macaddr']] \
                .drop_duplicates() \
                .rename(columns={'hostname': 'peerHostname'})
            df = df.merge(addr, on=['namespace', 'macaddr'], how='left') \
                   .dropna(how='any') \
                   .rename(columns={'oif': 'ifname'}) \
                   .drop_duplicates()

            # Use MAC table entries to find the local port for a MAC on an SVI
            mac_df = macs.MacsObj(context=self.ctxt) \
                         .get(namespace=self._namespaces, localOnly=True,
                              columns=['namespace', 'hostname', 'vlan',
                                       'macaddr', 'oif'])
            df = df.merge(mac_df,
                          on=['namespace', 'hostname', 'macaddr'],
                          how='outer') \
                .dropna(subset=['ipAddress'])
            df['ifname'] = np.where(df['oif'].isnull(), df['ifname'],
                                    df['oif'])

            df['arpndBidir'] = df.apply(lambda x, y: True if not y.query(
                f'namespace=="{x.namespace}" and '
                f'hostname=="{x.peerHostname}" and '
                f'peerHostname=="{x.hostname}"').empty else False,
                                        args=(df, ),
                                        axis=1)

        self._arpnd_df = df
        return self._arpnd_df
Beispiel #3
0
    def _augment_arpnd_show(self, df):

        if not df.empty:
            # address are where I find the neighbor, these own the mac
            addr = self.address_df[['namespace', 'hostname', 'macaddr']] \
                .drop_duplicates() \
                .rename(columns={'hostname': 'peerHostname'})
            df = df.merge(addr, on=['namespace', 'macaddr'], how='left').dropna(how='any') \
                .rename(columns={'oif': 'ifname'}) \
                .drop_duplicates()

            # these are the macs we that are learned via EVPN so we don't want
            evpn_macs = macs.MacsObj(context=self.ctxt).get(namespace=self._namespaces) \
                .query('remoteVtepIp != ""')[['namespace', 'hostname', 'macaddr']]
            df = df.merge(evpn_macs, on=['namespace', 'hostname', 'macaddr'], how='outer', indicator=True) \
                   .query('_merge=="left_only"') \
                   .drop(columns=['_merge'])

        self._arpnd_df = df
        return self._arpnd_df
Beispiel #4
0
    def _init_dfs(self, namespace, source, dest):
        """Initialize the dataframes used in this path hunt"""

        self.source = source
        self.dest = dest
        self._underlay_dfs = {}  # lpm entries for each vtep IP

        try:
            self._if_df = interfaces.IfObj(context=self.ctxt) \
                                    .get(namespace=namespace, state='up',
                                         addnl_fields=['macaddr']) \
                                    .explode('ipAddressList') \
                                    .fillna({'ipAddressList': ''}) \
                                    .explode('ip6AddressList') \
                                    .fillna({'ip6AddressList': ''}) \
                                    .reset_index(drop=True)
            if self._if_df.empty:
                raise EmptyDataframeError
        except (EmptyDataframeError, KeyError):
            raise EmptyDataframeError(
                f"No interface information found for {namespace}")

        # Need this in determining L2 peer
        mlag_df = mlag.MlagObj(context=self.ctxt).get(namespace=namespace)
        mlag_peers = defaultdict(str)
        mlag_peerlink = defaultdict(str)
        if not mlag_df.empty:
            peerlist = [x.tolist()
                        for x in mlag_df.groupby(by=['systemId'])['hostname']
                        .unique().tolist()]
            for peers in peerlist:
                mlag_peers[peers[0]] = peers[1]
                mlag_peers[peers[1]] = peers[0]
            for row in mlag_df.itertuples():
                mlag_peerlink[row.hostname] = expand_nxos_ifname(row.peerLink)
        self._mlag_peers = mlag_peers
        self._mlag_peerlink = mlag_peerlink

        try:
            # access-internal is an internal Junos route we want to
            # ignore
            self._rdf = routes.RoutesObj(context=self.ctxt) \
                              .lpm(namespace=namespace, address=dest) \
                              .query('protocol != "access-internal"') \
                              .reset_index(drop=True)
            if self._rdf.empty:
                raise EmptyDataframeError
        except (KeyError, EmptyDataframeError):
            raise EmptyDataframeError("No Routes information found for {}".
                                      format(dest))

        try:
            self._rpf_df = routes.RoutesObj(context=self.ctxt) \
                                 .lpm(namespace=namespace, address=source) \
                                 .query('protocol != "access-internal"') \
                                 .reset_index(drop=True)
            if self._rpf_df.empty:
                raise EmptyDataframeError
        except (KeyError, EmptyDataframeError):
            raise EmptyDataframeError("No Routes information found for {}".
                                      format(source))

        # We ignore the lack of ARPND for now
        self._arpnd_df = arpnd.ArpndObj(
            context=self.ctxt).get(namespace=namespace)
        if self._arpnd_df.empty:
            raise EmptyDataframeError(
                f"No ARPND information found for {dest}")

        # Enhance the ARPND table with the VRF field
        self._arpnd_df = self._arpnd_df.merge(
            self._if_df[['namespace', 'hostname', 'ifname', 'master']],
            left_on=['namespace', 'hostname', 'oif'],
            right_on=['namespace', 'hostname', 'ifname'], how='left') \
            .drop(columns=['ifname']) \
            .rename(columns={'master': 'vrf'}) \
            .replace({'vrf': {'': 'default'}}) \
            .query('state != "failed"') \
            .reset_index(drop=True)

        self._macsobj = macs.MacsObj(context=self.ctxt, namespace=namespace)

        if ':' in source:
            self._src_df = self._if_df[self._if_df.ip6AddressList.astype(str)
                                       .str.contains(source + "/")]
        else:
            self._src_df = self._if_df[self._if_df.ipAddressList.astype(str)
                                       .str.contains(source + "/")]

        if self._src_df.empty:
            # TODO: No host with this src addr. Is addr a local ARP entry?
            self._src_df = self._find_fhr_df(None, source)

        if self._src_df.empty:
            raise AttributeError(f"Invalid src {source}")

        if self._src_df.hostname.nunique() == 1 and len(self._src_df) > 1:
            # Multiple interfaces with the same IP address. Possible case
            # of Unnumbered interfaces. See if there's a loopback in there
            if 'loopback' in self._src_df.type.unique().tolist():
                self._src_df = self._src_df.query('type == "loopback"')

        if ':' in dest:
            self._dest_df = self._if_df[self._if_df.ip6AddressList.astype(str)
                                        .str.contains(dest + "/")]
        else:
            self._dest_df = self._if_df[self._if_df.ipAddressList.astype(str)
                                        .str.contains(dest + "/")]

        srcnet = self._src_df.ipAddressList.tolist()[0]
        if ip_address(dest) in ip_network(srcnet, strict=False):
            self.is_l2 = True
        else:
            self.is_l2 = False

        if self._dest_df.empty:
            # TODO: No host with this dest addr. Is addr a local ARP entry?
            self._dest_df = self._find_fhr_df(None, dest)

        if self._dest_df.empty:
            raise AttributeError(f"Invalid dest {dest}")

        if self._dest_df.hostname.nunique() == 1 and len(self._dest_df) > 1:
            # Multiple interfaces with the same IP address. Possible case
            # of Unnumbered interfaces. See if there's a loopback in there
            if 'loopback' in self._dest_df.type.unique().tolist():
                self._dest_df = self._dest_df.query('type == "loopback"')

        self.dest_device = self._dest_df["hostname"].unique()
        self.src_device = self._src_df["hostname"].unique()

        # Start with the source host and find its route to the destination
        if self._rdf[self._rdf["hostname"].isin(self.src_device)].empty:
            raise EmptyDataframeError(f"No routes found for {self.src_device}")
Beispiel #5
0
    def _init_dfs(self, namespace, source, dest):
        """Initialize the dataframes used in this path hunt"""

        self.source = source
        self.dest = dest
        self._underlay_dfs = {}  # lpm entries for each vtep IP

        try:
            self._if_df = interfaces.IfObj(context=self.ctxt) \
                                    .get(namespace=namespace,
                                         addnl_fields=['macaddr']) \
                                    .explode('ipAddressList') \
                                    .fillna({'ipAddressList': ''}) \
                                    .explode('ip6AddressList') \
                                    .fillna({'ip6AddressList': ''})
            if self._if_df.empty:
                raise EmptyDataframeError
        except (EmptyDataframeError, KeyError):
            raise EmptyDataframeError(
                f"No interface information found for {namespace}")

        try:
            self._rdf = routes.RoutesObj(context=self.ctxt) \
                              .lpm(namespace=namespace, address=dest)
            if self._rdf.empty:
                raise EmptyDataframeError
        except (KeyError, EmptyDataframeError):
            raise EmptyDataframeError(
                "No Routes information found for {}".format(dest))

        # We ignore the lack of ARPND for now
        self._arpnd_df = arpnd.ArpndObj(context=self.ctxt).get(
            namespace=namespace)
        if self._arpnd_df.empty:
            raise EmptyDataframeError(f"No ARPND information found for {dest}")

        # Enhance the ARPND table with the VRF field
        self._arpnd_df = self._arpnd_df.merge(
            self._if_df[['namespace', 'hostname', 'ifname', 'master']],
            left_on=['namespace', 'hostname', 'oif'],
            right_on=['namespace', 'hostname', 'ifname'], how='left') \
            .drop(columns=['ifname']) \
            .rename(columns={'master': 'vrf'}) \
            .replace({'vrf': {'': 'default'}})

        self._macsobj = macs.MacsObj(context=self.ctxt, namespace=namespace)

        if ':' in source:
            self._src_df = self._if_df[self._if_df.ip6AddressList.astype(
                str).str.contains(source + "/")]
        else:
            self._src_df = self._if_df[self._if_df.ipAddressList.astype(
                str).str.contains(source + "/")]

        if self._src_df.empty:
            # TODO: No host with this src addr. Is addr a local ARP entry?
            self._src_df = self._find_fhr_df(source)

        if self._src_df.empty:
            raise AttributeError(f"Invalid src {source}")

        if ':' in dest:
            self._dest_df = self._if_df[self._if_df.ip6AddressList.astype(
                str).str.contains(dest + "/")]
        else:
            self._dest_df = self._if_df[self._if_df.ipAddressList.astype(
                str).str.contains(dest + "/")]

        srcnet = self._src_df.ipAddressList.tolist()[0]
        if ip_address(dest) in ip_network(srcnet, strict=False):
            self.is_l2 = True
        else:
            self.is_l2 = False

        if self._dest_df.empty:
            # TODO: No host with this dest addr. Is addr a local ARP entry?
            self._dest_df = self._find_fhr_df(dest)

        if self._dest_df.empty:
            raise AttributeError(f"Invalid dest {dest}")

        self.dest_device = self._dest_df["hostname"].unique()
        self.src_device = self._src_df["hostname"].unique()

        # Start with the source host and find its route to the destination
        if self._rdf[self._rdf["hostname"].isin(self.src_device)].empty:
            raise EmptyDataframeError(f"No routes found for {self.src_device}")