Skip to content

Commit 8b839e8

Browse files
authored
Merge pull request #2512 from anarkiwi/master
Move active LACP to fast_advertise() service.
2 parents b24730e + 0297543 commit 8b839e8

File tree

5 files changed

+51
-42
lines changed

5 files changed

+51
-42
lines changed

README.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Faucet
22
======
33

4-
:version: 1.8.21
4+
:version: 1.8.22
55

66
.. image:: https://travis-ci.com/faucetsdn/faucet.svg?branch=master
77
:target: https://travis-ci.com/faucetsdn/faucet

faucet/dp.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,9 @@ class DP(Conf):
101101
'learn_ban_timeout': 0,
102102
# When banning/limiting learning, wait this many seconds before learning can be retried
103103
'advertise_interval': 30,
104-
# How often to advertise (eg. IPv6 RAs)
104+
# How often to slow advertise (eg. IPv6 RAs)
105+
'fast_advertise_interval': 5,
106+
# How often to fast advertise (eg. LACP)
105107
'proactive_learn_v4': True,
106108
# whether proactive learning is enabled for IPv4 nexthops
107109
'proactive_learn_v6': True,
@@ -171,6 +173,7 @@ class DP(Conf):
171173
'learn_jitter': int,
172174
'learn_ban_timeout': int,
173175
'advertise_interval': int,
176+
'fast_advertise_interval': int,
174177
'proactive_learn_v4': bool,
175178
'proactive_learn_v6': bool,
176179
'use_idle_timeout': bool,
@@ -230,6 +233,7 @@ def __init__(self, _id, dp_id, conf):
230233
self.acls = None
231234
self.acls_in = None
232235
self.advertise_interval = None
236+
self.fast_advertise_interval = None
233237
self.arp_neighbor_timeout = None
234238
self.nd_neighbor_timeout = None
235239
self.bgp_local_address = None

faucet/faucet.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ class EventFaucetExperimentalAPIRegistered(event.EventBase): # pylint: disable=t
4747
pass
4848

4949

50+
class EventFaucetMetricUpdate(event.EventBase): # pylint: disable=too-few-public-methods
51+
"""Event used to trigger update of metrics."""
52+
pass
53+
54+
5055
class EventFaucetResolveGateways(event.EventBase): # pylint: disable=too-few-public-methods
5156
"""Event used to trigger gateway re/resolution."""
5257
pass
@@ -56,9 +61,8 @@ class EventFaucetStateExpire(event.EventBase): # pylint: disable=too-few-public-
5661
"""Event used to trigger expiration of state in controller."""
5762
pass
5863

59-
60-
class EventFaucetMetricUpdate(event.EventBase): # pylint: disable=too-few-public-methods
61-
"""Event used to trigger update of metrics."""
64+
class EventFaucetFastStateExpire(event.EventBase): # pylint: disable=too-few-public-methods
65+
"""Event used to trigger fast expiration of state in controller."""
6266
pass
6367

6468

@@ -67,15 +71,11 @@ class EventFaucetAdvertise(event.EventBase): # pylint: disable=too-few-public-me
6771
pass
6872

6973

70-
class EventFaucetLLDPAdvertise(event.EventBase): # pylint: disable=too-few-public-methods
71-
"""Event used to trigger periodic LLDP beacons."""
74+
class EventFaucetFastAdvertise(event.EventBase): # pylint: disable=too-few-public-methods
75+
"""Event used to trigger periodic fast network advertisements (eg LACP)."""
7276
pass
7377

7478

75-
class EventFaucetStackLinkStates(event.EventBase): # pylint: disable=too-few-public-methods
76-
"""Event used to update link stack states."""
77-
pass
78-
7979

