Skip to content

Commit 8e94c3b

Browse files
idoschdavem330
authored andcommitted
drop_monitor: Allow user to start monitoring hardware drops
Drop monitor has start and stop commands, but so far these were only used to start and stop monitoring of software drops. Now that drop monitor can also monitor hardware drops, we should allow the user to control these as well. Do that by adding SW and HW flags to these commands. If no flag is specified, then only start / stop monitoring software drops. This is done in order to maintain backward-compatibility with existing user space applications. Signed-off-by: Ido Schimmel <[email protected]> Acked-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d40e1de commit 8e94c3b

File tree

2 files changed

+123
-3
lines changed

2 files changed

+123
-3
lines changed

include/uapi/linux/net_dropmon.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ enum net_dm_attr {
9090
NET_DM_ATTR_HW_ENTRIES, /* nested */
9191
NET_DM_ATTR_HW_ENTRY, /* nested */
9292
NET_DM_ATTR_HW_TRAP_COUNT, /* u32 */
93+
NET_DM_ATTR_SW_DROPS, /* flag */
94+
NET_DM_ATTR_HW_DROPS, /* flag */
9395

9496
__NET_DM_ATTR_MAX,
9597
NET_DM_ATTR_MAX = __NET_DM_ATTR_MAX - 1

net/core/drop_monitor.c

Lines changed: 121 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -952,13 +952,82 @@ static const struct net_dm_alert_ops *net_dm_alert_ops_arr[] = {
952952
void net_dm_hw_report(struct sk_buff *skb,
953953
const struct net_dm_hw_metadata *hw_metadata)
954954
{
955+
rcu_read_lock();
956+
955957
if (!monitor_hw)
956-
return;
958+
goto out;
957959

958960
net_dm_alert_ops_arr[net_dm_alert_mode]->hw_probe(skb, hw_metadata);
961+
962+
out:
963+
rcu_read_unlock();
959964
}
960965
EXPORT_SYMBOL_GPL(net_dm_hw_report);
961966

967+
static int net_dm_hw_monitor_start(struct netlink_ext_ack *extack)
968+
{
969+
const struct net_dm_alert_ops *ops;
970+
int cpu;
971+
972+
if (monitor_hw) {
973+
NL_SET_ERR_MSG_MOD(extack, "Hardware monitoring already enabled");
974+
return -EAGAIN;
975+
}
976+
977+
ops = net_dm_alert_ops_arr[net_dm_alert_mode];
978+
979+
if (!try_module_get(THIS_MODULE)) {
980+
NL_SET_ERR_MSG_MOD(extack, "Failed to take reference on module");
981+
return -ENODEV;
982+
}
983+
984+
for_each_possible_cpu(cpu) {
985+
struct per_cpu_dm_data *hw_data = &per_cpu(dm_hw_cpu_data, cpu);
986+
struct net_dm_hw_entries *hw_entries;
987+
988+
INIT_WORK(&hw_data->dm_alert_work, ops->hw_work_item_func);
989+
timer_setup(&hw_data->send_timer, sched_send_work, 0);
990+
hw_entries = net_dm_hw_reset_per_cpu_data(hw_data);
991+
kfree(hw_entries);
992+
}
993+
994+
monitor_hw = true;
995+
996+
return 0;
997+
}
998+
999+
static void net_dm_hw_monitor_stop(struct netlink_ext_ack *extack)
1000+
{
1001+
int cpu;
1002+
1003+
if (!monitor_hw)
1004+
NL_SET_ERR_MSG_MOD(extack, "Hardware monitoring already disabled");
1005+
1006+
monitor_hw = false;
1007+
1008+
/* After this call returns we are guaranteed that no CPU is processing
1009+
* any hardware drops.
1010+
*/
1011+
synchronize_rcu();
1012+
1013+
for_each_possible_cpu(cpu) {
1014+
struct per_cpu_dm_data *hw_data = &per_cpu(dm_hw_cpu_data, cpu);
1015+
struct sk_buff *skb;
1016+
1017+
del_timer_sync(&hw_data->send_timer);
1018+
cancel_work_sync(&hw_data->dm_alert_work);
1019+
while ((skb = __skb_dequeue(&hw_data->drop_queue))) {
1020+
struct net_dm_hw_metadata *hw_metadata;
1021+
1022+
hw_metadata = NET_DM_SKB_CB(skb)->hw_metadata;
1023+
net_dm_hw_metadata_free(hw_metadata);
1024+
consume_skb(skb);
1025+
}
1026+
}
1027+
1028+
module_put(THIS_MODULE);
1029+
}
1030+
9621031
static int net_dm_trace_on_set(struct netlink_ext_ack *extack)
9631032
{
9641033
const struct net_dm_alert_ops *ops;
@@ -1153,14 +1222,61 @@ static int net_dm_cmd_config(struct sk_buff *skb,
11531222
return 0;
11541223
}
11551224

1225+
static int net_dm_monitor_start(bool set_sw, bool set_hw,
1226+
struct netlink_ext_ack *extack)
1227+
{
1228+
bool sw_set = false;
1229+
int rc;
1230+
1231+
if (set_sw) {
1232+
rc = set_all_monitor_traces(TRACE_ON, extack);
1233+
if (rc)
1234+
return rc;
1235+
sw_set = true;
1236+
}
1237+
1238+
if (set_hw) {
1239+
rc = net_dm_hw_monitor_start(extack);
1240+
if (rc)
1241+
goto err_monitor_hw;
1242+
}
1243+
1244+
return 0;
1245+
1246+
err_monitor_hw:
1247+
if (sw_set)
1248+
set_all_monitor_traces(TRACE_OFF, extack);
1249+
return rc;
1250+
}
1251+
1252+
static void net_dm_monitor_stop(bool set_sw, bool set_hw,
1253+
struct netlink_ext_ack *extack)
1254+
{
1255+
if (set_hw)
1256+
net_dm_hw_monitor_stop(extack);
1257+
if (set_sw)
1258+
set_all_monitor_traces(TRACE_OFF, extack);
1259+
}
1260+
11561261
static int net_dm_cmd_trace(struct sk_buff *skb,
11571262
struct genl_info *info)
11581263
{
1264+
bool set_sw = !!info->attrs[NET_DM_ATTR_SW_DROPS];
1265+
bool set_hw = !!info->attrs[NET_DM_ATTR_HW_DROPS];
1266+
struct netlink_ext_ack *extack = info->extack;
1267+
1268+
/* To maintain backward compatibility, we start / stop monitoring of
1269+
* software drops if no flag is specified.
1270+
*/
1271+
if (!set_sw && !set_hw)
1272+
set_sw = true;
1273+
11591274
switch (info->genlhdr->cmd) {
11601275
case NET_DM_CMD_START:
1161-
return set_all_monitor_traces(TRACE_ON, info->extack);
1276+
return net_dm_monitor_start(set_sw, set_hw, extack);
11621277
case NET_DM_CMD_STOP:
1163-
return set_all_monitor_traces(TRACE_OFF, info->extack);
1278+
net_dm_monitor_stop(set_sw, set_hw, extack);
1279+
return 0;
11641280
}
11651281

11661282
return -EOPNOTSUPP;
@@ -1392,6 +1508,8 @@ static const struct nla_policy net_dm_nl_policy[NET_DM_ATTR_MAX + 1] = {
13921508
[NET_DM_ATTR_ALERT_MODE] = { .type = NLA_U8 },
13931509
[NET_DM_ATTR_TRUNC_LEN] = { .type = NLA_U32 },
13941510
[NET_DM_ATTR_QUEUE_LEN] = { .type = NLA_U32 },
1511+
[NET_DM_ATTR_SW_DROPS] = {. type = NLA_FLAG },
1512+
[NET_DM_ATTR_HW_DROPS] = {. type = NLA_FLAG },
13951513
};
13961514

13971515
static const struct genl_ops dropmon_ops[] = {

0 commit comments

Comments
 (0)