cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
1315
Views
0
Helpful
7
Replies
Highlighted
Beginner

How to massively list all the MAC adresses related to an ACI LEAF ports?

Hi,

the context is a migration path : moving the servers and VMs 's Ethernet interfaces from old Legacy Nexus LAN Access switchs to the new  ACI LEAFs.

 

We want to check that after reconnecting all the Server's interface to the LEAFs , the LEAFs must get the knowledge of all the MAC addresses (of the servers / VMs) . It is the way we want to verify that the migration operation is OK by comparing the old list (show mac address-table on each Nexus's (ports) interfaces) with the new list.

 

But how can i build this list with ACI? How can i gather the list of all the MAC  ADRESSES associated to each LEAF port (interface) ? is there an ANSIBLE Playbook to help?

 

PS1 : i know the show endpoint commands , i know EP Enhanced Tracker but i don't find the answer there.

PS2 : perhaps there is also another to check the server migration is ok?.

 

Thanks  a lot for in advance for your advices

.

 

7 REPLIES 7
Highlighted
Enthusiast

Hi @tlequertier,

 

You can pull all the Macs via REST using the command below:
GET https://{{URL}}/api/node/class/fvCEp.json

 

You will get a JSON payload that looks something like below (from the Always on Sandbox).

You can get your current show Mac-address output using various methods, Netmiko, TextFSM, Ansible, Nornir, etc.

The trick is the comparison. Because there could be more than simple logic here I'd probably do this in Python and probably with Nornir.

Here is an example which is very similar to what you are trying to do based on a similar need I had (make sure all the IPs are there after a migration)

https://gratuitous-arp.net/pandas-for-network-engineers-who-doesnt-love-pandas/

 

{
    "totalCount": "4",
    "imdata": [
        {
            "fvCEp": {
                "attributes": {
                    "annotation": "",
                    "childAction": "",
                    "contName": "",
                    "dn": "uni/tn-SnV/ap-Rescue/epg-Web/cep-42:5D:BC:C4:00:00",
                    "encap": "vlan-123",
                    "extMngdBy": "",
                    "id": "0",
                    "idepdn": "",
                    "ip": "10.193.101.10",
                    "lcC": "learned",
                    "lcOwn": "local",
                    "mac": "42:5D:BC:C4:00:00",
                    "mcastAddr": "not-applicable",
                    "modTs": "2020-04-10T11:11:11.736+00:00",
                    "monPolDn": "uni/tn-common/monepg-default",
                    "name": "42:5D:BC:C4:00:00",
                    "nameAlias": "",
                    "status": "",
                    "uid": "0",
                    "uuid": "",
                    "vmmSrc": ""
                }
            }
        },
        {
            "fvCEp": {
                "attributes": {
                    "annotation": "",
                    "childAction": "",
                    "contName": "",
                    "dn": "uni/tn-SnV/ap-Evolution_X/epg-Web/cep-42:5D:BC:C4:00:00",
                    "encap": "vlan-121",
                    "extMngdBy": "",
                    "id": "0",
                    "idepdn": "",
                    "ip": "2222::65:a",
                    "lcC": "learned",
                    "lcOwn": "local",
                    "mac": "42:5D:BC:C4:00:00",
                    "mcastAddr": "not-applicable",
                    "modTs": "2020-04-10T11:11:11.736+00:00",
                    "monPolDn": "uni/tn-common/monepg-default",
                    "name": "42:5D:BC:C4:00:00",
                    "nameAlias": "",
                    "status": "",
                    "uid": "0",
                    "uuid": "",
                    "vmmSrc": ""
                }
            }
        },
        {
            "fvCEp": {
                "attributes": {
                    "annotation": "",
                    "childAction": "",
                    "contName": "",
                    "dn": "uni/tn-SnV/ap-Chaos/epg-Web/cep-42:5D:BC:C4:00:00",
                    "encap": "vlan-125",
                    "extMngdBy": "",
                    "id": "0",
                    "idepdn": "",
                    "ip": "10.193.101.10",
                    "lcC": "learned",
                    "lcOwn": "local",
                    "mac": "42:5D:BC:C4:00:00",
                    "mcastAddr": "not-applicable",
                    "modTs": "2020-04-10T11:11:11.736+00:00",
                    "monPolDn": "uni/tn-common/monepg-default",
                    "name": "42:5D:BC:C4:00:00",
                    "nameAlias": "",
                    "status": "",
                    "uid": "0",
                    "uuid": "",
                    "vmmSrc": ""
                }
            }
        },
        {
            "fvCEp": {
                "attributes": {
                    "annotation": "",
                    "childAction": "",
                    "contName": "",
                    "dn": "uni/tn-SnV/ap-Power_Up/epg-Web/cep-42:5D:BC:C4:00:00",
                    "encap": "vlan-127",
                    "extMngdBy": "",
                    "id": "0",
                    "idepdn": "",
                    "ip": "2222::65:a",
                    "lcC": "learned",
                    "lcOwn": "local",
                    "mac": "42:5D:BC:C4:00:00",
                    "mcastAddr": "not-applicable",
                    "modTs": "2020-04-10T11:11:11.736+00:00",
                    "monPolDn": "uni/tn-common/monepg-default",
                    "name": "42:5D:BC:C4:00:00",
                    "nameAlias": "",
                    "status": "",
                    "uid": "0",
                    "uuid": "",
                    "vmmSrc": ""
                }
            }
        }
    ]
}
Highlighted
Collaborator

