Set R-bit in neighbor advertisement if replying as a router

Change-Id: Ic51140cf7ab88064df0bc87fb4d1fbc976ce7bc7
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
index af62525..cfef0f1 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
@@ -107,7 +107,7 @@
                         pkt.inPort().deviceId(), pkt.sender());
                 return;
             }
-            sendResponse(pkt, targetMac, hostService);
+            sendResponse(pkt, targetMac, hostService, true);
         } else {
             // NOTE: Ignore ARP packets except those target for the router
             //       We will reconsider enabling this when we have host learning support
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index 3ec8b23..cb604a7 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -333,7 +333,7 @@
                         pkt.inPort().deviceId(), pkt.sender());
                 return;
             }
-            sendResponse(pkt, routerMac, hostService);
+            sendResponse(pkt, routerMac, hostService, true);
         } else {
 
             // Process NDP targets towards EUI-64 address.
@@ -343,7 +343,7 @@
                 Optional<Ip6Address> linkLocalIp = getLinkLocalIp(pkt.inPort());
                 if (linkLocalIp.isPresent() && pkt.target().equals(linkLocalIp.get())) {
                     MacAddress routerMac = config.getDeviceMac(deviceId);
-                    sendResponse(pkt, routerMac, hostService);
+                    sendResponse(pkt, routerMac, hostService, true);
                 }
             } catch (DeviceConfigNotFoundException e) {
                 log.warn(e.getMessage() + " Unable to handle NDP packet to {}. Aborting.", pkt.target());
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java
index 200a190..8ef8e7e 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java
@@ -121,8 +121,10 @@
      * @param pkt the request
      * @param targetMac the target mac
      * @param hostService the host service
+     * @param isRouter true if this reply is sent on behalf of a router
      */
-    protected void sendResponse(NeighbourMessageContext pkt, MacAddress targetMac, HostService hostService) {
+    protected void sendResponse(NeighbourMessageContext pkt, MacAddress targetMac, HostService hostService,
+                                boolean isRouter) {
         // if this is false, check if host exists in the store
         if (!respondToUnknownHosts()) {
             short vlanId = pkt.packet().getQinQVID();
@@ -135,6 +137,7 @@
                 return;
             }
         }
+        pkt.setIsRouter(isRouter);
         pkt.reply(targetMac);
     }
 
diff --git a/core/api/src/main/java/org/onosproject/net/neighbour/NeighbourMessageContext.java b/core/api/src/main/java/org/onosproject/net/neighbour/NeighbourMessageContext.java
index 65042c6..04bc8e9 100644
--- a/core/api/src/main/java/org/onosproject/net/neighbour/NeighbourMessageContext.java
+++ b/core/api/src/main/java/org/onosproject/net/neighbour/NeighbourMessageContext.java
@@ -131,4 +131,21 @@
      * Drops the incoming message.
      */
     void drop();
+
+    /**
+     * Gets whether this neighbour message context involves a router.
+     *
+     * @return true if this neighbour message context involves a router
+     */
+    default boolean isRouter() {
+        return false;
+    }
+
+    /**
+     * Sets whether this neighbour message context involves a router.
+     *
+     * @param isRouter true if this neighbour message context involves a router
+     */
+    default void setIsRouter(boolean isRouter) {
+    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActions.java b/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActions.java
index cdbd35c..2e9395c 100644
--- a/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActions.java
+++ b/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageActions.java
@@ -97,7 +97,7 @@
             break;
         case NDP:
             sendTo(buildNdpReply((Ip6Address) context.target(), targetMac,
-                    context.packet()), context.inPort());
+                    context.packet(), context.isRouter()), context.inPort());
             break;
         default:
             break;
@@ -140,10 +140,11 @@
      * @param srcIp   the IP address to use as the reply source
      * @param srcMac  the MAC address to use as the reply source
      * @param request the Neighbor Solicitation request we got
+     * @param isRouter true if this reply is sent on behalf of a router
      * @return an Ethernet frame containing the Neighbor Advertisement reply
      */
     private Ethernet buildNdpReply(Ip6Address srcIp, MacAddress srcMac,
-                                   Ethernet request) {
+                                   Ethernet request, boolean isRouter) {
         Ethernet eth = new Ethernet();
         eth.setDestinationMACAddress(request.getSourceMAC());
         eth.setSourceMACAddress(srcMac);
@@ -164,6 +165,9 @@
         nadv.setTargetAddress(srcIp.toOctets());
         nadv.setSolicitedFlag((byte) 1);
         nadv.setOverrideFlag((byte) 1);
+        if (isRouter) {
+            nadv.setRouterFlag((byte) 1);
+        }
         nadv.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS,
                 srcMac.toBytes());
 
diff --git a/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageContext.java b/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageContext.java
index 2e013af..9cf000f 100644
--- a/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageContext.java
+++ b/core/net/src/main/java/org/onosproject/net/neighbour/impl/DefaultNeighbourMessageContext.java
@@ -54,6 +54,8 @@
 
     private final NeighbourMessageActions actions;
 
+    private boolean isRouter;
+
     /**
      * Creates a new neighbour message context.
      *
@@ -77,6 +79,7 @@
         this.type = type;
         this.target = target;
         this.sender = sender;
+        this.isRouter = false;
     }
 
     @Override
@@ -152,8 +155,18 @@
     }
 
     @Override
+    public boolean isRouter() {
+        return this.isRouter;
+    }
+
+    @Override
+    public void setIsRouter(boolean isRouter) {
+        this.isRouter = isRouter;
+    }
+
+    @Override
     public int hashCode() {
-        return Objects.hash(protocol, type, target, sender, eth, inPort);
+        return Objects.hash(protocol, type, target, sender, eth, inPort, isRouter);
     }
 
     @Override
@@ -169,7 +182,8 @@
                 Objects.equals(target, that.target) &&
                 Objects.equals(sender, that.sender) &&
                 Objects.equals(eth, that.eth) &&
-                Objects.equals(inPort, that.inPort);
+                Objects.equals(inPort, that.inPort) &&
+                Objects.equals(isRouter, that.isRouter);
     }
 
     /**