Skip to content

Commit

Permalink
[fdborch] support mac update (sonic-net#877)
Browse files Browse the repository at this point in the history
Signed-off-by: leo.li <[email protected]>
  • Loading branch information
shine4chen authored and lguohan committed Aug 1, 2019
1 parent a5e6bea commit 9143018
Show file tree
Hide file tree
Showing 2 changed files with 266 additions and 8 deletions.
13 changes: 5 additions & 8 deletions orchagent/fdborch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,14 +442,6 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const
{
SWSS_LOG_ENTER();

if (m_entries.count(entry) != 0) // we already have such entries
{
// FIXME: should we check that the entry are moving to another port?
// FIXME: should we check that the entry are changing its type?
SWSS_LOG_ERROR("FDB entry already exists. mac=%s bv_id=0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id);
return true;
}

sai_fdb_entry_t fdb_entry;

fdb_entry.switch_id = gSwitchId;
Expand Down Expand Up @@ -490,6 +482,11 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const
attr.value.s32 = SAI_PACKET_ACTION_FORWARD;
attrs.push_back(attr);

if (m_entries.count(entry) != 0) // we already have such entries
{
removeFdbEntry(entry);
}

sai_status_t status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data());
if (status != SAI_STATUS_SUCCESS)
{
Expand Down
261 changes: 261 additions & 0 deletions tests/test_fdb_update.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
from swsscommon import swsscommon
import os
import sys
import time
import json
from distutils.version import StrictVersion

def create_entry(tbl, key, pairs):
fvs = swsscommon.FieldValuePairs(pairs)
tbl.set(key, fvs)

# FIXME: better to wait until DB create them
time.sleep(1)
def remove_entry(tbl, key):
tbl._del(key)
time.sleep(1)

def create_entry_tbl(db, table, key, pairs):
tbl = swsscommon.Table(db, table)
create_entry(tbl, key, pairs)

def remove_entry_tbl(db, table, key):
tbl = swsscommon.Table(db, table)
remove_entry(tbl, key)

def create_entry_pst(db, table, key, pairs):
tbl = swsscommon.ProducerStateTable(db, table)
create_entry(tbl, key, pairs)

def remove_entry_pst(db, table, key):
tbl = swsscommon.ProducerStateTable(db, table)
remove_entry(tbl, key)

def how_many_entries_exist(db, table):
tbl = swsscommon.Table(db, table)
return len(tbl.getKeys())

def get_mac_by_bridge_id(dvs, bridge_id):
tbl = swsscommon.Table(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY")
keys = tbl.getKeys()

mac = []
for key in keys:
(status, fvs) = tbl.get(key)
assert status
value = dict(fvs)
if value["SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID"] == bridge_id:
try:
d_key = json.loads(key)
except ValueError:
d_key = json.loads('{' + key + '}')
mac.append(d_key["mac"])
return mac

def test_FDBAddedAndUpdated(dvs, testlog):
dvs.setup_db()

dvs.runcmd("sonic-clear fdb all")
time.sleep(2)

# create a FDB entry in Application DB
create_entry_pst(
dvs.pdb,
"FDB_TABLE", "Vlan2:52-54-00-25-06-E9",
[
("port", "Ethernet0"),
("type", "dynamic"),
]
)

# check that the FDB entry wasn't inserted into ASIC DB
assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 0, "The fdb entry leaked to ASIC"

vlan_before = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN")
bp_before = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT")
vm_before = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER")

# create vlan
create_entry_tbl(
dvs.cdb,
"VLAN", "Vlan2",
[
("vlanid", "2"),
]
)

# create vlan member entry in Config db
create_entry_tbl(
dvs.cdb,
"VLAN_MEMBER", "Vlan2|Ethernet0",
[
("tagging_mode", "untagged"),
]
)

# check that the vlan information was propagated
vlan_after = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN")
bp_after = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT")
vm_after = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER")

assert vlan_after - vlan_before == 1, "The Vlan2 wasn't created"
assert bp_after - bp_before == 1, "The bridge port wasn't created"
assert vm_after - vm_before == 1, "The vlan member wasn't added"

# Get mapping between interface name and its bridge port_id
iface_2_bridge_port_id = dvs.get_map_iface_bridge_port_id(dvs.adb)

# check that the FDB entry was inserted into ASIC DB
assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The fdb entry wasn't inserted to ASIC"

ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY",
[("mac", "52-54-00-25-06-E9"), ("vlan", "2")],
[("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"),
("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"]),
('SAI_FDB_ENTRY_ATTR_PACKET_ACTION', 'SAI_PACKET_ACTION_FORWARD')]
)
assert ok, str(extra)

# create vlan member entry in Config DB
create_entry_tbl(
dvs.cdb,
"VLAN_MEMBER", "Vlan2|Ethernet4",
[
("tagging_mode", "untagged"),
]
)

# update FDB entry port in Application DB
create_entry_pst(
dvs.pdb,
"FDB_TABLE", "Vlan2:52-54-00-25-06-E9",
[
("port", "Ethernet4"),
("type", "dynamic"),
]
)

# Get mapping between interface name and its bridge port_id
iface_2_bridge_port_id = dvs.get_map_iface_bridge_port_id(dvs.adb)

ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY",
[("mac", "52-54-00-25-06-E9"), ("vlan", "2")],
[("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"),
("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet4"]),
('SAI_FDB_ENTRY_ATTR_PACKET_ACTION', 'SAI_PACKET_ACTION_FORWARD')]
)
assert ok, str(extra)

