@@ -26,6 +26,8 @@ static void remove_nexthop(struct net *net, struct nexthop *nh,
2626#define NH_DEV_HASHBITS 8
2727#define NH_DEV_HASHSIZE (1U << NH_DEV_HASHBITS)
2828
29+ #define NHA_OP_FLAGS_DUMP_ALL (NHA_OP_FLAG_DUMP_STATS)
30+
2931static const struct nla_policy rtm_nh_policy_new [] = {
3032 [NHA_ID ] = { .type = NLA_U32 },
3133 [NHA_GROUP ] = { .type = NLA_BINARY },
@@ -41,7 +43,8 @@ static const struct nla_policy rtm_nh_policy_new[] = {
4143
4244static const struct nla_policy rtm_nh_policy_get [] = {
4345 [NHA_ID ] = { .type = NLA_U32 },
44- [NHA_OP_FLAGS ] = NLA_POLICY_MASK (NLA_U32 , 0 ),
46+ [NHA_OP_FLAGS ] = NLA_POLICY_MASK (NLA_U32 ,
47+ NHA_OP_FLAGS_DUMP_ALL ),
4548};
4649
4750static const struct nla_policy rtm_nh_policy_del [] = {
@@ -53,7 +56,8 @@ static const struct nla_policy rtm_nh_policy_dump[] = {
5356 [NHA_GROUPS ] = { .type = NLA_FLAG },
5457 [NHA_MASTER ] = { .type = NLA_U32 },
5558 [NHA_FDB ] = { .type = NLA_FLAG },
56- [NHA_OP_FLAGS ] = NLA_POLICY_MASK (NLA_U32 , 0 ),
59+ [NHA_OP_FLAGS ] = NLA_POLICY_MASK (NLA_U32 ,
60+ NHA_OP_FLAGS_DUMP_ALL ),
5761};
5862
5963static const struct nla_policy rtm_nh_res_policy_new [] = {
@@ -671,8 +675,78 @@ static void nh_grp_entry_stats_inc(struct nh_grp_entry *nhge)
671675 u64_stats_update_end (& cpu_stats -> syncp );
672676}
673677
674- static int nla_put_nh_group (struct sk_buff * skb , struct nh_group * nhg )
678+ static void nh_grp_entry_stats_read (struct nh_grp_entry * nhge ,
679+ u64 * ret_packets )
680+ {
681+ int i ;
682+
683+ * ret_packets = 0 ;
684+
685+ for_each_possible_cpu (i ) {
686+ struct nh_grp_entry_stats * cpu_stats ;
687+ unsigned int start ;
688+ u64 packets ;
689+
690+ cpu_stats = per_cpu_ptr (nhge -> stats , i );
691+ do {
692+ start = u64_stats_fetch_begin (& cpu_stats -> syncp );
693+ packets = u64_stats_read (& cpu_stats -> packets );
694+ } while (u64_stats_fetch_retry (& cpu_stats -> syncp , start ));
695+
696+ * ret_packets += packets ;
697+ }
698+ }
699+
700+ static int nla_put_nh_group_stats_entry (struct sk_buff * skb ,
701+ struct nh_grp_entry * nhge )
702+ {
703+ struct nlattr * nest ;
704+ u64 packets ;
705+
706+ nh_grp_entry_stats_read (nhge , & packets );
707+
708+ nest = nla_nest_start (skb , NHA_GROUP_STATS_ENTRY );
709+ if (!nest )
710+ return - EMSGSIZE ;
711+
712+ if (nla_put_u32 (skb , NHA_GROUP_STATS_ENTRY_ID , nhge -> nh -> id ) ||
713+ nla_put_uint (skb , NHA_GROUP_STATS_ENTRY_PACKETS , packets ))
714+ goto nla_put_failure ;
715+
716+ nla_nest_end (skb , nest );
717+ return 0 ;
718+
719+ nla_put_failure :
720+ nla_nest_cancel (skb , nest );
721+ return - EMSGSIZE ;
722+ }
723+
724+ static int nla_put_nh_group_stats (struct sk_buff * skb , struct nexthop * nh )
675725{
726+ struct nh_group * nhg = rtnl_dereference (nh -> nh_grp );
727+ struct nlattr * nest ;
728+ int i ;
729+
730+ nest = nla_nest_start (skb , NHA_GROUP_STATS );
731+ if (!nest )
732+ return - EMSGSIZE ;
733+
734+ for (i = 0 ; i < nhg -> num_nh ; i ++ )
735+ if (nla_put_nh_group_stats_entry (skb , & nhg -> nh_entries [i ]))
736+ goto cancel_out ;
737+
738+ nla_nest_end (skb , nest );
739+ return 0 ;
740+
741+ cancel_out :
742+ nla_nest_cancel (skb , nest );
743+ return - EMSGSIZE ;
744+ }
745+
746+ static int nla_put_nh_group (struct sk_buff * skb , struct nexthop * nh ,
747+ u32 op_flags )
748+ {
749+ struct nh_group * nhg = rtnl_dereference (nh -> nh_grp );
676750 struct nexthop_grp * p ;
677751 size_t len = nhg -> num_nh * sizeof (* p );
678752 struct nlattr * nla ;
@@ -701,14 +775,19 @@ static int nla_put_nh_group(struct sk_buff *skb, struct nh_group *nhg)
701775 if (nhg -> resilient && nla_put_nh_group_res (skb , nhg ))
702776 goto nla_put_failure ;
703777
778+ if (op_flags & NHA_OP_FLAG_DUMP_STATS &&
779+ nla_put_nh_group_stats (skb , nh ))
780+ goto nla_put_failure ;
781+
704782 return 0 ;
705783
706784nla_put_failure :
707785 return - EMSGSIZE ;
708786}
709787
710788static int nh_fill_node (struct sk_buff * skb , struct nexthop * nh ,
711- int event , u32 portid , u32 seq , unsigned int nlflags )
789+ int event , u32 portid , u32 seq , unsigned int nlflags ,
790+ u32 op_flags )
712791{
713792 struct fib6_nh * fib6_nh ;
714793 struct fib_nh * fib_nh ;
@@ -735,7 +814,7 @@ static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
735814
736815 if (nhg -> fdb_nh && nla_put_flag (skb , NHA_FDB ))
737816 goto nla_put_failure ;
738- if (nla_put_nh_group (skb , nhg ))
817+ if (nla_put_nh_group (skb , nh , op_flags ))
739818 goto nla_put_failure ;
740819 goto out ;
741820 }
@@ -866,7 +945,7 @@ static void nexthop_notify(int event, struct nexthop *nh, struct nl_info *info)
866945 if (!skb )
867946 goto errout ;
868947
869- err = nh_fill_node (skb , nh , event , info -> portid , seq , nlflags );
948+ err = nh_fill_node (skb , nh , event , info -> portid , seq , nlflags , 0 );
870949 if (err < 0 ) {
871950 /* -EMSGSIZE implies BUG in nh_nlmsg_size() */
872951 WARN_ON (err == - EMSGSIZE );
@@ -3093,7 +3172,7 @@ static int rtm_get_nexthop(struct sk_buff *in_skb, struct nlmsghdr *nlh,
30933172 goto errout_free ;
30943173
30953174 err = nh_fill_node (skb , nh , RTM_NEWNEXTHOP , NETLINK_CB (in_skb ).portid ,
3096- nlh -> nlmsg_seq , 0 );
3175+ nlh -> nlmsg_seq , 0 , op_flags );
30973176 if (err < 0 ) {
30983177 WARN_ON (err == - EMSGSIZE );
30993178 goto errout_free ;
@@ -3264,7 +3343,7 @@ static int rtm_dump_nexthop_cb(struct sk_buff *skb, struct netlink_callback *cb,
32643343
32653344 return nh_fill_node (skb , nh , RTM_NEWNEXTHOP ,
32663345 NETLINK_CB (cb -> skb ).portid ,
3267- cb -> nlh -> nlmsg_seq , NLM_F_MULTI );
3346+ cb -> nlh -> nlmsg_seq , NLM_F_MULTI , filter -> op_flags );
32683347}
32693348
32703349/* rtnl */
0 commit comments