Skip to content

Commit ea27328

Browse files
committed
rework termination mac handling
Rework termination mac handling by tying termination mac entries to interfaces: * create entries on interface creation * remove them on interface deletion with the values of * port_id, vid 0 for the base port/bond interface (any vid) * port_id, vid for vlan interfaces on top of those * port_id 0, vid 0 for the base bridge interface (any port, any vid) * port_id 0, vid for vlan interface on top of bridge Since these combinations are unique, we can just add/remove the entries without the need of having refcounts. Advantages: * simplication of code * ip addresses assigned to lo will just work Disadvantages: * higher use of termination mac flows, which are limited (0.5k to 1k), so only (256 - ports) to (512 - ports) number of vlan/bridge/bond interfaces are supported * (this is a lie though, since both termination mac entries for an interface share the same underlying resource) Signed-off-by: Jonas Gorski <jonas.gorski@bisdn.de>
1 parent 3c6cdba commit ea27328

File tree

4 files changed

+50
-180
lines changed

4 files changed

+50
-180
lines changed

src/netlink/cnetlink.cc

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,8 @@ int cnetlink::add_l3_configuration(rtnl_link *link) {
568568

569569
// add all ip addresses and routes from collected interfaces
570570
for (auto l : links) {
571+
add_termination_mac(l);
572+
571573
rv = add_l3_addresses(l);
572574
if (rv < 0)
573575
LOG(WARNING) << __FUNCTION__ << ": failed to add l3 addresses (" << rv
@@ -601,22 +603,53 @@ int cnetlink::remove_l3_configuration(rtnl_link *link) {
601603
if (rv < 0)
602604
LOG(WARNING) << __FUNCTION__ << ": failed to remove l3 addresses (" << rv
603605
<< " from link " << OBJ_CAST(l);
606+
remove_termination_mac(l);
604607
}
605608

606609
return rv;
607610
}
608611

612+
int cnetlink::add_termination_mac(rtnl_link *link) {
613+
struct nl_addr *addr = rtnl_link_get_addr(link);
614+
auto mac = rofl::caddress_ll((uint8_t *)nl_addr_get_binary_addr(addr),
615+
nl_addr_get_len(addr));
616+
uint32_t port_id = get_port_id(link);
617+
uint16_t vid = 0;
618+
619+
if (rtnl_link_is_vlan(link))
620+
vid = rtnl_link_vlan_get_id(link);
621+
622+
swi->l3_termination_add(port_id, vid, mac);
623+
swi->l3_termination_add_v6(port_id, vid, mac);
624+
625+
return 0;
626+
}
627+
628+
int cnetlink::remove_termination_mac(rtnl_link *link) {
629+
struct nl_addr *addr = rtnl_link_get_addr(link);
630+
auto mac = rofl::caddress_ll((uint8_t *)nl_addr_get_binary_addr(addr),
631+
nl_addr_get_len(addr));
632+
uint32_t port_id = get_port_id(link);
633+
uint16_t vid = 0;
634+
635+
if (rtnl_link_is_vlan(link))
636+
vid = rtnl_link_vlan_get_id(link);
637+
638+
swi->l3_termination_remove_v6(port_id, vid, mac);
639+
swi->l3_termination_remove(port_id, vid, mac);
640+
641+
return 0;
642+
}
643+
609644
int cnetlink::update_on_mac_change(rtnl_link *old_link, rtnl_link *new_link) {
610645
int rv = 0;
611646
int port_id = get_port_id(old_link);
612647
uint16_t vid = vlan->get_vid(old_link);
613648
struct nl_addr *old_mac = rtnl_link_get_addr(old_link);
614649
struct nl_addr *new_mac = rtnl_link_get_addr(new_link);
615650

616-
rv = l3->update_l3_termination(port_id, vid, old_mac, new_mac);
617-
if (rv < 0)
618-
VLOG(1) << __FUNCTION__ << ": failed to update termination MAC, old link="
619-
<< OBJ_CAST(old_link) << " new link=" << OBJ_CAST(new_link);
651+
remove_termination_mac(old_link);
652+
add_termination_mac(new_link);
620653

621654
// In response to the MAC address change on the interface, linux deletes the
622655
// neighbors configured on the interface. We are tracking the state
@@ -1343,6 +1376,8 @@ void cnetlink::link_created(rtnl_link *link) noexcept {
13431376
VLOG(1) << __FUNCTION__ << ": new vlan interface " << OBJ_CAST(link);
13441377
uint16_t vid = rtnl_link_vlan_get_id(link);
13451378
vlan->add_vlan(link, vid, true);
1379+
if (is_switch_interface(link))
1380+
add_termination_mac(link);
13461381
} break;
13471382
case LT_BOND: {
13481383
VLOG(1) << __FUNCTION__ << ": new bond interface " << OBJ_CAST(link);
@@ -1358,6 +1393,7 @@ void cnetlink::link_created(rtnl_link *link) noexcept {
13581393

13591394
port_man->set_offloaded(link, FLAGS_mark_fwd_offload);
13601395
swi->port_set_config(port_id, port_man->get_hwaddr(port_id), false);
1396+
add_termination_mac(link);
13611397
} else {
13621398
LOG(WARNING) << __FUNCTION__ << ": ignoring link with lt=" << lt
13631399
<< " link:" << OBJ_CAST(link);
@@ -1534,6 +1570,7 @@ void cnetlink::link_deleted(rtnl_link *link) noexcept {
15341570
bridge->clear_tpid_entries(); // clear the Egress TPID table
15351571
delete bridge;
15361572
bridge = nullptr;
1573+
remove_termination_mac(link);
15371574
}
15381575
break;
15391576
case LT_VXLAN: {
@@ -1550,6 +1587,8 @@ void cnetlink::link_deleted(rtnl_link *link) noexcept {
15501587
case LT_VLAN:
15511588
VLOG(1) << __FUNCTION__ << ": removed vlan interface " << OBJ_CAST(link);
15521589
vlan->remove_vlan(link, rtnl_link_vlan_get_id(link), true);
1590+
if (is_switch_interface(link))
1591+
remove_termination_mac(link);
15531592
break;
15541593
case LT_BOND: {
15551594
VLOG(1) << __FUNCTION__ << ": removed bond interface " << OBJ_CAST(link);

src/netlink/cnetlink.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class cnetlink final : public rofl::cthread_env {
6666
int add_l3_configuration(rtnl_link *link);
6767
int remove_l3_configuration(rtnl_link *link);
6868

69+
int add_termination_mac(rtnl_link *link);
70+
int remove_termination_mac(rtnl_link *link);
71+
6972
int update_on_mac_change(rtnl_link *old_link, rtnl_link *new_link);
7073

7174
bool has_l3_addresses(rtnl_link *link);

src/netlink/nl_bond.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ int nl_bond::add_lag(rtnl_link *bond) {
142142
swi->lag_remove(lag_id);
143143
}
144144

145+
nl->add_termination_mac(bond);
146+
145147
#endif
146148

147149
return rv;
@@ -158,6 +160,8 @@ int nl_bond::remove_lag(rtnl_link *bond) {
158160
return -ENODEV;
159161
}
160162

163+
nl->remove_termination_mac(bond);
164+
161165
rv = swi->lag_remove(it->second);
162166
if (rv < 0) {
163167
LOG(ERROR) << __FUNCTION__

src/netlink/nl_l3.cc

Lines changed: 0 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,6 @@ std::unordered_map<
6969
l3_interface>
7070
l3_interface_mapping;
7171

72-
// key: source port_id, vid, src_mac, af ; value: refcount
73-
std::unordered_set<std::tuple<int, uint16_t, rofl::caddress_ll, uint16_t>>
74-
termination_mac_entries;
75-
7672
// ECMP mapping
7773
std::unordered_multimap<std::set<uint32_t>, l3_interface> l3_ecmp_mapping;
7874

@@ -191,29 +187,13 @@ int nl_l3::add_l3_addr(struct rtnl_addr *a) {
191187
return -EINVAL;
192188
}
193189

194-
// XXX TODO split this into several functions
195-
if (!is_loopback) {
196-
int port_id = nl->get_port_id(link);
197-
auto addr = rtnl_link_get_addr(link);
198-
rofl::caddress_ll mac = libnl_lladdr_2_rofl(addr);
199-
200-
rv = add_l3_termination(port_id, vid, mac, AF_INET);
201-
if (rv < 0) {
202-
LOG(ERROR) << __FUNCTION__
203-
<< ": failed to setup termination mac port_id=" << port_id
204-
<< ", vid=" << vid << " mac=" << mac << "; rv=" << rv;
205-
return rv;
206-
}
207-
}
208-
209190
// get v4 dst (local v4 addr)
210191
auto prefixlen = rtnl_addr_get_prefixlen(a);
211192
auto addr = rtnl_addr_get_local(a);
212193
rofl::caddress_in4 ipv4_dst = libnl_in4addr_2_rofl(addr, &rv);
213194
rofl::caddress_in4 mask = rofl::build_mask_in4(prefixlen);
214195

215196
if (rv < 0) {
216-
// TODO shall we remove the l3_termination mac?
217197
LOG(ERROR) << __FUNCTION__ << ": could not parse addr " << addr;
218198
return rv;
219199
}
@@ -248,7 +228,6 @@ int nl_l3::add_l3_addr(struct rtnl_addr *a) {
248228
if (prefixlen == 32) {
249229
rv = sw->l3_unicast_host_add(ipv4_dst, 0, false, update, vrf_id);
250230
if (rv < 0) {
251-
// TODO shall we remove the l3_termination mac?
252231
LOG(ERROR) << __FUNCTION__ << ": failed to setup l3 addr " << addr;
253232
}
254233
}
@@ -299,20 +278,6 @@ int nl_l3::add_l3_addr_v6(struct rtnl_addr *a) {
299278

300279
uint16_t vid = vlan->get_vid(link);
301280

302-
if (!is_loopback) {
303-
int port_id = nl->get_port_id(link);
304-
auto addr = rtnl_link_get_addr(link);
305-
rofl::caddress_ll mac = libnl_lladdr_2_rofl(addr);
306-
307-
rv = add_l3_termination(port_id, vid, mac, AF_INET6);
308-
if (rv < 0) {
309-
LOG(ERROR) << __FUNCTION__
310-
<< ": failed to setup termination mac port_id=" << port_id
311-
<< ", vid=" << vid << " mac=" << mac << "; rv=" << rv;
312-
return rv;
313-
}
314-
}
315-
316281
if (is_loopback) {
317282
rv = add_lo_addr_v6(a);
318283
return rv;
@@ -491,20 +456,6 @@ int nl_l3::del_l3_addr(struct rtnl_addr *a) {
491456
get_l3_addrs(other, &addresses, family);
492457
}
493458

494-
if (addresses.empty()) {
495-
int port_id = nl->get_port_id(link);
496-
497-
addr = rtnl_link_get_addr(link);
498-
rofl::caddress_ll mac = libnl_lladdr_2_rofl(addr);
499-
500-
rv = del_l3_termination(port_id, vid, mac, family);
501-
if (rv < 0 && rv != -ENODATA) {
502-
LOG(ERROR) << __FUNCTION__
503-
<< ": failed to remove l3 termination mac(local) vid=" << vid
504-
<< "; rv=" << rv;
505-
}
506-
}
507-
508459
// del vlan
509460
// Avoid deleting table VLAN entry for the following two cases
510461
// Loopback: does not require entry on the Ingress table
@@ -1223,133 +1174,6 @@ int nl_l3::del_l3_route(struct rtnl_route *r) {
12231174
}
12241175
}
12251176

1226-
int nl_l3::add_l3_termination(uint32_t port_id, uint16_t vid,
1227-
const rofl::caddress_ll &mac, int af) noexcept {
1228-
int rv = 0;
1229-
1230-
// lookup if this already exists
1231-
auto needle = std::make_tuple(port_id, vid, mac, static_cast<uint16_t>(af));
1232-
auto it = termination_mac_entries.find(needle);
1233-
if (it != termination_mac_entries.end())
1234-
return 0;
1235-
1236-
termination_mac_entries.emplace(std::move(needle));
1237-
1238-
switch (af) {
1239-
case AF_INET:
1240-
rv = sw->l3_termination_add(port_id, vid, mac);
1241-
break;
1242-
1243-
case AF_INET6:
1244-
rv = sw->l3_termination_add_v6(port_id, vid, mac);
1245-
break;
1246-
1247-
default:
1248-
LOG(FATAL) << __FUNCTION__ << ": invalid address family " << af;
1249-
break;
1250-
}
1251-
1252-
if (rv == 0)
1253-
1254-
VLOG(3) << __FUNCTION__ << ": added l3 termination for port=" << port_id
1255-
<< " vid=" << vid << " mac=" << mac << " af=" << af;
1256-
1257-
return rv;
1258-
}
1259-
1260-
int nl_l3::del_l3_termination(uint32_t port_id, uint16_t vid,
1261-
const rofl::caddress_ll &mac, int af) noexcept {
1262-
int rv = 0;
1263-
1264-
VLOG(4) << __FUNCTION__ << ": trying to delete for port_id=" << port_id
1265-
<< ", vid=" << vid << ", mac=" << mac << ", af=" << af;
1266-
1267-
// lookup if this exists
1268-
auto needle = std::make_tuple(port_id, vid, mac, static_cast<uint16_t>(af));
1269-
auto it = termination_mac_entries.find(needle);
1270-
if (it == termination_mac_entries.end()) {
1271-
LOG(WARNING)
1272-
<< __FUNCTION__
1273-
<< ": tried to delete a non existing termination mac for port_id="
1274-
<< port_id << ", vid=" << vid << ", mac=" << mac << ", af=" << af;
1275-
return -ENODATA;
1276-
}
1277-
1278-
switch (af) {
1279-
case AF_INET:
1280-
rv = sw->l3_termination_remove(port_id, vid, mac);
1281-
break;
1282-
1283-
case AF_INET6:
1284-
rv = sw->l3_termination_remove_v6(port_id, vid, mac);
1285-
break;
1286-
1287-
default:
1288-
LOG(FATAL) << __FUNCTION__ << ": invalid address family " << af;
1289-
break;
1290-
}
1291-
1292-
termination_mac_entries.erase(it);
1293-
1294-
return rv;
1295-
}
1296-
1297-
int nl_l3::update_l3_termination(int port_id, uint16_t vid,
1298-
struct nl_addr *old_mac,
1299-
struct nl_addr *new_mac) noexcept {
1300-
int rv = 0;
1301-
1302-
auto o_mac = libnl_lladdr_2_rofl(old_mac);
1303-
auto n_mac = libnl_lladdr_2_rofl(new_mac);
1304-
1305-
// parse the AF list and remove the entry from the termination mac set
1306-
// call the switch function to remove and insert the entry with the
1307-
// new mac address.
1308-
if (termination_mac_entries.find(std::make_tuple(
1309-
port_id, vid, o_mac, AF_INET)) != termination_mac_entries.end()) {
1310-
rv = del_l3_termination(port_id, vid, o_mac, AF_INET);
1311-
if (rv < 0)
1312-
VLOG(3) << __FUNCTION__
1313-
<< ": failed to remove termination mac port=" << port_id
1314-
<< " vid=" << vid << " mac=" << o_mac;
1315-
rv = add_l3_termination(port_id, vid, n_mac, AF_INET);
1316-
if (rv < 0) {
1317-
VLOG(3) << __FUNCTION__
1318-
<< ": failed to add termination mac port=" << port_id
1319-
<< " vid=" << vid << " mac=" << n_mac;
1320-
return rv;
1321-
}
1322-
1323-
VLOG(2) << __FUNCTION__
1324-
<< ": updated Termination MAC for port_id=" << port_id
1325-
<< " old mac address=" << o_mac << " new mac address=" << n_mac
1326-
<< " AF=" << AF_INET;
1327-
}
1328-
1329-
if (termination_mac_entries.find(std::make_tuple(
1330-
port_id, vid, o_mac, AF_INET6)) != termination_mac_entries.end()) {
1331-
rv = del_l3_termination(port_id, vid, o_mac, AF_INET6);
1332-
if (rv < 0)
1333-
VLOG(3) << __FUNCTION__
1334-
<< ": failed to remove termination mac port=" << port_id
1335-
<< " vid=" << vid << " mac=" << o_mac;
1336-
rv = add_l3_termination(port_id, vid, n_mac, AF_INET6);
1337-
if (rv < 0) {
1338-
VLOG(3) << __FUNCTION__
1339-
<< ": failed to add termination mac port=" << port_id
1340-
<< " vid=" << vid << " mac=" << n_mac;
1341-
return rv;
1342-
}
1343-
1344-
VLOG(2) << __FUNCTION__
1345-
<< ": updated Termination MAC for port_id=" << port_id
1346-
<< " old mac address=" << o_mac << " new mac address=" << n_mac
1347-
<< " AF=" << AF_INET6;
1348-
}
1349-
1350-
return rv;
1351-
}
1352-
13531177
int nl_l3::update_l3_egress(int port_id, uint16_t vid, struct nl_addr *old_mac,
13541178
struct nl_addr *new_mac) noexcept {
13551179

0 commit comments

Comments
 (0)