Skip to content
This repository was archived by the owner on Jun 27, 2018. It is now read-only.

Commit f4648f6

Browse files
author
Joshua Reich
committed
improved update logic
1 parent 1904ef0 commit f4648f6

File tree

1 file changed

+56
-30
lines changed

1 file changed

+56
-30
lines changed

pyretic/core/runtime.py

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ def __init__(self, backend, main, kwargs, mode='interpreted', verbosity='normal'
7373
self.extended_values_lock = RLock()
7474
self.dynamic_sub_pols = set()
7575
self.update_dynamic_sub_pols()
76-
self.in_update_network = False
76+
self.in_network_update = False
77+
self.in_bucket_apply = False
78+
self.network_triggered_policy_update = False
79+
self.bucket_triggered_policy_update = False
7780
self.global_outstanding_queries_lock = Lock()
7881
self.global_outstanding_queries = {}
7982
self.manager = Manager()
@@ -111,14 +114,23 @@ def handle_packet_in(self, concrete_pkt):
111114
output = self.policy.eval(pyretic_pkt)
112115

113116
# apply the queries whose buckets have received new packets
117+
self.in_bucket_apply = True
114118
for q in queries:
115119
q.apply()
116-
120+
self.in_bucket_apply = False
121+
122+
# if the query changed the policy, update the controller and switch state
123+
if self.bucket_triggered_policy_update:
124+
self.update_dynamic_sub_pols()
125+
self.update_switch_classifiers()
126+
self.bucket_triggered_policy_update = False
127+
117128
# send output of evaluation into the network
118129
concrete_output = map(self.pyretic2concrete,output)
119130
map(self.send_packet,concrete_output)
120131

121132
# if in reactive mode and no packets are forwarded to buckets, install microflow
133+
# Note: lack of forwarding to bucket implies no bucket-trigger update could have occured
122134
if self.mode == 'reactive0' and not queries:
123135
self.reactive0_install(pyretic_pkt,output)
124136

@@ -132,59 +144,73 @@ def handle_policy_change(self,sub_pol):
132144
Updates runtime behavior (both interpreter and switch classifiers)
133145
some sub-policy in self.policy changes.
134146
"""
135-
map(lambda p: p.invalidate_classifier(),
136-
on_recompile_path(set(),id(sub_pol),self.policy))
147+
with self.policy_lock:
137148

138-
if self.in_update_network:
139-
return
149+
# tag stale classifiers as invalid
150+
map(lambda p: p.invalidate_classifier(),
151+
on_recompile_path(set(),id(sub_pol),self.policy))
152+
153+
# if change was driven by a network update, flag
154+
if self.in_network_update:
155+
self.network_triggered_policy_update = True
156+
157+
# if this change driven by a bucket side-effect, flag
158+
elif self.in_bucket_apply:
159+
self.bucket_triggered_policy_update = True
160+
161+
# otherwise, update controller and switches accordingly
162+
else:
163+
self.update_dynamic_sub_pols()
164+
self.update_switch_classifiers()
140165

141-
with self.policy_lock:
142-
self.update_dynamic_sub_pols()
143-
classifier = None
144-
if self.mode == 'proactive0' or self.mode == 'proactive1':
145-
classifier = self.policy.compile()
146166

147-
self.update_switches(classifier)
148-
149167
def handle_network_change(self):
150168
"""
151169
Updates runtime behavior (both interpreter and switch classifiers)
152170
when the concrete network topology changes.
153171
"""
154172
with self.network_lock:
155-
if self.network.topology != self.prev_network.topology:
156-
self.in_update_network = True
157-
self.prev_network = self.network.copy()
158173

159-
with self.policy_lock:
160-
for policy in self.dynamic_sub_pols:
161-
policy.set_network(self.network)
162-
self.update_dynamic_sub_pols()
163-
classifier = None
164-
if self.mode == 'proactive0' or self.mode == 'proactive1':
165-
classifier = self.policy.compile()
174+
# if the topology hasn't changed, ignore
175+
if self.network.topology == self.prev_network.topology:
176+
return
166177

167-
self.update_switches(classifier)
178+
# otherwise copy the network object
179+
self.in_network_update = True
180+
self.prev_network = self.network.copy()
168181

169-
self.in_update_network = False
182+
# update the policy w/ the new network object
183+
with self.policy_lock:
184+
for policy in self.dynamic_sub_pols:
185+
policy.set_network(self.network)
170186

171-
def update_switches(self,classifier):
172-
"""
173-
Updates switch tables based on input classifier
187+
if self.network_triggered_policy_update:
188+
self.update_dynamic_sub_pols()
189+
self.update_switch_classifiers()
190+
self.network_triggered_policy_update = False
174191

175-
:param classifier: the input classifier
176-
:type classifier: Classifier
192+
self.in_network_update = False
193+
194+
195+
def update_switch_classifiers(self):
177196
"""
197+
Updates switch classifiers
198+
"""
199+
classifier = None
200+
178201
if self.mode == 'reactive0':
179202
self.clear_all()
203+
180204
elif self.mode == 'proactive0' or self.mode == 'proactive1':
205+
classifier = self.policy.compile()
181206
self.log.debug(
182207
'|%s|\n\t%s\n\t%s\n\t%s\n' % (str(datetime.now()),
183208
"generate classifier",
184209
"policy="+repr(self.policy),
185210
"classifier="+repr(classifier)))
186211
self.install_classifier(classifier)
187212

213+
188214
def update_dynamic_sub_pols(self):
189215
"""
190216
Updates the set of active dynamic sub-policies in self.policy

0 commit comments

Comments
 (0)