@Override
    public void process(PacketContext context) {
      // Stop processing if the packet has been handled, since we
      // can't do any more to it.
      if (context.isHandled()) {
        return;
      }

      InboundPacket pkt = context.inPacket();
      Ethernet ethPkt = pkt.parsed();

      if (ethPkt == null) {
        return;
      }

      // Bail if this is deemed to be a control packet.
      if (isControlPacket(ethPkt)) {
        return;
      }

      // Skip IPv6 multicast packet when IPv6 forward is disabled.
      if (!ipv6Forwarding && isIpv6Multicast(ethPkt)) {
        return;
      }

      HostId id = HostId.hostId(ethPkt.getDestinationMAC());

      // Do not process link-local addresses in any way.
      if (id.mac().isLinkLocal()) {
        return;
      }

      // Do we know who this is for? If not, flood and bail.
      Host dst = hostService.getHost(id);
      if (dst == null) {
        flood(context);
        return;
      }

      // Are we on an edge switch that our destination is on? If so,
      // simply forward out to the destination and bail.
      if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
        if (!context.inPacket().receivedFrom().port().equals(dst.location().port())) {
          installRule(context, dst.location().port());
        }
        return;
      }

      // Otherwise, get a set of paths that lead from here to the
      // destination edge switch.
      Set<Path> paths =
          topologyService.getPaths(
              topologyService.currentTopology(),
              pkt.receivedFrom().deviceId(),
              dst.location().deviceId());
      if (paths.isEmpty()) {
        // If there are no paths, flood and bail.
        flood(context);
        return;
      }

      // Otherwise, pick a path that does not lead back to where we
      // came from; if no such path, flood and bail.
      Path path = pickForwardPath(paths, pkt.receivedFrom().port());
      if (path == null) {
        log.warn(
            "Doh... don't know where to go... {} -> {} received on {}",
            ethPkt.getSourceMAC(),
            ethPkt.getDestinationMAC(),
            pkt.receivedFrom());
        flood(context);
        return;
      }

      // Otherwise forward and be done with it.
      installRule(context, path.src().port());
    }