# remove FDB entry from Application DB
remove_entry_pst(
dvs.pdb,
"FDB_TABLE", "Vlan2:52-54-00-25-06-E9"
)

# remove vlan member entry from Config DB
remove_entry_tbl(
dvs.cdb,
"VLAN_MEMBER", "Vlan2|Ethernet4"
)
remove_entry_tbl(
dvs.cdb,
"VLAN_MEMBER", "Vlan2|Ethernet0"
)

#remove vlan entry from Config DB
remove_entry_tbl(
dvs.cdb,
"VLAN", "Vlan2"
)

def test_FDBLearnedAndUpdated(dvs, testlog):
dvs.setup_db()

dvs.runcmd("sonic-clear fdb all")

# create vlan; create vlan member
dvs.create_vlan("6")
dvs.create_vlan_member("6", "Ethernet64")
dvs.create_vlan_member("6", "Ethernet68")
dvs.create_vlan_member("6", "Ethernet72")

# Get mapping between interface name and its bridge port_id
time.sleep(2)
iface_2_bridge_port_id = dvs.get_map_iface_bridge_port_id(dvs.adb)

# bring up vlan and member
dvs.set_interface_status("Vlan6", "up")

dvs.add_ip_address("Vlan6", "6.6.6.1/24")

dvs.set_interface_status("Ethernet64", "up")
dvs.set_interface_status("Ethernet68", "up")
dvs.set_interface_status("Ethernet72", "up")

dvs.servers[16].runcmd("ifconfig eth0 hw ether 00:00:00:00:00:11")
dvs.servers[16].runcmd("ifconfig eth0 6.6.6.6/24 up")
dvs.servers[16].runcmd("ip route add default via 6.6.6.1")
dvs.servers[17].runcmd("ifconfig eth0 6.6.6.7/24 up")
dvs.servers[17].runcmd("ip route add default via 6.6.6.1")
time.sleep(2)

# get neighbor and arp entry
rc = dvs.servers[16].runcmd("ping -c 1 6.6.6.7")
assert rc == 0
rc = dvs.servers[17].runcmd("ping -c 1 6.6.6.6")
assert rc == 0
time.sleep(2)

# check that the FDB entries were inserted into ASIC DB
Ethernet64_mac = get_mac_by_bridge_id(dvs, iface_2_bridge_port_id["Ethernet64"])
assert "00:00:00:00:00:11" in Ethernet64_mac

# update FDB entry port in Application DB
create_entry_pst(
dvs.pdb,
"FDB_TABLE", "Vlan6:00-00-00-00-00-11",
[
("port", "Ethernet72"),
("type", "dynamic"),
]
)

# check that the FDB entry was updated in ASIC DB
Ethernet72_mac = get_mac_by_bridge_id(dvs, iface_2_bridge_port_id["Ethernet72"])
assert "00:00:00:00:00:11" in Ethernet72_mac, "Updating fdb entry to Ethernet72 failed"

Ethernet64_mac = get_mac_by_bridge_id(dvs, iface_2_bridge_port_id["Ethernet64"])
assert "00:00:00:00:00:11" not in Ethernet64_mac, "Updating fdb entry from Ethernet64 failed"

# remove FDB entry from Application DB
remove_entry_pst(
dvs.pdb,
"FDB_TABLE", "Vlan6:00-00-00-00-00-11"
)

# restore the default value of the servers
dvs.servers[16].runcmd("ip route del default via 6.6.6.1")
dvs.servers[16].runcmd("ifconfig eth0 0")
dvs.servers[17].runcmd("ip route del default via 6.6.6.1")
dvs.servers[17].runcmd("ifconfig eth0 0")

# bring down port
dvs.set_interface_status("Ethernet64", "down")
dvs.set_interface_status("Ethernet68", "down")
dvs.set_interface_status("Ethernet72", "down")

# remove vlan ip
key = "Vlan6" + "|" + "6.6.6.1/24"
remove_entry_tbl(dvs.cdb, "VLAN_INTERFACE", key)

# bring down vlan
dvs.set_interface_status("Vlan6", "down")

# remove vlan member; remove vlan
dvs.remove_vlan_member("6", "Ethernet64")
dvs.remove_vlan_member("6", "Ethernet68")
dvs.remove_vlan_member("6", "Ethernet72")
dvs.remove_vlan("6")

# clear fdb
dvs.runcmd("sonic-clear fdb all")

0 comments on commit 9143018

Please sign in to comment.