2016-06-25 15 views
5

私はIPV4のデータ構造を探しています。何を保管すべきですか?接頭辞:(ベース+マスク) - >例えば85.23.0.0/16ipv4ストレージのデータ構造+アルゴリズム - プレフィックスの効率的な検索

基地= 85.23.0.0 - > 32ビット符号なし

マスク= 16 AKA 255.255.0.0 -

>チャー8ビット符号なし

だから、分ホストは85.23.0.0で、最大ホストが85.23.255.255(私はそれが正常な場合には.0.1と.255.254なければならないことを知っているが、私はそれを簡素化したい)

である私が必要と主なものはスピードであります格納されたプレフィックス内のIPを検索する。たとえば、私はunsigned int(32bit)を与え、それが存在するかどうかを知る必要があります。

私は私は今では、STLセット(対ベース+マスク)に格納され、私は1つずつ検索していますので、それはOのソート(N)(除くあるSTL

を使用することができるC++で書いていそれはおそらくBSTツリーなので、それを通って歩くとO(n)よりも遅くなるかもしれません)

要約:私はIPV4を格納するのに効率的な方法を必要としません。データ構造。また、データ構造はポートやファミリタイプなどを保存しません。PREFIX(ベース+マスク)を格納します。

そして私はデータ構造+検索アルゴリズムを探しています。

+0

プレフィックスの総数があまり多くない場合は、最上位ビットから最下位ビットまでを表す単純なバイナリツリーで十分です。 –

+0

私は多数のプレフィックスでも効率を保証しなければならないのは心配です。 – user3613919

+0

64bit unsigned intとして保存できますか? – Logman

答えて

2

なぜstd:unordered_mapを使用しないのですか? O(1)とO(n)の間にあるか、O(log n)の固定のパフォーマンスが必要な場合はstd:mapを使用することができます(検索フェーズでのみパフォーマンスに関心がある場合)。データセットが大きい場合を除いて、大きな違いはないことがわかります。

+0

また、https://github.com/sparsehash/sparsehashを使用して、スピードまたはスペースの両方に最適化することもできます。 – Robbykk

1

この方法はマスク範囲1〜31でのみ機能します。あなたが保存できるネットワークアドレスの単純なプロパティを使用して、完全な範囲のための高速なバイナリ検索を行うことが(0-32)あなたはおそらく64ビットの整数の内側にマスクとアドレスを保存する必要があります(例のために。このstd::vector<unsigned long long> networkAddrs(bases.size());のように... networkAddrs[i] = (bases[i] << 32) + masks[i];

ネットワークアドレスの未使用ビットの内部にあるマスクを使用して、単一の32ビット整数の中にマスクとベースを格納し、そのベクトルをソートしてバイナリ検索を行うことができます。このような何か:

#include <iostream> 
#include <string> 
#include <vector> 
#include <algorithm> 
#include <cmath> 

unsigned int insertMask(unsigned int ip, unsigned int mask) 
{ 
    unsigned int longMask = (~0) << (32-mask); 
    unsigned int netAdd = (ip & longMask) + (1 << (31-mask)); 
    return netAdd; 
} 

bool isInNetwork(std::vector<unsigned int>& nAs, unsigned int ip, unsigned int mask) 
{ 
    unsigned int netAdd = insertMask(ip, mask); 
    auto pos = std::lower_bound(nAs.begin(), nAs.end(), netAdd); 
    return pos != nAs.end() && *pos == netAdd; 
} 

int main() 
{ 

    std::vector<unsigned int> bases { 
     (192u<<24)+(168<<16)+(0<<8)+(0) 
     ,190u<<24 
     ,191u<<24 
     ,192u<<24 
     ,193u<<24 
     ,194u<<24 
     ,195u<<24 
     ,196u<<24 
    }; 

    std::vector<unsigned int> masks {24,24,24,24,24,16,8,4}; 

    std::vector<unsigned int> networkAddrs(bases.size()); 

    for(int i=0; i<bases.size(); i++) 
    { 
     networkAddrs[i] = insertMask(bases[i], masks[i]); 
    } 

    std::sort (networkAddrs.begin(), networkAddrs.end()); 

    unsigned int ip_addr = (192u<<24)+(168<<16)+(0<<8)+(17); 
    unsigned int mask = 24; 

    if(isInNetwork(networkAddrs, ip_addr, mask)) 
    std::cout << "TRUE"; 
    else 
    std::cout << "FALSE"; 

    std::cout << '\n'; 

} 

EDIT:

のIP XXX.XXX.YYY.YYYため

/16
0B XXXXXXXX XXXXXXXX 10000000 00000000

用: は、私はこのようなようなコードマスクに方法を変更IP(XXX.XXX.0xXY.YYY/12)
0B XXXXXXXX XXXXXXXX XXXX1000 00000000

+0

あなたは私になぜunsigned int netAdd =(ip&longMask)+ maskを説明できますか?あなたはマスクを追加しますか? – user3613919

+1

これは簡単です;)この例を見てください:ip:192.168.1.17/24は16進数 "c0 a8 01 11"でマスク "ff ff ff 00"です。これによりネットワークアドレスに "c0 a8 01 ** 00 **"が与えられ、ネットワークアドレスの最後の5ビットに圧縮マスク "24"(0x18またはバイナリ0b11000)を格納できるようになりました。 IPが格納されたネットワークに属しているかどうかをチェックする方法は、今からベースからマスクを分離することはできません。 – Logman

