Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EtherSwitch configuration #479

Open
p4pe opened this issue Feb 12, 2021 · 15 comments
Open

EtherSwitch configuration #479

p4pe opened this issue Feb 12, 2021 · 15 comments

Comments

@p4pe
Copy link

p4pe commented Feb 12, 2021

Hello, I'm using EtherSwitch element in order to implement a simple switch (at first) with only one input and one output port.
The click configuration is this:

from_port0::FromDevice(enp6s0f1)
to_port0::ToDevice(enp6s0f0)
in_supp, out_supp :: Suppressor;
switch::EtherSwitch()
q0 :: Queue -> to_port0;

from_port0->[0] in_supp [0] -> [0] switch [0] -> [0] out_supp [0] ->q0;

But when I'm trying to start the router, I can't and took this error:

switch.click:4: ‘switch :: EtherSwitch’ input 1 unused
switch.click:4: ‘switch :: EtherSwitch’ output 1 unused

Where is my misconfiguration?

@ahenning
Copy link

ahenning commented Feb 13, 2021

your config says that a packet received on port 0 is sent out port 0. A switch prevents this.

from_eth0 -> [0]switch[1] -> to_eth1;
from_eth1 -> [1]switch[0] -> to_eth0;

@p4pe
Copy link
Author

p4pe commented Feb 13, 2021

Yes I know that a switch prevents this.
It was a misunderstanding from me and I thought that the output port 0 is not the same port with the input port 0.
I believe that were different ports.

@tbarbette
Copy link
Collaborator

You have to build at least 2 ports to your switch, or it can't "switch" :p You have this kind of requirements in the documentation at https://github.com/kohler/click/wiki/EtherSwitch.

from_port0::FromDevice(enp6s0f0)
from_port1::FromDevice(enp6s0f1)
to_port0::ToDevice(enp6s0f0)
to_port1::ToDevice(enp6s0f1)
in_supp0, out_supp0 :: Suppressor;
in_supp1, out_supp1 :: Suppressor;
switch::EtherSwitch()
q0 :: Queue -> to_port0;
q1 :: Queue -> to_port1;

from_port0->in_supp0  -> [0] switch [0] ->  out_supp0  ->q0;
from_port1->in_supp1  -> [1] switch [1] ->  out_supp1  ->q1;

Note that I have from and to port0 tied to enp6sf0, else I think it's a call for problem.

@p4pe
Copy link
Author

p4pe commented Feb 13, 2021

Yes, it was my misunderstanding, Ι don't know what I was thinking when I read the documentation. :p :P

@p4pe
Copy link
Author

p4pe commented Feb 15, 2021

@tbarbette I saw again your configuration, If I am not completely wrong, we have ingress port enp6s0f0 and also egress port enp6s0f0.

Is this right? or I did not understand the element?

In my scenario I want something like this:
switch

I followed @ahenning example.
So I create a tap interface on the Switch for the incoming traffic from the vnf

 Idle -> tap :: KernelTap(1.1.0.1/24, DEVNAME vEth1);
switch::EtherSwitch()
***The right dashed line***
FromDevice(enp6s0f2)-> [0]switch[1]->Queue->ToDevice(enp6s0f3)
FromDevice(enp6s0f3)-> [1]switch[0] -> Queue -> ToDevice(enp6s0f2)
***The left dashed line***
FromDevice(vEth1)->[2]switch[3]->Queue->ToDevice(enp6s0f1) 
FromDevice(enp6s0f1)->[3]switch[2]->Queue->ToDevice(vEth1)

The VNF configuration is simple forwarder for testing:

FromDevice(enp6s0f2)->Queue->ToDevice(vEth1)

Obviously this configuration did not work and Im trying to figure out, where is my misunderstanding

@tbarbette
Copy link
Collaborator

tbarbette commented Feb 15, 2021

All ports have 2 sides, rx and tx. FromDevice is rx and ToDevice is tx for a real device, a real NIC.

KernelTap includes both at once for a virtual Tap. On the left of kernel tap you handle the tx and on the right the rx. There should be no Idle().

@p4pe
Copy link
Author

p4pe commented Feb 15, 2021

Thanks for the clarification.
This is my only mistake, Ι'm impressed :P ?

@ahenning
Copy link

ahenning commented Feb 15, 2021

@p4pe when a packet is received on a port on the switch, the switch uses the destination mac address to decide which port to switch the packet to (if the MAC is known). In your config, the packets would not take the VNF path by it self. Connecting devices to ports does not tell the switch how to switch the packets. I am assuming this is what you want to engineer with the config, i.e to redirect traffic to the VNF. If not please let me know.

If yes, and you always want the traffic to be sent to the VNF, and it will only be in the direction as per the diagram, then you don't need the complexity of the EtherSwitch. You can simply pump the packet to the KernelTap and assuming the VNF returns the packets, take the packets from KernelTap and send it out the interface you want. In that scenario the switch is not needed.
from_eth0 -> [0]tap[0] -> to_eth1

Of course the L2 headers will need to be set, but that is the path to match the diagram. If the diagram is accurate, I would recommend to remove the switch.