Welcome to my world, my friend!

If I would be in charge of solving this problem, I would do it the easy way: python + APIC REST API + NX-API (as you mentioned you have nexus switches in your legacy network).

How to do it?

1. Make sure you have nxapi enabled on nexus switches

conf t
feature nxapi

2. Use a script to get all mac addresses from legacy network

import json
import requests

# add ip, user and password url='http://<ip-address>/ins' switchuser='admin' switchpassword='password'
# nxapi constructs myheaders={'content-type':'application/json'} payload={ "ins_api":{ "version": "1.0", "type": "cli_show", "chunk": "0", "sid": "1", "input": "show mac address-table dynamic ", "output_format": "json" } } response = requests.post(url, data=json.dumps(payload), headers=myheaders, auth=(switchuser, switchpassword)).json()
# filter the mac list
output_list = response['ins_api']['outputs']['output']['body']['TABLE_mac_address']['ROW_mac_address'] dynamic_mac_list = [mac['disp_mac_addr'].replace('.', '') for mac in output_list] dynamic_mac_list.sort()
# print them as well if you wish
print(dynamic_mac_list)
#save them to a file. change name from old_list to whatever name you want with open('old_list', 'w') as f: f.write('\n'.join(dynamic_mac_list))

3. After migration, use a script to get the mac addresses from APIC (this will include all MAC addresses learned from all leaves)

import json
import requests

#change with APIC IP base_url = 'http://<apic-ip>/api/' # change user and password name_pwd = {'aaaUser': {'attributes': {'name': 'admin', 'pwd': '<password>'}}} json_credentials = json.dumps(name_pwd) # log in to API login_url = base_url + 'aaaLogin.json' post_response = requests.post(login_url, data=json_credentials) # get token from login response structure auth = json.loads(post_response.text) login_attributes = auth['imdata'][0]['aaaLogin']['attributes'] auth_token = login_attributes['token'] # create cookie array from token cookies = {} cookies['APIC-Cookie'] = auth_token # read mac addresses sensor_url = base_url + 'node/class/fvCEp.json' r = requests.get(sensor_url, cookies=cookies, verify=False).json() mac_list = [ep['fvCEp']['attributes']['mac'].replace(':', '') for ep in r['imdata']] mac_list.sort() # print mac addresses if you wish print(mac_list) # write mac list to file with open('new_list', 'w') as f: f.write('\n'.join(mac_list))

