kohler / click

The Click modular router: fast modular packet processing and analysis
Other
734 stars 324 forks source link

NAT implementation #476

Open p4pe opened 3 years ago

p4pe commented 3 years ago

Hello, I'm currently implement a simple NAT click configuration which is like this:

FromDevice(enp6s0f1)
-> Strip(14)
-> CheckIPHeader()
//-> GetIPAddress(16)
->rw::IPRewriter(pattern 27.32.11.3 1000 - 1001 0 1);

rw[0]->IPPrint("NAT")->Queue->ToDevice(enp6s0f0);

rw[1] -> IPPrint(rw1) -> Discard;

Script(wait 1, print rw.udp_table, loop);

I generate traffic in the source:

FastUDPSource(50000, 100000000, 60, 3c:fd:fe:05:ce:c2, 192.168.2.2, 1234,                                                                                                                                    
                                    3c:fd:fe:05:94:c2, 192.168.2.7, 1234)                                                                                                                         
  -> ToDevice(enp6s0f1); 

From what I've understand my NAT configuration seems ok (print the udp_table)

nat

My question is how can I create a big NAT table with many entries (e.g 10k) ? To be more precise, I would like to observe if there is a degradation(e.g throughput) due to many lookups in the NAT table.

Can I do this(feel the NAT table with many entries) within click?

Thank you in advance for your help

ahenning commented 3 years ago

The question is not clear to me. Do you have trouble configuring large NAT tables? What prevents creating large NAT tables? Perhaps take a look if the element support write handlers which will allow to update the table through the control socket while the router is running and if that is not possible use a bash/perl/python script to generate a click config with 10k rules and reload the router. Perhaps I am missing the issue, but there should normally not be an issue with creating large configs. One notable exception is that if the config is larger than 65K, then by default reloading the config via hotswapping (click -R) will not work, but I doubt you need it for this test.

Regarding the intended throughput test. One thing to consider with tests like this is that the traffic L3/L4 headers needs to be fairly random. If the traffic is static/predictable for example using the same source and destination ports and addresses, then the traffic would match one rule irrespective if there are 10 patterns or 10k patterns and will give the illusion there is little or no performance hit. To accurately test the traffic needs to match rules up and down the table/tree.

p4pe commented 3 years ago

The issue is that I don't know how to configure the large table.. :D If I understood well ' in this configuration rw::IPRewriter(pattern 27.32.11.3 1000 - 1001 0 1);

This means that change the source ipX with 27.32.11.3 and srcport with 1000, dst ip will stay the same, and srcport will change to 1001.

0 and 1 are the output ports.

So with this configuration every packet (even if src is 192.168.2.2 or 192.168.4.5 ) will enter the IPRewritter and will hit this pattern

The question is and sorry if it is a silly question, how can i configure for example

src:192.168.2.2 to match with pattern 1
   src: 192.168.4.2 to match with patern 2 etc etc..

Thank you for your time

ahenning commented 3 years ago

Maybe the solution is not to create more static nat rules, but to create more random source ports in the traffic generator. Each new source port will create a dynamic entry in the iprewriter table until you reached 10k rules.

rw::IPRewriter(pattern 192.168.1.1 50000-60000 - - 0 1);

p4pe commented 3 years ago

Good idea @ahenning , I will see if i can do this with, FastUDPSource or InfiniteSource. Or if you have to suggest me something else as traffic generator

Thank you for your time.

p4pe commented 3 years ago

Seems that is working.

nat_table

I change the IPs manually in the FastUDPSource, I have to automate this.

Do you know if this is possible inside the click configuratio (i.e with script element) or i have to use python etc?

ahenning commented 3 years ago

Maybe SetRandIPAddress does what you need?

https://github.com/kohler/click/wiki/SetRandIPAddress

InfiniteSource(LENGTH 1000, LIMIT 3, STOP true) -> SetRandIPAddress(192.168.0.0/24, 32) -> UDPIPEncap(1.1.1.1,123, DST_ANNO, 123) -> ipsec_rt::RadixIPsecLookup( 10.10.1.1/32 0, 192.168.0.0/24 10.10.2.1 1 111 1111111111111111 1111111111111111 1 0 , 0.0.0.0/0 2 );

I have not tried Random IP address annotations with FastUDPSource, but I am fairly sure at 220k pkts/s FastUDPSource is not needed and if it is really needed, perhaps copy the Random IP code from SetRandIPAddress into a FastUDPSource to create a new element called something like FastRandUDPSource.

p4pe commented 3 years ago

Finally I used the INTERVAL feauture of the FastUDPSource element, and I manage to feed the NAT table with 65k of flow mappings.

May I ask you something, if you know, what do you think is the best way to measure the throughput on the sink? i) Sending random IPs:ports with FastUDPsource ii) Sending static IPs:ports with FastUDPsource

Does IPRewritter do some kind of caching and it does not have to Lookup all the time in the table (I observe that if I send the same IP from the source, the throughput on the sink is higher) Does a smaller range in the IPRewritter (e.g rw::IPRewriter(pattern 27.32.11.3 1024-10000 - - 0 1); Which element is better for this AverageCounter or Counter?

I really appreciate your help