Skip to content

Commit 1f8205f

Browse files
authored
Merge pull request #3529 from anarkiwi/dot1xmanage
Remove stack ref from standalone, clean up and deflake 8021x.
2 parents 97037f6 + c1afc8d commit 1f8205f

File tree

4 files changed

+62
-48
lines changed

4 files changed

+62
-48
lines changed

faucet/valve.py

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,20 +1783,16 @@ def reload_config(self, _now, new_dp):
17831783
self.notify({'CONFIG_CHANGE': {'restart_type': restart_type}})
17841784
return ofmsgs
17851785

1786-
def _del_native_vlan(self, port):
1787-
vlan_table = self.dp.tables['vlan']
1788-
ofmsg = vlan_table.flowdel(
1789-
vlan_table.match(in_port=port.number, vlan=port.native_vlan),
1790-
priority=self.dp.low_priority,
1791-
)
1792-
return [ofmsg]
1793-
1794-
def _warm_reconfig_port_vlans(self, port, vlans):
1786+
def _warm_reconfig_port_native_vlans(self, port, new_dyn_dot1x_native_vlan):
17951787
ofmsgs = []
1788+
old_vlan = port.dyn_dot1x_native_vlan
17961789
ofmsgs.extend(self.switch_manager.del_port(port))
1790+
port.dyn_dot1x_native_vlan = new_dyn_dot1x_native_vlan
1791+
for vlan in (old_vlan,) + (port.dyn_dot1x_native_vlan, port.native_vlan):
1792+
if vlan is not None:
1793+
vlan.reset_ports(self.dp.ports.values())
1794+
ofmsgs.extend(self.switch_manager.update_vlan(vlan))
17971795
ofmsgs.extend(self.switch_manager.add_port(port))
1798-
for vlan in vlans:
1799-
ofmsgs.extend(self.switch_manager.update_vlan(vlan))
18001796
return ofmsgs
18011797

18021798
def add_dot1x_native_vlan(self, port_num, vlan_name):
@@ -1805,27 +1801,14 @@ def add_dot1x_native_vlan(self, port_num, vlan_name):
18051801
vlans = [vlan for vlan in self.dp.vlans.values() if vlan.name == vlan_name]
18061802
if vlans:
18071803
vlan = vlans[0]
1808-
port.dyn_dot1x_native_vlan = vlan
1809-
vlan.reset_ports(self.dp.ports.values())
1810-
ofmsgs.extend(self._del_native_vlan(port))
1811-
ofmsgs.extend(self._warm_reconfig_port_vlans(
1812-
port, (port.dyn_dot1x_native_vlan, port.native_vlan)))
1804+
ofmsgs.extend(self._warm_reconfig_port_native_vlans(port, vlan))
18131805
return ofmsgs
18141806

18151807
def del_dot1x_native_vlan(self, port_num):
18161808
ofmsgs = []
18171809
port = self.dp.ports[port_num]
18181810
if port.dyn_dot1x_native_vlan is not None:
1819-
dyn_vlan = port.dyn_dot1x_native_vlan
1820-
port.dyn_dot1x_native_vlan = None
1821-
dyn_vlan.reset_ports(self.dp.ports.values())
1822-
# Delete any existing native VLAN rule.
1823-
vlan_table = self.dp.tables['vlan']
1824-
ofmsgs.append(vlan_table.flowdel(
1825-
vlan_table.match(in_port=port.number, vlan=NullVLAN()),
1826-
priority=self.dp.low_priority))
1827-
ofmsgs.extend(self._warm_reconfig_port_vlans(
1828-
port, (dyn_vlan, port.native_vlan)))
1811+
ofmsgs.extend(self._warm_reconfig_port_native_vlans(port, None))
18291812
return ofmsgs
18301813

18311814
def router_vlan_for_ip_gw(self, vlan, ip_gw):

faucet/valve_switch_stack.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,13 @@ def add_port(self, port):
467467
inst=self.pipeline.accept_to_classification()))
468468
return ofmsgs
469469