+0

あなたのアイデアを理解できなかったかもしれませんが、 1)マスクが32の場合はどうなりますか? 2)netAddにマスクを追加して、それをベクトルで検索しますか? – user3613919

3
あなたは2012年から 'ソフトウェアに毎秒億のルーティングルックアップに向けて' DXR紙を確認することができ

http://info.iet.unipi.it/~luigi/papers/20120601-dxr.pdf

このホワイトペーパーでは、DXR、簡単に現代のCPUのキャッシュ階層に収まるコンパクトなルックアップ構造に大きなルーティングテーブルを変換に基づいて、ルックアップスキームを提示します。

トランスフォームは、417,000個のIPv4プレフィックスと213個の異なるネクストホップを持つ実世界のBGPスナップショットを、782 KBしか消費しないプレフィックスあたり2バイト未満の構造にします。実験では、対応するルックアップアルゴリズムがCPUコアの数と直線的に比例することを示しています.1つの汎用8コアCPU上で実行すると、一様にランダムなIPv4キーの平均スループットは毎秒8億4000ルックアップになります。メモリが非常に遅く、CPUのキャッシュが速く(コンピュータmemory hierarchymemory wallの変種)であるため、

あなたが「IPV4を格納するための効率的な方法を必要としない」を求めている一方で、コンパクトに収納は、検索のパフォーマンスに役立ちます。よりコンパクトな表現は、L3キャッシュからメモリへのミスを少なくし、より高速にすることができる。ランダム検索キーで

(Aワーストケースの状態)D18Rは、毎秒117百万個のルックアップ(紙ジャケット仕様から行く:

DXRは(DDR3 1866MHzメモリを搭載した3.6 GHzのAMDのFX-8150に)非常に良いスピードを持っています)を840MIPSに拡張し、8つのコアをすべてアクティブにします。 DXRは、構成とクエリのパターンに応じて、1コアで1秒あたり50〜250,000ルックアップを達成します。

117 mlps on 3.6 GHzはルックアップごとに約30 cpuティックです。 DDR3 1866MHzのメモリランダムアクセスレイテンシは、DRAMの行が開いているときにメモリからメモリコントローラに最初のバイトを取得する場合にのみ9-10 nsまたは32-36cpサイクルを超えます(通常は開かない行も遅くなります)。フルキャッシュラインを読み出すためにはさらに時間が必要であり、このキャッシュラインをL3、L2、L1、レジスタに転送するにはもう少しの時間が必要です。完全メモリの待ち時間はclose to 100 ns(360 cpuサイクル)です。

+0

DXRサイト、アップデート、およびソースは、http://www.nxlab.fer.hr/dxr/です。ペーパー「DXR:ソフトウェアで1秒あたり10億回のルックアップを目指す」は、ACM Computer Communication Review、Vol。 42(5)、2012、pp。29-36。これらの中で興味深い論文があるかもしれません:https://scholar.google.com/scholar?gws_rd=ssl&um=1&ie=UTF-8&lr&cites=17851808599136542137 – osgx

0

CritBitツリーを使用できます。彼らは非常にシンプルですが、多くのオープンソースのバリエーションもあります。プレフィックスの共有を使用する検索可能なツリーで、同じ接頭辞を持つすべての値が同じサブツリーに格納されます。実装によっては、すべてのエントリではなく、プレフィックスを一度だけ保存するため、プレフィックス共有もスペース削減のために使用できます。

関連する問題