8080
class Faucet(RyuAppBase):
8181
"""A RyuApp that implements an L2/L3 learning VLAN switch.
@@ -92,9 +92,9 @@ class Faucet(RyuAppBase):
9292
EventFaucetMetricUpdate: (None, 5),
9393
EventFaucetResolveGateways: ('resolve_gateways', 2),
9494
EventFaucetStateExpire: ('state_expire', 5),
95-
EventFaucetAdvertise: ('advertise', 5),
96-
EventFaucetLLDPAdvertise: ('send_lldp_beacons', 5),
97-
EventFaucetStackLinkStates: ('update_stack_link_states', 2),
95+
EventFaucetFastStateExpire: ('fast_state_expire', 2),
96+
EventFaucetAdvertise: ('advertise', 15),
97+
EventFaucetFastAdvertise: ('fast_advertise', 5),
9898
}
9999
logname = 'faucet'
100100
exc_logname = logname + '.exception'
@@ -199,9 +199,9 @@ def metric_update(self, _):
199199

200200
@set_ev_cls(EventFaucetResolveGateways, MAIN_DISPATCHER)
201201
@set_ev_cls(EventFaucetStateExpire, MAIN_DISPATCHER)
202+
@set_ev_cls(EventFaucetFastStateExpire, MAIN_DISPATCHER)
202203
@set_ev_cls(EventFaucetAdvertise, MAIN_DISPATCHER)
203-
@set_ev_cls(EventFaucetLLDPAdvertise, MAIN_DISPATCHER)
204-
@set_ev_cls(EventFaucetStackLinkStates, MAIN_DISPATCHER)
204+
@set_ev_cls(EventFaucetFastAdvertise, MAIN_DISPATCHER)
205205
@kill_on_exception(exc_logname)
206206
def _valve_flow_services(self, ryu_event):
207207
"""Call a method on all Valves and send any resulting flows."""

faucet/valve.py

+26-20
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class Valve:
8787
'ofchannel_logger',
8888
'recent_ofmsgs',
8989
'_last_advertise_sec',
90+
'_last_fast_advertise_sec',
9091
'_last_packet_in_sec',
9192
'_last_pipeline_flows',
9293
'_packet_in_count_sec',
@@ -110,11 +111,7 @@ def __init__(self, dp, logname, metrics, notifier, dot1x):
110111
self.ofchannel_logger = None
111112
self.logger = None
112113
self.recent_ofmsgs = deque(maxlen=32)
113-
self._last_advertise_sec = 0
114114
self._last_pipeline_flows = []
115-
self._last_packet_in_sec = 0
116-
self._packet_in_count_sec = 0
117-
self._port_highwater = {}
118115
self.dp_init()
119116

120117
def port_labels(self, port):
@@ -153,6 +150,7 @@ def dp_init(self):
153150
self._packet_in_count_sec = 0
154151
self._last_packet_in_sec = 0
155152
self._last_advertise_sec = 0
153+
self._last_fast_advertise_sec = 0
156154
self._route_manager_by_ipv = {}
157155
self._route_manager_by_eth_type = {}
158156
self._port_highwater = {}
@@ -517,16 +515,15 @@ def _decode_port_status(reason):
517515
def advertise(self, now, _other_values):
518516
"""Called periodically to advertise services (eg. IPv6 RAs)."""
519517
ofmsgs = []
520-
if (self.dp.advertise_interval and
521-
now - self._last_advertise_sec > self.dp.advertise_interval):
522-
for route_manager in list(self._route_manager_by_ipv.values()):
523-
for vlan in list(self.dp.vlans.values()):
524-
ofmsgs.extend(route_manager.advertise(vlan))
525-
for port in list(self.dp.lacp_active_ports):
526-
if port.running():
527-
pkt = self._lacp_pkt(port.dyn_last_lacp_pkt, port)
528-
ofmsgs.append(valve_of.packetout(port.number, pkt.data))
529-
self._last_advertise_sec = now
518+
if (not self.dp.advertise_interval or
519+
now - self._last_advertise_sec < self.dp.advertise_interval):
520+
return ofmsgs
521+
self._last_advertise_sec = now
522+
523+
for route_manager in list(self._route_manager_by_ipv.values()):
524+
for vlan in list(self.dp.vlans.values()):
525+
ofmsgs.extend(route_manager.advertise(vlan))
526+
530527
return ofmsgs
531528

532529
def _send_lldp_beacon_on_port(self, port, now):
@@ -549,19 +546,28 @@ def _send_lldp_beacon_on_port(self, port, now):
549546
port.dyn_last_lldp_beacon_time = now
550547
return valve_of.packetout(port.number, lldp_beacon_pkt.data)
551548

552-
def send_lldp_beacons(self, now, _other_valves):
553-
"""Called periodically to send LLDP beacon packets."""
549+
def fast_advertise(self, now, _other_valves):
550+
"""Called periodically to send LLDP/LACP packets."""
554551
# TODO: the beacon service is specifically NOT to support conventional R/STP.
555552
# It is intended to facilitate physical troubleshooting (e.g.
556553
# a standard cable tester can display OF port information).
557554
# It is used also by stacking to verify stacking links.
558555
# TODO: in the stacking case, provide an authentication scheme for the probes
559556
# so they cannot be forged.
560557
ofmsgs = []
558+
if (not self.dp.fast_advertise_interval or
559+
now - self._last_fast_advertise_sec < self.dp.fast_advertise_interval):
560+
return ofmsgs
561+
self._last_fast_advertise_sec = now
562+
563+
for port in list(self.dp.lacp_active_ports):
564+
if port.running():
565+
pkt = self._lacp_pkt(port.dyn_last_lacp_pkt, port)
566+
ofmsgs.append(valve_of.packetout(port.number, pkt.data))
567+
561568
ports = self.dp.lldp_beacon_send_ports(now)
562-
if ports:
563-
self.logger.debug('sending LLDP beacons on %s' % ports)
564-
ofmsgs = [self._send_lldp_beacon_on_port(port, now) for port in ports]
569+
ofmsgs.extend([self._send_lldp_beacon_on_port(port, now) for port in ports])
570+
565571
return ofmsgs
566572

567573
def _next_stack_link_state(self, port, now):
@@ -617,7 +623,7 @@ def _update_stack_link_state(self, port, now, other_valves):
617623
for valve in [self] + other_valves:
618624
valve.flood_manager.update_stack_topo(port_stack_up, self.dp, port)
619625

620-
def update_stack_link_states(self, now, other_valves):
626+
def fast_state_expire(self, now, other_valves):
621627
"""Called periodically to verify the state of stack ports."""
622628
for port in self.dp.stack_ports:
623629
self._update_stack_link_state(port, now, other_valves)

tests/unit/faucet/test_valve.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -603,8 +603,7 @@ def rcv_packet(self, port, vid, match):
603603
rcv_packet_ofmsgs = self.last_flows_to_dp[self.DP_ID]
604604
self.table.apply_ofmsgs(rcv_packet_ofmsgs)
605605
for valve_service in (
606-
'resolve_gateways', 'advertise',
607-
'send_lldp_beacons', 'state_expire'):
606+
'resolve_gateways', 'advertise', 'fast_advertise', 'state_expire'):
608607
self.valves_manager.valve_flow_services(
609608
now, valve_service)
610609
self.valves_manager.update_metrics(now)
@@ -1285,7 +1284,7 @@ def test_port_acl_deny(self):
12851284
def test_lldp_beacon(self):
12861285
"""Test LLDP beacon service."""
12871286
# TODO: verify LLDP packet content.
1288-
self.assertTrue(self.valve.send_lldp_beacons(time.time(), None))
1287+
self.assertTrue(self.valve.fast_advertise(time.time(), None))
12891288

12901289
def test_unknown_port(self):
12911290
"""Test port status change for unknown port handled."""
@@ -1887,7 +1886,7 @@ def test_stack_probe(self):
18871886
other_dp = self.valves_manager.valves[2].dp
18881887
other_port = other_dp.ports[1]
18891888
other_valves = self.valves_manager._other_running_valves(self.valve)
1890-
self.valve.update_stack_link_states(time.time(), other_valves)
1889+
self.valve.fast_state_expire(time.time(), other_valves)
18911890
self.assertTrue(stack_port.is_stack_down())
18921891
for change_func, check_func in [
18931892
('stack_init', 'is_stack_init'),
@@ -1920,7 +1919,7 @@ def test_stack_lost_lldp(self):
19201919
self.rcv_lldp(stack_port, other_dp, other_port)
19211920
self.assertTrue(stack_port.is_stack_init())
19221921
other_valves = self.valves_manager._other_running_valves(self.valve)
1923-
self.valve.update_stack_link_states(time.time() + 300, other_valves) # simulate packet loss
1922+
self.valve.fast_state_expire(time.time() + 300, other_valves) # simulate packet loss
19241923
self.assertTrue(stack_port.is_stack_down())
19251924

19261925

@@ -1947,7 +1946,7 @@ def down_stack_port(port):
19471946
peer_port.stack_down()
19481947
self.valves_manager.valve_flow_services(
19491948
time.time() + 600,
1950-
'update_stack_link_states')
1949+
'fast_state_expire')
19511950
self.assertTrue(port.is_stack_down())
19521951

19531952
def verify_stack_learn_edges(num_edges, edge=None, test_func=None):

0 commit comments

Comments
 (0)