ipv4: Reject routes specifying ECN bits in rtm_tos
Use the new dscp_t type to replace the fc_tos field of fib_config, to ensure IPv4 routes aren't influenced by ECN bits when configured with non-zero rtm_tos. Before this patch, IPv4 routes specifying an rtm_tos with some of the ECN bits set were accepted. However they wouldn't work (never match) as IPv4 normally clears the ECN bits with IPTOS_RT_MASK before doing a FIB lookup (although a few buggy code paths don't). After this patch, IPv4 routes specifying an rtm_tos with any ECN bit set is rejected. Note: IPv6 routes ignore rtm_tos altogether, any rtm_tos is accepted, but treated as if it were 0. Signed-off-by: Guillaume Nault <gnault@redhat.com> Acked-by: David Ahern <dsahern@kernel.org> Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
563f8e97e0
commit
f55fbb6afb
|
@ -17,6 +17,7 @@
|
|||
#include <linux/rcupdate.h>
|
||||
#include <net/fib_notifier.h>
|
||||
#include <net/fib_rules.h>
|
||||
#include <net/inet_dscp.h>
|
||||
#include <net/inetpeer.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/notifier.h>
|
||||
|
@ -24,7 +25,7 @@
|
|||
|
||||
struct fib_config {
|
||||
u8 fc_dst_len;
|
||||
u8 fc_tos;
|
||||
dscp_t fc_dscp;
|
||||
u8 fc_protocol;
|
||||
u8 fc_scope;
|
||||
u8 fc_type;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <net/inet_dscp.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/route.h>
|
||||
|
@ -735,8 +736,16 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
|
|||
memset(cfg, 0, sizeof(*cfg));
|
||||
|
||||
rtm = nlmsg_data(nlh);
|
||||
|
||||
if (!inet_validate_dscp(rtm->rtm_tos)) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Invalid dsfield (tos): ECN bits must be 0");
|
||||
err = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
cfg->fc_dscp = inet_dsfield_to_dscp(rtm->rtm_tos);
|
||||
|
||||
cfg->fc_dst_len = rtm->rtm_dst_len;
|
||||
cfg->fc_tos = rtm->rtm_tos;
|
||||
cfg->fc_table = rtm->rtm_table;
|
||||
cfg->fc_protocol = rtm->rtm_protocol;
|
||||
cfg->fc_scope = rtm->rtm_scope;
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include <linux/vmalloc.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/inet_dscp.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/route.h>
|
||||
|
@ -1210,9 +1211,9 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
|
|||
struct fib_info *fi;
|
||||
u8 plen = cfg->fc_dst_len;
|
||||
u8 slen = KEYLENGTH - plen;
|
||||
u8 tos = cfg->fc_tos;
|
||||
u32 key;
|
||||
int err;
|
||||
u8 tos;
|
||||
|
||||
key = ntohl(cfg->fc_dst);
|
||||
|
||||
|
@ -1227,6 +1228,7 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
|
|||
goto err;
|
||||
}
|
||||
|
||||
tos = inet_dscp_to_dsfield(cfg->fc_dscp);
|
||||
l = fib_find_node(t, &tp, key);
|
||||
fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority,
|
||||
tb->tb_id, false) : NULL;
|
||||
|
@ -1703,8 +1705,8 @@ int fib_table_delete(struct net *net, struct fib_table *tb,
|
|||
struct key_vector *l, *tp;
|
||||
u8 plen = cfg->fc_dst_len;
|
||||
u8 slen = KEYLENGTH - plen;
|
||||
u8 tos = cfg->fc_tos;
|
||||
u32 key;
|
||||
u8 tos;
|
||||
|
||||
key = ntohl(cfg->fc_dst);
|
||||
|
||||
|
@ -1715,6 +1717,7 @@ int fib_table_delete(struct net *net, struct fib_table *tb,
|
|||
if (!l)
|
||||
return -ESRCH;
|
||||
|
||||
tos = inet_dscp_to_dsfield(cfg->fc_dscp);
|
||||
fa = fib_find_alias(&l->leaf, slen, tos, 0, tb->tb_id, false);
|
||||
if (!fa)
|
||||
return -ESRCH;
|
||||
|
|
|
@ -1447,6 +1447,81 @@ ipv4_local_rt_cache()
|
|||
log_test $? 0 "Cached route removed from VRF port device"
|
||||
}
|
||||
|
||||
ipv4_rt_dsfield()
|
||||
{
|
||||
echo
|
||||
echo "IPv4 route with dsfield tests"
|
||||
|
||||
run_cmd "$IP route flush 172.16.102.0/24"
|
||||
|
||||
# New routes should reject dsfield options that interfere with ECN
|
||||
run_cmd "$IP route add 172.16.102.0/24 dsfield 0x01 via 172.16.101.2"
|
||||
log_test $? 2 "Reject route with dsfield 0x01"
|
||||
|
||||
run_cmd "$IP route add 172.16.102.0/24 dsfield 0x02 via 172.16.101.2"
|
||||
log_test $? 2 "Reject route with dsfield 0x02"
|
||||
|
||||
run_cmd "$IP route add 172.16.102.0/24 dsfield 0x03 via 172.16.101.2"
|
||||
log_test $? 2 "Reject route with dsfield 0x03"
|
||||
|
||||
# A generic route that doesn't take DSCP into account
|
||||
run_cmd "$IP route add 172.16.102.0/24 via 172.16.101.2"
|
||||
|
||||
# A more specific route for DSCP 0x10
|
||||
run_cmd "$IP route add 172.16.102.0/24 dsfield 0x10 via 172.16.103.2"
|
||||
|
||||
# DSCP 0x10 should match the specific route, no matter the ECN bits
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x10 | \
|
||||
grep -q "via 172.16.103.2"
|
||||
log_test $? 0 "IPv4 route with DSCP and ECN:Not-ECT"
|
||||
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x11 | \
|
||||
grep -q "via 172.16.103.2"
|
||||
log_test $? 0 "IPv4 route with DSCP and ECN:ECT(1)"
|
||||
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x12 | \
|
||||
grep -q "via 172.16.103.2"
|
||||
log_test $? 0 "IPv4 route with DSCP and ECN:ECT(0)"
|
||||
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x13 | \
|
||||
grep -q "via 172.16.103.2"
|
||||
log_test $? 0 "IPv4 route with DSCP and ECN:CE"
|
||||
|
||||
# Unknown DSCP should match the generic route, no matter the ECN bits
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x14 | \
|
||||
grep -q "via 172.16.101.2"
|
||||
log_test $? 0 "IPv4 route with unknown DSCP and ECN:Not-ECT"
|
||||
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x15 | \
|
||||
grep -q "via 172.16.101.2"
|
||||
log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(1)"
|
||||
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x16 | \
|
||||
grep -q "via 172.16.101.2"
|
||||
log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(0)"
|
||||
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x17 | \
|
||||
grep -q "via 172.16.101.2"
|
||||
log_test $? 0 "IPv4 route with unknown DSCP and ECN:CE"
|
||||
|
||||
# Null DSCP should match the generic route, no matter the ECN bits
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x00 | \
|
||||
grep -q "via 172.16.101.2"
|
||||
log_test $? 0 "IPv4 route with no DSCP and ECN:Not-ECT"
|
||||
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x01 | \
|
||||
grep -q "via 172.16.101.2"
|
||||
log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(1)"
|
||||
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x02 | \
|
||||
grep -q "via 172.16.101.2"
|
||||
log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(0)"
|
||||
|
||||
$IP route get fibmatch 172.16.102.1 dsfield 0x03 | \
|
||||
grep -q "via 172.16.101.2"
|
||||
log_test $? 0 "IPv4 route with no DSCP and ECN:CE"
|
||||
}
|
||||
|
||||
ipv4_route_test()
|
||||
{
|
||||
route_setup
|
||||
|
@ -1454,6 +1529,7 @@ ipv4_route_test()
|
|||
ipv4_rt_add
|
||||
ipv4_rt_replace
|
||||
ipv4_local_rt_cache
|
||||
ipv4_rt_dsfield
|
||||
|
||||
route_cleanup
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue