Commit Graph

68 Commits

Author SHA1 Message Date
f7e1bb951d Sync IPv4 and IPv6 addresses from VPP to LCP
There are three ways in which IP addresses will want to be copied
from VPP into the companion Linux devices:

1) set interface ip address ... adds an IPv4 or IPv6 address
  - this is handled by lcp_itf_ip[46]_add_del_interface_addr() which
    is a callback installed in lcp_itf_pair_init()
2) set interface ip address del ... removes them
  - also handled by lcp_itf_ip[46]_add_del_interface_addr() but
    curiously there is no upstream vnet_netlink_del_ip[46]_addr() so
    I wrote them inline here - I will try to get them upstreamed, as
    they appear to be obvious companions in vnet/device/netlink.h
3) Upon LIP creation, it could be that there are L3 addresses already
   on the VPP interface. If so, set them with lcp_itf_set_interface_addr()

This means that now, at any time a new LIP is created, its state from
VPP is fully copied over (MTU, Link state, IPv4/IPv6 addresses)!

At runtime, new addresses can be set/removed as well.
2021-08-13 16:50:32 +02:00
7c15c84f6c Sync interface state from VPP to LCP
This is the first in a series of functions that aims to copy forward
interface changes in the VPP dataplane into the linux interfaces.

Capture link state changes (set interface state ...) and apply them
to Linux.

There's an important dissonance here:
- When Linux sets a parent interface up, all children also go up.

ip link set enp66s0f1 down
ip link add link enp66s0f1 name foo type vlan id 1234
ip link set foo down
ip link | grep enp66s0f1
9: enp66s0f1: <BROADCAST,MULTICAST> mtu 9000 qdisc mq state DOWN mode DEFAULT group default qlen 1000
61: foo@enp66s0f1: <BROADCAST,MULTICAST,M-DOWN> mtu 9000 qdisc noop state DOWN mode DEFAULT group default qlen 1000

ip link set enp66s0f1 up
ip link | grep s0f1
9: enp66s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP mode DEFAULT group default qlen 1000
61: foo@enp66s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UP mode DEFAULT group default qlen 1000

While in VPP this is not so, there each individual interface and
sub-interface stands for itself. I think the proper fix here is to walk
all sub-interfaces when a phy changes, and force a sync of those from
VPP to LCP as well. I'll do that in a followup commit so it's easier to
roll back.
2021-08-13 13:27:20 +02:00
97b9894dce Restore the plugin to its original state
When I started in my copy, I removed a bunch of code and options that I
felt were distracting. I also renamed lots of elements like 'linux-cp'
and 'Linux CP' and 'Linux-CP' to just be 'lcpng'.

Now, rename all of this back, and make it ready for upstreaming.

The only diffs between my repo and upstream now are the includes and the
lcpng_interface.[ch] code changes, which is good.
2021-08-12 21:26:34 +02:00
a6e71359c5 Add the ability to create QinQ and QinAD
In this situation, Linux and VPP really diverge. In VPP, any
sub-interface can carry arbitrary configuration, they can be dot1q,
dot1ad, with or without an inner dot1q. So the following is valid in
VPP:

vppctl create sub TenGigabitEthernet3/0/0 10 dot1ad 100 inner-dot1q 200 exact-match

In Linux however, double tagged interfaces have to be created as a chain
of two interfaces, first with the outer and then with the inner tag. So
there is no equivalent of the above command in Linux, where we must:

ip link add link e0 name e0.100 type vlan id 100 proto 802.1ad
ip link add link e0.100 name e0.100.200 type vlan id 200 proto 802.1q

So in order to create Q-in-Q sub-interfaces, for Linux their intermediary
parent must exist, while in VPP this is not true.

I have to make a compromise, so I'll be a bit more explicit and allow
this type of LCP to be created under these conditions:
*   A sub-int exists with the intermediary (in this case, `dot1ad 100
    exact-match`)
*   That sub-int itself has an LCP, with a Linux interface device that
    we can spawn the inner-dot1q 200 interface off of

Creation of qinq and qinad interfaces becomes thus:

vppctl create sub TenGigabitEthernet3/0/0 10 dot1ad 100 exact-match
vppctl create sub TenGigabitEthernet3/0/0 11 dot1ad 100 inner-dot1q 200 exact-match
vppctl lcpng create TenGigabitEthernet3/0/0 host-if e0
vppctl lcpng create TenGigabitEthernet3/0/0.10 host-if e0.10
vppctl lcpng create TenGigabitEthernet3/0/0.11 host-if e0.11

And the resulting situation in Linux:

pim@hippo:~/src/lcpng$ ip link | grep e0
397: e0: <BROADCAST,MULTICAST> mtu 9000 qdisc mq state DOWN mode DEFAULT group default qlen 1000
398: e0.10@e0: <BROADCAST,MULTICAST,M-DOWN> mtu 9000 qdisc noop state DOWN mode DEFAULT group default qlen 1000
399: e0.11@e0.10: <BROADCAST,MULTICAST,M-DOWN> mtu 9000 qdisc noop state DOWN mode DEFAULT group default qlen 1000
2021-08-12 20:06:40 +02:00
7c3e1eaf3f Fix two crashes and one potential crash
If there are no LCPs defined yet, and I try to create an LCP for a sub-int,
there is a NULL deref in lcp_itf_pair_get() because the pool hasn't been
initiated yet. Fix this by returning NULL if the pool isn't initialized,
and catching the invalid `lip` returning an error.

While I was here, I took a look at a few possible crashes:
- if the pair_create() is called with an invalid phy_sw_if_index, catch
  this and return an error.
- if a pair_add_sub() is called but the parent cannot be found, catch
  this and return an error.
2021-08-12 16:38:10 +02:00
d43b583c7b Initialize the TAP host state from the VPP state
DBGvpp# set interface state TenGigabitEthernet3/0/0 down
DBGvpp# lcpng create TenGigabitEthernet3/0/0 host-if e0
DBGvpp# set interface state TenGigabitEthernet3/0/1 up
DBGvpp# lcpng create TenGigabitEthernet3/0/1 host-if e1

Yields:

pim@hippo:~/src/lcpng$ ip link show e0
304: e0: <BROADCAST,MULTICAST> mtu 9000 qdisc mq state DOWN mode DEFAULT group default qlen 1000
    link/ether 68:05:ca:32:46:14 brd ff:ff:ff:ff:ff:ff

pim@hippo:~/src/lcpng$ ip link show e1
305: e1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 68:05:ca:32:46:15 brd ff:ff:ff:ff:ff:ff
2021-08-12 15:22:35 +02:00
de5c01280e Refuse to create an LCP for sub-interfaces that does not have exact-match set 2021-08-12 13:01:00 +02:00
954385fd86 Add the ability to set the VLAN protocol on the netlink interfaces -- this will be needed when the VPP interface outer is dot1ad rather than dot1q; Note: this change took for-ever to create! I was stumped on the set_protocol() call succeeding but the add_link() call returning 'Protocol mismatch'; but this was simply a missing ntohs() wrapper on the protocol, pff. Golden hint on https://github.com/thom311/libnl/blob/master/lib/route/link/vlan.c#L454 2021-08-11 18:43:48 +02:00
3c1ccbfcc6 Add a bunch of useful logging.
This is to debug why creating QinQ subinterfaces is failing. Consider
the following:

vppctl create sub TenGigabitEthernet3/0/0 1234
vppctl create sub TenGigabitEthernet3/0/0 1235 dot1q 1234 inner-dot1q 1000
vppctl lcpng create TenGigabitEthernet3/0/0 host-if e0
vppctl lcpng create TenGigabitEthernet3/0/0.1234 host-if e0.1234
vppctl lcpng create TenGigabitEthernet3/0/0.1235 host-if e0.1235

Creating the sub-interfaces works, the first is a normal .1q with
tag 1234. Creating its LCP works well, the parent is looked up,
a netlink VLAN link is created as a child, and it gets tag 1234.

Now the second one: it's also operating on parent Te3/0/0 which is
looked up, but now a netlink VLAN link is created as a child, again
with dot1q 1234: this interface already exists, so that's a no-go
and an error is thrown.

-- Thoughts on a fix for this:
I think the fix is probably retrieving the correct lip, ie not
the lip of the phy parent interface (e0) but the lip of the pair that
has the outer vlan 1234 already (e0.1234), and then asking netlink to
create a child interface with vlan 1235 on that e0.1234, rather than
the phy e0.

Although creating a dot1ad.dot1q or a dot1q.dot1q interface in VPP
is strictly valid, we will not be able to succeed without the
intermediate interface in the Linux model, so we return an error
in that case.
2021-08-10 22:03:40 +02:00
eea724445f Catch null on non-existent interface 2021-08-09 00:19:38 +02:00
915e3598ac Add a bunch more interface phy_add logging to help auto-create/delete LCP in a followup commit 2021-08-09 00:16:03 +02:00
d11c4fccbf Remove lcp_if_process()
Remove the functionality that allows for a configuration of pairs in the
startup.conf -- I am intending on creating interfaces for each/any phy
and sub and tunnel interfaceb that is created.

Instead of injecting events and having a process listening for them,
simply use the callback to create LCP interfaces. This change removes
the old code and sets a helpful logging entry on line 870, in which
future automatic creations and removals of LCP taps will occur.

This way, three desirable usability properties are obtained:
1) on startup, all physical interfaces will be copied into LCP
2) on sub-interface or tunnel creation (or phy insertion), new
   interfaces will be created.
3) Deletions and removals will allow for auto-cleanup of the LCP.
2021-08-08 23:08:43 +02:00
69d7cb73cc Copy L3 VPP interface MTU if available
Still use a sensible default of 9216, but if the L3 packet size is set
on the VPP interface, copy it forward (just as we do in the 'host'
interface of the TAP itself, ie the interface created in the linux
namespace). Now they will all line up initially.
2021-08-08 21:53:04 +02:00
4b79f042bf Remove hardcoded 9216 with ETHERNET_MAX_PACKET_BYTES 2021-08-08 21:40:56 +02:00
8111d1e9a8 Force MTU 9216 on lcpng TAP interfaces
The TAP interface does copy forward the host MTU based on the VPP
interface's L3 MTU, but it should also ensure that the VPP tap
interface has an MTU that is greater-or-equal to those.  Considering
users can set the interfaces at runtime (set interface mtu packet ...)
ensure that the tap MTU is large enough.

Ideally, a callback updates the MTU to the same value as the L3 MTU of
the VPP interface, or the L3 MTU of the host interface, if either of
those change. For now, it's a safe bet to take jumbo 9216.
2021-08-08 21:35:13 +02:00
2f51a196fc cosmetic - rename 'lcp-itf-process' to 'lcpng-if-process' 2021-08-08 21:21:18 +02:00
ca273dc953 Remove ability to override netns
This gives a lot of operational problems later. It's definitely reasonable
to be able to create tap interfaces in other namespaces, and this is
still possible (see below for syntax).

However, changing the runtime netns makes the netlink listener much more
complicated because it will have to listen on not just one netns, but all
of them, for netlink updates.

So, for now, let's remove the ability to set the namespace in the API.
Still possible:
- set at startup.conf in lcpng { netns <x> }
- force creating in 'lcpng create ... netns <x>'

This will nudge folks to create one singular namespace (say,
'dataplane', in the startup.conf), and then handle all netlink messages
in that namespace only.
2021-08-08 20:54:43 +02:00
80934a5c46 Initial checkin - renamed the files to avoid clashing with 'lcp' and 'linux-cp' plugin 2021-08-08 19:50:25 +02:00