04-10-2020 07:04 AM
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
.
04-10-2020 07:37 AM
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": "" } } } ] }
04-10-2020 10:04 AM
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
04-10-2020 02:14 PM - edited 04-10-2020 02:15 PM
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
04-14-2020 12:18 AM
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.
04-14-2020 04:43 PM
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 @Sergiu.Daniluk 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
04-17-2020 07:41 AM
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
04-19-2020 12:03 PM
HI @tlequertier
The workflow I was thinking of is as follows.
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" } }
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide