@@ -2205,6 +2205,7 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put)
struct offload_info info;
ovs_be16 dst_port = 0;
uint8_t csum_on = false;
+ int n_meters = 0;
int err;
info.tc_modify_flow_deleted = false;
@@ -2245,6 +2246,19 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put)
csum_on = tnl_cfg->csum;
}
netdev_close(outdev);
+ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_METER) {
+ uint32_t meter_id = nl_attr_get_u32(nla);
+ uint32_t police_idx;
+
+ if (meter_id_lookup(meter_id, &police_idx)) {
+ err = EINVAL;
+ goto out;
+ }
+ if (n_meters >= MAX_OFFLOAD_METERS) {
+ err = EOPNOTSUPP;
+ goto out;
+ }
+ info.police_ids[n_meters++] = police_idx;
}
}
@@ -1016,7 +1016,8 @@ parse_tc_flower_to_match(struct tc_flower *flower,
}
break;
case TC_ACT_POLICE: {
- /* Not supported yet */
+ nl_msg_put_u32(buf, OVS_ACTION_ATTR_METER,
+ action->police.meter_id);
}
break;
}
@@ -1584,6 +1585,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
uint32_t block_id = 0;
struct nlattr *nla;
struct tcf_id id;
+ int n_meters = 0;
uint32_t chain;
size_t left;
int prio = 0;
@@ -1921,6 +1923,11 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
action->type = TC_ACT_GOTO;
action->chain = 0; /* 0 is reserved and not used by recirc. */
flower.action_count++;
+ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_METER) {
+ action->type = TC_ACT_POLICE;
+ action->police.meter_id = nl_attr_get_u32(nla);
+ action->police.index = info->police_ids[n_meters++];
+ flower.action_count++;
} else {
VLOG_DBG_RL(&rl, "unsupported put action type: %d",
nl_attr_type(nla));
@@ -27,6 +27,8 @@
extern "C" {
#endif
+#define MAX_OFFLOAD_METERS 4
+
struct dp_packet_batch;
struct dp_packet;
struct netdev_class;
@@ -77,6 +79,8 @@ struct offload_info {
bool tc_modify_flow_deleted; /* Indicate the tc modify flow put success
* to delete the original flow. */
odp_port_t orig_in_port; /* Originating in_port for tnl flows. */
+ uint32_t police_ids[MAX_OFFLOAD_METERS]; /* police ids of the offloaded
+ * meters in the flow */
};
int netdev_flow_flush(struct netdev *);
@@ -2333,6 +2333,22 @@ nl_msg_put_act_gact(struct ofpbuf *request, uint32_t chain)
}
static void
+nl_msg_put_act_police_index(struct ofpbuf *request, uint32_t police_idx)
+{
+ struct tc_police police;
+ size_t offset;
+
+ memset(&police, 0, sizeof police);
+ police.index = police_idx;
+
+ nl_msg_put_string(request, TCA_ACT_KIND, "police");
+ offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
+ nl_msg_put_unspec(request, TCA_POLICE_TBF, &police, sizeof police);
+ nl_msg_put_u32(request, TCA_POLICE_RESULT, TC_ACT_PIPE);
+ nl_msg_end_nested(request, offset);
+}
+
+static void
nl_msg_put_act_ct(struct ofpbuf *request, struct tc_action *action)
{
uint16_t ct_action = 0;
@@ -2783,7 +2799,14 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
}
break;
case TC_ACT_POLICE: {
- /* Not supported yet */
+ struct tc_cookie act_cookie;
+
+ act_offset = nl_msg_start_nested(request, act_index++);
+ nl_msg_put_act_police_index(request, action->police.index);
+ act_cookie.data = &action->police.meter_id;
+ act_cookie.len = sizeof(action->police.meter_id);
+ nl_msg_put_act_cookie(request, &act_cookie);
+ nl_msg_end_nested(request, act_offset);
}
break;
}