On Mon, 27 Oct 2025 12:39:57 -0500, Daniel Jurgens <[email protected]> wrote: > - Get total number of rules. There's no user interface for this. It is > used to allocate an appropriately sized buffer for getting all the > rules. > > - Get specific rule > $ ethtool -u ens9 rule 0 > Filter: 0 > Rule Type: UDP over IPv4 > Src IP addr: 0.0.0.0 mask: 255.255.255.255 > Dest IP addr: 192.168.5.2 mask: 0.0.0.0 > TOS: 0x0 mask: 0xff > Src port: 0 mask: 0xffff > Dest port: 4321 mask: 0x0 > Action: Direct to queue 16 > > - Get all rules: > $ ethtool -u ens9 > 31 RX rings available > Total 2 rules > > Filter: 0 > Rule Type: UDP over IPv4 > Src IP addr: 0.0.0.0 mask: 255.255.255.255 > Dest IP addr: 192.168.5.2 mask: 0.0.0.0 > ... > > Filter: 1 > Flow Type: Raw Ethernet > Src MAC addr: 00:00:00:00:00:00 mask: FF:FF:FF:FF:FF:FF > Dest MAC addr: 08:11:22:33:44:54 mask: 00:00:00:00:00:00 > > Signed-off-by: Daniel Jurgens <[email protected]> > Reviewed-by: Parav Pandit <[email protected]> > Reviewed-by: Shahar Shitrit <[email protected]>
Reviewed-by: Xuan Zhuo <[email protected]> > --- > v4: Answered questions about rules_limit overflow with no changes. > --- > drivers/net/virtio_net.c | 78 ++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 78 insertions(+) > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c > index 2a24fb601cc1..e01febca8b75 100644 > --- a/drivers/net/virtio_net.c > +++ b/drivers/net/virtio_net.c > @@ -307,6 +307,13 @@ static int virtnet_ethtool_flow_insert(struct virtnet_ff > *ff, > struct ethtool_rx_flow_spec *fs, > u16 curr_queue_pairs); > static int virtnet_ethtool_flow_remove(struct virtnet_ff *ff, int location); > +static int virtnet_ethtool_get_flow_count(struct virtnet_ff *ff, > + struct ethtool_rxnfc *info); > +static int virtnet_ethtool_get_flow(struct virtnet_ff *ff, > + struct ethtool_rxnfc *info); > +static int > +virtnet_ethtool_get_all_flows(struct virtnet_ff *ff, > + struct ethtool_rxnfc *info, u32 *rule_locs); > > #define VIRTNET_Q_TYPE_RX 0 > #define VIRTNET_Q_TYPE_TX 1 > @@ -5645,6 +5652,28 @@ static u32 virtnet_get_rx_ring_count(struct net_device > *dev) > return vi->curr_queue_pairs; > } > > +static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc > *info, u32 *rule_locs) > +{ > + struct virtnet_info *vi = netdev_priv(dev); > + int rc = 0; > + > + switch (info->cmd) { > + case ETHTOOL_GRXCLSRLCNT: > + rc = virtnet_ethtool_get_flow_count(&vi->ff, info); > + break; > + case ETHTOOL_GRXCLSRULE: > + rc = virtnet_ethtool_get_flow(&vi->ff, info); > + break; > + case ETHTOOL_GRXCLSRLALL: > + rc = virtnet_ethtool_get_all_flows(&vi->ff, info, rule_locs); > + break; > + default: > + rc = -EOPNOTSUPP; > + } > + > + return rc; > +} > + > static int virtnet_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc > *info) > { > struct virtnet_info *vi = netdev_priv(dev); > @@ -5686,6 +5715,7 @@ static const struct ethtool_ops virtnet_ethtool_ops = { > .get_rxfh_fields = virtnet_get_hashflow, > .set_rxfh_fields = virtnet_set_hashflow, > .get_rx_ring_count = virtnet_get_rx_ring_count, > + .get_rxnfc = virtnet_get_rxnfc, > .set_rxnfc = virtnet_set_rxnfc, > }; > > @@ -7605,6 +7635,54 @@ static int virtnet_ethtool_flow_remove(struct > virtnet_ff *ff, int location) > return err; > } > > +static int virtnet_ethtool_get_flow_count(struct virtnet_ff *ff, > + struct ethtool_rxnfc *info) > +{ > + if (!ff->ff_supported) > + return -EOPNOTSUPP; > + > + info->rule_cnt = ff->ethtool.num_rules; > + info->data = le32_to_cpu(ff->ff_caps->rules_limit) | RX_CLS_LOC_SPECIAL; > + > + return 0; > +} > + > +static int virtnet_ethtool_get_flow(struct virtnet_ff *ff, > + struct ethtool_rxnfc *info) > +{ > + struct virtnet_ethtool_rule *eth_rule; > + > + if (!ff->ff_supported) > + return -EOPNOTSUPP; > + > + eth_rule = xa_load(&ff->ethtool.rules, info->fs.location); > + if (!eth_rule) > + return -ENOENT; > + > + info->fs = eth_rule->flow_spec; > + > + return 0; > +} > + > +static int > +virtnet_ethtool_get_all_flows(struct virtnet_ff *ff, > + struct ethtool_rxnfc *info, u32 *rule_locs) > +{ > + struct virtnet_ethtool_rule *eth_rule; > + unsigned long i = 0; > + int idx = 0; > + > + if (!ff->ff_supported) > + return -EOPNOTSUPP; > + > + xa_for_each(&ff->ethtool.rules, i, eth_rule) > + rule_locs[idx++] = i; > + > + info->data = le32_to_cpu(ff->ff_caps->rules_limit); > + > + return 0; > +} > + > static size_t get_mask_size(u16 type) > { > switch (type) { > -- > 2.50.1 >
