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}")
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
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
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}")
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}")