BgpRouter: Batch flow updates

Change-Id: If472e8e93140bce7fbb01c1a2f1847de421108c9
diff --git a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
index f151bc3..f461269 100644
--- a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
+++ b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
@@ -69,9 +69,11 @@
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * BgpRouter component.
@@ -189,6 +191,8 @@
     }
 
     private void updateFibEntry(Collection<FibUpdate> updates) {
+        Map<FibEntry, Group> toInstall = new HashMap<>(updates.size());
+
         for (FibUpdate update : updates) {
             FibEntry entry = update.entry();
 
@@ -206,17 +210,30 @@
                 }
             }
 
-            installFlow(update.entry(), group);
+            toInstall.put(update.entry(), group);
         }
+
+        installFlows(toInstall);
     }
 
-    private void installFlow(FibEntry entry, Group group) {
-        FlowRule flowRule = generateRibFlowRule(entry.prefix(), group);
+    private void installFlows(Map<FibEntry, Group> entriesToInstall) {
+        FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
 
-        flowService.applyFlowRules(flowRule);
+        for (Map.Entry<FibEntry, Group> entry : entriesToInstall.entrySet()) {
+            FibEntry fibEntry = entry.getKey();
+            Group group = entry.getValue();
+
+            FlowRule flowRule = generateRibFlowRule(fibEntry.prefix(), group);
+
+            builder.add(flowRule);
+        }
+
+        flowService.apply(builder.build());
     }
 
     private synchronized void deleteFibEntry(Collection<FibUpdate> withdraws) {
+        FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
+
         for (FibUpdate update : withdraws) {
             FibEntry entry = update.entry();
 
@@ -228,8 +245,10 @@
 
             FlowRule flowRule = generateRibFlowRule(entry.prefix(), group);
 
-            flowService.removeFlowRules(flowRule);
+            builder.remove(flowRule);
         }
+
+        flowService.apply(builder.build());
     }
 
     private FlowRule generateRibFlowRule(IpPrefix prefix, Group group) {
@@ -332,7 +351,7 @@
         private Map<PortNumber, VlanId> portVlanPair = Maps.newHashMap();
 
         public void provision(boolean install, Set<Interface> intfs) {
-            getIntefaceConfig(intfs);
+            getInterfaceConfig(intfs);
             processTableZero(install);
             processTableOne(install);
             processTableTwo(install);
@@ -342,7 +361,7 @@
             processTableNine(install);
         }
 
-        private void getIntefaceConfig(Set<Interface> intfs) {
+        private void getInterfaceConfig(Set<Interface> intfs) {
             log.info("Processing {} router interfaces", intfs.size());
             for (Interface intf : intfs) {
                 intfIps.addAll(intf.ipAddresses());
@@ -665,8 +684,14 @@
             if (event.type() == GroupEvent.Type.GROUP_ADDED ||
                     event.type() == GroupEvent.Type.GROUP_UPDATED) {
                 synchronized (pendingUpdates) {
-                    pendingUpdates.removeAll(group.appCookie())
-                            .forEach((entry) -> installFlow(entry, group));
+
+                    Map<FibEntry, Group> entriesToInstall =
+                            pendingUpdates.removeAll(group.appCookie())
+                                    .stream()
+                                    .collect(Collectors
+                                                     .toMap(e -> e, e -> group));
+
+                    installFlows(entriesToInstall);
                 }
             }
         }