This patch set adds the new "strict mode" functionality to the Virtual
Routing and Forwarding infrastructure (VRF). Hereafter we discuss the
requirements and the main features of the "strict mode" for VRF.
On VRF creation, it is necessary to specify the associated routing table used
during the lookup operations. Currently, there is no mechanism that avoids
creating multiple VRFs sharing the same routing table. In other words, it is not
possible to force a one-to-one relationship between a specific VRF and the table
associated with it.
The "strict mode" imposes that each VRF can be associated to a routing table
only if such routing table is not already in use by any other VRF.
In particular, the strict mode ensures that:
1) given a specific routing table, the VRF (if exists) is uniquely identified;
2) given a specific VRF, the related table is not shared with any other VRF.
Constraints (1) and (2) force a one-to-one relationship between each VRF and the
corresponding routing table.
The strict mode feature is designed to be network-namespace aware and it can be
directly enabled/disabled acting on the "strict_mode" parameter.
Read and write operations are carried out through the classic sysctl command on
net.vrf.strict_mode path, i.e: sysctl -w net.vrf.strict_mode=1.
Only two distinct values {0,1} are accepted by the strict_mode parameter:
- with strict_mode=0, multiple VRFs can be associated with the same table.
This is the (legacy) default kernel behavior, the same that we experience
when the strict mode patch set is not applied;
- with strict_mode=1, the one-to-one relationship between the VRFs and the
associated tables is guaranteed. In this configuration, the creation of a VRF
which refers to a routing table already associated with another VRF fails and
the error is returned to the user.
The kernel keeps track of the associations between a VRF and the routing table
during the VRF setup, in the "management" plane. Therefore, the strict mode does
not impact the performance or intrinsic functionality of the data plane in any
way.
When the strict mode is active it is always possible to disable the strict mode,
while the reverse operation is not always allowed.
Setting the strict_mode parameter to 0 is equivalent to removing the one-to-one
constraint between any single VRF and its associated routing table.
Conversely, if the strict mode is disabled and there are multiple VRFs that
refer to the same routing table, then it is prohibited to set the strict_mode
parameter to 1. In this configuration, any attempt to perform the operation will
lead to an error and it will be reported to the user.
To enable strict mode once again (by setting the strict_mode parameter to 1),
you must first remove all the VRFs that share common tables.
There are several use cases which can take advantage from the introduction of
the strict mode feature. In particular, the strict mode allows us to:
i) guarantee the proper functioning of some applications which deal with
routing protocols;
ii) perform some tunneling decap operations which require to use specific
routing tables for segregating and forwarding the traffic.
Considering (i), the creation of different VRFs that point to the same table
leads to the situation where two different routing entities believe they have
exclusive access to the same table. This leads to the situation where different
routing daemons can conflict for gaining routes control due to overlapping
tables. By enabling strict mode it is possible to prevent this situation which
often occurs due to incorrect configurations done by the users.
The ability to enable/disable the strict mode functionality does not depend on
the tool used for configuring the networking. In essence, the strict mode patch
solves, at the kernel level, what some other patches [1] had tried to solve at
the userspace level (using only iproute2) with all the related problems.
Considering (ii), the introduction of the strict mode functionality allows us
implementing the SRv6 End.DT4 behavior. Such behavior terminates a SR tunnel and
it forwards the IPv4 traffic according to the routes present in the routing
table supplied during the configuration. The SRv6 End.DT4 can be realized
exploiting the routing capabilities made available by the VRF infrastructure.
This behavior could leverage a specific VRF for forcing the traffic to be
forwarded in accordance with the routes available in the VRF table.
Anyway, in order to make the End.DT4 properly work, it must be guaranteed that
the table used for the route lookup operations is bound to one and only one VRF.
In this way, it is possible to use the table for uniquely retrieving the
associated VRF and for routing packets.
I would like to thank David Ahern for his constant and valuable support during
the design and development phases of this patch set.
Comments, suggestions and improvements are very welcome!
Thanks,
Andrea Mayer
[1] https://lore.kernel.org/netdev/[email protected]/
Andrea Mayer (5):
l3mdev: add infrastructure for table to VRF mapping
vrf: track associations between VRF devices and tables
vrf: add sysctl parameter for strict mode
vrf: add l3mdev registration for table to VRF device lookup
selftests: add selftest for the VRF strict mode
drivers/net/vrf.c | 450 +++++++++++++++++-
include/net/l3mdev.h | 37 ++
net/l3mdev/l3mdev.c | 95 ++++
.../selftests/net/vrf_strict_mode_test.sh | 390 +++++++++++++++
4 files changed, 963 insertions(+), 9 deletions(-)
create mode 100755 tools/testing/selftests/net/vrf_strict_mode_test.sh
--
2.20.1
During the initialization phase of the VRF module, the callback for table
to VRF device lookup is registered in l3mdev.
Signed-off-by: Andrea Mayer <[email protected]>
---
drivers/net/vrf.c | 59 +++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 55 insertions(+), 4 deletions(-)
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index bac118b615bc..65d5f5ff4c67 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -182,6 +182,19 @@ static struct vrf_map *netns_vrf_map_by_dev(struct net_device *dev)
return netns_vrf_map(dev_net(dev));
}
+static int vrf_map_elem_get_vrf_ifindex(struct vrf_map_elem *me)
+{
+ struct list_head *me_head = &me->vrf_list;
+ struct net_vrf *vrf;
+
+ if (list_empty(me_head))
+ return -ENODEV;
+
+ vrf = list_first_entry(me_head, struct net_vrf, me_list);
+
+ return vrf->ifindex;
+}
+
static struct vrf_map_elem *vrf_map_elem_alloc(gfp_t flags)
{
struct vrf_map_elem *me;
@@ -383,6 +396,34 @@ static void vrf_map_unregister_dev(struct net_device *dev)
vrf_map_unlock(vmap);
}
+/* returns the vrf device index associated with the table_id */
+static int vrf_ifindex_lookup_by_table_id(struct net *net, u32 table_id)
+{
+ struct vrf_map *vmap = netns_vrf_map(net);
+ struct vrf_map_elem *me;
+ int ifindex;
+
+ vrf_map_lock(vmap);
+
+ if (!vmap->strict_mode) {
+ ifindex = -EPERM;
+ goto unlock;
+ }
+
+ me = vrf_map_lookup_elem(vmap, table_id);
+ if (!me) {
+ ifindex = -ENODEV;
+ goto unlock;
+ }
+
+ ifindex = vrf_map_elem_get_vrf_ifindex(me);
+
+unlock:
+ vrf_map_unlock(vmap);
+
+ return ifindex;
+}
+
/* by default VRF devices do not have a qdisc and are expected
* to be created with only a single queue.
*/
@@ -1847,14 +1888,24 @@ static int __init vrf_init_module(void)
if (rc < 0)
goto error;
+ rc = l3mdev_table_lookup_register(L3MDEV_TYPE_VRF,
+ vrf_ifindex_lookup_by_table_id);
+ if (rc < 0)
+ goto unreg_pernet;
+
rc = rtnl_link_register(&vrf_link_ops);
- if (rc < 0) {
- unregister_pernet_subsys(&vrf_net_ops);
- goto error;
- }
+ if (rc < 0)
+ goto table_lookup_unreg;
return 0;
+table_lookup_unreg:
+ l3mdev_table_lookup_unregister(L3MDEV_TYPE_VRF,
+ vrf_ifindex_lookup_by_table_id);
+
+unreg_pernet:
+ unregister_pernet_subsys(&vrf_net_ops);
+
error:
unregister_netdevice_notifier(&vrf_notifier_block);
return rc;
--
2.20.1
Thanks for doing this Andrea. This is a very important patch. I'll let
the others comment on the specificity of the patch, but strict mode=1
should be the default .
Dinesh
On 6/12/20 9:49 AM, Andrea Mayer wrote:
> This patch set adds the new "strict mode" functionality to the Virtual
> Routing and Forwarding infrastructure (VRF). Hereafter we discuss the
> requirements and the main features of the "strict mode" for VRF.
>
> On VRF creation, it is necessary to specify the associated routing table used
> during the lookup operations. Currently, there is no mechanism that avoids
> creating multiple VRFs sharing the same routing table. In other words, it is not
> possible to force a one-to-one relationship between a specific VRF and the table
> associated with it.
>
>
> The "strict mode" imposes that each VRF can be associated to a routing table
> only if such routing table is not already in use by any other VRF.
> In particular, the strict mode ensures that:
>
> 1) given a specific routing table, the VRF (if exists) is uniquely identified;
> 2) given a specific VRF, the related table is not shared with any other VRF.
>
> Constraints (1) and (2) force a one-to-one relationship between each VRF and the
> corresponding routing table.
>
>
> The strict mode feature is designed to be network-namespace aware and it can be
> directly enabled/disabled acting on the "strict_mode" parameter.
> Read and write operations are carried out through the classic sysctl command on
> net.vrf.strict_mode path, i.e: sysctl -w net.vrf.strict_mode=1.
>
> Only two distinct values {0,1} are accepted by the strict_mode parameter:
>
> - with strict_mode=0, multiple VRFs can be associated with the same table.
> This is the (legacy) default kernel behavior, the same that we experience
> when the strict mode patch set is not applied;
>
> - with strict_mode=1, the one-to-one relationship between the VRFs and the
> associated tables is guaranteed. In this configuration, the creation of a VRF
> which refers to a routing table already associated with another VRF fails and
> the error is returned to the user.
>
>
> The kernel keeps track of the associations between a VRF and the routing table
> during the VRF setup, in the "management" plane. Therefore, the strict mode does
> not impact the performance or intrinsic functionality of the data plane in any
> way.
>
> When the strict mode is active it is always possible to disable the strict mode,
> while the reverse operation is not always allowed.
> Setting the strict_mode parameter to 0 is equivalent to removing the one-to-one
> constraint between any single VRF and its associated routing table.
>
> Conversely, if the strict mode is disabled and there are multiple VRFs that
> refer to the same routing table, then it is prohibited to set the strict_mode
> parameter to 1. In this configuration, any attempt to perform the operation will
> lead to an error and it will be reported to the user.
> To enable strict mode once again (by setting the strict_mode parameter to 1),
> you must first remove all the VRFs that share common tables.
>
> There are several use cases which can take advantage from the introduction of
> the strict mode feature. In particular, the strict mode allows us to:
>
> i) guarantee the proper functioning of some applications which deal with
> routing protocols;
>
> ii) perform some tunneling decap operations which require to use specific
> routing tables for segregating and forwarding the traffic.
>
>
> Considering (i), the creation of different VRFs that point to the same table
> leads to the situation where two different routing entities believe they have
> exclusive access to the same table. This leads to the situation where different
> routing daemons can conflict for gaining routes control due to overlapping
> tables. By enabling strict mode it is possible to prevent this situation which
> often occurs due to incorrect configurations done by the users.
> The ability to enable/disable the strict mode functionality does not depend on
> the tool used for configuring the networking. In essence, the strict mode patch
> solves, at the kernel level, what some other patches [1] had tried to solve at
> the userspace level (using only iproute2) with all the related problems.
>
> Considering (ii), the introduction of the strict mode functionality allows us
> implementing the SRv6 End.DT4 behavior. Such behavior terminates a SR tunnel and
> it forwards the IPv4 traffic according to the routes present in the routing
> table supplied during the configuration. The SRv6 End.DT4 can be realized
> exploiting the routing capabilities made available by the VRF infrastructure.
> This behavior could leverage a specific VRF for forcing the traffic to be
> forwarded in accordance with the routes available in the VRF table.
> Anyway, in order to make the End.DT4 properly work, it must be guaranteed that
> the table used for the route lookup operations is bound to one and only one VRF.
> In this way, it is possible to use the table for uniquely retrieving the
> associated VRF and for routing packets.
>
> I would like to thank David Ahern for his constant and valuable support during
> the design and development phases of this patch set.
>
> Comments, suggestions and improvements are very welcome!
>
> Thanks,
> Andrea Mayer
>
>
> [1] https://lore.kernel.org/netdev/[email protected]/
>
> Andrea Mayer (5):
> l3mdev: add infrastructure for table to VRF mapping
> vrf: track associations between VRF devices and tables
> vrf: add sysctl parameter for strict mode
> vrf: add l3mdev registration for table to VRF device lookup
> selftests: add selftest for the VRF strict mode
>
> drivers/net/vrf.c | 450 +++++++++++++++++-
> include/net/l3mdev.h | 37 ++
> net/l3mdev/l3mdev.c | 95 ++++
> .../selftests/net/vrf_strict_mode_test.sh | 390 +++++++++++++++
> 4 files changed, 963 insertions(+), 9 deletions(-)
> create mode 100755 tools/testing/selftests/net/vrf_strict_mode_test.sh
>
On Fri, 12 Jun 2020 10:05:49 -0700
Dinesh G Dutt <[email protected]> wrote:
> Thanks for doing this Andrea. This is a very important patch. I'll let
> the others comment on the specificity of the patch, but strict mode=1
> should be the default .
>
> Dinesh
Hi Dinesh,
thanks for your comments! I chose to disable the strict mode(=0) by default to
be conservative.
Andrea
On 6/13/20 4:39 PM, Dinesh Dutt wrote:
> Understand Andrea. I guess I didn't say it well. What I meant to say was
> that the strict mode is the default expected behavior in a classical router.
>
it has to be off by default for backwards compatibility.