Added policy routing feature including segment stiching feature in Segment Routing app and driver.

Change-Id: I56c185eeb208ba9117f33fc37a6da43f11ecb686
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
index 81586d8..f799617 100644
--- a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
+++ b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
@@ -877,6 +877,23 @@
         return;
     }
 
+
+    private void createGroupForMplsLabel(int groupId, String nodeId,
+            int nextGroupId, boolean bos) {
+        List<BucketInfo> buckets = new ArrayList<BucketInfo>();
+        BucketInfo bucket = new BucketInfo(nextGroupId,
+                Integer.parseInt(nodeId), bos);
+        buckets.add(bucket);
+        EcmpInfo ecmpInfo = new EcmpInfo(groupId, buckets);
+        setPolicyEcmpGroup(ecmpInfo);
+//        ecmpGroups.put(ns, ecmpInfo);
+        log.debug(
+                "createGroupForANeighborSet: Creating ecmp group {} in sw {} "
+                        + "for pushing label {} and group to {}",
+                groupId, getStringId(), nodeId, nextGroupId);
+        return;
+    }
+
     /**
      * createGroups creates ECMP groups for all ports on this router connected
      * to other routers (in the OF network). The information for ports is
@@ -899,6 +916,7 @@
      * <li>7) all ports to R1, R2, and R3
      */
     private void createGroups() {
+
         Set<Dpid> dpids = neighbors.keySet();
         if (dpids == null || dpids.isEmpty()) {
             return;
@@ -961,7 +979,9 @@
         MacAddress srcMac;
         MacAddress dstMac;
         PortNumber outport;
+        int groupNo;
         int mplsLabel;
+        boolean bos;
 
         BucketInfo(Dpid nDpid, MacAddress smac, MacAddress dmac,
                 PortNumber p, int label) {
@@ -970,13 +990,26 @@
             dstMac = dmac;
             outport = p;
             mplsLabel = label;
+            groupNo = -1;
         }
 
+        BucketInfo(int no, int label, boolean b) {
+            neighborDpid = null;
+            srcMac = null;
+            dstMac = null;
+            outport = null;
+            groupNo = no;
+            mplsLabel = label;
+            bos = b;
+        }
+
+
         @Override
         public String toString() {
             return " {neighborDpid: " + neighborDpid + ", dstMac: " + dstMac +
                     ", srcMac: " + srcMac + ", outport: " + outport +
-                    "mplsLabel: " + mplsLabel + "}";
+                    ", groupNo: " + groupNo +
+                    ", mplsLabel: " + mplsLabel + "}";
         }
     }
 
@@ -1042,6 +1075,84 @@
         }
     }
 
