Skip to content

Commit 8086637

Browse files
authored
Merge pull request #2548 from anarkiwi/master
Implement idle_eth workaround for broken idle time reset on flow refresh, and test.
2 parents 5288f78 + 00d2661 commit 8086637

File tree

4 files changed

+54
-6
lines changed

4 files changed

+54
-6
lines changed

faucet/dp.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ class DP(Conf):
142142
# Apply strict packet in checking to all packet ins.
143143
'multi_out': True,
144144
# Have OFA copy packet outs to multiple ports.
145+
'idle_dst': True,
146+
# If False, workaround for flow idle timer not reset on flow refresh.
145147
}
146148

147149
defaults_types = {
@@ -193,6 +195,7 @@ class DP(Conf):
193195
'strict_packet_in_cookie': bool,
194196
'multi_out': bool,
195197
'lacp_timeout': int,
198+
'idle_dst': bool,
196199
}
197200

198201
default_table_sizes_types = {
@@ -295,6 +298,7 @@ def __init__(self, _id, dp_id, conf):
295298
self.use_classification = None
296299
self.strict_packet_in_cookie = None
297300
self.multi_out = None
301+
self.idle_dst = None
298302

299303
self.acls = {}
300304
self.vlans = {}
@@ -329,7 +333,7 @@ def check_config(self):
329333
test_config_condition(not (self.arp_neighbor_timeout < (self.timeout / 2)), (
330334
'L2 timeout must be > ARP timeout * 2'))
331335
test_config_condition(not (self.nd_neighbor_timeout < (self.timeout / 2)), (
332-
'L2 timeout must be > ARP timeout * 2'))
336+
'L2 timeout must be > ND timeout * 2'))
333337
if self.cache_update_guard_time == 0:
334338
self.cache_update_guard_time = int(self.timeout / 2)
335339
if self.learn_jitter == 0:

faucet/valve.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ def dp_init(self):
210210
self.dp.tables['eth_dst'], eth_dst_hairpin_table, self.pipeline,
211211
self.dp.timeout, self.dp.learn_jitter, self.dp.learn_ban_timeout,
212212
self.dp.low_priority, self.dp.highest_priority,
213-
self.dp.cache_update_guard_time)
213+
self.dp.cache_update_guard_time, self.dp.idle_dst)
214214
table_configs = sorted([
215215
(table.table_id, str(table.table_config)) for table in self.dp.tables.values()])
216216
for table_id, table_config in table_configs:
@@ -1343,6 +1343,9 @@ def state_expire(self, now, _other_valves):
13431343
if self.dp.dyn_running:
13441344
for vlan in self.dp.vlans.values():
13451345
expired_hosts = self.host_manager.expire_hosts_from_vlan(vlan, now)
1346+
if not self.dp.idle_dst:
1347+
for entry in expired_hosts:
1348+
ofmsgs.extend(self.host_manager.delete_host_from_vlan(entry.eth_src, vlan))
13461349
for entry in expired_hosts:
13471350
self._notify(
13481351
{'L2_EXPIRE': {

faucet/valve_host.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class ValveHostManager(ValveManagerBase):
3030
def __init__(self, logger, ports, vlans, eth_src_table, eth_dst_table,
3131
eth_dst_hairpin_table, pipeline, learn_timeout,
3232
learn_jitter, learn_ban_timeout, low_priority, host_priority,
33-
cache_update_guard_time):
33+
cache_update_guard_time, idle_dst):
3434
self.logger = logger
3535
self.ports = ports
3636
self.vlans = vlans
@@ -45,6 +45,7 @@ def __init__(self, logger, ports, vlans, eth_src_table, eth_dst_table,
4545
self.host_priority = host_priority
4646
self.cache_update_guard_time = cache_update_guard_time
4747
self.output_table = self.eth_dst_table
48+
self.idle_dst = idle_dst
4849
if self.eth_dst_hairpin_table:
4950
self.output_table = self.eth_dst_hairpin_table
5051

@@ -146,6 +147,8 @@ def learn_host_timeouts(self, port):
146147
src_rule_idle_timeout = 0
147148
src_rule_hard_timeout = learn_timeout
148149
dst_rule_idle_timeout = learn_timeout + self.cache_update_guard_time
150+
if not self.idle_dst:
151+
dst_rule_idle_timeout = 0
149152
return (src_rule_idle_timeout, src_rule_hard_timeout, dst_rule_idle_timeout)
150153

151154
def learn_host_on_vlan_port_flows(self, port, vlan, eth_src,

tests/integration/mininet_tests.py

+41-3
Original file line numberDiff line numberDiff line change
@@ -1894,6 +1894,7 @@ class FaucetSingleHostsTimeoutPrometheusTest(FaucetUntaggedTest):
18941894
nd_neighbor_timeout: 4
18951895
ignore_learn_ins: 0
18961896
learn_jitter: 0
1897+
cache_update_guard_time: 1
18971898
interfaces:
18981899
%(port_1)d:
18991900
native_vlan: 100
@@ -1967,17 +1968,54 @@ def learn_then_down_hosts(base, count):
19671968
# make sure at least one host still learned
19681969
learned_macs = self.hosts_learned(all_learned_mac_ports)
19691970
self.assertTrue(learned_macs)
1971+
before_expiry_learned_macs = learned_macs
19701972

19711973
# make sure they all eventually expire
1972-
for _ in range(self.TIMEOUT * 2):
1974+
for _ in range(self.TIMEOUT * 3):
19731975
learned_macs = self.hosts_learned(all_learned_mac_ports)
19741976
self.verify_learn_counters(
19751977
100, list(range(1, len(self.net.hosts) + 1)))
19761978
if not learned_macs:
1977-
return
1979+
break
19781980
time.sleep(1)
19791981

1980-
self.fail('MACs did not expire: %s' % learned_macs)
1982+
self.assertFalse(learned_macs, msg='MACs did not expire: %s' % learned_macs)
1983+
1984+
self.assertTrue(before_expiry_learned_macs)
1985+
for mac in before_expiry_learned_macs:
1986+
self.assertFalse(
1987+
self.get_matching_flow(
1988+
match={'eth_dst': mac}, table_id=self._ETH_DST_TABLE))
1989+
1990+
1991+
class FaucetSingleHostsNoIdleTimeoutPrometheusTest(FaucetSingleHostsTimeoutPrometheusTest):
1992+
1993+
"""Test broken reset idle timer on flow refresh workaround."""
1994+
1995+
CONFIG = """
1996+
timeout: 10
1997+
arp_neighbor_timeout: 4
1998+
nd_neighbor_timeout: 4
1999+
ignore_learn_ins: 0
2000+
learn_jitter: 0
2001+
cache_update_guard_time: 1
2002+
idle_dst: False
2003+
interfaces:
2004+
%(port_1)d:
2005+
native_vlan: 100
2006+
description: "b1"
2007+
%(port_2)d:
2008+
native_vlan: 100
2009+
description: "b2"
2010+
%(port_3)d:
2011+
native_vlan: 100
2012+
description: "b3"
2013+
%(port_4)d:
2014+
native_vlan: 100
2015+
description: "b4"
2016+
"""
2017+
2018+
19812019

19822020

19832021
class FaucetSingleL3LearnMACsOnPortTest(FaucetUntaggedTest):

0 commit comments

Comments
 (0)