On 5/6/18 6:59 PM, Roopa Prabhu wrote: > From: Roopa Prabhu <ro...@cumulusnetworks.com> > > This is a followup to fib rules sport, dport match support. > Having them supported in getroute makes it easier to test > fib rule lookups. Used by fib rule self tests. Before this patch > getroute used same skb to pass through the route lookup and > for the netlink getroute reply msg. This patch allocates separate > skb's to keep flow dissector happy. > > Signed-off-by: Roopa Prabhu <ro...@cumulusnetworks.com> > --- > include/uapi/linux/rtnetlink.h | 2 + > net/ipv4/route.c | 151 > ++++++++++++++++++++++++++++++----------- > 2 files changed, 115 insertions(+), 38 deletions(-) > > diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h > index 9b15005..630ecf4 100644 > --- a/include/uapi/linux/rtnetlink.h > +++ b/include/uapi/linux/rtnetlink.h > @@ -327,6 +327,8 @@ enum rtattr_type_t { > RTA_PAD, > RTA_UID, > RTA_TTL_PROPAGATE, > + RTA_SPORT, > + RTA_DPORT,
If you are going to add sport and dport because of the potential for FIB rules, you need to add ip-proto as well. I realize existing code assumed UDP, but the FIB rules cover any IP proto. Yes, I know this makes the change much larger to generate tcp, udp as well as iphdr options; the joys of new features. ;-) I also suggest a comment that these new RTA attributes are used for GETROUTE only. And you need to add the new entries to rtm_ipv4_policy. > __RTA_MAX > }; > > diff --git a/net/ipv4/route.c b/net/ipv4/route.c > index 1412a7b..e91ed62 100644 > --- a/net/ipv4/route.c > +++ b/net/ipv4/route.c > @@ -2568,11 +2568,10 @@ struct rtable *ip_route_output_flow(struct net *net, > struct flowi4 *flp4, > EXPORT_SYMBOL_GPL(ip_route_output_flow); > > /* called with rcu_read_lock held */ > -static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 > table_id, > - struct flowi4 *fl4, struct sk_buff *skb, u32 portid, > - u32 seq) > +static int rt_fill_info(struct net *net, __be32 dst, __be32 src, > + struct rtable *rt, u32 table_id, struct flowi4 *fl4, > + struct sk_buff *skb, u32 portid, u32 seq) > { > - struct rtable *rt = skb_rtable(skb); > struct rtmsg *r; > struct nlmsghdr *nlh; > unsigned long expires = 0; > @@ -2651,6 +2650,14 @@ static int rt_fill_info(struct net *net, __be32 dst, > __be32 src, u32 table_id, > from_kuid_munged(current_user_ns(), fl4->flowi4_uid))) > goto nla_put_failure; > > + if (fl4->fl4_sport && > + nla_put_be16(skb, RTA_SPORT, fl4->fl4_sport)) > + goto nla_put_failure; > + > + if (fl4->fl4_dport && > + nla_put_be16(skb, RTA_DPORT, fl4->fl4_dport)) > + goto nla_put_failure; Why return the attributes to the user? I can't see any value in that. UID option is not returned either so there is precedence. > + > error = rt->dst.error; > > if (rt_is_input_route(rt)) { > @@ -2668,7 +2675,7 @@ static int rt_fill_info(struct net *net, __be32 dst, > __be32 src, u32 table_id, > } > } else > #endif > - if (nla_put_u32(skb, RTA_IIF, skb->dev->ifindex)) > + if (nla_put_u32(skb, RTA_IIF, fl4->flowi4_iif)) > goto nla_put_failure; > } > > @@ -2683,35 +2690,86 @@ static int rt_fill_info(struct net *net, __be32 dst, > __be32 src, u32 table_id, > return -EMSGSIZE; > } > > +static int nla_get_port(struct nlattr *attr, __be16 *port) > +{ > + int p = nla_get_be16(attr); __be16 p; > + > + if (p <= 0 || p >= 0xffff) > + return -EINVAL; This check is not needed by definition of be16. > + > + *port = p; > + return 0; > +} > + > +static int inet_rtm_getroute_reply(struct sk_buff *in_skb, struct nlmsghdr > *nlh, > + __be32 dst, __be32 src, struct flowi4 *fl4, > + struct rtable *rt, struct fib_result *res) > +{ > + struct net *net = sock_net(in_skb->sk); > + struct rtmsg *rtm = nlmsg_data(nlh); > + u32 table_id = RT_TABLE_MAIN; > + struct sk_buff *skb; > + int err = 0; > + > + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); > + if (!skb) { > + err = -ENOMEM; > + return err; > + } just 'return -ENOMEM' and without the {}. > + > + if (rtm->rtm_flags & RTM_F_LOOKUP_TABLE) > + table_id = res->table ? res->table->tb_id : 0; > + > + if (rtm->rtm_flags & RTM_F_FIB_MATCH) > + err = fib_dump_info(skb, NETLINK_CB(in_skb).portid, > + nlh->nlmsg_seq, RTM_NEWROUTE, table_id, > + rt->rt_type, res->prefix, res->prefixlen, > + fl4->flowi4_tos, res->fi, 0); > + else > + err = rt_fill_info(net, dst, src, rt, table_id, > + fl4, skb, NETLINK_CB(in_skb).portid, > + nlh->nlmsg_seq); > + if (err < 0) > + goto errout; > + > + return rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); > + > +errout: > + kfree_skb(skb); > + return err; > +} > + > static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, > struct netlink_ext_ack *extack) > { > struct net *net = sock_net(in_skb->sk); > - struct rtmsg *rtm; > struct nlattr *tb[RTA_MAX+1]; > + __be16 sport = 0, dport = 0; > struct fib_result res = {}; > struct rtable *rt = NULL; > + struct sk_buff *skb; > + struct rtmsg *rtm; > struct flowi4 fl4; > + struct iphdr *iph; > + struct udphdr *udph; > __be32 dst = 0; > __be32 src = 0; > + kuid_t uid; > u32 iif; > int err; > int mark; > - struct sk_buff *skb; > - u32 table_id = RT_TABLE_MAIN; > - kuid_t uid; > > err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy, > extack); > if (err < 0) > - goto errout; > + return err; > > rtm = nlmsg_data(nlh); > > skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); > if (!skb) { > err = -ENOBUFS; > - goto errout; > + return err; just return -ENOBUFS > } > > /* Reserve room for dummy headers, this skb can pass