@@ -911,6 +911,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,
.is_switch = ldp->is_switch,
.group_table = l_ctx_out->group_table,
.meter_table = l_ctx_out->meter_table,
+ .collector_ids = l_ctx_in->collector_ids,
.lflow_uuid = lflow->header_.uuid,
.dp_key = ldp->datapath->tunnel_key,
@@ -43,11 +43,12 @@
#include "openvswitch/uuid.h"
#include "openvswitch/list.h"
-struct ovn_extend_table;
-struct ovsdb_idl_index;
-struct ovn_desired_flow_table;
struct hmap;
struct hmap_node;
+struct ovn_desired_flow_table;
+struct ovn_extend_table;
+struct ovsdb_idl_index;
+struct ovsrec_flow_sample_collector_set_table;
struct sbrec_chassis;
struct sbrec_load_balancer;
struct sbrec_logical_flow_table;
@@ -114,6 +115,7 @@ struct lflow_ctx_in {
const struct hmap *dhcpv6_opts;
const struct controller_event_options *controller_event_opts;
const struct smap *template_vars;
+ const struct flow_collector_ids *collector_ids;
bool lb_hairpin_use_ct_mark;
};
@@ -1047,6 +1047,8 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
ovsdb_idl_add_column(ovs_idl, &ovsrec_ssl_col_private_key);
ovsdb_idl_add_table(ovs_idl, &ovsrec_table_datapath);
ovsdb_idl_add_column(ovs_idl, &ovsrec_datapath_col_capabilities);
+ ovsdb_idl_add_table(ovs_idl, &ovsrec_table_flow_sample_collector_set);
+
chassis_register_ovs_idl(ovs_idl);
encaps_register_ovs_idl(ovs_idl);
binding_register_ovs_idl(ovs_idl);
@@ -1063,6 +1065,10 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
ovsdb_idl_track_add_column(ovs_idl, &ovsrec_port_col_name);
ovsdb_idl_track_add_column(ovs_idl, &ovsrec_port_col_interfaces);
ovsdb_idl_track_add_column(ovs_idl, &ovsrec_port_col_external_ids);
+ ovsdb_idl_track_add_column(ovs_idl,
+ &ovsrec_flow_sample_collector_set_col_bridge);
+ ovsdb_idl_track_add_column(ovs_idl,
+ &ovsrec_flow_sample_collector_set_col_id);
mirror_register_ovs_idl(ovs_idl);
}
@@ -1102,7 +1108,8 @@ enum sb_engine_node {
OVS_NODE(bridge, "bridge") \
OVS_NODE(port, "port") \
OVS_NODE(interface, "interface") \
- OVS_NODE(qos, "qos")
+ OVS_NODE(qos, "qos") \
+ OVS_NODE(flow_sample_collector_set, "flow_sample_collector_set")
enum ovs_engine_node {
#define OVS_NODE(NAME, NAME_STR) OVS_##NAME,
@@ -2873,6 +2880,9 @@ struct ed_type_lflow_output {
/* Fixed controller_event supported options. */
struct controller_event_options controller_event_opts;
+
+ /* Configured Flow Sample Collector Sets. */
+ struct flow_collector_ids collector_ids;
};
static void
@@ -3011,6 +3021,7 @@ init_lflow_ctx(struct engine_node *node,
l_ctx_in->dhcpv6_opts = &dhcp_opts->v6_opts;
l_ctx_in->controller_event_opts = &fo->controller_event_opts;
l_ctx_in->template_vars = &template_vars->local_templates;
+ l_ctx_in->collector_ids = &fo->collector_ids;
l_ctx_out->flow_table = &fo->flow_table;
l_ctx_out->group_table = &fo->group_table;
@@ -3040,6 +3051,7 @@ en_lflow_output_init(struct engine_node *node OVS_UNUSED,
data->hd.pool = id_pool_create(1, UINT32_MAX - 1);
nd_ra_opts_init(&data->nd_ra_opts);
controller_event_opts_init(&data->controller_event_opts);
+ flow_collector_ids_init(&data->collector_ids);
return data;
}
@@ -3066,6 +3078,7 @@ en_lflow_output_cleanup(void *data)
id_pool_destroy(flow_output_data->hd.pool);
nd_ra_opts_destroy(&flow_output_data->nd_ra_opts);
controller_event_opts_destroy(&flow_output_data->controller_event_opts);
+ flow_collector_ids_destroy(&flow_output_data->collector_ids);
}
static void
@@ -3135,6 +3148,45 @@ lflow_output_sb_logical_flow_handler(struct engine_node *node, void *data)
return handled;
}
+static bool
+lflow_output_flow_sample_collector_set_handler(struct engine_node *node,
+ void *data OVS_UNUSED)
+{
+ const struct ovsrec_flow_sample_collector_set_table *flow_collector_table =
+ EN_OVSDB_GET(engine_get_input("OVS_flow_sample_collector_set", node));
+ const struct ovsrec_open_vswitch_table *ovs_table =
+ EN_OVSDB_GET(engine_get_input("OVS_open_vswitch", node));
+ const struct ovsrec_bridge_table *bridge_table =
+ EN_OVSDB_GET(engine_get_input("OVS_bridge", node));
+
+ const struct ovsrec_open_vswitch *cfg =
+ ovsrec_open_vswitch_table_first(ovs_table);
+ if (!cfg) {
+ return true;
+ }
+
+ const struct ovsrec_bridge *br_int;
+ br_int = get_bridge(bridge_table, br_int_name(cfg));
+ if (!br_int) {
+ return true;
+ }
+
+ const struct ovsrec_flow_sample_collector_set *set;
+ OVSREC_FLOW_SAMPLE_COLLECTOR_SET_TABLE_FOR_EACH_TRACKED (set,
+ flow_collector_table) {
+ if (set->bridge == br_int) {
+ struct ed_type_lflow_output *lfo = data;
+ flow_collector_ids_clear(&lfo->collector_ids);
+ flow_collector_ids_init_from_table(&lfo->collector_ids,
+ flow_collector_table);
+ return false;
+ }
+ }
+
+ engine_set_node_state(node, EN_UPDATED);
+ return true;
+}
+
static bool
lflow_output_sb_mac_binding_handler(struct engine_node *node, void *data)
{
@@ -4250,6 +4302,8 @@ main(int argc, char *argv[])
engine_add_input(&en_lflow_output, &en_ovs_open_vswitch, NULL);
engine_add_input(&en_lflow_output, &en_ovs_bridge, NULL);
+ engine_add_input(&en_lflow_output, &en_ovs_flow_sample_collector_set,
+ lflow_output_flow_sample_collector_set_handler);
engine_add_input(&en_lflow_output, &en_sb_mac_binding,
lflow_output_sb_mac_binding_handler);
@@ -33,6 +33,7 @@ struct ofpbuf;
struct shash;
struct simap;
struct ovn_extend_table;
+struct collector_set_ids;
/* List of OVN logical actions.
*
@@ -831,6 +832,9 @@ struct ovnact_encode_params {
/* A struct to figure out the meter_id for meter actions. */
struct ovn_extend_table *meter_table;
+ /* A struct to lookup Flow_Sample_Collector_Set ids */
+ const struct flow_collector_ids *collector_ids;
+
/* The logical flow uuid that drove this action. */
struct uuid lflow_uuid;
@@ -4384,7 +4384,14 @@ encode_SAMPLE(const struct ovnact_sample *sample,
const struct ovnact_encode_params *ep,
struct ofpbuf *ofpacts)
{
- struct ofpact_sample *os = ofpact_put_SAMPLE(ofpacts);
+ struct ofpact_sample *os;
+ if (!ep->collector_ids ||
+ !flow_collector_ids_lookup(ep->collector_ids,
+ sample->collector_set_id)) {
+ return;
+ }
+
+ os = ofpact_put_SAMPLE(ofpacts);
os->probability = sample->probability;
os->collector_set_id = sample->collector_set_id;
os->obs_domain_id =
@@ -1044,3 +1044,54 @@ get_chassis_external_id_value_bool(const struct smap *external_ids,
free(chassis_key);
return ret;
}
+
+void flow_collector_ids_init(struct flow_collector_ids *ids)
+{
+ ovs_list_init(&ids->list);
+}
+
+void flow_collector_ids_init_from_table(struct flow_collector_ids *ids,
+ const struct ovsrec_flow_sample_collector_set_table *table)
+{
+ flow_collector_ids_init(ids);
+ const struct ovsrec_flow_sample_collector_set *ovs_collector_set;
+ OVSREC_FLOW_SAMPLE_COLLECTOR_SET_TABLE_FOR_EACH (ovs_collector_set,
+ table) {
+ flow_collector_ids_add(ids, ovs_collector_set->id);
+ }
+}
+
+void flow_collector_ids_add(struct flow_collector_ids *ids,
+ uint64_t id)
+{
+ struct flow_collector_id *collector = xzalloc(sizeof *collector);
+ collector->id = id;
+ ovs_list_push_back(&ids->list, &collector->node);
+}
+
+bool flow_collector_ids_lookup(const struct flow_collector_ids *ids,
+ uint32_t id)
+{
+ struct flow_collector_id *collector;
+ LIST_FOR_EACH (collector, node, &ids->list) {
+ if (collector->id == id) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void flow_collector_ids_destroy(struct flow_collector_ids *ids)
+{
+ struct flow_collector_id *collector;
+ LIST_FOR_EACH_SAFE (collector, node, &ids->list) {
+ ovs_list_remove(&collector->node);
+ free(collector);
+ }
+}
+
+void flow_collector_ids_clear(struct flow_collector_ids *ids)
+{
+ flow_collector_ids_destroy(ids);
+ flow_collector_ids_init(ids);
+}
@@ -28,15 +28,16 @@
#define ROUTE_ORIGIN_CONNECTED "connected"
#define ROUTE_ORIGIN_STATIC "static"
+struct eth_addr;
struct nbrec_logical_router_port;
+struct ovsrec_flow_sample_collector_set_table;
+struct sbrec_datapath_binding;
struct sbrec_logical_flow;
+struct sbrec_port_binding;
+struct smap;
struct svec;
struct uuid;
-struct eth_addr;
-struct sbrec_port_binding;
-struct sbrec_datapath_binding;
struct unixctl_conn;
-struct smap;
struct ipv4_netaddr {
ovs_be32 addr; /* 192.168.10.123 */
@@ -344,4 +345,21 @@ get_chassis_external_id_value_bool(const struct smap *,
const char *option_key,
bool def);
+/* flow_collector_ids is a helper struct used to store and lookup
+ * Flow_Sample_Collector_Set ids. */
+struct flow_collector_id {
+ struct ovs_list node; /* In flow_collector_ids->list */
+ uint64_t id;
+};
+struct flow_collector_ids {
+ struct ovs_list list;
+};
+void flow_collector_ids_init(struct flow_collector_ids *);
+void flow_collector_ids_init_from_table(struct flow_collector_ids *,
+ const struct ovsrec_flow_sample_collector_set_table *);
+void flow_collector_ids_add(struct flow_collector_ids *, uint64_t);
+bool flow_collector_ids_lookup(const struct flow_collector_ids *, uint32_t);
+void flow_collector_ids_destroy(struct flow_collector_ids *);
+void flow_collector_ids_clear(struct flow_collector_ids *);
+
#endif /* OVN_UTIL_H */
@@ -586,6 +586,30 @@ OVN_CONTROLLER_EXPECT_NO_HIT(
[ovn-nbctl --wait=hv meter-del meter0]
)
+OVN_CONTROLLER_EXPECT_HIT(
+ [hv1], [lflow_run],
+ [as hv1 ovs-vsctl --id=@br get Bridge br-int -- \
+ --id=@i create IPFIX targets=\"192.168.1.1\" -- \
+ create Flow_Sample_Collector_Set bridge=@br id=1 ipfix=@i]
+)
+
+OVN_CONTROLLER_EXPECT_NO_HIT(
+ [hv3], [lflow_run],
+ [as hv2 ovs-vsctl --id=@br get Bridge br-int -- \
+ --id=@i create IPFIX targets=\"192.168.1.1\" -- \
+ create Flow_Sample_Collector_Set bridge=@br id=1 ipfix=@i]
+)
+
+OVN_CONTROLLER_EXPECT_NO_HIT(
+ [hv1], [lflow_run],
+ [as hv1 ovs-vsctl set IPFIX . targets=\"192.168.1.2\"]
+)
+
+OVN_CONTROLLER_EXPECT_HIT(
+ [hv1], [lflow_run],
+ [as hv1 ovs-vsctl destroy Flow_Sample_Collector_Set .]
+)
+
for i in 1 2; do
j=$((i%2 + 1))
lp=lp$i
@@ -2216,6 +2216,10 @@ sample(probability=10);
formats as sample(probability=10,collector_set=0,obs_domain=0,obs_point=0);
encodes as sample(probability=10,collector_set_id=0,obs_domain_id=11259375,obs_point_id=0)
+# sample with a collector_set_id that is not configured in the chassis.
+sample(probability=100,collector_set=999,obs_domain=0,obs_point=1000);
+ encodes as drop
+
sample(probability=0,collector_set=200,obs_domain=0,obs_point=1000);
probability must be greater than zero
@@ -33902,6 +33906,10 @@ check_sample_drops() {
# Take match part of flows that contain "drop".
drop_matches="$(grep 'drop' oflows_nosample | grep -oP 'table=\d*, priority=.* ')"
+ ovs-vsctl --id=@br get Bridge br-int -- \
+ --id=@i create IPFIX targets=\"192.168.1.1\" -- \
+ create Flow_Sample_Collector_Set bridge=@br id=123 ipfix=@i
+
check ovn-nbctl -- set NB_Global . options:debug_drop_collector_set="123" \
-- set NB_Global . options:debug_drop_domain_id="1"
check ovn-nbctl --wait=hv sync
@@ -34,6 +34,7 @@
#include "ovn/logical-fields.h"
#include "lib/ovn-l7.h"
#include "lib/extend-table.h"
+#include "lib/ovn-util.h"
#include "ovs-thread.h"
#include "ovstest.h"
#include "openvswitch/shash.h"
@@ -1302,6 +1303,12 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED)
struct ovn_extend_table meter_table;
ovn_extend_table_init(&meter_table);
+ /* Initialize collector sets. */
+ struct flow_collector_ids collector_ids;
+ flow_collector_ids_init(&collector_ids);
+ flow_collector_ids_add(&collector_ids, 0);
+ flow_collector_ids_add(&collector_ids, 200);
+
simap_init(&ports);
simap_put(&ports, "eth0", 5);
simap_put(&ports, "eth1", 6);
@@ -1348,6 +1355,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED)
.is_switch = true,
.group_table = &group_table,
.meter_table = &meter_table,
+ .collector_ids = &collector_ids,
.pipeline = OVNACT_P_INGRESS,
.ingress_ptable = OFTABLE_LOG_INGRESS_PIPELINE,
@@ -1434,6 +1442,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED)
smap_destroy(&template_vars);
ovn_extend_table_destroy(&group_table);
ovn_extend_table_destroy(&meter_table);
+ flow_collector_ids_destroy(&collector_ids);
exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}