4. Compare the two files. You can do that through linux diff function, or simply using notepad++/sublime if you are in windows.

 

Note: since nxos return the mac address in format AAAA.BBBB.CCCC and APIC return it in format AA:AA:BB:BB:CC:CC, I normalized the mac address to AAAABBBBCCCC. This is how they will be listed in the file.

 

Hope it helps,

Sergiu

 

 

Highlighted
Collaborator

Hi @tlequertier ,

You have some great answers here, but to me it seems that if you want to compare the output of show mac address-table from a set of Nexus switches, the easiest way would be to use the show mac address-table on the APIC!!

Here's how you issue a show mac address-table on the APIC for a reange of leaf switches, in my case I only have 2, so the range is 101-102

apic1# fabric 101-102 show mac address-table
----------------------------------------------------------------
 Node 101 (Leaf101)
----------------------------------------------------------------
Legend:
	* - primary entry, G - Gateway MAC, (R) - Routed MAC, O - Overlay MAC
	age - seconds since last seen,+ - primary entry using vPC Peer-Link,
	(T) - True, (F) - False
   VLAN     MAC Address      Type      age     Secure NTFY Ports/SWID.SSID.LID
---------+-----------------+--------+---------+------+----+------------------
* 18       a036.9f21.cbd4    dynamic      -       F    F    eth1/26
* 20       a036.9f56.206e    dynamic      -       F    F    eth1/15
* 23       a036.9f56.206c    dynamic      -       F    F    eth1/14
* 30       a036.9f61.88fe    dynamic      -       F    F    eth1/21

----------------------------------------------------------------
 Node 102 (Leaf102)
----------------------------------------------------------------
Legend:
	* - primary entry, G - Gateway MAC, (R) - Routed MAC, O - Overlay MAC
	age - seconds since last seen,+ - primary entry using vPC Peer-Link,
	(T) - True, (F) - False
   VLAN     MAC Address      Type      age     Secure NTFY Ports/SWID.SSID.LID
---------+-----------------+--------+---------+------+----+------------------
* 18       a036.9f21.cbd5    dynamic      -       F    F    eth1/26
* 22       a036.9f56.206f    dynamic      -       F    F    eth1/15
* 28       a036.9f61.88ff    dynamic      -       F    F    eth1/21
* 13       84b8.02f5.efd1    dynamic      -       F    F    eth1/47

And because the APIC CLI is zsh (bash), if you wanted just the mac addresses, you could do say

apic1# fabric 101-102 show mac address-table | grep dynamic | cut -b 12-26
a036.9f21.cbd4
a036.9f56.206e
a036.9f56.206c
a036.9f61.88fe
a036.9f21.cbd5
a036.9f56.206f
a036.9f61.88ff
84b8.02f5.efd1

I hope this helps


Don't forget to mark answers as correct if it solves your problem. This helps others find the correct answer if they search for the same problem


RedNectar
aka Chris Welsh


Don't forget to mark answers as correct if it solves your problem. This helps others find the correct answer if they search for the same problem

Highlighted

Good Morning,

 

at fist , many thanks Claudia, Sergiu and Chris for your answers.

 

I must digest some of them now :) ….to determine my way.

 

I will indicate my feedback to you.

Highlighted

Good luck @tlequertier !  Please do let us know what you find works best for you.

 

I put together an example python script that takes in the nx-os style output from show mac address-table and the JSON response from the REST query and uses a few Pandas (a python module) commands to do the comparison. 

 

The script is structured so that if you want to replace the function that loads the data with what @msdaniluk shared or with what @RedNectar shared you have examples of how to parse out the data (very simply) and do a comparison.

 

Script

https://github.com/cldeluna/pandas_neteng/blob/master/simple_mac_compare.py

 

Additional documentation

https://github.com/cldeluna/pandas_neteng/wiki


