Skip to content

Commit 404eb77

Browse files
roopa-prabhudavem330
authored andcommitted
ipv4: support sport, dport and ip_proto in RTM_GETROUTE
This is a followup to fib rules sport, dport and ipproto match support. Only supports tcp, udp and icmp for ipproto. Used by fib rule self tests. Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 273de02 commit 404eb77

File tree

6 files changed

+140
-40
lines changed

6 files changed

+140
-40
lines changed

include/net/ip.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,4 +664,7 @@ extern int sysctl_icmp_msgs_burst;
664664
int ip_misc_proc_init(void);
665665
#endif
666666

667+
int rtm_getroute_parse_ip_proto(struct nlattr *attr, u8 *ip_proto,
668+
struct netlink_ext_ack *extack);
669+
667670
#endif /* _IP_H */

include/uapi/linux/rtnetlink.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ enum rtattr_type_t {
327327
RTA_PAD,
328328
RTA_UID,
329329
RTA_TTL_PROPAGATE,
330+
RTA_IP_PROTO,
331+
RTA_SPORT,
332+
RTA_DPORT,
330333
__RTA_MAX
331334
};
332335

net/ipv4/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ obj-y := route.o inetpeer.o protocol.o \
1414
udp_offload.o arp.o icmp.o devinet.o af_inet.o igmp.o \
1515
fib_frontend.o fib_semantics.o fib_trie.o fib_notifier.o \
1616
inet_fragment.o ping.o ip_tunnel_core.o gre_offload.o \
17-
metrics.o
17+
metrics.o netlink.o
1818

1919
obj-$(CONFIG_BPFILTER) += bpfilter/
2020

net/ipv4/fib_frontend.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,9 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = {
649649
[RTA_ENCAP] = { .type = NLA_NESTED },
650650
[RTA_UID] = { .type = NLA_U32 },
651651
[RTA_MARK] = { .type = NLA_U32 },
652+
[RTA_IP_PROTO] = { .type = NLA_U8 },
653+
[RTA_SPORT] = { .type = NLA_U16 },
654+
[RTA_DPORT] = { .type = NLA_U16 },
652655
};
653656

654657
static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,

net/ipv4/netlink.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <linux/netlink.h>
2+
#include <linux/rtnetlink.h>
3+
#include <linux/types.h>
4+
#include <net/net_namespace.h>
5+
#include <net/netlink.h>
6+
#include <net/ip.h>
7+
8+
int rtm_getroute_parse_ip_proto(struct nlattr *attr, u8 *ip_proto,
9+
struct netlink_ext_ack *extack)
10+
{
11+
*ip_proto = nla_get_u8(attr);
12+
13+
switch (*ip_proto) {
14+
case IPPROTO_TCP:
15+
case IPPROTO_UDP:
16+
case IPPROTO_ICMP:
17+
return 0;
18+
default:
19+
NL_SET_ERR_MSG(extack, "Unsupported ip proto");
20+
return -EOPNOTSUPP;
21+
}
22+
}
23+
EXPORT_SYMBOL_GPL(rtm_getroute_parse_ip_proto);

net/ipv4/route.c

Lines changed: 107 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2574,11 +2574,10 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4,
25742574
EXPORT_SYMBOL_GPL(ip_route_output_flow);
25752575

25762576
/* called with rcu_read_lock held */
2577-
static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 table_id,
2578-
struct flowi4 *fl4, struct sk_buff *skb, u32 portid,
2579-
u32 seq)
2577+
static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
2578+
struct rtable *rt, u32 table_id, struct flowi4 *fl4,
2579+
struct sk_buff *skb, u32 portid, u32 seq)
25802580
{
2581-
struct rtable *rt = skb_rtable(skb);
25822581
struct rtmsg *r;
25832582
struct nlmsghdr *nlh;
25842583
unsigned long expires = 0;
@@ -2674,7 +2673,7 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 table_id,
26742673
}
26752674
} else
26762675
#endif
2677-
if (nla_put_u32(skb, RTA_IIF, skb->dev->ifindex))
2676+
if (nla_put_u32(skb, RTA_IIF, fl4->flowi4_iif))
26782677
goto nla_put_failure;
26792678
}
26802679

@@ -2689,43 +2688,93 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 table_id,
26892688
return -EMSGSIZE;
26902689
}
26912690

2691+
static struct sk_buff *inet_rtm_getroute_build_skb(__be32 src, __be32 dst,
2692+
u8 ip_proto, __be16 sport,
2693+
__be16 dport)
2694+
{
2695+
struct sk_buff *skb;
2696+
struct iphdr *iph;
2697+
2698+
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2699+
if (!skb)
2700+
return NULL;
2701+
2702+
/* Reserve room for dummy headers, this skb can pass
2703+
* through good chunk of routing engine.
2704+
*/
2705+
skb_reset_mac_header(skb);
2706+
skb_reset_network_header(skb);
2707+
skb->protocol = htons(ETH_P_IP);
2708+
iph = skb_put(skb, sizeof(struct iphdr));
2709+
iph->protocol = ip_proto;
2710+
iph->saddr = src;
2711+
iph->daddr = dst;
2712+
iph->version = 0x4;
2713+
iph->frag_off = 0;
2714+
iph->ihl = 0x5;
2715+
skb_set_transport_header(skb, skb->len);
2716+
2717+
switch (iph->protocol) {
2718+
case IPPROTO_UDP: {
2719+
struct udphdr *udph;
2720+
2721+
udph = skb_put_zero(skb, sizeof(struct udphdr));
2722+
udph->source = sport;
2723+
udph->dest = dport;
2724+
udph->len = sizeof(struct udphdr);
2725+
udph->check = 0;
2726+
break;
2727+
}
2728+
case IPPROTO_TCP: {
2729+
struct tcphdr *tcph;
2730+
2731+
tcph = skb_put_zero(skb, sizeof(struct tcphdr));
2732+
tcph->source = sport;
2733+
tcph->dest = dport;
2734+
tcph->doff = sizeof(struct tcphdr) / 4;
2735+
tcph->rst = 1;
2736+
tcph->check = ~tcp_v4_check(sizeof(struct tcphdr),
2737+
src, dst, 0);
2738+
break;
2739+
}
2740+
case IPPROTO_ICMP: {
2741+
struct icmphdr *icmph;
2742+
2743+
icmph = skb_put_zero(skb, sizeof(struct icmphdr));
2744+
icmph->type = ICMP_ECHO;
2745+
icmph->code = 0;
2746+
}
2747+
}
2748+
2749+
return skb;
2750+
}
2751+
26922752
static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
26932753
struct netlink_ext_ack *extack)
26942754
{
26952755
struct net *net = sock_net(in_skb->sk);
2696-
struct rtmsg *rtm;
26972756
struct nlattr *tb[RTA_MAX+1];
2757+
u32 table_id = RT_TABLE_MAIN;
2758+
__be16 sport = 0, dport = 0;
26982759
struct fib_result res = {};
2760+
u8 ip_proto = IPPROTO_UDP;
26992761
struct rtable *rt = NULL;
2762+
struct sk_buff *skb;
2763+
struct rtmsg *rtm;
27002764
struct flowi4 fl4;
27012765
__be32 dst = 0;
27022766
__be32 src = 0;
2767+
kuid_t uid;
27032768
u32 iif;
27042769
int err;
27052770
int mark;
2706-
struct sk_buff *skb;
2707-
u32 table_id = RT_TABLE_MAIN;
2708-
kuid_t uid;
27092771

27102772
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy,
27112773
extack);
27122774
if (err < 0)
2713-
goto errout;
2775+
return err;
27142776

27152777
rtm = nlmsg_data(nlh);
2716-
2717-
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2718-
if (!skb) {
2719-
err = -ENOBUFS;
2720-
goto errout;
2721-
}
2722-
2723-
/* Reserve room for dummy headers, this skb can pass
2724-
through good chunk of routing engine.
2725-
*/
2726-
skb_reset_mac_header(skb);
2727-
skb_reset_network_header(skb);
2728-
27292778
src = tb[RTA_SRC] ? nla_get_in_addr(tb[RTA_SRC]) : 0;
27302779
dst = tb[RTA_DST] ? nla_get_in_addr(tb[RTA_DST]) : 0;
27312780
iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0;
@@ -2735,14 +2784,22 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
27352784
else
27362785
uid = (iif ? INVALID_UID : current_uid());
27372786

2738-
/* Bugfix: need to give ip_route_input enough of an IP header to
2739-
* not gag.
2740-
*/
2741-
ip_hdr(skb)->protocol = IPPROTO_UDP;
2742-
ip_hdr(skb)->saddr = src;
2743-
ip_hdr(skb)->daddr = dst;
2787+
if (tb[RTA_IP_PROTO]) {
2788+
err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO],
2789+
&ip_proto, extack);
2790+
if (err)
2791+
return err;
2792+
}
2793+
2794+
if (tb[RTA_SPORT])
2795+
sport = nla_get_be16(tb[RTA_SPORT]);
27442796

2745-
skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr));
2797+
if (tb[RTA_DPORT])
2798+
dport = nla_get_be16(tb[RTA_DPORT]);
2799+
2800+
skb = inet_rtm_getroute_build_skb(src, dst, ip_proto, sport, dport);
2801+
if (!skb)
2802+
return -ENOBUFS;
27462803

27472804
memset(&fl4, 0, sizeof(fl4));
27482805
fl4.daddr = dst;
@@ -2751,6 +2808,11 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
27512808
fl4.flowi4_oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0;
27522809
fl4.flowi4_mark = mark;
27532810
fl4.flowi4_uid = uid;
2811+
if (sport)
2812+
fl4.fl4_sport = sport;
2813+
if (dport)
2814+
fl4.fl4_dport = dport;
2815+
fl4.flowi4_proto = ip_proto;
27542816

27552817
rcu_read_lock();
27562818

@@ -2760,10 +2822,10 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
27602822
dev = dev_get_by_index_rcu(net, iif);
27612823
if (!dev) {
27622824
err = -ENODEV;
2763-
goto errout_free;
2825+
goto errout_rcu;
27642826
}
27652827

2766-
skb->protocol = htons(ETH_P_IP);
2828+
fl4.flowi4_iif = iif; /* for rt_fill_info */
27672829
skb->dev = dev;
27682830
skb->mark = mark;
27692831
err = ip_route_input_rcu(skb, dst, src, rtm->rtm_tos,
@@ -2783,42 +2845,48 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
27832845
}
27842846

27852847
if (err)
2786-
goto errout_free;
2848+
goto errout_rcu;
27872849

27882850
if (rtm->rtm_flags & RTM_F_NOTIFY)
27892851
rt->rt_flags |= RTCF_NOTIFY;
27902852

27912853
if (rtm->rtm_flags & RTM_F_LOOKUP_TABLE)
27922854
table_id = res.table ? res.table->tb_id : 0;
27932855

2856+
/* reset skb for netlink reply msg */
2857+
skb_trim(skb, 0);
2858+
skb_reset_network_header(skb);
2859+
skb_reset_transport_header(skb);
2860+
skb_reset_mac_header(skb);
2861+
27942862
if (rtm->rtm_flags & RTM_F_FIB_MATCH) {
27952863
if (!res.fi) {
27962864
err = fib_props[res.type].error;
27972865
if (!err)
27982866
err = -EHOSTUNREACH;
2799-
goto errout_free;
2867+
goto errout_rcu;
28002868
}
28012869
err = fib_dump_info(skb, NETLINK_CB(in_skb).portid,
28022870
nlh->nlmsg_seq, RTM_NEWROUTE, table_id,
28032871
rt->rt_type, res.prefix, res.prefixlen,
28042872
fl4.flowi4_tos, res.fi, 0);
28052873
} else {
2806-
err = rt_fill_info(net, dst, src, table_id, &fl4, skb,
2874+
err = rt_fill_info(net, dst, src, rt, table_id, &fl4, skb,
28072875
NETLINK_CB(in_skb).portid, nlh->nlmsg_seq);
28082876
}
28092877
if (err < 0)
2810-
goto errout_free;
2878+
goto errout_rcu;
28112879

28122880
rcu_read_unlock();
28132881

28142882
err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
2815-
errout:
2816-
return err;
28172883

28182884
errout_free:
2885+
return err;
2886+
errout_rcu:
28192887
rcu_read_unlock();
28202888
kfree_skb(skb);
2821-
goto errout;
2889+
goto errout_free;
28222890
}
28232891

28242892
void ip_rt_multicast_event(struct in_device *in_dev)

0 commit comments

Comments
 (0)