@@ -73,7 +73,10 @@ def __init__(self, backend, main, kwargs, mode='interpreted', verbosity='normal'
73
73
self .extended_values_lock = RLock ()
74
74
self .dynamic_sub_pols = set ()
75
75
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
77
80
self .global_outstanding_queries_lock = Lock ()
78
81
self .global_outstanding_queries = {}
79
82
self .manager = Manager ()
@@ -111,14 +114,23 @@ def handle_packet_in(self, concrete_pkt):
111
114
output = self .policy .eval (pyretic_pkt )
112
115
113
116
# apply the queries whose buckets have received new packets
117
+ self .in_bucket_apply = True
114
118
for q in queries :
115
119
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
+
117
128
# send output of evaluation into the network
118
129
concrete_output = map (self .pyretic2concrete ,output )
119
130
map (self .send_packet ,concrete_output )
120
131
121
132
# 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
122
134
if self .mode == 'reactive0' and not queries :
123
135
self .reactive0_install (pyretic_pkt ,output )
124
136
@@ -132,59 +144,73 @@ def handle_policy_change(self,sub_pol):
132
144
Updates runtime behavior (both interpreter and switch classifiers)
133
145
some sub-policy in self.policy changes.
134
146
"""
135
- map (lambda p : p .invalidate_classifier (),
136
- on_recompile_path (set (),id (sub_pol ),self .policy ))
147
+ with self .policy_lock :
137
148
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 ()
140
165
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 ()
146
166
147
- self .update_switches (classifier )
148
-
149
167
def handle_network_change (self ):
150
168
"""
151
169
Updates runtime behavior (both interpreter and switch classifiers)
152
170
when the concrete network topology changes.
153
171
"""
154
172
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 ()
158
173
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
166
177
167
- self .update_switches (classifier )
178
+ # otherwise copy the network object
179
+ self .in_network_update = True
180
+ self .prev_network = self .network .copy ()
168
181
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 )
170
186
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
174
191
175
- :param classifier: the input classifier
176
- :type classifier: Classifier
192
+ self .in_network_update = False
193
+
194
+
195
+ def update_switch_classifiers (self ):
177
196
"""
197
+ Updates switch classifiers
198
+ """
199
+ classifier = None
200
+
178
201
if self .mode == 'reactive0' :
179
202
self .clear_all ()
203
+
180
204
elif self .mode == 'proactive0' or self .mode == 'proactive1' :
205
+ classifier = self .policy .compile ()
181
206
self .log .debug (
182
207
'|%s|\n \t %s\n \t %s\n \t %s\n ' % (str (datetime .now ()),
183
208
"generate classifier" ,
184
209
"policy=" + repr (self .policy ),
185
210
"classifier=" + repr (classifier )))
186
211
self .install_classifier (classifier )
187
212
213
+
188
214
def update_dynamic_sub_pols (self ):
189
215
"""
190
216
Updates the set of active dynamic sub-policies in self.policy
0 commit comments