+    private void setPolicyEcmpGroup(EcmpInfo ecmpInfo) {
+        List<OFMessage> msglist = new ArrayList<OFMessage>();
+        OFGroup group = OFGroup.of(ecmpInfo.groupId);
+
+        List<OFBucket> buckets = new ArrayList<OFBucket>();
+        List<OFAction> actions = new ArrayList<OFAction>();
+        for (BucketInfo b : ecmpInfo.buckets) {
+            if (b.dstMac != null && b.srcMac != null && b.outport != null) {
+                OFOxmEthDst dmac = factory.oxms()
+                        .ethDst(b.dstMac);
+                OFAction setDA = factory.actions().buildSetField()
+                        .setField(dmac).build();
+                OFOxmEthSrc smac = factory.oxms()
+                        .ethSrc(b.srcMac);
+                OFAction setSA = factory.actions().buildSetField()
+                        .setField(smac).build();
+                OFAction outp = factory.actions().buildOutput()
+                        .setPort(OFPort.of(b.outport.shortValue()))
+                        .build();
+                actions.add(setSA);
+                actions.add(setDA);
+                actions.add(outp);
+            }
+            if (b.groupNo > 0) {
+                OFAction groupTo = factory.actions().buildGroup()
+                        .setGroup(OFGroup.of(b.groupNo))
+                        .build();
+                actions.add(groupTo);
+            }
+            if (b.mplsLabel != -1) {
+                OFAction pushLabel = factory.actions().buildPushMpls()
+                        .setEthertype(EthType.MPLS_UNICAST).build();
+
+                OFBooleanValue bosValue = null;
+                if (b.bos)
+                    bosValue = OFBooleanValue.TRUE;
+                else
+                    bosValue = OFBooleanValue.FALSE;
+                OFOxmMplsBos bosX = factory.oxms()
+                        .mplsBos(bosValue);
+                OFAction setBX = factory.actions().buildSetField()
+                        .setField(bosX).build();
+                OFOxmMplsLabel lid = factory.oxms()
+                        .mplsLabel(U32.of(b.mplsLabel));
+                OFAction setLabel = factory.actions().buildSetField()
+                        .setField(lid).build();
+                OFAction copyTtl = factory.actions().copyTtlOut();
+                OFAction decrTtl = factory.actions().decMplsTtl();
+                actions.add(pushLabel);
+                actions.add(setLabel);
+                actions.add(setBX);
+                actions.add(copyTtl);
+                // decrement TTL only when the first MPLS label is pushed
+                if (b.bos)
+                    actions.add(decrTtl);
+            }
+            OFBucket ofb = factory.buildBucket()
+                    .setWeight(1)
+                    .setActions(actions)
+                    .build();
+            buckets.add(ofb);
+        }
+
+        OFMessage gm = factory.buildGroupAdd()
+                .setGroup(group)
+                .setBuckets(buckets)
+                .setGroupType(OFGroupType.SELECT)
+                .setXid(getNextTransactionId())
+                .build();
+        msglist.add(gm);
+        try {
+            write(msglist);
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
     private void modifyEcmpGroup(EcmpInfo ecmpInfo) {
         List<OFMessage> msglist = new ArrayList<OFMessage>();
         OFGroup group = OFGroup.of(ecmpInfo.groupId);
@@ -1155,15 +1266,23 @@
             EthType ethertype = ((PopMplsAction) action).getEthType();
             ofAction = factory.actions().popMpls(ethertype);
         } else if (action instanceof GroupAction) {
-            NeighborSet ns = ((GroupAction) action).getDpids();
-            EcmpInfo ei = ecmpGroups.get(ns);
-            if (ei == null) {
-                log.debug("Unable to find ecmp group for neighbors {} at "
-                        + "switch {} and hence creating it", ns, getStringId());
-                createGroupForANeighborSet(ns, groupid.incrementAndGet());
-                ei = ecmpGroups.get(ns);
+            // If group Id can be specified explicitly in case of policy routing.
+            int gid = -1;
+            GroupAction ga = (GroupAction)action;
+            if (ga.getGroupId() > 0) {
+                gid = ga.getGroupId();
             }
-            int gid = ei.groupId;
+            else {
+                NeighborSet ns = ((GroupAction) action).getDpids();
+                EcmpInfo ei = ecmpGroups.get(ns);
+                if (ei == null) {
+                    log.debug("Unable to find ecmp group for neighbors {} at "
+                            + "switch {} and hence creating it", ns, getStringId());
+                    createGroupForANeighborSet(ns, groupid.incrementAndGet());
+                    ei = ecmpGroups.get(ns);
+                }
+                gid = ei.groupId;
+            }
             ofAction = factory.actions().buildGroup()
                     .setGroup(OFGroup.of(gid))
                     .build();
@@ -1420,13 +1539,13 @@
                 .setTableId(TableId.of(TABLE_ACL))
                 .setMatch(matchBuilder.build())
                 .setInstructions(instructions)
-                .setPriority(MAX_PRIORITY / 2) // TODO: wrong - should be MA
-                                               // priority
+                .setPriority(MAX_PRIORITY) // exact match and exclusive
                 .setBufferId(OFBufferId.NO_BUFFER)
                 .setIdleTimeout(0)
                 .setHardTimeout(0)
                 .setXid(getNextTransactionId())
                 .build();
+
         return aclFlow;
     }
 
@@ -1499,10 +1618,35 @@
         }
     }
 
+    public int createTunnel(int tunnelId, List<String> route, NeighborSet ns) {
+
+        // create a last group of the group chaining
+        int finalGroupId = groupid.incrementAndGet();
+        createGroupForANeighborSet(ns, finalGroupId);
+
+        int groupId = 0;
+        int nextGroupId = finalGroupId;
+        boolean bos = false;
+
+        // process the node ID in reverse order
+        for (int i = 0; i < route.size(); i++) {
+            String nodeId = route.get(i);
+            groupId = groupid.incrementAndGet();
+            if (i == route.size()-1)
+                bos = true;
+            createGroupForMplsLabel(groupId, nodeId, nextGroupId, bos);
+            nextGroupId = groupId;
+        }
+
+        return groupId;
+    }
+
+
     // *****************************
     // Unused
     // *****************************
 
+
     @SuppressWarnings("unused")
     private void setAsyncConfig() throws IOException {
         List<OFMessage> msglist = new ArrayList<OFMessage>(3);