3

現在、一種のイーサネット パケット処理ライブラリを開発しています。基本的な考え方は、パケットにはネットワーク インターフェイスと pcap ダンプ ファイルの 2 つの異なるソースがあるということです。パケットはフローごとにグループ化する必要があり、フローはフィルタリングする必要があり、UDP フローはある方法で処理し、TCP は別の方法で処理する必要があります。コンジットなしでバージョンを開発しましたが、現在、重複するコードが多すぎることがわかりました。私は抽象化しようとしていますが、コンジットに似たものを発明しています。それで、コンジットに切り替えようとしましたが、行き詰まりました。

したがって、写真は次のようになります。

                                   [UDP processing]
[pcap source]   |                 /                \
                |---[flow map]-->*                  *->[dump to many files]
                |                 \                /  
[iface source]  |                  [TCP processing]

最初の問題はフロー マップです。フローを蓄積する必要があり、フローにあるしきい値よりも多くのパケットがある場合は、それを処理に渡します。

2 つ目の問題は、UDP と TCP の処理に別のパイプを使用したいので、パイプを何らかの方法で分割する必要があることです。

そして、このすべてのものをマルチスレッド化する必要があるという別の問題があるため、プロデューサーとコンシューマーは異なるスレッドにある必要があります。

では、この図では、コンジットに関して何をすべきでしょうか?

ソースはソースです、それは明らかです。しかし、フロー マップはどうあるべきでしょうか。さらに処理するためのソースを生成するシンク? フローの数は膨大であるため、さらに処理する前にすべてのパケットをメモリに蓄積することは避けなければなりません。

何か案は?繰り返しになりますが、これらすべてをコンジットなしで行う方法は非常に明確なので、コンジットを使用して適切に設計する方法が問題になります。

アップデート。

  data FlowFrame = FlowFrame { flowKey   :: !F.FlowKey
                             , flowFrame :: [Packet]
                             }

  data FlowState

  flowFrames :: MonadIO m => Conduit Packet m FlowFrame
  flowFrames = awaitForever $ \p -> do
    let (Right (l3, _)) = runGet F.readL3Headers (pktData p)
    let fk = F.flowKey l3
    yield (FlowFrame fk [p])

  sinkPrintFlow :: MonadIO m => Consumer FlowFrame m ()
  sinkPrintFlow = awaitForever $ liftIO.putStrLn.show.pPrint.flowKey

  isA :: F.Protocol -> FlowFrame -> Bool
  isA p frame =
    case ((flowKey frame)) of
      F.FlowKey p _ _ -> True
      _               -> False

  processUDP :: MonadIO m => Conduit FlowFrame m FlowFrame
  processUDP = CL.filter (isA F.PROTO_UDP)

  processTCP :: MonadIO m => Conduit FlowFrame m FlowFrame
  processTCP = CL.filter (isA F.PROTO_TCP)

  main = do 
    (file:_) <- getArgs
    input <- openOffline file
    sourcePcap input
      $$ flowFrames =$= void (sequenceConduits [processUDP, processTCP])
      $= sinkPrintFlow
    putStrLn "done"
4

2 に答える 2