The second scenario is that maybe some packets need to be sent to the VNF and some packets will be sent straight through the switch. This is more complex. In this scenario the switch makes sense, but how will switch know where to send the packets to? The L2 headers need to be set to determine where the packets will be switched to.

Here is another example config with a switch and KernelTap
from_eth0 -> [0]switch[0] -> to_eth0;
from_eth1 -> [1]switch[1] -> to_eth1;
tap[0] -> [2]switch[2] -> [0]tap;

So if you want to use the switch to redirect packets to the VNF you need to do that redirect on the L2 header. In other words, lets say your KernelTap MAC address is 01:01:01:01:01:01 then before the packets are sent to the switch, the L2 header info needs to be changed so that the destination of the packets are 01:01:01:01:01. The destination in L2 header tells the switch which port the packets will be sent out. Assuming you want to redirect the traffic to the VNF, in the above config that would be port 2.

If bidirectional traffic is needed, then the EtherSwitch will make sense. Again either the traffic needs to be redirected with EtherEncap or the L2 headers needs to be set at the Source and Sink so that the L2 info tells the switch to send the packets to the tap port.

@p4pe
Copy link
Author

p4pe commented Feb 15, 2021

Thank you for the answer @ahenning , yes I want the traffic to be redirected to the VNF, and then to a second VNF before goes to the sink.

I already did your first suggestion, but I was asked to do the second one with the EtherSwitch acting as an virtual switch(I was also tried a scenario with OVS and docker, but this killed the throughput).
I do not need bidirectional traffic(yet), I want just to steer the traffic as I show in the figure.

Something that I forgot to say(and write in the config) is that all interfaces are on promisc mode.

@tbarbette
Copy link
Collaborator

tbarbette commented Feb 15, 2021

Start with no VF, then one VF, then two :p Also if you're not handling backward traffic, then the EtherSwitch will probably not be able to learn MACs, so the switch won't work?
So you should maybe hard-wire your configuration (you use no switching element, just Click edges):
from_eth0->tap0;
tap0->tap1;
tap1->to_eth0;

@p4pe
Copy link
Author

p4pe commented Feb 15, 2021

The no VF scenario is working :P I already did this with the hard-wired approach.. (but my supervisor wants the switch...)

@p4pe
Copy link
Author

p4pe commented Feb 22, 2021

Following your advice @tbarbette (I convinced my supervisor :P) not to use the etherswitch. So I have the following setup

chain

For my NAT configuration:

FromDevice(enp6s0f1)
-> Strip(14)
-> CheckIPHeader()
->rw::IPRewriter(pattern 27.32.11.3 1024-65535 - - 0 1);
rw[0]->Queue->ToDevice(vEth1);
rw[1] -> Discard;

For my IPSec:

tap :: KernelTap(192.168.5.0/24, DEVNAME vEth1)
-> c::Counter
-> Strip(14)
-> CheckIPHeader()
-> ipsec_rt::RadixIPsecLookup( 10.10.1.1/32 0,
27.32.11.3/32 10.10.2.1 1 111 1111111111111111 1111111111111111 1 0 ,
0.0.0.0/0 2
);
ipsec_rt[0]
// Receive
-> Discard;
ipsec_rt[1]
-> IPsecESPEncap()
-> IPsecAuthHMACSHA1(0)
-> IPsecAES(1)
-> UDPIPEncap(10.10.1.1 , 4500 , 192.168.2.7 , 4500)
-> EtherEncap(0x800,3c:fd:fe:05:7a:80, 3c:fd:fe:04:a4:42)
-> Queue
-> c1::Counter
-> out::ToDevice(enp6s0f1);
ipsec_rt[2]
// Default
-> Discard;
Script(wait 1, print c1.rate, loop);

But it seems that the 27.32.11.3/32 register in the radixipseclookup table does not working. Why?

@tbarbette
Copy link
Collaborator

I've never used RadixIPsecLookup, and actually IPsec. You're sure you want that one and not RadixIPLookup? What are those supplementary parameters? I know the second term should be the port, then eventually the gateway. But those "1111111111" ?

BTW, you probably want "SNIFFING false" to FromDevice, as you don't want packets to continue in the IP stack.

@ahenning
Copy link

ahenning commented Mar 3, 2021

@p4pe

As Tom mentioned previously:

All ports have 2 sides, rx and tx. FromDevice is rx and ToDevice is tx for a real device, a real NIC.

Using these elements on virtual interfaces might not work so I recommend to use real NIC to save a lot of trouble.

Also I would again recommend to use Print and IPPrint elements to trace the packets. E.g. here the suspect is the Ipsec config but I doubt the packets are even passing through the KernelTap interface.

Here is an example of chaining separate click configs together:
On the Linux host:
ip link add veth0 type veth peer name veth1
Make sure the virtual interfaces are up

Source:
FastUDPSource(1, 1000, 600, 00:0c:29:92:68:92, 192.168.32.128, 1234, 04:04:04:04:04:05, 192.168.32.132, 1234) -> Print("source") -> ToDevice(veth0);

Sink:
FromDevice(veth1, PROMISC true) -> Print("fd sink") -> Discard;

@p4pe
Copy link
Author

p4pe commented Mar 4, 2021

Hello, thank you very much for the directions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants