@@ -85,6 +85,8 @@ enum dpif_ipfix_tunnel_type {
typedef struct ofputil_ipfix_stats ofproto_ipfix_stats;
struct dpif_ipfix_global_stats {
+ uint64_t dropped_packet_total_count;
+ uint64_t dropped_octet_total_count;
uint64_t packet_total_count;
uint64_t octet_total_count;
uint64_t octet_total_sum_of_squares;
@@ -363,17 +365,21 @@ OVS_PACKED(
struct ipfix_data_record_aggregated_common {
ovs_be32 flow_start_delta_microseconds; /* FLOW_START_DELTA_MICROSECONDS */
ovs_be32 flow_end_delta_microseconds; /* FLOW_END_DELTA_MICROSECONDS */
+ ovs_be64 dropped_packet_delta_count; /* DROPPED_PACKET_DELTA_COUNT */
+ ovs_be64 dropped_packet_total_count; /* DROPPED_PACKET_TOTAL_COUNT */
ovs_be64 packet_delta_count; /* PACKET_DELTA_COUNT */
ovs_be64 packet_total_count; /* PACKET_TOTAL_COUNT */
ovs_be64 layer2_octet_delta_count; /* LAYER2_OCTET_DELTA_COUNT */
ovs_be64 layer2_octet_total_count; /* LAYER2_OCTET_TOTAL_COUNT */
uint8_t flow_end_reason; /* FLOW_END_REASON */
});
-BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_aggregated_common) == 41);
+BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_aggregated_common) == 57);
/* Part of data record for IP aggregated elements. */
OVS_PACKED(
struct ipfix_data_record_aggregated_ip {
+ ovs_be64 dropped_octet_delta_count; /* DROPPED_OCTET_DELTA_COUNT */
+ ovs_be64 dropped_octet_total_count; /* DROPPED_OCTET_TOTAL_COUNT */
ovs_be64 octet_delta_count; /* OCTET_DELTA_COUNT */
ovs_be64 octet_total_count; /* OCTET_TOTAL_COUNT */
ovs_be64 octet_delta_sum_of_squares; /* OCTET_DELTA_SUM_OF_SQUARES */
@@ -381,7 +387,7 @@ struct ipfix_data_record_aggregated_ip {
ovs_be64 minimum_ip_total_length; /* MINIMUM_IP_TOTAL_LENGTH */
ovs_be64 maximum_ip_total_length; /* MAXIMUM_IP_TOTAL_LENGTH */
});
-BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_aggregated_ip) == 48);
+BUILD_ASSERT_DECL(sizeof(struct ipfix_data_record_aggregated_ip) == 64);
/* Part of data record for TCP aggregated elements. */
OVS_PACKED(
@@ -476,10 +482,14 @@ struct ipfix_flow_cache_entry {
/* Common aggregated elements. */
uint64_t flow_start_timestamp_usec;
uint64_t flow_end_timestamp_usec;
+ uint64_t dropped_packet_delta_count;
+ uint64_t dropped_packet_total_count;
uint64_t packet_delta_count;
uint64_t packet_total_count;
uint64_t layer2_octet_delta_count;
uint64_t layer2_octet_total_count;
+ uint64_t dropped_octet_delta_count;
+ uint64_t dropped_octet_total_count;
uint64_t octet_delta_count;
uint64_t octet_total_count;
uint64_t octet_delta_sum_of_squares; /* 0 if not IP. */
@@ -1252,6 +1262,8 @@ ipfix_define_template_fields(enum ipfix_proto_l2 l2, enum ipfix_proto_l3 l3,
DEF(FLOW_START_DELTA_MICROSECONDS);
DEF(FLOW_END_DELTA_MICROSECONDS);
+ DEF(DROPPED_PACKET_DELTA_COUNT);
+ DEF(DROPPED_PACKET_TOTAL_COUNT);
DEF(PACKET_DELTA_COUNT);
DEF(PACKET_TOTAL_COUNT);
DEF(LAYER2_OCTET_DELTA_COUNT);
@@ -1259,6 +1271,8 @@ ipfix_define_template_fields(enum ipfix_proto_l2 l2, enum ipfix_proto_l3 l3,
DEF(FLOW_END_REASON);
if (l3 != IPFIX_PROTO_L3_UNKNOWN) {
+ DEF(DROPPED_OCTET_DELTA_COUNT);
+ DEF(DROPPED_OCTET_TOTAL_COUNT);
DEF(OCTET_DELTA_COUNT);
DEF(OCTET_TOTAL_COUNT);
DEF(OCTET_DELTA_SUM_OF_SQUARES);
@@ -1466,16 +1480,25 @@ ipfix_cache_aggregate_entries(struct ipfix_flow_cache_entry *from_entry,
*to_end = *from_end;
}
+
+ to_entry->dropped_packet_delta_count +=
+ from_entry->dropped_packet_delta_count;
to_entry->packet_delta_count += from_entry->packet_delta_count;
to_entry->layer2_octet_delta_count += from_entry->layer2_octet_delta_count;
+ to_entry->dropped_packet_total_count =
+ from_entry->dropped_packet_total_count;
to_entry->packet_total_count = from_entry->packet_total_count;
to_entry->layer2_octet_total_count = from_entry->layer2_octet_total_count;
+ to_entry->dropped_octet_delta_count +=
+ from_entry->dropped_octet_delta_count;
to_entry->octet_delta_count += from_entry->octet_delta_count;
to_entry->octet_delta_sum_of_squares +=
from_entry->octet_delta_sum_of_squares;
+ to_entry->dropped_octet_total_count =
+ from_entry->dropped_octet_total_count;
to_entry->octet_total_count = from_entry->octet_total_count;
to_entry->octet_total_sum_of_squares =
from_entry->octet_total_sum_of_squares;
@@ -1646,7 +1669,8 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
enum nx_action_sample_direction direction,
const struct dpif_ipfix_port *tunnel_port,
const struct flow_tnl *tunnel_key,
- struct dpif_ipfix_global_stats *stats)
+ struct dpif_ipfix_global_stats *stats,
+ const struct dpif_ipfix_actions *ipfix_actions)
{
struct ipfix_flow_key *flow_key;
struct dp_packet msg;
@@ -1840,14 +1864,17 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
xgettimeofday(&now);
entry->flow_end_timestamp_usec = now.tv_usec + 1000000LL * now.tv_sec;
entry->flow_start_timestamp_usec = entry->flow_end_timestamp_usec;
+ entry->dropped_packet_delta_count = ipfix_actions->output_action ?
+ 0 : packet_delta_count;
entry->packet_delta_count = packet_delta_count;
entry->layer2_octet_delta_count = layer2_octet_delta_count;
+ stats->dropped_packet_total_count += entry->dropped_packet_delta_count;
stats->packet_total_count += packet_delta_count;
stats->layer2_octet_total_count += layer2_octet_delta_count;
+ entry->dropped_packet_total_count = stats->dropped_packet_total_count;
entry->packet_total_count = stats->packet_total_count;
entry->layer2_octet_total_count = stats->layer2_octet_total_count;
-
}
if (l3 != IPFIX_PROTO_L3_UNKNOWN) {
@@ -1860,11 +1887,14 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
* length. */
octet_delta_count = packet_delta_count * ip_total_length;
+ entry->dropped_octet_delta_count = ipfix_actions->output_action ?
+ 0 : octet_delta_count;
entry->octet_delta_count = octet_delta_count;
entry->octet_delta_sum_of_squares = octet_delta_count * ip_total_length;
entry->minimum_ip_total_length = ip_total_length;
entry->maximum_ip_total_length = ip_total_length;
+ stats->dropped_octet_total_count += entry->dropped_octet_delta_count;
stats->octet_total_count += octet_delta_count;
stats->octet_total_sum_of_squares += entry->octet_delta_sum_of_squares;
@@ -1874,8 +1904,9 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
entry->maximum_ip_total_length = 0;
}
- entry->octet_total_sum_of_squares = stats->octet_total_sum_of_squares;
+ entry->dropped_octet_total_count = stats->dropped_octet_total_count;
entry->octet_total_count = stats->octet_total_count;
+ entry->octet_total_sum_of_squares = stats->octet_total_sum_of_squares;
if (l4 == IPFIX_PROTO_L4_TCP) {
uint16_t tcp_flags = ntohs(flow->tcp_flags);
@@ -1965,6 +1996,10 @@ ipfix_put_data_set(uint32_t export_time_sec,
flow_start_delta_usec);
data_aggregated_common->flow_end_delta_microseconds = htonl(
flow_end_delta_usec);
+ data_aggregated_common->dropped_packet_delta_count = htonll(
+ entry->dropped_packet_delta_count);
+ data_aggregated_common->dropped_packet_total_count = htonll(
+ entry->dropped_packet_total_count);
data_aggregated_common->packet_delta_count = htonll(
entry->packet_delta_count);
data_aggregated_common->packet_total_count = htonll(
@@ -1981,6 +2016,10 @@ ipfix_put_data_set(uint32_t export_time_sec,
data_aggregated_ip = dp_packet_put_zeros(
msg, sizeof *data_aggregated_ip);
+ data_aggregated_ip->dropped_octet_delta_count = htonll(
+ entry->dropped_octet_delta_count);
+ data_aggregated_ip->dropped_octet_total_count = htonll(
+ entry->dropped_octet_total_count);
data_aggregated_ip->octet_delta_count = htonll(
entry->octet_delta_count);
data_aggregated_ip->octet_total_count = htonll(
@@ -2053,7 +2092,8 @@ dpif_ipfix_sample(struct dpif_ipfix_exporter *exporter,
uint32_t obs_point_id, odp_port_t output_odp_port,
enum nx_action_sample_direction direction,
const struct dpif_ipfix_port *tunnel_port,
- const struct flow_tnl *tunnel_key)
+ const struct flow_tnl *tunnel_key,
+ const struct dpif_ipfix_actions *ipfix_actions)
{
struct ipfix_flow_cache_entry *entry;
enum ipfix_sampled_packet_type sampled_packet_type;
@@ -2066,7 +2106,8 @@ dpif_ipfix_sample(struct dpif_ipfix_exporter *exporter,
obs_domain_id, obs_point_id,
output_odp_port, direction,
tunnel_port, tunnel_key,
- &exporter->ipfix_global_stats);
+ &exporter->ipfix_global_stats,
+ ipfix_actions);
ipfix_cache_update(exporter, entry, sampled_packet_type);
}
@@ -2081,7 +2122,8 @@ void
dpif_ipfix_bridge_sample(struct dpif_ipfix *di, const struct dp_packet *packet,
const struct flow *flow,
odp_port_t input_odp_port, odp_port_t output_odp_port,
- const struct flow_tnl *output_tunnel_key)
+ const struct flow_tnl *output_tunnel_key,
+ const struct dpif_ipfix_actions *ipfix_actions)
OVS_EXCLUDED(mutex)
{
uint64_t packet_delta_count;
@@ -2131,7 +2173,7 @@ dpif_ipfix_bridge_sample(struct dpif_ipfix *di, const struct dp_packet *packet,
di->bridge_exporter.options->obs_domain_id,
di->bridge_exporter.options->obs_point_id,
output_odp_port, NX_ACTION_SAMPLE_DEFAULT,
- tunnel_port, tunnel_key);
+ tunnel_port, tunnel_key, ipfix_actions);
ovs_mutex_unlock(&mutex);
}
@@ -2140,7 +2182,8 @@ dpif_ipfix_flow_sample(struct dpif_ipfix *di, const struct dp_packet *packet,
const struct flow *flow,
const union user_action_cookie *cookie,
odp_port_t input_odp_port,
- const struct flow_tnl *output_tunnel_key)
+ const struct flow_tnl *output_tunnel_key,
+ const struct dpif_ipfix_actions *ipfix_actions)
OVS_EXCLUDED(mutex)
{
struct dpif_ipfix_flow_exporter_map_node *node;
@@ -2175,7 +2218,7 @@ dpif_ipfix_flow_sample(struct dpif_ipfix *di, const struct dp_packet *packet,
cookie->flow_sample.obs_domain_id,
cookie->flow_sample.obs_point_id,
output_odp_port, cookie->flow_sample.direction,
- tunnel_port, tunnel_key);
+ tunnel_port, tunnel_key, ipfix_actions);
}
ovs_mutex_unlock(&mutex);
}
@@ -2306,3 +2349,48 @@ dpif_ipfix_wait(struct dpif_ipfix *di) OVS_EXCLUDED(mutex)
}
ovs_mutex_unlock(&mutex);
}
+
+void
+dpif_ipfix_read_actions(const struct flow *flow OVS_UNUSED,
+ const struct nlattr *actions,
+ size_t actions_len,
+ struct dpif_ipfix_actions *ipfix_actions)
+{
+ const struct nlattr *a;
+ unsigned int left;
+
+ if (actions_len == 0) {
+ return;
+ }
+
+ NL_ATTR_FOR_EACH (a, left, actions, actions_len) {
+ enum ovs_action_attr type = nl_attr_type(a);
+ switch (type) {
+ case OVS_ACTION_ATTR_OUTPUT:
+ ipfix_actions->output_action = true;
+ break;
+ case OVS_ACTION_ATTR_TUNNEL_POP:
+ case OVS_ACTION_ATTR_TUNNEL_PUSH:
+ case OVS_ACTION_ATTR_TRUNC:
+ case OVS_ACTION_ATTR_USERSPACE:
+ case OVS_ACTION_ATTR_RECIRC:
+ case OVS_ACTION_ATTR_HASH:
+ case OVS_ACTION_ATTR_CT:
+ case OVS_ACTION_ATTR_METER:
+ case OVS_ACTION_ATTR_SET_MASKED:
+ case OVS_ACTION_ATTR_SET:
+ case OVS_ACTION_ATTR_PUSH_VLAN:
+ case OVS_ACTION_ATTR_POP_VLAN:
+ case OVS_ACTION_ATTR_PUSH_MPLS:
+ case OVS_ACTION_ATTR_POP_MPLS:
+ case OVS_ACTION_ATTR_PUSH_ETH:
+ case OVS_ACTION_ATTR_POP_ETH:
+ case OVS_ACTION_ATTR_SAMPLE:
+ case OVS_ACTION_ATTR_CLONE:
+ case OVS_ACTION_ATTR_UNSPEC:
+ case __OVS_ACTION_ATTR_MAX:
+ default:
+ break;
+ }
+ }
+}
@@ -29,6 +29,11 @@ struct ofproto_ipfix_flow_exporter_options;
struct flow_tnl;
struct ofport;
+struct dpif_ipfix_actions {
+ bool output_action; /* Set to true if packet has at least one
+ OVS_ACTION_ATTR_OUTPUT action. */
+};
+
struct dpif_ipfix *dpif_ipfix_create(void);
struct dpif_ipfix *dpif_ipfix_ref(const struct dpif_ipfix *);
void dpif_ipfix_unref(struct dpif_ipfix *);
@@ -52,12 +57,19 @@ int dpif_ipfix_get_stats(const struct dpif_ipfix *, bool, struct ovs_list *);
void dpif_ipfix_bridge_sample(struct dpif_ipfix *, const struct dp_packet *,
const struct flow *,
- odp_port_t, odp_port_t, const struct flow_tnl *);
+ odp_port_t, odp_port_t, const struct flow_tnl *,
+ const struct dpif_ipfix_actions *);
void dpif_ipfix_flow_sample(struct dpif_ipfix *, const struct dp_packet *,
const struct flow *, const union user_action_cookie *,
- odp_port_t, const struct flow_tnl *);
+ odp_port_t, const struct flow_tnl *,
+ const struct dpif_ipfix_actions *);
void dpif_ipfix_run(struct dpif_ipfix *);
void dpif_ipfix_wait(struct dpif_ipfix *);
+void dpif_ipfix_read_actions(const struct flow *flow,
+ const struct nlattr *actions,
+ size_t actions_len,
+ struct dpif_ipfix_actions *ipfix_actions);
+
#endif /* ofproto/ofproto-dpif-ipfix.h */
@@ -1278,6 +1278,59 @@ out:
return error;
}
+static size_t
+dpif_get_actions(struct udpif *udpif, struct upcall *upcall,
+ const struct nlattr **actions)
+{
+ size_t actions_len = 0;
+
+ if (upcall->actions) {
+ /* Actions were passed up from datapath. */
+ *actions = nl_attr_get(upcall->actions);
+ actions_len = nl_attr_get_size(upcall->actions);
+ }
+
+ if (actions_len == 0) {
+ /* Lookup actions in userspace cache. */
+ struct udpif_key *ukey = ukey_lookup(udpif, upcall->ufid,
+ upcall->pmd_id);
+ if (ukey) {
+ ukey_get_actions(ukey, actions, &actions_len);
+ }
+ }
+
+ return actions_len;
+}
+
+static size_t
+dpif_read_actions(struct udpif *udpif, struct upcall *upcall,
+ const struct flow *flow, enum upcall_type type,
+ void *upcall_data)
+{
+ const struct nlattr *actions = NULL;
+ size_t actions_len = dpif_get_actions(udpif, upcall, &actions);
+
+ if (!actions || !actions_len) {
+ return 0;
+ }
+
+ switch (type) {
+ case SFLOW_UPCALL:
+ dpif_sflow_read_actions(flow, actions, actions_len, upcall_data);
+ break;
+ case FLOW_SAMPLE_UPCALL:
+ case IPFIX_UPCALL:
+ dpif_ipfix_read_actions(flow, actions, actions_len, upcall_data);
+ break;
+ case BAD_UPCALL:
+ case MISS_UPCALL:
+ default:
+ break;
+ }
+
+ return actions_len;
+}
+
static int
process_upcall(struct udpif *udpif, struct upcall *upcall,
struct ofpbuf *odp_actions, struct flow_wildcards *wc)
@@ -1285,8 +1338,10 @@ process_upcall(struct udpif *udpif, struct upcall *upcall,
const struct nlattr *userdata = upcall->userdata;
const struct dp_packet *packet = upcall->packet;
const struct flow *flow = upcall->flow;
+ size_t actions_len = 0;
+ enum upcall_type upcall_type = classify_upcall(upcall->type, userdata);
- switch (classify_upcall(upcall->type, userdata)) {
+ switch (upcall_type) {
case MISS_UPCALL:
upcall_xlate(udpif, upcall, odp_actions, wc);
return 0;
@@ -1294,31 +1349,14 @@ process_upcall(struct udpif *udpif, struct upcall *upcall,
case SFLOW_UPCALL:
if (upcall->sflow) {
union user_action_cookie cookie;
- const struct nlattr *actions;
- size_t actions_len = 0;
struct dpif_sflow_actions sflow_actions;
+
memset(&sflow_actions, 0, sizeof sflow_actions);
memset(&cookie, 0, sizeof cookie);
memcpy(&cookie, nl_attr_get(userdata), sizeof cookie.sflow);
- if (upcall->actions) {
- /* Actions were passed up from datapath. */
- actions = nl_attr_get(upcall->actions);
- actions_len = nl_attr_get_size(upcall->actions);
- if (actions && actions_len) {
- dpif_sflow_read_actions(flow, actions, actions_len,
- &sflow_actions);
- }
- }
- if (actions_len == 0) {
- /* Lookup actions in userspace cache. */
- struct udpif_key *ukey = ukey_lookup(udpif, upcall->ufid,
- upcall->pmd_id);
- if (ukey) {
- ukey_get_actions(ukey, &actions, &actions_len);
- dpif_sflow_read_actions(flow, actions, actions_len,
+
+ actions_len = dpif_read_actions(udpif, upcall, flow, upcall_type,
&sflow_actions);
- }
- }
dpif_sflow_received(upcall->sflow, packet, flow,
flow->in_port.odp_port, &cookie,
actions_len > 0 ? &sflow_actions : NULL);
@@ -1329,18 +1367,24 @@ process_upcall(struct udpif *udpif, struct upcall *upcall,
if (upcall->ipfix) {
union user_action_cookie cookie;
struct flow_tnl output_tunnel_key;
+ struct dpif_ipfix_actions ipfix_actions;
memset(&cookie, 0, sizeof cookie);
memcpy(&cookie, nl_attr_get(userdata), sizeof cookie.ipfix);
+ memset(&ipfix_actions, 0, sizeof ipfix_actions);
if (upcall->out_tun_key) {
odp_tun_key_from_attr(upcall->out_tun_key, &output_tunnel_key);
}
+
+ actions_len = dpif_read_actions(udpif, upcall, flow, upcall_type,
+ &ipfix_actions);
dpif_ipfix_bridge_sample(upcall->ipfix, packet, flow,
flow->in_port.odp_port,
cookie.ipfix.output_odp_port,
upcall->out_tun_key ?
- &output_tunnel_key : NULL);
+ &output_tunnel_key : NULL,
+ actions_len > 0 ? &ipfix_actions: NULL);
}
break;
@@ -1348,20 +1392,25 @@ process_upcall(struct udpif *udpif, struct upcall *upcall,
if (upcall->ipfix) {
union user_action_cookie cookie;
struct flow_tnl output_tunnel_key;
+ struct dpif_ipfix_actions ipfix_actions;
memset(&cookie, 0, sizeof cookie);
memcpy(&cookie, nl_attr_get(userdata), sizeof cookie.flow_sample);
+ memset(&ipfix_actions, 0, sizeof ipfix_actions);
if (upcall->out_tun_key) {
odp_tun_key_from_attr(upcall->out_tun_key, &output_tunnel_key);
}
+ actions_len = dpif_read_actions(udpif, upcall, flow, upcall_type,
+ &ipfix_actions);
/* The flow reflects exactly the contents of the packet.
* Sample the packet using it. */
dpif_ipfix_flow_sample(upcall->ipfix, packet, flow,
&cookie, flow->in_port.odp_port,
upcall->out_tun_key ?
- &output_tunnel_key : NULL);
+ &output_tunnel_key : NULL,
+ actions_len > 0 ? &ipfix_actions: NULL);
}
break;
Patch based on RFC 5102, section 5.10. It implements per-flow drop counters: - droppedPacketDeltaCount - droppedPacketTotalCount - droppedOctetDeltaCount - droppedOctetTotalCount In order to determine if packet is going to be dropped, flow actions associated with packet are read. If there is no OVS_ACTION_ATTR_OUTPUT action, packet will be dropped. Signed-off-by: Przemyslaw Szczerbik <przemyslawx.szczerbik@intel.com> --- ofproto/ofproto-dpif-ipfix.c | 110 +++++++++++++++++++++++++++++++++++++----- ofproto/ofproto-dpif-ipfix.h | 16 +++++- ofproto/ofproto-dpif-upcall.c | 95 +++++++++++++++++++++++++++--------- 3 files changed, 185 insertions(+), 36 deletions(-)