You wind up with something like this:

Found 1 MAC(s): 
  0_x  1_x               2        3 normalized_mac                0_y       1_y Exist
8   *  700  0050.5680.6564  dynamic   005056806564  00:50:56:80:65:64  vlan-700  both


22 MAC(s) MISSING: 
    0_x  1_x               2        3 normalized_mac                0_y       1_y       Exist
0     *   98  0008.e3ff.fd8c  dynamic   0008e3fffd8c                NaN       NaN   left_only
1     *  704  0008.e3ff.fd8c  dynamic   0008e3fffd8c                NaN       NaN   left_only
2     *  699  0008.e3ff.fd8c  dynamic   0008e3fffd8c                NaN       NaN   left_only
3     *   98  0050.5684.5b01  dynamic   005056845b01                NaN       NaN   left_only
4     *   99  0000.0000.0100  dynamic   000000000100                NaN       NaN   left_only
5     *  750  a025.b5f2.5000  dynamic   a025b5f25000                NaN       NaN   left_only
6     *  750  a025.b5f2.5004  dynamic   a025b5f25004                NaN       NaN   left_only
7     *  700  0050.5680.5f61  dynamic   005056805f61                NaN       NaN   left_only
9     *  700  0050.5684.5f2f  dynamic   005056845f2f                NaN       NaN   left_only
10    *  700  0050.5684.cca7  dynamic   00505684cca7                NaN       NaN   left_only
11    *  700  0050.5684.d66e  dynamic   00505684d66e                NaN       NaN   left_only
12    *  700  80e0.1d37.1e18  dynamic   80e01d371e18                NaN       NaN   left_only
13    *  700  80e0.1d37.1e1e  dynamic   80e01d371e1e                NaN       NaN   left_only
14    +  700  80e0.1d37.2b7c  dynamic   80e01d372b7c                NaN       NaN   left_only
15    *  700  80e0.1d37.2b82  dynamic   80e01d372b82                NaN       NaN   left_only
16    +  700  e4aa.5dac.81f6  dynamic   e4aa5dac81f6                NaN       NaN   left_only
17    *  700  e4aa.5dac.81f7  dynamic   e4aa5dac81f7                NaN       NaN   left_only
18    *  699  02a0.98d3.71f5  dynamic   02a098d371f5                NaN       NaN   left_only
19  NaN  NaN             NaN      NaN   425dbcc40000  42:5D:BC:C4:00:00  vlan-123  right_only
20  NaN  NaN             NaN      NaN   425dbcc40000  42:5D:BC:C4:00:00  vlan-121  right_only
21  NaN  NaN             NaN      NaN   425dbcc40000  42:5D:BC:C4:00:00  vlan-125  right_only
22  NaN  NaN             NaN      NaN   425dbcc40000  42:5D:BC:C4:00:00  vlan-127  right_only


============== SUMMARY ============== 
Of 23 Total MACs both legacy and ACI: 
        - FOUND         1 
        - MISSING       22 
Highlighted

I get two addtional sub-questions : 

1)  You explained  how to use (it is one of the methods you indicated to me) the REST/API command :  GET https://{{URL}}/api/node/class/fvCEp.json

I will process the migration that way : the servers connected to the legacy LAN 2 x Nexus 7018 cards (ex F1) will be deconnected and then reconnected to 2 x LEAFs (N9k-c93180yc-fx).

==> Can i use the above "api/rest" command by specifying only the 2 Leafs Nodeids? so i could only collect the MAC adresses that are involved in my migration Step (related to 2 Leafs only) ?  (/node/class => /Leaf101/class or something like that? )

 

2)  i discover also /api/class/fvRsCEpToPathEp.json  that seems to permit to get the  Leaf Nodeid,  the Port number and the MACs 

What could be your best recommendation ? is there some disavantages to use that command? 

can also use it spercifying only 2 Leafs instead of getting all the MACs/Ports/Leaf Nodeids? 

 

