Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 43 additions & 5 deletions src/netlink/cnetlink.cc
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,8 @@ int cnetlink::add_l3_configuration(rtnl_link *link) {

// add all ip addresses and routes from collected interfaces
for (auto l : links) {
add_termination_mac(l);

rv = add_l3_addresses(l);
if (rv < 0)
LOG(WARNING) << __FUNCTION__ << ": failed to add l3 addresses (" << rv
Expand Down Expand Up @@ -663,23 +665,53 @@ int cnetlink::remove_l3_configuration(rtnl_link *link) {
if (rv < 0)
LOG(WARNING) << __FUNCTION__ << ": failed to remove l3 addresses (" << rv
<< " from link " << l;
remove_termination_mac(l);
}

return rv;
}

int cnetlink::add_termination_mac(rtnl_link *link) {
struct nl_addr *addr = rtnl_link_get_addr(link);
auto mac = rofl::caddress_ll((uint8_t *)nl_addr_get_binary_addr(addr),
nl_addr_get_len(addr));
uint32_t port_id = get_port_id(link);
uint16_t vid = 0;

if (rtnl_link_is_vlan(link))
vid = rtnl_link_vlan_get_id(link);

swi->l3_termination_add(port_id, vid, mac);
swi->l3_termination_add_v6(port_id, vid, mac);

return 0;
}

int cnetlink::remove_termination_mac(rtnl_link *link) {
struct nl_addr *addr = rtnl_link_get_addr(link);
auto mac = rofl::caddress_ll((uint8_t *)nl_addr_get_binary_addr(addr),
nl_addr_get_len(addr));
uint32_t port_id = get_port_id(link);
uint16_t vid = 0;

if (rtnl_link_is_vlan(link))
vid = rtnl_link_vlan_get_id(link);

swi->l3_termination_remove_v6(port_id, vid, mac);
swi->l3_termination_remove(port_id, vid, mac);

return 0;
}

int cnetlink::update_on_mac_change(rtnl_link *old_link, rtnl_link *new_link) {
int rv = 0;
int port_id = get_port_id(old_link);
uint16_t vid = vlan->get_vid(old_link);
struct nl_addr *old_mac = rtnl_link_get_addr(old_link);
struct nl_addr *new_mac = rtnl_link_get_addr(new_link);

rv = l3->update_l3_termination(port_id, vid, old_mac, new_mac);
if (rv < 0)
VLOG(1) << __FUNCTION__
<< ": failed to update termination MAC, old link=" << old_link
<< " new link=" << new_link;
remove_termination_mac(old_link);
add_termination_mac(new_link);

// In response to the MAC address change on the interface, linux deletes the
// neighbors configured on the interface. We are tracking the state
Expand Down Expand Up @@ -1512,6 +1544,8 @@ void cnetlink::link_created(rtnl_link *link) noexcept {
VLOG(1) << __FUNCTION__ << ": new vlan interface " << link;
uint16_t vid = rtnl_link_vlan_get_id(link);
vlan->add_vlan(link, vid, true);
if (is_switch_interface(link))
add_termination_mac(link);
} break;
case LT_BOND: {
VLOG(1) << __FUNCTION__ << ": new bond interface " << link;
Expand All @@ -1533,6 +1567,7 @@ void cnetlink::link_created(rtnl_link *link) noexcept {
swi->port_set_move_learn(
port_id, switch_interface::
SAI_BRIDGE_PORT_FDB_LEARNING_MODE_FDB_LOG_NOTIFICATION);
add_termination_mac(link);
} else {
LOG(WARNING) << __FUNCTION__ << ": ignoring link with lt=" << lt
<< " link:" << link;
Expand Down Expand Up @@ -1732,6 +1767,7 @@ void cnetlink::link_deleted(rtnl_link *link) noexcept {
bridge = nullptr;
} else {
ignored_bridges.erase(rtnl_link_get_ifindex(link));
remove_termination_mac(link);
}
break;
case LT_VXLAN: {
Expand All @@ -1748,6 +1784,8 @@ void cnetlink::link_deleted(rtnl_link *link) noexcept {
case LT_VLAN:
VLOG(1) << __FUNCTION__ << ": removed vlan interface " << link;
vlan->remove_vlan(link, rtnl_link_vlan_get_id(link), true);
if (is_switch_interface(link))
remove_termination_mac(link);
break;
case LT_BOND: {
VLOG(1) << __FUNCTION__ << ": removed bond interface " << link;
Expand Down
3 changes: 3 additions & 0 deletions src/netlink/cnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ class cnetlink final : public rofl::cthread_env {
int add_l3_configuration(rtnl_link *link);
int remove_l3_configuration(rtnl_link *link);

int add_termination_mac(rtnl_link *link);
int remove_termination_mac(rtnl_link *link);

int update_on_mac_change(rtnl_link *old_link, rtnl_link *new_link);

bool has_l3_addresses(rtnl_link *link);
Expand Down
4 changes: 4 additions & 0 deletions src/netlink/nl_bond.cc
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ int nl_bond::add_lag(rtnl_link *bond) {
nl->link_created(br_link);
}
}
nl->add_termination_mac(bond);

#endif

return rv;
Expand All @@ -162,6 +164,8 @@ int nl_bond::remove_lag(rtnl_link *bond) {
return -ENODEV;
}

nl->remove_termination_mac(bond);

rv = swi->lag_remove(it->second);
if (rv < 0) {
LOG(ERROR) << __FUNCTION__
Expand Down
176 changes: 0 additions & 176 deletions src/netlink/nl_l3.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,6 @@ std::unordered_map<
l3_interface>
l3_interface_mapping;

// key: source port_id, vid, src_mac, af ; value: refcount
std::unordered_set<std::tuple<int, uint16_t, rofl::caddress_ll, uint16_t>>
termination_mac_entries;

// ECMP mapping
std::unordered_map<std::set<nh_stub>, l3_interface> nh_grp_to_l3_ecmp_mapping;

Expand Down Expand Up @@ -228,29 +224,13 @@ int nl_l3::add_l3_addr(struct rtnl_addr *a) {
return -EINVAL;
}

// XXX TODO split this into several functions
if (!is_loopback) {
int port_id = nl->get_port_id(link);
auto addr = rtnl_link_get_addr(link);
rofl::caddress_ll mac = libnl_lladdr_2_rofl(addr);

rv = add_l3_termination(port_id, vid, mac, AF_INET);
if (rv < 0) {
LOG(ERROR) << __FUNCTION__
<< ": failed to setup termination mac port_id=" << port_id
<< ", vid=" << vid << " mac=" << mac << "; rv=" << rv;
return rv;
}
}

// get v4 dst (local v4 addr)
auto prefixlen = rtnl_addr_get_prefixlen(a);
auto addr = rtnl_addr_get_local(a);
rofl::caddress_in4 ipv4_dst = libnl_in4addr_2_rofl(addr, &rv);
rofl::caddress_in4 mask = rofl::build_mask_in4(prefixlen);

if (rv < 0) {
// TODO shall we remove the l3_termination mac?
LOG(ERROR) << __FUNCTION__ << ": could not parse addr " << addr;
return rv;
}
Expand Down Expand Up @@ -281,7 +261,6 @@ int nl_l3::add_l3_addr(struct rtnl_addr *a) {
if (prefixlen == 32) {
rv = sw->l3_unicast_host_add(ipv4_dst, 0, false, update, vrf_id);
if (rv < 0) {
// TODO shall we remove the l3_termination mac?
LOG(ERROR) << __FUNCTION__ << ": failed to setup l3 addr " << addr;
}
}
Expand Down Expand Up @@ -332,20 +311,6 @@ int nl_l3::add_l3_addr_v6(struct rtnl_addr *a) {

uint16_t vid = vlan->get_vid(link);

if (!is_loopback) {
int port_id = nl->get_port_id(link);
auto addr = rtnl_link_get_addr(link);
rofl::caddress_ll mac = libnl_lladdr_2_rofl(addr);

rv = add_l3_termination(port_id, vid, mac, AF_INET6);
if (rv < 0) {
LOG(ERROR) << __FUNCTION__
<< ": failed to setup termination mac port_id=" << port_id
<< ", vid=" << vid << " mac=" << mac << "; rv=" << rv;
return rv;
}
}

if (is_loopback) {
rv = add_lo_addr_v6(a);
return rv;
Expand Down Expand Up @@ -520,20 +485,6 @@ int nl_l3::del_l3_addr(struct rtnl_addr *a) {
get_l3_addrs(other, &addresses, family);
}

if (addresses.empty()) {
int port_id = nl->get_port_id(link);

addr = rtnl_link_get_addr(link);
rofl::caddress_ll mac = libnl_lladdr_2_rofl(addr);

rv = del_l3_termination(port_id, vid, mac, family);
if (rv < 0 && rv != -ENODATA) {
LOG(ERROR) << __FUNCTION__
<< ": failed to remove l3 termination mac(local) vid=" << vid
<< "; rv=" << rv;
}
}

// del vlan
// Avoid deleting table VLAN entry for the following two cases
// Loopback: does not require entry on the Ingress table
Expand Down Expand Up @@ -1233,133 +1184,6 @@ int nl_l3::del_l3_route(struct rtnl_route *r) {
}
}

int nl_l3::add_l3_termination(uint32_t port_id, uint16_t vid,
const rofl::caddress_ll &mac, int af) noexcept {
int rv = 0;

// lookup if this already exists
auto needle = std::make_tuple(port_id, vid, mac, static_cast<uint16_t>(af));
auto it = termination_mac_entries.find(needle);
if (it != termination_mac_entries.end())
return 0;

termination_mac_entries.emplace(std::move(needle));

switch (af) {
case AF_INET:
rv = sw->l3_termination_add(port_id, vid, mac);
break;

case AF_INET6:
rv = sw->l3_termination_add_v6(port_id, vid, mac);
break;

default:
LOG(FATAL) << __FUNCTION__ << ": invalid address family " << af;
break;
}

if (rv == 0)

VLOG(3) << __FUNCTION__ << ": added l3 termination for port=" << port_id
<< " vid=" << vid << " mac=" << mac << " af=" << af;

return rv;
}

int nl_l3::del_l3_termination(uint32_t port_id, uint16_t vid,
const rofl::caddress_ll &mac, int af) noexcept {
int rv = 0;

VLOG(4) << __FUNCTION__ << ": trying to delete for port_id=" << port_id
<< ", vid=" << vid << ", mac=" << mac << ", af=" << af;

// lookup if this exists
auto needle = std::make_tuple(port_id, vid, mac, static_cast<uint16_t>(af));
auto it = termination_mac_entries.find(needle);
if (it == termination_mac_entries.end()) {
LOG(WARNING)
<< __FUNCTION__
<< ": tried to delete a non existing termination mac for port_id="
<< port_id << ", vid=" << vid << ", mac=" << mac << ", af=" << af;
return -ENODATA;
}

switch (af) {
case AF_INET:
rv = sw->l3_termination_remove(port_id, vid, mac);
break;

case AF_INET6:
rv = sw->l3_termination_remove_v6(port_id, vid, mac);
break;

default:
LOG(FATAL) << __FUNCTION__ << ": invalid address family " << af;
break;
}

termination_mac_entries.erase(it);

return rv;
}

int nl_l3::update_l3_termination(int port_id, uint16_t vid,
struct nl_addr *old_mac,
struct nl_addr *new_mac) noexcept {
int rv = 0;

auto o_mac = libnl_lladdr_2_rofl(old_mac);
auto n_mac = libnl_lladdr_2_rofl(new_mac);

// parse the AF list and remove the entry from the termination mac set
// call the switch function to remove and insert the entry with the
// new mac address.
if (termination_mac_entries.find(std::make_tuple(
port_id, vid, o_mac, AF_INET)) != termination_mac_entries.end()) {
rv = del_l3_termination(port_id, vid, o_mac, AF_INET);
if (rv < 0)
VLOG(3) << __FUNCTION__
<< ": failed to remove termination mac port=" << port_id
<< " vid=" << vid << " mac=" << o_mac;
rv = add_l3_termination(port_id, vid, n_mac, AF_INET);
if (rv < 0) {
VLOG(3) << __FUNCTION__
<< ": failed to add termination mac port=" << port_id
<< " vid=" << vid << " mac=" << n_mac;
return rv;
}

VLOG(2) << __FUNCTION__
<< ": updated Termination MAC for port_id=" << port_id
<< " old mac address=" << o_mac << " new mac address=" << n_mac
<< " AF=" << AF_INET;
}

if (termination_mac_entries.find(std::make_tuple(
port_id, vid, o_mac, AF_INET6)) != termination_mac_entries.end()) {
rv = del_l3_termination(port_id, vid, o_mac, AF_INET6);
if (rv < 0)
VLOG(3) << __FUNCTION__
<< ": failed to remove termination mac port=" << port_id
<< " vid=" << vid << " mac=" << o_mac;
rv = add_l3_termination(port_id, vid, n_mac, AF_INET6);
if (rv < 0) {
VLOG(3) << __FUNCTION__
<< ": failed to add termination mac port=" << port_id
<< " vid=" << vid << " mac=" << n_mac;
return rv;
}

VLOG(2) << __FUNCTION__
<< ": updated Termination MAC for port_id=" << port_id
<< " old mac address=" << o_mac << " new mac address=" << n_mac
<< " AF=" << AF_INET6;
}

return rv;
}

int nl_l3::update_l3_egress(int port_id, uint16_t vid, struct nl_addr *old_mac,
struct nl_addr *new_mac) noexcept {

Expand Down
Loading