diff --git a/src/netlink/cnetlink.cc b/src/netlink/cnetlink.cc index e9de4329..1445aa5b 100644 --- a/src/netlink/cnetlink.cc +++ b/src/netlink/cnetlink.cc @@ -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 @@ -663,11 +665,44 @@ 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); @@ -675,11 +710,8 @@ int cnetlink::update_on_mac_change(rtnl_link *old_link, rtnl_link *new_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 @@ -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; @@ -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; @@ -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: { @@ -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; diff --git a/src/netlink/cnetlink.h b/src/netlink/cnetlink.h index 2911df8f..96076438 100644 --- a/src/netlink/cnetlink.h +++ b/src/netlink/cnetlink.h @@ -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); diff --git a/src/netlink/nl_bond.cc b/src/netlink/nl_bond.cc index 7d693495..c90d990d 100644 --- a/src/netlink/nl_bond.cc +++ b/src/netlink/nl_bond.cc @@ -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; @@ -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__ diff --git a/src/netlink/nl_l3.cc b/src/netlink/nl_l3.cc index 032da9ea..abc906c5 100644 --- a/src/netlink/nl_l3.cc +++ b/src/netlink/nl_l3.cc @@ -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> - termination_mac_entries; - // ECMP mapping std::unordered_map, l3_interface> nh_grp_to_l3_ecmp_mapping; @@ -228,21 +224,6 @@ 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); @@ -250,7 +231,6 @@ int nl_l3::add_l3_addr(struct rtnl_addr *a) { 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; } @@ -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; } } @@ -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; @@ -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 @@ -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(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(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 {