Many thanks in advance for your advices.

Have a good and safe weekend 

Thierry

 

 

 

Highlighted

HI @tlequertier 

 

The workflow I was thinking of is as follows.

  1. Run show mac address-table on the legacy Nexus switch and save that output
  2. After migration pull the mac address table from the fabric with GET https://{{URL}}/api/node/class/fvCEp.json
  3. Compare and look for the MACs in Step 1 in the fabric 

So to answer your first question, you can filter the fvCEp results but the response does not have the node information.  You can filter by EPG or encapsulation for example by looking for values in the dn (or other attributes or keys that are returned in the response).

 

Example: Filter the fvCEp class objects by a wildcard value (think "contains") in the DN.  This will return any fvCEp objects that have "web" in the dn (web in this case would be the EPG name)

/api/node/class/fvCEp.json?query-target-filter=and(wcard(fvCEp.dn,"web"))&order-by=fvCEp.modTs|desc

 

Example: Filter the fvCEp class objects by a wildcard value (think "contains") in the DN,  This will return any fvCEp objects that have "Heroes" in the DN and here "Heroes" would be the tenant name.

/api/node/class/fvCEp.json?query-target-filter=and(wcard(fvCEp.dn,"Heroes"))&order-by=fvCEp.modTs|desc

 

Example:  Filter the fvCEp class objects on the value of the key "encap" looking for fvCEp objects with a vlan encapsulation of "200" 

/api/node/class/fvCEp.json?query-target-filter=and(eq(fvCEp.encap,"vlan-200"))&order-by=fvCEp.modTs|desc

 

Question Number 2: 

 

fvRsCEpToPathEp class objects will return something like the example below.   You can use these objects and filter first on tDn or dn to filter out the node ids you want and then you will have to filter on dn (see examples above) to look for the MACs as they are embedded in the dn.  with fvCEp they are available in their own key (that is it is specifically called out as an attribute in the response).  

 

fvCEP: "mac": "45:CD:BB:C0:00:00",

 

fvRsCEpToPathEp:   "dn": "uni/tn-Heroes/ap-Save_The_Planet/epg-db/cep-44:CD:BB:C0:00:00/rscEpToPathEp-[topology/pod-1/protpaths-101-102/pathep-[Heroes_FI-2A]]",

 

Using fvCEP objects can help you answer the question. "Is my MAC seen on the ACI fabric?" (can also help with EPG, ANP, Tenant, and IP)

 

Using fvRsCEpToPathEp objects can help you answer the question "Is my MAC seen on this leaf node?" (can also help with Tenant, EPG, ANP and interface constructs)

 

To use the sample script I shared, you would need to take the response to your fvRsCEpToPathEp request and parse out the MAC, normalize it, and then merge the two data sets into a new view but you can also do this just with python iterating over the data, filtering as you need to, and looking for the NX-OS macs.

 

The other option is to do what @RedNectar suggested and run the NX-OS style command on your leaf, save that output and you already have an example of how to parse that out.

 

fvRsCEpToPathEp class object example:

  {
            "fvRsCEpToPathEp": {
                "attributes": {
                    "childAction": "",
                    "dn": "uni/tn-Heroes/ap-Save_The_Planet/epg-db/cep-44:CD:BB:C0:00:00/rscEpToPathEp-[topology/pod-1/protpaths-101-102/pathep-[Heroes_FI-2A]]",
                    "forceResolve": "yes",
                    "lcC": "learned",
                    "lcOwn": "local",
                    "modTs": "2020-04-19T20:02:20.576+00:00",
                    "rType": "mo",
                    "state": "formed",
                    "stateQual": "none",
                    "status": "",
                    "tCl": "fabricAPathEp",
                    "tDn": "topology/pod-1/protpaths-101-102/pathep-[Heroes_FI-2A]",
                    "tType": "mo"
                }
            }