470+
def del_port(self, port):
471+
ofmsgs = super(ValveSwitchStackManagerBase, self).del_port(port)
472+
if port.stack:
473+
for vlan in self.vlans.values():
474+
vlan.clear_cache_hosts_on_port(port)
475+
return ofmsgs
476+
470477

471478
class ValveSwitchStackManagerNoReflection(ValveSwitchStackManagerBase):
472479
"""Stacks of size 2 - all switches directly connected to root.

faucet/valve_switch_standalone.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,12 @@ def _port_add_vlan_rules(self, port, vlan, mirror_act, push_vlan=True):
344344
self.vlan_table.match(in_port=port.number, vlan=match_vlan),
345345
priority=self.low_priority, inst=inst)
346346

347+
def _native_vlan(self, port):
348+
for native_vlan in (port.dyn_dot1x_native_vlan, port.native_vlan):
349+
if native_vlan is not None:
350+
return native_vlan
351+
return None
352+
347353
def add_port(self, port):
348354
if port.vlans():
349355
mirror_act = port.mirror_actions()
@@ -352,11 +358,10 @@ def add_port(self, port):
352358
tagged_ofmsgs.append(self._port_add_vlan_rules(
353359
port, vlan, mirror_act, push_vlan=False))
354360
untagged_ofmsgs = []
355-
for native_vlan in (port.dyn_dot1x_native_vlan, port.native_vlan):
356-
if native_vlan is not None:
357-
untagged_ofmsgs.append(self._port_add_vlan_rules(
358-
port, native_vlan, mirror_act))
359-
break
361+
native_vlan = self._native_vlan(port)
362+
if native_vlan is not None:
363+
untagged_ofmsgs.append(self._port_add_vlan_rules(
364+
port, native_vlan, mirror_act))
360365
# If no untagged VLANs, add explicit drop rule for untagged packets.
361366
if port.count_untag_vlan_miss and not untagged_ofmsgs:
362367
untagged_ofmsgs.append(self.vlan_table.flowmod(
@@ -374,11 +379,13 @@ def del_port(self, port):
374379
# per OF 1.3.5 B.6.23, the OFA will match flows
375380
# that have an action targeting this port.
376381
ofmsgs.append(table.flowdel(out_port=port.number))
377-
vlans = port.vlans()
378-
if port.stack:
379-
vlans = self.vlans.values()
380-
for vlan in vlans:
382+
for vlan in port.vlans():
381383
vlan.clear_cache_hosts_on_port(port)
384+
native_vlan = self._native_vlan(port)
385+
if native_vlan is not None:
386+
ofmsgs.append(self.vlan_table.flowdel(
387+
self.vlan_table.match(in_port=port.number, vlan=port.native_vlan),
388+
priority=self.low_priority))
382389
return ofmsgs
383390

384391
def build_flood_rules(self, vlan, modify=False):

tests/integration/mininet_tests.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -362,9 +362,20 @@ def insert_dynamic_values(dot1x_expected_events):
362362
msg='expected event: {} not in events_that_happened {}'.format(
363363
expected_event, events_that_happened))
364364

365+
def _eapol_filter(self, fields):
366+
return '(' + ' and '.join(('ether proto 0x888e',) + fields) + ')'
367+
368+
def _success_eapol_filter(self, expect_success):
369+
eap_code = '0x04'
370+
if expect_success:
371+
eap_code = '0x03'
372+
return self._eapol_filter(('ether[14:4] == 0x01000004', 'ether[18] == %s' % eap_code))
373+
374+
def _logoff_eapol_filter(self):
375+
return self._eapol_filter(('ether[14:4] == 0x01020000',))
376+
365377
def try_8021x(self, host, port_num, conf, and_logoff=False, terminate_wpasupplicant=False,
366-
wpasup_timeout=180, tcpdump_timeout=15, tcpdump_packets=10,
367-
expect_success=True):
378+
wpasup_timeout=180, tcpdump_timeout=30, expect_success=True):
368379
if expect_success:
369380
self.wait_8021x_flows(port_num)
370381
port_labels = self.port_labels(port_num)
@@ -380,7 +391,11 @@ def try_8021x(self, host, port_num, conf, and_logoff=False, terminate_wpasupplic
380391
'dp_dot1x_failure_total', default=0)
381392
dp_logoff_total = self.scrape_prometheus_var(
382393
'dp_dot1x_logoff_total', default=0)
383-
tcpdump_filter = 'ether proto 0x888e'
394+
tcpdump_filters = [self._success_eapol_filter(expect_success)]
395+
if and_logoff:
396+
tcpdump_filters.append(self._logoff_eapol_filter())
397+
tcpdump_packets = len(tcpdump_filters)
398+
tcpdump_filter = ' or '.join(tcpdump_filters)
384399
tcpdump_txt = self.tcpdump_helper(
385400
host, tcpdump_filter, [
386401
lambda: self.wpa_supplicant_callback(
@@ -393,6 +408,8 @@ def try_8021x(self, host, port_num, conf, and_logoff=False, terminate_wpasupplic
393408
if not and_logoff:
394409
self.wait_8021x_success_flows(host, port_num)
395410
success = 'Success' in tcpdump_txt
411+
if expect_success != success:
412+
return False
396413
new_success_total = self.scrape_prometheus_var(
397414
'port_dot1x_success_total', labels=port_labels, default=0)
398415
new_failure_total = self.scrape_prometheus_var(
@@ -405,8 +422,6 @@ def try_8021x(self, host, port_num, conf, and_logoff=False, terminate_wpasupplic
405422
'dp_dot1x_failure_total', default=0)
406423
new_dp_logoff_total = self.scrape_prometheus_var(
407424
'dp_dot1x_logoff_total', default=0)
408-
if expect_success != success:
409-
return False
410425
if expect_success and success:
411426
self.assertGreater(new_success_total, success_total)
412427
self.assertGreater(new_dp_success_total, dp_success_total)
@@ -735,11 +750,10 @@ class Faucet8021XIdentityOnPortUpTest(Faucet8021XBaseTest):
735750
def test_untagged(self):
736751
port_no1 = self.port_map['port_1']
737752

738-
# start wpa sup, logon, then send id request. should then be 2 success.
753+
# start wpa sup, logon, then send id request.
739754
self.set_port_up(port_no1)
740755
self.assertTrue(self.try_8021x(
741-
self.eapol1_host, port_no1, self.wpasupplicant_conf_1, and_logoff=False,
742-
tcpdump_timeout=180, tcpdump_packets=6))
756+
self.eapol1_host, port_no1, self.wpasupplicant_conf_1, and_logoff=False))
743757
self.set_port_down(port_no1)
744758
self.one_ipv4_ping(
745759
self.eapol1_host, self.ping_host.IP(),
@@ -749,15 +763,18 @@ def port_up(port):
749763
self.set_port_up(port)
750764
self.wait_8021x_flows(port)
751765

752-
tcpdump_filter = 'ether proto 0x888e'
766+
username = 'user'
767+
username_bytes = ''.join(('%2x' % ord(c) for c in username))
768+
tcpdump_filter = ' or '.join((
769+
self._success_eapol_filter(True),
770+
self._eapol_filter(('ether[23:4] == 0x%s' % username_bytes,))))
753771
tcpdump_txt = self.tcpdump_helper(
754772
self.eapol1_host, tcpdump_filter, [
755773
lambda: port_up(port_no1)],
756-
timeout=80, vflags='-vvv', packets=10)
774+
timeout=30, vflags='-vvv', packets=2)
757775
for req_str in (
758-
'len 5, Request (1)', # assume that this is the identity request
759-
'Identity: user', # supplicant replies with username
760-
'Success', # supplicant success
776+
'Identity: %s' % username, # supplicant replies with username
777+
'Success', # supplicant success
761778
):
762779
self.assertTrue(req_str in tcpdump_txt, msg='%s not in %s' % (req_str, tcpdump_txt))
763780

0 commit comments

Comments
 (0)