Jonathan Hart

BGP router now handles the case where groups don't exists right away.

Also reworked some logic to make delete routes work.

Change-Id: I1f65279284b85144a847f1295fcbd7695cb59167
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
16 package org.onosproject.bgprouter; 16 package org.onosproject.bgprouter;
17 17
18 import com.google.common.collect.ConcurrentHashMultiset; 18 import com.google.common.collect.ConcurrentHashMultiset;
19 +import com.google.common.collect.HashMultimap;
20 +import com.google.common.collect.Maps;
21 +import com.google.common.collect.Multimap;
19 import com.google.common.collect.Multiset; 22 import com.google.common.collect.Multiset;
20 import org.apache.felix.scr.annotations.Activate; 23 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 24 import org.apache.felix.scr.annotations.Component;
...@@ -24,6 +27,8 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -24,6 +27,8 @@ import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality; 27 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 import org.onlab.packet.Ethernet; 28 import org.onlab.packet.Ethernet;
26 import org.onlab.packet.MacAddress; 29 import org.onlab.packet.MacAddress;
30 +import org.onlab.packet.IpAddress;
31 +import org.onlab.packet.IpPrefix;
27 import org.onosproject.core.ApplicationId; 32 import org.onosproject.core.ApplicationId;
28 import org.onosproject.core.CoreService; 33 import org.onosproject.core.CoreService;
29 import org.onosproject.net.DeviceId; 34 import org.onosproject.net.DeviceId;
...@@ -42,9 +47,12 @@ import org.onosproject.net.group.Group; ...@@ -42,9 +47,12 @@ import org.onosproject.net.group.Group;
42 import org.onosproject.net.group.GroupBucket; 47 import org.onosproject.net.group.GroupBucket;
43 import org.onosproject.net.group.GroupBuckets; 48 import org.onosproject.net.group.GroupBuckets;
44 import org.onosproject.net.group.GroupDescription; 49 import org.onosproject.net.group.GroupDescription;
50 +import org.onosproject.net.group.GroupEvent;
45 import org.onosproject.net.group.GroupKey; 51 import org.onosproject.net.group.GroupKey;
52 +import org.onosproject.net.group.GroupListener;
46 import org.onosproject.net.group.GroupService; 53 import org.onosproject.net.group.GroupService;
47 import org.onosproject.net.packet.PacketService; 54 import org.onosproject.net.packet.PacketService;
55 +import org.onosproject.routing.FibEntry;
48 import org.onosproject.routing.FibListener; 56 import org.onosproject.routing.FibListener;
49 import org.onosproject.routing.FibUpdate; 57 import org.onosproject.routing.FibUpdate;
50 import org.onosproject.routing.RoutingService; 58 import org.onosproject.routing.RoutingService;
...@@ -55,7 +63,6 @@ import org.slf4j.LoggerFactory; ...@@ -55,7 +63,6 @@ import org.slf4j.LoggerFactory;
55 63
56 import java.util.Collection; 64 import java.util.Collection;
57 import java.util.Collections; 65 import java.util.Collections;
58 -import java.util.HashMap;
59 import java.util.Map; 66 import java.util.Map;
60 67
61 /** 68 /**
...@@ -90,20 +97,32 @@ public class BgpRouter { ...@@ -90,20 +97,32 @@ public class BgpRouter {
90 97
91 private ApplicationId appId; 98 private ApplicationId appId;
92 99
93 - private final Multiset<NextHop> nextHops = ConcurrentHashMultiset.create(); 100 + // Reference count for how many times a next hop is used by a route
94 - private final Map<NextHop, NextHopGroupKey> groups = new HashMap<>(); 101 + private final Multiset<IpAddress> nextHopsCount = ConcurrentHashMultiset.create();
102 +
103 + // Mapping from prefix to its current next hop
104 + private final Map<IpPrefix, IpAddress> prefixToNextHop = Maps.newHashMap();
105 +
106 + // Mapping from next hop IP to next hop object containing group info
107 + private final Map<IpAddress, NextHop> nextHops = Maps.newHashMap();
108 +
109 + // Stores FIB updates that are waiting for groups to be set up
110 + private final Multimap<GroupKey, FibEntry> pendingUpdates = HashMultimap.create();
95 111
96 private DeviceId deviceId = DeviceId.deviceId("of:0000000000000001"); // TODO config 112 private DeviceId deviceId = DeviceId.deviceId("of:0000000000000001"); // TODO config
97 113
114 + private final GroupListener groupListener = new InternalGroupListener();
115 +
98 private TunnellingConnectivityManager connectivityManager; 116 private TunnellingConnectivityManager connectivityManager;
99 117
100 private InternalTableHandler provisionStaticTables = new InternalTableHandler(); 118 private InternalTableHandler provisionStaticTables = new InternalTableHandler();
101 119
102 @Activate 120 @Activate
103 protected void activate() { 121 protected void activate() {
104 - log.info("Bgp1Router started");
105 appId = coreService.registerApplication(BGP_ROUTER_APP); 122 appId = coreService.registerApplication(BGP_ROUTER_APP);
106 123
124 + groupService.addListener(groupListener);
125 +
107 provisionStaticTables.provision(true); 126 provisionStaticTables.provision(true);
108 127
109 connectivityManager = new TunnellingConnectivityManager(appId, 128 connectivityManager = new TunnellingConnectivityManager(appId,
...@@ -123,50 +142,58 @@ public class BgpRouter { ...@@ -123,50 +142,58 @@ public class BgpRouter {
123 connectivityManager.stop(); 142 connectivityManager.stop();
124 provisionStaticTables.provision(false); 143 provisionStaticTables.provision(false);
125 144
145 + groupService.removeListener(groupListener);
146 +
126 log.info("BgpRouter stopped"); 147 log.info("BgpRouter stopped");
127 } 148 }
128 149
129 private void updateFibEntry(Collection<FibUpdate> updates) { 150 private void updateFibEntry(Collection<FibUpdate> updates) {
130 for (FibUpdate update : updates) { 151 for (FibUpdate update : updates) {
131 - NextHop nextHop = new NextHop(update.entry().nextHopIp(), 152 + FibEntry entry = update.entry();
132 - update.entry().nextHopMac());
133 153
134 - addNextHop(nextHop); 154 + addNextHop(entry);
135 155
136 - TrafficSelector selector = DefaultTrafficSelector.builder() 156 + Group group;
137 - .matchEthType(Ethernet.TYPE_IPV4) 157 + synchronized (pendingUpdates) {
138 - .matchIPDst(update.entry().prefix()) 158 + NextHop nextHop = nextHops.get(entry.nextHopIp());
139 - .build(); 159 + group = groupService.getGroup(deviceId, nextHop.group());
140 160
141 - // TODO ensure group exists 161 + if (group == null) {
142 - NextHopGroupKey groupKey = groups.get(nextHop); 162 + log.debug("Adding pending flow {}", update.entry());
143 - Group group = groupService.getGroup(deviceId, groupKey); 163 + pendingUpdates.put(nextHop.group(), update.entry());
144 - if (group == null) { 164 + continue;
145 - // TODO handle this 165 + }
146 - log.warn("oops, group {} wasn't there");
147 - continue;
148 } 166 }
149 167
150 - TrafficTreatment treatment = DefaultTrafficTreatment.builder() 168 + installFlow(update.entry(), group);
151 - .group(group.id()) 169 + }
152 - .build(); 170 + }
153 171
154 - FlowRule flowRule = new DefaultFlowRule(deviceId, selector, treatment, 172 + private void installFlow(FibEntry entry, Group group) {
155 - PRIORITY, appId, 0, true, 173 + TrafficSelector selector = DefaultTrafficSelector.builder()
156 - FlowRule.Type.IP); 174 + .matchEthType(Ethernet.TYPE_IPV4)
175 + .matchIPDst(entry.prefix())
176 + .build();
157 177
158 - flowService.applyFlowRules(flowRule); 178 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
159 - } 179 + .group(group.id())
180 + .build();
181 +
182 + FlowRule flowRule = new DefaultFlowRule(deviceId, selector, treatment,
183 + PRIORITY, appId, 0, true,
184 + FlowRule.Type.IP);
185 +
186 + flowService.applyFlowRules(flowRule);
160 } 187 }
161 188
162 - private void deleteFibEntry(Collection<FibUpdate> withdraws) { 189 + private synchronized void deleteFibEntry(Collection<FibUpdate> withdraws) {
163 for (FibUpdate update : withdraws) { 190 for (FibUpdate update : withdraws) {
164 - NextHop nextHop = new NextHop(update.entry().nextHopIp(), 191 + FibEntry entry = update.entry();
165 - update.entry().nextHopMac());
166 192
167 - deleteNextHop(nextHop); 193 + deleteNextHop(entry.prefix());
168 194
169 TrafficSelector selector = DefaultTrafficSelector.builder() 195 TrafficSelector selector = DefaultTrafficSelector.builder()
196 + .matchEthType(Ethernet.TYPE_IPV4)
170 .matchIPDst(update.entry().prefix()) 197 .matchIPDst(update.entry().prefix())
171 .build(); 198 .build();
172 199
...@@ -178,18 +205,20 @@ public class BgpRouter { ...@@ -178,18 +205,20 @@ public class BgpRouter {
178 } 205 }
179 } 206 }
180 207
181 - private void addNextHop(NextHop nextHop) { 208 + private synchronized void addNextHop(FibEntry entry) {
182 - if (nextHops.add(nextHop, 1) == 0) { 209 + prefixToNextHop.put(entry.prefix(), entry.nextHopIp());
210 + if (nextHopsCount.count(entry.nextHopIp()) == 0) {
183 // There was no next hop in the multiset 211 // There was no next hop in the multiset
184 212
185 - Interface egressIntf = configService.getMatchingInterface(nextHop.ip()); 213 + Interface egressIntf = configService.getMatchingInterface(entry.nextHopIp());
186 if (egressIntf == null) { 214 if (egressIntf == null) {
187 - log.warn("no egress interface found for {}", nextHop); 215 + log.warn("no egress interface found for {}", entry);
188 return; 216 return;
189 } 217 }
190 218
191 - NextHopGroupKey groupKey = new NextHopGroupKey(nextHop.ip()); 219 + NextHopGroupKey groupKey = new NextHopGroupKey(entry.nextHopIp());
192 - groups.put(nextHop, groupKey); 220 +
221 + NextHop nextHop = new NextHop(entry.nextHopIp(), entry.nextHopMac(), groupKey);
193 222
194 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 223 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
195 .setEthSrc(egressIntf.mac()) 224 .setEthSrc(egressIntf.mac())
...@@ -209,17 +238,30 @@ public class BgpRouter { ...@@ -209,17 +238,30 @@ public class BgpRouter {
209 appId); 238 appId);
210 239
211 groupService.addGroup(groupDescription); 240 groupService.addGroup(groupDescription);
241 +
242 + nextHops.put(nextHop.ip(), nextHop);
243 +
212 } 244 }
245 +
246 + nextHopsCount.add(entry.nextHopIp());
213 } 247 }
214 248
215 - private void deleteNextHop(NextHop nextHop) { 249 + private synchronized void deleteNextHop(IpPrefix prefix) {
216 - if (nextHops.remove(nextHop, 1) <= 1) { 250 + IpAddress nextHopIp = prefixToNextHop.remove(prefix);
251 + NextHop nextHop = nextHops.get(nextHopIp);
252 + if (nextHop == null) {
253 + log.warn("No next hop found when removing prefix {}", prefix);
254 + return;
255 + }
256 +
257 + if (nextHopsCount.remove(nextHopIp, 1) <= 1) {
217 // There was one or less next hops, so there are now none 258 // There was one or less next hops, so there are now none
218 259
219 - log.debug("removing group"); 260 + log.debug("removing group for next hop {}", nextHop);
261 +
262 + nextHops.remove(nextHopIp);
220 263
221 - GroupKey groupKey = groups.remove(nextHop); 264 + groupService.removeGroup(deviceId, nextHop.group(), appId);
222 - groupService.removeGroup(deviceId, groupKey, appId);
223 } 265 }
224 } 266 }
225 267
...@@ -238,7 +280,6 @@ public class BgpRouter { ...@@ -238,7 +280,6 @@ public class BgpRouter {
238 private static final int CONTROLLER_PRIORITY = 255; 280 private static final int CONTROLLER_PRIORITY = 255;
239 private static final int DROP_PRIORITY = 0; 281 private static final int DROP_PRIORITY = 0;
240 282
241 -
242 public void provision(boolean install) { 283 public void provision(boolean install) {
243 284
244 processTableZero(install); 285 processTableZero(install);
...@@ -262,14 +303,14 @@ public class BgpRouter { ...@@ -262,14 +303,14 @@ public class BgpRouter {
262 treatment.transition(FlowRule.Type.VLAN_MPLS); 303 treatment.transition(FlowRule.Type.VLAN_MPLS);
263 304
264 FlowRule rule = new DefaultFlowRule(deviceId, selector.build(), 305 FlowRule rule = new DefaultFlowRule(deviceId, selector.build(),
265 - treatment.build(), CONTROLLER_PRIORITY, 306 + treatment.build(),
266 - appId, 0, true); 307 + CONTROLLER_PRIORITY, appId, 0,
308 + true);
267 309
268 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 310 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
269 311
270 ops = install ? ops.add(rule) : ops.remove(rule); 312 ops = install ? ops.add(rule) : ops.remove(rule);
271 313
272 -
273 //Drop rule 314 //Drop rule
274 selector = DefaultTrafficSelector.builder(); 315 selector = DefaultTrafficSelector.builder();
275 treatment = DefaultTrafficTreatment.builder(); 316 treatment = DefaultTrafficTreatment.builder();
...@@ -277,8 +318,8 @@ public class BgpRouter { ...@@ -277,8 +318,8 @@ public class BgpRouter {
277 treatment.drop(); 318 treatment.drop();
278 319
279 rule = new DefaultFlowRule(deviceId, selector.build(), 320 rule = new DefaultFlowRule(deviceId, selector.build(),
280 - treatment.build(), DROP_PRIORITY, 321 + treatment.build(), DROP_PRIORITY, appId,
281 - appId, 0, true, FlowRule.Type.VLAN_MPLS); 322 + 0, true, FlowRule.Type.VLAN_MPLS);
282 323
283 ops = install ? ops.add(rule) : ops.remove(rule); 324 ops = install ? ops.add(rule) : ops.remove(rule);
284 325
...@@ -298,16 +339,16 @@ public class BgpRouter { ...@@ -298,16 +339,16 @@ public class BgpRouter {
298 339
299 private void processTableOne(boolean install) { 340 private void processTableOne(boolean install) {
300 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 341 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
301 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); 342 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment
343 + .builder();
302 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 344 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
303 FlowRule rule; 345 FlowRule rule;
304 346
305 selector.matchEthType(Ethernet.TYPE_IPV4); 347 selector.matchEthType(Ethernet.TYPE_IPV4);
306 treatment.transition(FlowRule.Type.VLAN); 348 treatment.transition(FlowRule.Type.VLAN);
307 349
308 - rule = new DefaultFlowRule(deviceId, selector.build(), 350 + rule = new DefaultFlowRule(deviceId, selector.build(), treatment.build(), CONTROLLER_PRIORITY,
309 - treatment.build(), CONTROLLER_PRIORITY, 351 + appId, 0, true, FlowRule.Type.VLAN_MPLS);
310 - appId, 0, true, FlowRule.Type.VLAN_MPLS);
311 352
312 ops = install ? ops.add(rule) : ops.remove(rule); 353 ops = install ? ops.add(rule) : ops.remove(rule);
313 354
...@@ -342,8 +383,8 @@ public class BgpRouter { ...@@ -342,8 +383,8 @@ public class BgpRouter {
342 treatment.drop(); 383 treatment.drop();
343 384
344 rule = new DefaultFlowRule(deviceId, selector.build(), 385 rule = new DefaultFlowRule(deviceId, selector.build(),
345 - treatment.build(), DROP_PRIORITY, 386 + treatment.build(), DROP_PRIORITY, appId,
346 - appId, 0, true, FlowRule.Type.VLAN_MPLS); 387 + 0, true, FlowRule.Type.VLAN_MPLS);
347 388
348 ops = install ? ops.add(rule) : ops.remove(rule); 389 ops = install ? ops.add(rule) : ops.remove(rule);
349 390
...@@ -355,7 +396,8 @@ public class BgpRouter { ...@@ -355,7 +396,8 @@ public class BgpRouter {
355 396
356 @Override 397 @Override
357 public void onError(FlowRuleOperations ops) { 398 public void onError(FlowRuleOperations ops) {
358 - log.info("Failed to provision vlan/mpls table for bgp router"); 399 + log.info(
400 + "Failed to provision vlan/mpls table for bgp router");
359 } 401 }
360 })); 402 }));
361 403
...@@ -363,7 +405,8 @@ public class BgpRouter { ...@@ -363,7 +405,8 @@ public class BgpRouter {
363 405
364 private void processTableTwo(boolean install) { 406 private void processTableTwo(boolean install) {
365 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 407 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
366 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); 408 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment
409 + .builder();
367 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 410 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
368 FlowRule rule; 411 FlowRule rule;
369 412
...@@ -372,8 +415,8 @@ public class BgpRouter { ...@@ -372,8 +415,8 @@ public class BgpRouter {
372 treatment.drop(); 415 treatment.drop();
373 416
374 rule = new DefaultFlowRule(deviceId, selector.build(), 417 rule = new DefaultFlowRule(deviceId, selector.build(),
375 - treatment.build(), DROP_PRIORITY, 418 + treatment.build(), DROP_PRIORITY, appId,
376 - appId, 0, true, FlowRule.Type.VLAN); 419 + 0, true, FlowRule.Type.VLAN);
377 420
378 ops = install ? ops.add(rule) : ops.remove(rule); 421 ops = install ? ops.add(rule) : ops.remove(rule);
379 422
...@@ -390,11 +433,10 @@ public class BgpRouter { ...@@ -390,11 +433,10 @@ public class BgpRouter {
390 })); 433 }));
391 } 434 }
392 435
393 -
394 -
395 private void processTableThree(boolean install) { 436 private void processTableThree(boolean install) {
396 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 437 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
397 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); 438 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment
439 + .builder();
398 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 440 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
399 FlowRule rule; 441 FlowRule rule;
400 442
...@@ -426,8 +468,8 @@ public class BgpRouter { ...@@ -426,8 +468,8 @@ public class BgpRouter {
426 treatment.drop(); 468 treatment.drop();
427 469
428 rule = new DefaultFlowRule(deviceId, selector.build(), 470 rule = new DefaultFlowRule(deviceId, selector.build(),
429 - treatment.build(), DROP_PRIORITY, 471 + treatment.build(), DROP_PRIORITY, appId,
430 - appId, 0, true, FlowRule.Type.VLAN_MPLS); 472 + 0, true, FlowRule.Type.VLAN_MPLS);
431 473
432 ops = install ? ops.add(rule) : ops.remove(rule); 474 ops = install ? ops.add(rule) : ops.remove(rule);
433 475
...@@ -443,20 +485,20 @@ public class BgpRouter { ...@@ -443,20 +485,20 @@ public class BgpRouter {
443 } 485 }
444 })); 486 }));
445 487
446 -
447 } 488 }
448 489
449 private void processTableFive(boolean install) { 490 private void processTableFive(boolean install) {
450 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 491 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
451 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); 492 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment
493 + .builder();
452 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 494 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
453 FlowRule rule; 495 FlowRule rule;
454 496
455 treatment.transition(FlowRule.Type.IP); 497 treatment.transition(FlowRule.Type.IP);
456 498
457 rule = new DefaultFlowRule(deviceId, selector.build(), 499 rule = new DefaultFlowRule(deviceId, selector.build(),
458 - treatment.build(), DROP_PRIORITY, 500 + treatment.build(), DROP_PRIORITY, appId,
459 - appId, 0, true, FlowRule.Type.COS); 501 + 0, true, FlowRule.Type.COS);
460 502
461 ops = install ? ops.add(rule) : ops.remove(rule); 503 ops = install ? ops.add(rule) : ops.remove(rule);
462 504
...@@ -476,7 +518,8 @@ public class BgpRouter { ...@@ -476,7 +518,8 @@ public class BgpRouter {
476 518
477 private void processTableSix(boolean install) { 519 private void processTableSix(boolean install) {
478 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 520 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
479 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); 521 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment
522 + .builder();
480 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 523 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
481 FlowRule rule; 524 FlowRule rule;
482 525
...@@ -485,8 +528,8 @@ public class BgpRouter { ...@@ -485,8 +528,8 @@ public class BgpRouter {
485 treatment.drop(); 528 treatment.drop();
486 529
487 rule = new DefaultFlowRule(deviceId, selector.build(), 530 rule = new DefaultFlowRule(deviceId, selector.build(),
488 - treatment.build(), DROP_PRIORITY, 531 + treatment.build(), DROP_PRIORITY, appId,
489 - appId, 0, true, FlowRule.Type.IP); 532 + 0, true, FlowRule.Type.IP);
490 533
491 ops = install ? ops.add(rule) : ops.remove(rule); 534 ops = install ? ops.add(rule) : ops.remove(rule);
492 535
...@@ -505,7 +548,8 @@ public class BgpRouter { ...@@ -505,7 +548,8 @@ public class BgpRouter {
505 548
506 private void processTableNine(boolean install) { 549 private void processTableNine(boolean install) {
507 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 550 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
508 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); 551 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment
552 + .builder();
509 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 553 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
510 FlowRule rule; 554 FlowRule rule;
511 555
...@@ -529,6 +573,21 @@ public class BgpRouter { ...@@ -529,6 +573,21 @@ public class BgpRouter {
529 } 573 }
530 })); 574 }));
531 } 575 }
576 + }
532 577
578 + private class InternalGroupListener implements GroupListener {
579 +
580 + @Override
581 + public void event(GroupEvent event) {
582 + Group group = event.subject();
583 +
584 + if (event.type() == GroupEvent.Type.GROUP_ADDED ||
585 + event.type() == GroupEvent.Type.GROUP_UPDATED) {
586 + synchronized (pendingUpdates) {
587 + pendingUpdates.removeAll(group.appCookie())
588 + .forEach((entry) -> installFlow(entry, group));
589 + }
590 + }
591 + }
533 } 592 }
534 } 593 }
......
...@@ -18,30 +18,59 @@ package org.onosproject.bgprouter; ...@@ -18,30 +18,59 @@ package org.onosproject.bgprouter;
18 import com.google.common.base.MoreObjects; 18 import com.google.common.base.MoreObjects;
19 import org.onlab.packet.IpAddress; 19 import org.onlab.packet.IpAddress;
20 import org.onlab.packet.MacAddress; 20 import org.onlab.packet.MacAddress;
21 +import org.onosproject.net.group.GroupKey;
21 22
22 import java.util.Objects; 23 import java.util.Objects;
23 24
24 /** 25 /**
25 - * Created by jono on 2/12/15. 26 + * Represents a next hop for routing, whose MAC address has already been resolved.
26 */ 27 */
27 public class NextHop { 28 public class NextHop {
28 29
29 private final IpAddress ip; 30 private final IpAddress ip;
30 private final MacAddress mac; 31 private final MacAddress mac;
32 + private final GroupKey group;
31 33
32 - public NextHop(IpAddress ip, MacAddress mac) { 34 + /**
35 + * Creates a new next hop.
36 + *
37 + * @param ip next hop's IP address
38 + * @param mac next hop's MAC address
39 + * @param group next hop's group
40 + */
41 + public NextHop(IpAddress ip, MacAddress mac, GroupKey group) {
33 this.ip = ip; 42 this.ip = ip;
34 this.mac = mac; 43 this.mac = mac;
44 + this.group = group;
35 } 45 }
36 46
47 + /**
48 + * Returns the next hop's IP address.
49 + *
50 + * @return next hop's IP address
51 + */
37 public IpAddress ip() { 52 public IpAddress ip() {
38 return ip; 53 return ip;
39 } 54 }
40 55
56 + /**
57 + * Returns the next hop's MAC address.
58 + *
59 + * @return next hop's MAC address
60 + */
41 public MacAddress mac() { 61 public MacAddress mac() {
42 return mac; 62 return mac;
43 } 63 }
44 64
65 + /**
66 + * Returns the next hop group.
67 + *
68 + * @return group
69 + */
70 + public GroupKey group() {
71 + return group;
72 + }
73 +
45 @Override 74 @Override
46 public boolean equals(Object o) { 75 public boolean equals(Object o) {
47 if (!(o instanceof NextHop)) { 76 if (!(o instanceof NextHop)) {
...@@ -51,12 +80,13 @@ public class NextHop { ...@@ -51,12 +80,13 @@ public class NextHop {
51 NextHop that = (NextHop) o; 80 NextHop that = (NextHop) o;
52 81
53 return Objects.equals(this.ip, that.ip) && 82 return Objects.equals(this.ip, that.ip) &&
54 - Objects.equals(this.mac, that.mac); 83 + Objects.equals(this.mac, that.mac) &&
84 + Objects.equals(this.group, that.group);
55 } 85 }
56 86
57 @Override 87 @Override
58 public int hashCode() { 88 public int hashCode() {
59 - return Objects.hash(ip, mac); 89 + return Objects.hash(ip, mac, group);
60 } 90 }
61 91
62 @Override 92 @Override
...@@ -64,6 +94,7 @@ public class NextHop { ...@@ -64,6 +94,7 @@ public class NextHop {
64 return MoreObjects.toStringHelper(getClass()) 94 return MoreObjects.toStringHelper(getClass())
65 .add("ip", ip) 95 .add("ip", ip)
66 .add("mac", mac) 96 .add("mac", mac)
97 + .add("group", group)
67 .toString(); 98 .toString();
68 } 99 }
69 } 100 }
......
...@@ -24,16 +24,26 @@ import java.util.Objects; ...@@ -24,16 +24,26 @@ import java.util.Objects;
24 import static com.google.common.base.Preconditions.checkNotNull; 24 import static com.google.common.base.Preconditions.checkNotNull;
25 25
26 /** 26 /**
27 - * Created by jono on 2/16/15. 27 + * Identifier for a next hop group.
28 */ 28 */
29 public class NextHopGroupKey implements GroupKey { 29 public class NextHopGroupKey implements GroupKey {
30 30
31 private final IpAddress address; 31 private final IpAddress address;
32 32
33 + /**
34 + * Creates a new next hop group key.
35 + *
36 + * @param address next hop's IP address
37 + */
33 public NextHopGroupKey(IpAddress address) { 38 public NextHopGroupKey(IpAddress address) {
34 this.address = checkNotNull(address); 39 this.address = checkNotNull(address);
35 } 40 }
36 41
42 + /**
43 + * Returns the next hop's IP address.
44 + *
45 + * @return next hop's IP address
46 + */
37 public IpAddress address() { 47 public IpAddress address() {
38 return address; 48 return address;
39 } 49 }
......
...@@ -288,8 +288,16 @@ public class DistributedStatisticStore implements StatisticStore { ...@@ -288,8 +288,16 @@ public class DistributedStatisticStore implements StatisticStore {
288 288
289 private ConnectPoint buildConnectPoint(FlowRule rule) { 289 private ConnectPoint buildConnectPoint(FlowRule rule) {
290 PortNumber port = getOutput(rule); 290 PortNumber port = getOutput(rule);
291 +
292 + boolean hasGoto = rule.treatment().instructions()
293 + .stream()
294 + .anyMatch(i -> (i instanceof Instructions.GroupInstruction)
295 + || (i instanceof Instructions.TableTypeTransition));
296 +
291 if (port == null) { 297 if (port == null) {
292 - log.debug("Rule {} has no output.", rule); 298 + if (!hasGoto) {
299 + log.debug("Rule {} has no output.", rule);
300 + }
293 return null; 301 return null;
294 } 302 }
295 ConnectPoint cp = new ConnectPoint(rule.deviceId(), port); 303 ConnectPoint cp = new ConnectPoint(rule.deviceId(), port);
......
...@@ -154,8 +154,16 @@ public class SimpleStatisticStore implements StatisticStore { ...@@ -154,8 +154,16 @@ public class SimpleStatisticStore implements StatisticStore {
154 154
155 private ConnectPoint buildConnectPoint(FlowRule rule) { 155 private ConnectPoint buildConnectPoint(FlowRule rule) {
156 PortNumber port = getOutput(rule); 156 PortNumber port = getOutput(rule);
157 +
158 + boolean hasGoto = rule.treatment().instructions()
159 + .stream()
160 + .anyMatch(i -> (i instanceof Instructions.GroupInstruction)
161 + || (i instanceof Instructions.TableTypeTransition));
162 +
157 if (port == null) { 163 if (port == null) {
158 - log.debug("Rule {} has no output.", rule); 164 + if (!hasGoto) {
165 + log.debug("Rule {} has no output.", rule);
166 + }
159 return null; 167 return null;
160 } 168 }
161 ConnectPoint cp = new ConnectPoint(rule.deviceId(), port); 169 ConnectPoint cp = new ConnectPoint(rule.deviceId(), port);
......
...@@ -310,7 +310,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv ...@@ -310,7 +310,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
310 break; 310 break;
311 } 311 }
312 default: 312 default:
313 - log.debug("Unhandled message type: {}", msg.getType()); 313 + break;
314 } 314 }
315 } 315 }
316 316
......