diff --git a/debian/changelog b/debian/changelog index a598f5d9..28cf095d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,42 @@ +vyatta-dataplane (3.12.44) unstable; urgency=medium + + [ Ian Wilson ] + * npf: Allow unit-tests to reset session ID to 0 + * ut: Test connsync packing and restoration of SNAT session + * ut: Verify the SNAT session json ssync3 test + * npf: Fix SNAT session restoration from connsync buffer + + [ Mark Gillott ] + * capture: ensure final cleanup occurs after interface cleanup + (Fixes: VRVDR-54831) + + [ Srinivas Narayan ] + * Move crypto & UDP teardown to a later point + + [ Charles (Chas) Williams ] + * fal: add FAL_RET_PLUGIN_CONSUMED framer type (Bugfix: VRVDR-53937) + * pktmbuf: add public API to set vrf (Bugfix: VRVDR-54447) + + -- Srinivas Narayan Mon, 12 Apr 2021 13:11:48 +0100 + +vyatta-dataplane (3.12.43) unstable; urgency=medium + + [ Nicholas Brown ] + * properly export env var in Jenkinsfile + + [ aroberts ] + * Add Aidan Gallagher to the reviewers for qos files + + [ Paul Aitken ] + * DPI: ensure nDPI is init'd on all cores + + [ Alan Dewar ] + * GPC: add initial counter support + * GPC: retrieve a policer's red packet count + * GPC: add support for resettable counters + + -- Srinivas Narayan Wed, 07 Apr 2021 15:28:36 +0100 + vyatta-dataplane (3.12.42) unstable; urgency=medium [ Ian Wilson ] diff --git a/debian/control b/debian/control index d4dd932c..f233451e 100644 --- a/debian/control +++ b/debian/control @@ -102,6 +102,7 @@ Provides: fal-acl, fal-qos-dscp-egressmap, fal-route-vrf-obj, fal-neigh-rtr-intf-obj, + fal-ret-plugin-consumed, Description: Vyatta optimized dataplane Vyatta dataplane is the set of tools to provide performance optimized routing and forwarding. It supports IPv4, IPv6, firewalling, bridging and more. @@ -118,6 +119,7 @@ Depends: check, libvyatta-jsonw1 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Provides: dp-pktmbuf-set-vrf, Description: Vyatta dataplane pipeline node build support Set of headers required for dataplane compilation @@ -204,6 +206,7 @@ Provides: fal-dev-acl, fal-dev-invalid-vrf-id, fal-dev-route-vrf-obj, fal-dev-neigh-rtr-intf-obj, + fal-dev-ret-plugin-consumed, Description: Forwarding Abstraction Library plugin development files An API for dataplane FAL plugins diff --git a/include/fal_plugin.h b/include/fal_plugin.h index 6c0961c4..7902e000 100644 --- a/include/fal_plugin.h +++ b/include/fal_plugin.h @@ -3177,7 +3177,8 @@ union fal_pkt_feature_info { enum fal_feat_framer_ret_value { FAL_RET_ETHER_INPUT, FAL_RET_PORTMONITOR_HW_INPUT, - FAL_RET_CAPTURE_HW_INPUT + FAL_RET_CAPTURE_HW_INPUT, + FAL_RET_PLUGIN_CONSUMED, }; /* diff --git a/include/pktmbuf.h b/include/pktmbuf.h index 68adef92..bea2314e 100644 --- a/include/pktmbuf.h +++ b/include/pktmbuf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, AT&T Intellectual Property. All rights reserved. + * Copyright (c) 2020-2021, AT&T Intellectual Property. All rights reserved. * * SPDX-License-Identifier: LGPL-2.1-only */ @@ -30,6 +30,15 @@ struct rte_mbuf *dp_pktmbuf_alloc_from_default(vrfid_t vrf_id); vrfid_t dp_pktmbuf_get_vrf(const struct rte_mbuf *m); +/* + * Set the vrf associated with the packet. + * + * @param[in] m The buffer to set the vrf on. + * @param[in] vrf_id The vrf to set. + */ +void +dp_pktmbuf_set_vrf(struct rte_mbuf *m, vrfid_t vrf_id); + /* * Mark a packet as having been locally generated. Locally generated * packets may get put in a higher priority qos queue if configured. diff --git a/src/capture.c b/src/capture.c index ea5032a3..daa0f89e 100644 --- a/src/capture.c +++ b/src/capture.c @@ -1167,6 +1167,7 @@ static int capture_main_send(fal_func_t func, void *arg) void capture_destroy(void) { + RTE_LOG(INFO, DATAPLANE, "Capture shutting down\n"); dp_unregister_event_socket(zsock_resolve(capture_sock_main)); zsock_destroy(&capture_sock_main); diff --git a/src/commands.c b/src/commands.c index 327f405a..b72795a6 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1744,7 +1744,7 @@ static const cmd_t cmd_table[] = { { 0, "debug", cmd_debug, "Debug logging level" }, { 0, "ecmp", cmd_ecmp, "Show/set ecmp options" }, { 0, "fal", cmd_fal, "FAL debugging commands" }, - { 0, "gpc", cmd_gpc_op, "GPC OP mode information" }, + { 1, "gpc", cmd_gpc_op, "GPC OP mode information" }, { 0, "gre", cmd_gre, "Show gre information" }, { 0, "help", cmd_help, "This help" }, { 0, "hotplug", cmd_hotplug, "Hotplug event" }, diff --git a/src/gpc/gpc_op_mode.c b/src/gpc/gpc_op_mode.c index cf04ae31..dc3939a3 100644 --- a/src/gpc/gpc_op_mode.c +++ b/src/gpc/gpc_op_mode.c @@ -20,10 +20,22 @@ #include "gpc_util.h" #include "json_writer.h" #include "npf/config/gpc_db_query.h" +#include "npf/config/gpc_hw.h" #include "urcu.h" #include "util.h" +/* + * Some maximum string lengths + */ #define PREFIX_STRLEN (INET6_ADDRSTRLEN + sizeof("/128")) +#define TABLE_ID_STRLEN (IFNAMSIZ + sizeof("/ingress/ipv4")) + +/* + * For the policer we are only interested in red/dropped packets. + */ +static enum fal_policer_stat_type policer_cntr_id[] = { + FAL_POLICER_STAT_RED_PACKETS +}; /* * Structure definitions @@ -56,6 +68,7 @@ gpc_op_show_match(struct gpc_pb_match *match, struct gpc_walk_context *walk_ctx) struct gpc_show_context *show_ctx = (struct gpc_show_context *)walk_ctx->data; json_writer_t *wr = show_ctx->wr; + uint16_t value; char prefix_str[PREFIX_STRLEN]; jsonw_start_object(wr); @@ -64,51 +77,63 @@ gpc_op_show_match(struct gpc_pb_match *match, struct gpc_walk_context *walk_ctx) break; case GPC_RULE_MATCH_VALUE_SRC_IP: if (!gpc_ip_prefix_str(&match->match_value.src_ip, - prefix_str, sizeof(prefix_str))) - jsonw_string_field(wr, "src-ip", prefix_str); + prefix_str, sizeof(prefix_str))) { + jsonw_string_field(wr, "match", "src-ip"); + jsonw_string_field(wr, "value", prefix_str); + } break; case GPC_RULE_MATCH_VALUE_DEST_IP: if (!gpc_ip_prefix_str(&match->match_value.dest_ip, - prefix_str, sizeof(prefix_str))) - jsonw_string_field(wr, "dest-ip", prefix_str); + prefix_str, sizeof(prefix_str))) { + jsonw_string_field(wr, "match", "dest-ip"); + jsonw_string_field(wr, "value", prefix_str); + } break; case GPC_RULE_MATCH_VALUE_SRC_PORT: - jsonw_uint_field(wr, "src-port", match->match_value.src_port); + jsonw_string_field(wr, "match", "src-port"); + jsonw_uint_field(wr, "value", match->match_value.src_port); break; case GPC_RULE_MATCH_VALUE_DEST_PORT: - jsonw_uint_field(wr, "dest-port", match->match_value.dest_port); + jsonw_string_field(wr, "match", "dest-port"); + jsonw_uint_field(wr, "value", match->match_value.dest_port); break; case GPC_RULE_MATCH_VALUE_FRAGMENT: - jsonw_uint_field(wr, "fragment", match->match_value.fragment); + jsonw_string_field(wr, "match", "fragment"); + jsonw_uint_field(wr, "value", match->match_value.fragment); break; case GPC_RULE_MATCH_VALUE_DSCP: - jsonw_uint_field(wr, "dscp", match->match_value.dscp); + jsonw_string_field(wr, "match", "dscp"); + jsonw_uint_field(wr, "value", match->match_value.dscp); break; case GPC_RULE_MATCH_VALUE_TTL: - jsonw_uint_field(wr, "ttl", match->match_value.ttl); + jsonw_string_field(wr, "match", "ttl"); + jsonw_uint_field(wr, "value", match->match_value.ttl); break; case GPC_RULE_MATCH_VALUE_ICMPV4: - jsonw_uint_field(wr, "icmp-type", - match->match_value.icmpv4.typenum); - jsonw_uint_field(wr, "icmp-code", - match->match_value.icmpv4.code); + jsonw_string_field(wr, "match", "icmpv4"); + value = match->match_value.icmpv4.typenum << 8; + value |= match->match_value.icmpv4.code; + jsonw_uint_field(wr, "value", value); break; case GPC_RULE_MATCH_VALUE_ICMPV6: - jsonw_uint_field(wr, "icmpv6-type", - match->match_value.icmpv6.typenum); - jsonw_uint_field(wr, "icmpv6-code", - match->match_value.icmpv6.code); + jsonw_string_field(wr, "match", "icmpv6"); + value = match->match_value.icmpv6.typenum << 8; + value |= match->match_value.icmpv6.code; + jsonw_uint_field(wr, "value", value); break; case GPC_RULE_MATCH_VALUE_ICMPV6_CLASS: - jsonw_uint_field(wr, "icmpv6-class", + jsonw_string_field(wr, "match", "icmpv6-class"); + jsonw_uint_field(wr, "value", match->match_value.icmpv6_class); break; case GPC_RULE_MATCH_VALUE_PROTO_BASE: - jsonw_uint_field(wr, "base-protocol", + jsonw_string_field(wr, "match", "base-protocol"); + jsonw_uint_field(wr, "value", match->match_value.proto_base); break; case GPC_RULE_MATCH_VALUE_PROTO_FINAL: - jsonw_uint_field(wr, "final-protocol", + jsonw_string_field(wr, "match", "final-protocol"); + jsonw_uint_field(wr, "value", match->match_value.proto_final); break; default: @@ -130,7 +155,6 @@ gpc_op_show_action(struct gpc_pb_action *action, json_writer_t *wr = show_ctx->wr; struct gpc_pb_policer *policer; - jsonw_start_object(wr); switch (action->action_type) { case GPC_RULE_ACTION_VALUE_NOT_SET: break; @@ -148,8 +172,8 @@ gpc_op_show_action(struct gpc_pb_action *action, break; case GPC_RULE_ACTION_VALUE_POLICER: policer = &action->action_value.policer; - - jsonw_uint_field(wr, "flags", policer->flags); + jsonw_name(wr, "police"); + jsonw_start_object(wr); if (policer->flags & POLICER_HAS_BW) jsonw_uint_field(wr, "bandwidth", policer->bw); if (policer->flags & POLICER_HAS_BURST) @@ -165,15 +189,31 @@ gpc_op_show_action(struct gpc_pb_action *action, const char *aware = gpc_get_policer_awareness_str(val); jsonw_string_field(wr, "awareness", aware); } - jsonw_uint_field(wr, "packets", 0); - jsonw_uint_field(wr, "drops", 0); + if (policer->objid != FAL_NULL_OBJECT_ID) { + uint64_t drops; + int rv; + + rv = fal_policer_get_stats_ext(policer->objid, 1, + policer_cntr_id, + FAL_STATS_MODE_READ, + &drops); + if (rv != 0) { + RTE_LOG(ERR, DATAPLANE, + "Failed to get GPC policer stats: %s\n", + strerror(-rv)); + drops = 0; + } else { + drops = drops - policer->reset_drops; + } + jsonw_uint_field(wr, "drops", drops); + } + jsonw_end_object(wr); break; default: RTE_LOG(ERR, GPC, "Unknown GPC Action action-type %u\n", action->action_type); break; } - jsonw_end_object(wr); return true; } @@ -184,6 +224,14 @@ gpc_op_show_rule(struct gpc_pb_rule *rule, struct gpc_walk_context *walk_ctx) struct gpc_show_context *show_ctx = (struct gpc_show_context *)walk_ctx->data; json_writer_t *wr = show_ctx->wr; + uint64_t bytes = 0; + uint64_t packets = 0; + + /* + * Rules with a number of zero are not being used + */ + if (rule->number == 0) + return true; jsonw_start_object(wr); jsonw_uint_field(wr, "rule-number", rule->number); @@ -193,10 +241,7 @@ gpc_op_show_rule(struct gpc_pb_rule *rule, struct gpc_walk_context *walk_ctx) gpc_pb_rule_match_walk(rule, gpc_op_show_match, walk_ctx); jsonw_end_array(wr); - jsonw_name(wr, "actions"); - jsonw_start_array(wr); gpc_pb_rule_action_walk(rule, gpc_op_show_action, walk_ctx); - jsonw_end_array(wr); if (rule->counter.counter_type != GPC_COUNTER_TYPE_UNKNOWN || rule->counter.name) { @@ -208,11 +253,17 @@ gpc_op_show_rule(struct gpc_pb_rule *rule, struct gpc_walk_context *walk_ctx) if (rule->counter.name) jsonw_string_field(wr, "counter-name", rule->counter.name); - jsonw_uint_field(wr, "packets", 0); - jsonw_uint_field(wr, "bytes", 0); + + struct gpc_cntr *cntr = gpc_rule_get_cntr(rule->gpc_rule); + + if (cntr && gpc_hw_counter_read(cntr, &packets, &bytes)) { + packets = packets - rule->counter.reset_packets; + bytes = bytes - rule->counter.reset_bytes; + } + jsonw_uint_field(wr, "packets", packets); + jsonw_uint_field(wr, "bytes", bytes); jsonw_end_object(wr); } - jsonw_uint_field(wr, "table-index", rule->table_index); jsonw_uint_field(wr, "orig-number", rule->orig_number); if (rule->result) @@ -229,21 +280,20 @@ gpc_op_show_table(struct gpc_pb_table *table, struct gpc_show_context *show_ctx = (struct gpc_show_context *)walk_ctx->data; json_writer_t *wr = show_ctx->wr; + char table_id_str[TABLE_ID_STRLEN]; uint32_t i; jsonw_start_object(wr); - jsonw_string_field(wr, "interface", table->ifname); - jsonw_string_field(wr, "location", - gpc_get_table_location_str(table->location)); + snprintf(table_id_str, TABLE_ID_STRLEN, "%s/%s/%s", table->ifname, + gpc_get_table_location_str(table->location), + gpc_get_traffic_type_str(table->traffic_type)); + jsonw_string_field(wr, "table-id", table_id_str); jsonw_name(wr, "rules"); jsonw_start_array(wr); gpc_pb_table_rule_walk(table, gpc_op_show_rule, walk_ctx); jsonw_end_array(wr); - jsonw_string_field(wr, "traffic-type", - gpc_get_traffic_type_str(table->traffic_type)); - jsonw_name(wr, "table-names"); jsonw_start_array(wr); for (i = 0; i < table->n_table_names; i++) { @@ -306,7 +356,7 @@ gpc_op_show_feature(struct gpc_pb_feature *feature, * Output in Yang compatible JSON. */ static int -gpc_show(FILE *f, int argc __unused, char **argv __unused) +gpc_show(FILE *f, int argc, char **argv) { struct gpc_show_context show_ctx; struct gpc_walk_context walk_ctx; @@ -337,13 +387,140 @@ gpc_show(FILE *f, int argc __unused, char **argv __unused) jsonw_pretty(show_ctx.wr, true); jsonw_name(show_ctx.wr, "gpc"); + jsonw_start_object(show_ctx.wr); + jsonw_name(show_ctx.wr, "features"); jsonw_start_array(show_ctx.wr); gpc_pb_feature_walk(gpc_op_show_feature, &walk_ctx); jsonw_end_array(show_ctx.wr); + jsonw_end_object(show_ctx.wr); jsonw_destroy(&show_ctx.wr); return 0; } +/* + * The clear functions - to reset the visible counters to zero. + */ + +static gpc_pb_rule_action_walker_cb gpc_op_clear_action; +static bool +gpc_op_clear_action(struct gpc_pb_action *action, + struct gpc_walk_context *walk_ctx __unused) +{ + struct gpc_pb_policer *policer; + uint64_t drops; + int rv; + + /* + * The only action we need to clear is the policer + */ + if (action->action_type == GPC_RULE_ACTION_VALUE_POLICER) { + policer = &action->action_value.policer; + if (policer->objid != FAL_NULL_OBJECT_ID) { + rv = fal_policer_get_stats_ext(policer->objid, 1, + policer_cntr_id, + FAL_STATS_MODE_READ, + &drops); + if (rv != 0) + RTE_LOG(ERR, DATAPLANE, + "Could not retrieve GPC policer stats: %s\n", + strerror(-rv)); + else + policer->reset_drops = drops; + } + } + return true; +} + +static gpc_pb_table_rule_walker_cb gpc_op_clear_rule; +static bool +gpc_op_clear_rule(struct gpc_pb_rule *rule, struct gpc_walk_context *walk_ctx) +{ + uint64_t bytes; + uint64_t packets; + + /* + * Rules with a number of zero are not being used + */ + if (rule->number == 0) + return true; + + gpc_pb_rule_action_walk(rule, gpc_op_clear_action, walk_ctx); + + if (rule->counter.counter_type != GPC_COUNTER_TYPE_UNKNOWN || + rule->counter.name) { + struct gpc_cntr *cntr = gpc_rule_get_cntr(rule->gpc_rule); + + if (cntr && gpc_hw_counter_read(cntr, &packets, &bytes)) { + rule->counter.reset_packets = packets; + rule->counter.reset_bytes = bytes; + } + } + return true; +} + +static gpc_pb_feature_table_walker_cb gpc_op_clear_table; +static bool +gpc_op_clear_table(struct gpc_pb_table *table, + struct gpc_walk_context *walk_ctx) +{ + gpc_pb_table_rule_walk(table, gpc_op_clear_rule, walk_ctx); + return true; // keep walking +} + +static gpc_pb_feature_counter_walker_cb gpc_op_clear_counter; +static bool +gpc_op_clear_counter(struct gpc_pb_counter *counter __unused, + struct gpc_walk_context *walk_ctx __unused) +{ + /* + * We don't support named counters yet + */ + return true; // keep walking +} + +static gpc_pb_feature_walker_cb gpc_op_clear_feature; +static bool +gpc_op_clear_feature(struct gpc_pb_feature *feature, + struct gpc_walk_context *walk_ctx) +{ + gpc_pb_feature_table_walk(feature, gpc_op_clear_table, walk_ctx); + gpc_pb_feature_counter_walk(feature, gpc_op_clear_counter, walk_ctx); + return true; // keep walking +} + +/* + * Handle: "gpc clear [ [ [ []]]]" + * Output in Yang compatible JSON. + */ +static int +gpc_clear(FILE * f __unused, int argc, char **argv) +{ + struct gpc_walk_context walk_ctx; + + --argc, ++argv; /* skip "clear" */ + + walk_ctx.data = NULL; + walk_ctx.feature_type = 0; + walk_ctx.ifname = NULL; + walk_ctx.location = 0; + walk_ctx.traffic_type = 0; + + if (argc > 0) + walk_ctx.feature_type = gpc_feature_str_to_type(argv[0]); + + if (argc > 1) + walk_ctx.ifname = argv[1]; + + if (argc > 2) + walk_ctx.location = gpc_table_location_str_to_value(argv[2]); + + if (argc > 3) + walk_ctx.traffic_type = gpc_traffic_type_str_to_value(argv[3]); + + gpc_pb_feature_walk(gpc_op_clear_feature, &walk_ctx); + return 0; +} + int cmd_gpc_op(FILE *f, int argc, char **argv) { @@ -356,6 +533,8 @@ cmd_gpc_op(FILE *f, int argc, char **argv) /* Check for op-mode commands first */ if (strcmp(argv[0], "show") == 0) return gpc_show(f, argc, argv); + if (strcmp(argv[0], "clear") == 0) + return gpc_clear(f, argc, argv); return 0; } diff --git a/src/gpc/gpc_pb.h b/src/gpc/gpc_pb.h index cdc531d1..325a836b 100644 --- a/src/gpc/gpc_pb.h +++ b/src/gpc/gpc_pb.h @@ -83,9 +83,10 @@ struct gpc_pb_policer { uint64_t burst; uint64_t excess_bw; uint64_t excess_burst; + uint64_t reset_drops; + fal_object_t objid; uint32_t flags; uint8_t awareness; - fal_object_t objid; }; /* @@ -143,6 +144,8 @@ struct gpc_pb_counter { }; struct gpc_pb_rule_counter { + uint64_t reset_packets; + uint64_t reset_bytes; uint32_t counter_type; char *name; }; diff --git a/src/gpc/gpc_pb_config.c b/src/gpc/gpc_pb_config.c index 035799fe..76d77b30 100644 --- a/src/gpc/gpc_pb_config.c +++ b/src/gpc/gpc_pb_config.c @@ -19,6 +19,8 @@ #include "gpc_pb.h" #include "gpc_util.h" #include "ip.h" +#include "npf/config/gpc_cntr_control.h" +#include "npf/config/gpc_cntr_query.h" #include "npf/config/gpc_db_control.h" #include "npf/config/gpc_db_query.h" #include "npf/config/pmf_rule.h" @@ -999,9 +1001,13 @@ gpc_pb_rule_delete(struct gpc_pb_rule *rule) { struct gpc_pb_match *match, *tmp_match; struct gpc_pb_action *action, *tmp_action; + struct gpc_cntr *cntr; assert(rule); + /* + * Rules with a number of zero are not being used + */ if (rule->number == 0) return; @@ -1014,16 +1020,27 @@ gpc_pb_rule_delete(struct gpc_pb_rule *rule) rule->number = 0; /* - * Delete the pmf_rule if we have one attached + * Delete any counter and gpc_rule that might be associated with this + * rule */ - pmf_rule_free(rule->pmf_rule); - rule->pmf_rule = NULL; + if (rule->gpc_rule) { + cntr = gpc_rule_get_cntr(rule->gpc_rule); + if (cntr) { + DP_DEBUG(GPC, DEBUG, GPC, + "Releasing GPC counter %p from GPC rule %p\n", + cntr, rule); + gpc_cntr_release(cntr); + } + + gpc_rule_delete(rule->gpc_rule); + rule->gpc_rule = NULL; + } /* - * Delete the gpc_rule if we have one attached + * Delete the pmf_rule if we have one attached */ - gpc_rule_delete(rule->gpc_rule); - rule->gpc_rule = NULL; + pmf_rule_free(rule->pmf_rule); + rule->pmf_rule = NULL; /* * Delete any matches and actions attached to this rule @@ -1038,6 +1055,55 @@ gpc_pb_rule_delete(struct gpc_pb_rule *rule) } +static int +gpc_pb_rule_counter_create(struct gpc_pb_table *table, struct gpc_pb_rule *rule) +{ + uint32_t counter_type = rule->counter.counter_type; + struct gpc_cntr *cntr = NULL; + + if (counter_type <= GPC_COUNTER_TYPE_DISABLED) + return 0; + + struct gpc_cntg *cntg = gpc_group_get_cntg(table->gpc_group); + + if (!cntg) { + enum gpc_cntr_type type; + + if (counter_type == GPC_COUNTER_TYPE_AUTO) + type = GPC_CNTT_NUMBERED; + else + type = GPC_CNTT_NAMED; + + cntg = gpc_cntg_create(table->gpc_group, type, + (GPC_CNTW_PACKET | GPC_CNTW_L3BYTE), + GPC_CNTS_INTERFACE); + if (!cntg) { + RTE_LOG(ERR, GPC, + "Failed to allocate GPC counter group\n"); + return -ENOMEM; + } + gpc_group_set_cntg(table->gpc_group, cntg); + } + + if (counter_type == GPC_COUNTER_TYPE_AUTO) { + cntr = gpc_cntr_create_numbered(cntg, rule->number); + } else if (counter_type == GPC_COUNTER_TYPE_NAMED) { + cntr = gpc_cntr_find_and_retain(cntg, rule->counter.name); + if (!cntr) + cntr = gpc_cntr_create_named(cntg, rule->counter.name); + } + if (!cntr) { + RTE_LOG(ERR, GPC, + "Failed to allocate GPC counter\n"); + return -ENOMEM; + } + + DP_DEBUG(GPC, DEBUG, GPC, "Added GPC counter %p to GPC rule %p\n", + cntr, rule); + gpc_rule_set_cntr(rule->gpc_rule, cntr); + return 0; +} + static int gpc_pb_rule_parse(struct gpc_pb_table *table, Rule *msg) { @@ -1103,6 +1169,19 @@ gpc_pb_rule_parse(struct gpc_pb_table *table, Rule *msg) rv = gpc_pb_rule_counter_parse(rule, msg->counter); if (rv) goto error_path; + + rv = gpc_pb_rule_counter_create(table, rule); + if (rv) + goto error_path; + + /* + * As we have added a counter to this rule, update the + * pmf_rule's summary and recalculate the gpc-group's + * summary + */ + rule->pmf_rule->pp_summary |= PMF_RAS_COUNT_REF; + (void)gpc_group_recalc_summary(table->gpc_group, + rule->pmf_rule); } if (msg->has_table_index) @@ -1202,6 +1281,11 @@ gpc_pb_rules_parse(struct gpc_pb_table *table, Rules *msg) error_path: RTE_LOG(ERR, GPC, "Problems parsing Rules protobuf: %d\n", rv); if (table->rules_table) { + /* + * We may enter this error path without all n_rules having been + * initialised, gpc_pb_rule_delete will skip over any + * uninitialised rules + */ for (i = 0; i < table->n_rules; i++) gpc_pb_rule_delete(&table->rules_table[i]); } @@ -1243,6 +1327,17 @@ gpc_pb_table_delete(struct gpc_pb_table *table) gpc_pb_rule_delete(&table->rules_table[i]); if (table->gpc_group) { + /* + * Getting and releasing the gpc_cntg may be unnecessary as the + * gpc_cntg is ref-counted by the number of rule counters + * hanging of it, so by deleting all the rule counters in + * gpc_pb_rule_delete, the gpc_cntg should have been freed. + */ + struct gpc_cntg *cntg = gpc_group_get_cntg(table->gpc_group); + + if (cntg) + gpc_cntg_release(cntg); + /* * Tell the hardware that we are deleting a bunch of stuff */ @@ -1358,6 +1453,24 @@ gpc_pb_table_add(struct gpc_pb_feature *feature, GPCTable *msg) * Everything should be in place - tell the FAL about all this stuff */ gpc_group_hw_ntfy_create(table->gpc_group, NULL); + + /* + * Now the gpc_group has been created down in the GPC hw layer + * we can now create any counters associated with the group's rules. + */ + for (i = 0; i < table->n_rules; i++) { + struct gpc_pb_rule *rule = &table->rules_table[i]; + + if (rule->number && rule->gpc_rule) { + struct gpc_cntg *cntg = + gpc_group_get_cntg(table->gpc_group); + struct gpc_cntr *cntr = + gpc_rule_get_cntr(rule->gpc_rule); + + if (cntg && cntr) + gpc_cntr_hw_ntfy_create(cntg, cntr); + } + } gpc_group_hw_ntfy_rules_create(table->gpc_group); gpc_group_hw_ntfy_attach(table->gpc_group); return rv; diff --git a/src/main.c b/src/main.c index 8ee7450d..3401d349 100644 --- a/src/main.c +++ b/src/main.c @@ -3678,9 +3678,6 @@ main(int argc, char **argv) crypto_pmd_remove_all(); stop_all_ports(); - dp_crypto_shutdown(); - - capture_destroy(); device_server_destroy(); console_destroy(); zactor_destroy(&vplane_auth); @@ -3689,13 +3686,13 @@ main(int argc, char **argv) pkt_ring_destroy(); vrf_cleanup(); npf_cleanup(); + capture_destroy(); dp_event(DP_EVT_UNINIT, 0, NULL, 0, 0, NULL); close_all_regular_ports(); dp_lcore_events_teardown(rte_lcore_id()); feature_unload_plugins(); - udp_handler_destroy(); platform_config_cleanup(); fal_cleanup(); close_all_backplane_ports(); @@ -3703,6 +3700,10 @@ main(int argc, char **argv) /* wait for all RCU handlers */ dp_rcu_barrier(); + + dp_crypto_shutdown(); + udp_handler_destroy(); + rcu_defer_unregister_thread(); dp_rcu_unregister_thread(); diff --git a/src/npf/dpi/ndpi.c b/src/npf/dpi/ndpi.c index b939d7ac..87a68e53 100644 --- a/src/npf/dpi/ndpi.c +++ b/src/npf/dpi/ndpi.c @@ -183,7 +183,7 @@ dpi_ndpi_init(void) set_ndpi_malloc(zmalloc_aligned); NDPI_BITMASK_SET_ALL(all); - RTE_LCORE_FOREACH(lcore) { + FOREACH_DP_LCORE(lcore) { struct ndpi_detection_module_struct *detect = ndpi_init_detection_module(ndpi_no_prefs); if (!detect) { diff --git a/src/npf/npf_nat.c b/src/npf/npf_nat.c index e0ee7707..8b5f52ce 100644 --- a/src/npf/npf_nat.c +++ b/src/npf/npf_nat.c @@ -1617,7 +1617,7 @@ int npf_nat_npf_pack_restore(struct npf_session *se, nt->nt_rl = npf_rule_get(rl); np = npf_rule_get_natpolicy(rl); - if (!np || np->n_apm) + if (!np || !np->n_apm) goto error; nt->nt_natpolicy = np; diff --git a/src/npf/npf_session.c b/src/npf/npf_session.c index 8a2697b8..e651bcd2 100644 --- a/src/npf/npf_session.c +++ b/src/npf/npf_session.c @@ -2011,7 +2011,17 @@ int npf_session_npf_pack_pack(npf_session_t *se, if (!se || !pns) return -EINVAL; - pns->pns_flags = se->s_flags; + + /* + * Do not sync SE_ACTIVE flag. The rcvr will call + * npf_session_npf_pack_activate to set the SE_ACTIVE flag and + * increment the intf session count. If the SE_ACTIVE flag is already + * set, then an error in the unpacking routine *before* + * npf_session_npf_pack_activate is called can result in + * npf_if_session_dec decrementing the session count erroneously. + */ + pns->pns_flags = se->s_flags & ~SE_ACTIVE; + rule = npf_session_get_fw_rule(se); pns->pns_fw_rule_hash = (rule ? npf_rule_get_hash(rule) : 0); rule = npf_session_get_rproc_rule(se); diff --git a/src/pipeline/nodes/l2_hw_hdr.c b/src/pipeline/nodes/l2_hw_hdr.c index a8fa39b0..0dbd9398 100644 --- a/src/pipeline/nodes/l2_hw_hdr.c +++ b/src/pipeline/nodes/l2_hw_hdr.c @@ -186,6 +186,9 @@ l2_hw_hdr_rx_process(struct pl_packet *pkt) buff->port = dpdk_port; capture_hardware(ifp, buff); return HW_HDR_IN_CONSUME; + + case FAL_RET_PLUGIN_CONSUMED: + return HW_HDR_IN_CONSUME; } drop: if_incr_dropped(pkt->in_ifp); diff --git a/src/pktmbuf.c b/src/pktmbuf.c index 1f245be6..fb37e933 100644 --- a/src/pktmbuf.c +++ b/src/pktmbuf.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2020, AT&T Intellectual Property. All rights reserved. + * Copyright (c) 2017-2021, AT&T Intellectual Property. All rights reserved. * Copyright (c) 2011-2016 by Brocade Communications Systems, Inc. * All rights reserved. * @@ -500,6 +500,12 @@ dp_pktmbuf_get_vrf(const struct rte_mbuf *m) return pktmbuf_get_vrf(m); } +void +dp_pktmbuf_set_vrf(struct rte_mbuf *m, vrfid_t vrf_id) +{ + pktmbuf_set_vrf(m, vrf_id); +} + void dp_pktmbuf_mark_locally_generated(struct rte_mbuf *m) { pktmbuf_mdata_set(m, PKT_MDATA_FROM_US); diff --git a/src/session/session.c b/src/session/session.c index 0c7ee3c3..36a7aadf 100644 --- a/src/session/session.c +++ b/src/session/session.c @@ -1223,6 +1223,15 @@ static struct session *se_alloc(void) return s; } +/* + * Reset the session_id to 0. Used by UTs between tests so we start each test + * with a known session ID value. + */ +void session_reset_session_id(void) +{ + rte_atomic64_set(&session_id, 0); +} + /* Initialise the logging requirements of the session */ static void se_init_logging(struct session *s) { diff --git a/src/session/session.h b/src/session/session.h index 8933e367..1c7d4190 100644 --- a/src/session/session.h +++ b/src/session/session.h @@ -882,6 +882,13 @@ void session_link_walk(struct session *s, bool do_unlink, */ int session_table_destroy_all(void); +/** + * Reset the session_id to 0. + * + * Used by UTs between tests. + */ +void session_reset_session_id(void); + /** * Extract elements of a sentry. * diff --git a/tests/whole_dp/src/dp_test_gpc_pb.c b/tests/whole_dp/src/dp_test_gpc_pb.c index a290522a..854dd881 100644 --- a/tests/whole_dp/src/dp_test_gpc_pb.c +++ b/tests/whole_dp/src/dp_test_gpc_pb.c @@ -465,84 +465,84 @@ dp_test_create_and_send_gpc_config_msg() const char *expected_reply_1 = "{" - " \"gpc\":[" - " {" - " \"type\":\"qos\"," - " \"tables\":[" - " {" - " \"interface\":\"dp1T0\"," - " \"location\":\"ingress\"," - " \"rules\":[" - " {" - " \"rule-number\":1," - " \"matches\":[" - " {" - " \"src-ip\":\"0.10.10.10/24\"" - " },{" - " \"dest-ip\": \"0.0.0.20/8\"" - " },{" - " \"src-port\":1234" - " },{" - " \"dest-port\":4321" - " },{" - " \"ttl\":64" - " }" - " ]," - " \"actions\":[" - " {" - " \"decision\":\"pass\"" - " },{" - " \"flags\": 1," - " \"bandwidth\": 12345678," - " \"packets\":0," - " \"drops\":0" - " }" - " ]," - " \"table-index\":1," - " \"orig-number\":1" - " },{" - " \"rule-number\":2," - " \"matches\":[" - " {" - " \"icmp-type\":3," - " \"icmp-code\":9" - " },{" - " \"icmpv6-type\":1," - " \"icmpv6-code\":3" - " },{" - " \"fragment\":1" - " },{" - " \"dscp\":63" - " },{" - " \"base-protocol\":19" - " },{" - " \"final-protocol\":100" - " }" - " ]," - " \"actions\":[" - " {" - " \"designation\":6" - " },{" - " \"colour\":\"yellow\"" - " }" - " ]," - " \"table-index\":1," - " \"orig-number\":2" - " }" - " ]," - " \"traffic-type\":\"ipv4\"," - " \"table-names\":[" - " {" - " \"table-index\": 1," - " \"name\": \"gpc-table-name-1\"" - " }" - " ]" - " }" - " ]," - " \"counters\":[" - " ]" - " }" - " ]" + " \"gpc\":{" + " \"features\":[" + " {" + " \"type\":\"qos\"," + " \"tables\":[" + " {" + " \"table-id\":\"dp1T0/ingress/ipv4\"," + " \"rules\":[" + " {" + " \"rule-number\":1," + " \"matches\":[" + " {" + " \"match\":\"src-ip\"," + " \"value\":\"0.10.10.10/24\"" + " },{" + " \"match\":\"dest-ip\"," + " \"value\": \"0.0.0.20/8\"" + " },{" + " \"match\":\"src-port\"," + " \"value\":1234" + " },{" + " \"match\":\"dest-port\"," + " \"value\":4321" + " },{" + " \"match\":\"ttl\"," + " \"value\":64" + " }" + " ]," + " \"decision\":\"pass\"," + " \"police\":{" + " \"bandwidth\": 12345678" + " }," + " \"table-index\":1," + " \"orig-number\":1" + " },{" + " \"rule-number\":2," + " \"matches\":[" + " {" + " \"match\":\"icmpv4\"," + /* type 3, code 9 -> (3 << 8) | 9 = 777 */ + " \"value\":777" + " },{" + " \"match\":\"icmpv6\"," + /* type 1, code 3 -> (1 << 8) | 3 = 259 */ + " \"value\":259" + " },{" + " \"match\":\"fragment\"," + " \"value\":1" + " },{" + " \"match\":\"dscp\"," + " \"value\":63" + " },{" + " \"match\":\"base-protocol\"," + " \"value\":19" + " },{" + " \"match\":\"final-protocol\"," + " \"value\":100" + " }" + " ]," + " \"designation\":6," + " \"colour\":\"yellow\"," + " \"table-index\":1," + " \"orig-number\":2" + " }" + " ]," + " \"table-names\":[" + " {" + " \"table-index\": 1," + " \"name\": \"gpc-table-name-1\"" + " }" + " ]" + " }" + " ]," + " \"counters\":[" + " ]" + " }" + " ]" + " }" "}"; static void @@ -580,7 +580,7 @@ dp_test_create_and_send_gpc_delete_msg() const char *expected_reply_2 = "{" - " \"gpc\":[]" + " \"gpc\":{\"features\":[]}" "}"; DP_DECL_TEST_SUITE(gpc_pb_suite); diff --git a/tests/whole_dp/src/dp_test_npf_lib.c b/tests/whole_dp/src/dp_test_npf_lib.c index 6c49eba5..4e29c515 100644 --- a/tests/whole_dp/src/dp_test_npf_lib.c +++ b/tests/whole_dp/src/dp_test_npf_lib.c @@ -1225,6 +1225,9 @@ dp_test_npf_cleanup(void) /* Clear sessions */ dp_test_npf_clear_sessions(); + /* Reset session ID to 0 */ + dp_test_npf_reset_session_id(); + /* Clear portmaps */ dp_test_npf_flush_portmap(); diff --git a/tests/whole_dp/src/dp_test_npf_sess_lib.c b/tests/whole_dp/src/dp_test_npf_sess_lib.c index d746d839..ec8c81d3 100644 --- a/tests/whole_dp/src/dp_test_npf_sess_lib.c +++ b/tests/whole_dp/src/dp_test_npf_sess_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020, AT&T Intellectual Property. All rights reserved. + * Copyright (c) 2017-2021, AT&T Intellectual Property. All rights reserved. * Copyright (c) 2015 by Brocade Communications Systems, Inc. * All rights reserved. * @@ -839,6 +839,14 @@ typedef bool (*dp_test_npf_json_session_cb)(json_object *jvalue, void *arg); static uint first_session_id; static uint first_nat_session_id; +/* Reset dataplane session ID to 0 */ +void dp_test_npf_reset_session_id(void) +{ + dp_test_session_reset_session_id(); + first_session_id = 0; + first_nat_session_id = 0; +} + json_object * dp_test_npf_json_fw_session_iterate(dp_test_npf_json_session_cb cb, void *arg, unsigned int *index) diff --git a/tests/whole_dp/src/dp_test_npf_sess_lib.h b/tests/whole_dp/src/dp_test_npf_sess_lib.h index 3e5588bd..27dcc621 100644 --- a/tests/whole_dp/src/dp_test_npf_sess_lib.h +++ b/tests/whole_dp/src/dp_test_npf_sess_lib.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020, AT&T Intellectual Property. All rights reserved. + * Copyright (c) 2017-2021, AT&T Intellectual Property. All rights reserved. * Copyright (c) 2015 by Brocade Communications Systems, Inc. * All rights reserved. * @@ -61,6 +61,8 @@ _dp_test_npf_nat_session_count_verify(uint exp_count, bool warn, void dp_test_npf_expire_sessions(void); +/* Reset session ID to 0 */ +void dp_test_npf_reset_session_id(void); /** * Extract source and destination IDs from a packet descriptor. e.g. for TCP diff --git a/tests/whole_dp/src/dp_test_session.c b/tests/whole_dp/src/dp_test_session.c index e558d2b9..ccf58ca2 100644 --- a/tests/whole_dp/src/dp_test_session.c +++ b/tests/whole_dp/src/dp_test_session.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020, AT&T Intellectual Property. All rights reserved. + * Copyright (c) 2017-2021, AT&T Intellectual Property. All rights reserved. * Copyright (c) 2017 by Brocade Communications Systems, Inc. * All rights reserved. * @@ -41,6 +41,7 @@ #include "dp_test_session_internal_lib.h" #include "dp_test_npf_fw_lib.h" #include "dp_test_npf_sess_lib.h" +#include "dp_test_npf_nat_lib.h" #define TEST_VRF 69 #define IF_NAME "dp1T0" @@ -1625,3 +1626,317 @@ DP_START_TEST(ssync2, test20) "aa:bb:cc:dd:2:11"); } DP_END_TEST; + + +/* + * Verify the normal SNAT session + * + * "time_to_expire" has been removed from the expected json + */ +static void session_suite_ssync3_verify_sess1(void) +{ + json_object *exp; + + exp = dp_test_json_create( + "{" + " \"config\":{" + " \"sessions\":{" + " \"1\":{" + " \"vrf_id\":1," + " \"src_addr\":\"192.0.2.103\"," + " \"src_port\":10000," + " \"dst_addr\":\"203.0.113.203\"," + " \"dst_port\":60000," + " \"proto\":17," + " \"interface\":\"dpT21\"," + " \"state_expire_window\":60," + " \"state\":2," + " \"gen_state\":2," + " \"parent\":0," + " \"duration\":0," + " \"feature_type\":2," + " \"features_count\":1," + " \"features\":[" + " {" + " \"type\":3," + " \"interface\":\"dpT21\"," + " \"flags\":518," + " \"nat\":{" + " \"trans_type\":2," + " \"trans_addr\":\"203.0.113.2\"," + " \"trans_port\":10000," + " \"masquerade\":0," + " \"rule\":{" + " \"name\":\"dpT21\"," + " \"number\":10" + " }" + " }" + " }" + " ]," + " \"counters\":{" + " \"packets_in\":1," + " \"bytes_in\":62," + " \"packets_out\":1," + " \"bytes_out\":62" + " }" + " }" + " }" + " }" + "}"); + + dp_test_check_json_poll_state("session-op show sessions full", exp, + DP_TEST_JSON_CHECK_SUBSET, + false, 1); +} + +/* + * Verify the SNAT session created from connsync restoration. + * + * "time_to_expire" has been removed from the expected json + * + * The *only* line that should have changed is line 4, the session ID. + */ +static void session_suite_ssync3_verify_sess2(void) +{ + json_object *exp; + + exp = dp_test_json_create( + "{" + " \"config\":{" + " \"sessions\":{" + " \"2\":{" + " \"vrf_id\":1," + " \"src_addr\":\"192.0.2.103\"," + " \"src_port\":10000," + " \"dst_addr\":\"203.0.113.203\"," + " \"dst_port\":60000," + " \"proto\":17," + " \"interface\":\"dpT21\"," + " \"state_expire_window\":60," + " \"state\":2," + " \"gen_state\":2," + " \"parent\":0," + " \"duration\":0," + " \"feature_type\":2," + " \"features_count\":1," + " \"features\":[" + " {" + " \"type\":3," + " \"interface\":\"dpT21\"," + " \"flags\":518," + " \"nat\":{" + " \"trans_type\":2," + " \"trans_addr\":\"203.0.113.2\"," + " \"trans_port\":10000," + " \"masquerade\":0," + " \"rule\":{" + " \"name\":\"dpT21\"," + " \"number\":10" + " }" + " }" + " }" + " ]," + " \"counters\":{" + " \"packets_in\":1," + " \"bytes_in\":62," + " \"packets_out\":1," + " \"bytes_out\":62" + " }" + " }" + " }" + " }" + "}"); + + dp_test_check_json_poll_state("session-op show sessions full", exp, + DP_TEST_JSON_CHECK_SUBSET, + false, 1); +} + +/* + * Test session sync for an SNAT session + * + * 1. Create SNAT session + * 2. Verify incoming pkt is translated ok + * 3. Pack session into connsync buffer + * 4. Clear session + * 5. Verify incoming pkt is now dropped + * 6. Unpack connsync buffer and restore session + * 7. Verify incoming pkt is now translated ok + */ +DP_DECL_TEST_CASE(session_suite, ssync3, NULL, NULL); +DP_START_TEST(ssync3, test19) +{ + /* Setup interfaces and neighbours */ + dp_test_nl_add_ip_addr_and_connected("dp1T0", "192.0.2.1/24"); + dp_test_nl_add_ip_addr_and_connected("dp2T1", "203.0.113.1/24"); + + dp_test_netlink_add_neigh("dp1T0", "192.0.2.103", + "aa:bb:cc:16:0:20"); + dp_test_netlink_add_neigh("dp2T1", "203.0.113.203", + "aa:bb:cc:18:0:1"); + + struct dp_test_npf_nat_rule_t snat = { + .desc = "snat rule", + .rule = "10", + .ifname = "dp2T1", + .proto = NAT_NULL_PROTO, + .map = "dynamic", + .port_alloc = NULL, + .from_addr = "192.0.2.0/24", + .from_port = NULL, + .to_addr = NULL, + .to_port = NULL, + .trans_addr = "203.0.113.2", + .trans_port = NULL, + }; + dp_test_npf_snat_add(&snat, true); + + /* Block inbound pkts that do not match a session */ + struct dp_test_npf_rule_t rules[] = { + { + .rule = "10", + .pass = BLOCK, + .stateful = STATELESS, + .npf = "dst-addr=203.0.113.2" + }, + RULE_DEF_BLOCK, + NULL_RULE + }; + + struct dp_test_npf_ruleset_t rset = { + .rstype = "fw-in", + .name = "FW1", + .enable = 1, + .attach_point = "dp2T1", + .fwd = FWD, + .dir = "in", + .rules = rules + }; + dp_test_npf_fw_add(&rset, false); + + /* Ensure session ID is 0 */ + dp_test_session_reset_session_id(); + + /* UDP Forwards */ + dpt_udp("dp1T0", "aa:bb:cc:16:0:20", + "192.0.2.103", 10000, "203.0.113.203", 60000, + "203.0.113.2", 10000, "203.0.113.203", 60000, + "aa:bb:cc:18:0:1", "dp2T1", + DP_TEST_FWD_FORWARDED); + + /* UDP Backwards */ + dpt_udp("dp2T1", "aa:bb:cc:18:0:1", + "203.0.113.203", 60000, "203.0.113.2", 10000, + "203.0.113.203", 60000, "192.0.2.103", 10000, + "aa:bb:cc:16:0:20", "dp1T0", + DP_TEST_FWD_FORWARDED); + + /* Verify session */ + session_suite_ssync3_verify_sess1(); + + /* + * Create a sentry_packet to match the forward flow + */ + uint32_t saddr; + uint32_t daddr; + const struct ifnet *ifp; + char realname[IFNAMSIZ]; + struct sentry_packet sp_forw; + int rc; + + dp_test_intf_real("dpT21", realname); + ifp = dp_ifnet_byifname(realname); + + inet_pton(AF_INET, "192.0.2.103", &saddr); + inet_pton(AF_INET, "203.0.113.203", &daddr); + + rc = dp_test_session_init_sentry_packet(&sp_forw, ifp->if_index, + SENTRY_IPv4, (uint8_t) IPPROTO_UDP, 1, htons(10000), + &saddr, htons(60000), &daddr); + dp_test_fail_unless(rc == 0, "session init sentry_packet: %d\n", rc); + + /* + * Use sentry_packet to lookup dataplane session + */ + struct session *s = NULL; + struct npf_session *se = NULL; + bool forw; + + rc = session_lookup_by_sentry_packet(&sp_forw, &s, &forw); + dp_test_fail_unless(rc == 0 && s != NULL, + "session_lookup_by_sentry_packet failed\n"); + + /* + * Get the npf session from the dataplane session + */ + se = session_feature_get(s, s->se_sen->sen_ifindex, + SESSION_FEATURE_NPF); + dp_test_fail_unless(se != NULL, "Failed to get npf session\n"); + + /* + * Pack session. Returns pmh_len if successful + */ + struct session *peer = NULL; + struct npf_pack_message buf; + + memset(&buf, 0, sizeof(buf)); + + rc = dp_session_pack(s, &buf, sizeof(buf), SESSION_PACK_FULL, &peer); + dp_test_fail_unless(rc > 0, "dp_session_pack failed\n"); + + /* + * There may be a good reason this changes if the data structs change + */ + dp_test_fail_unless(rc == 256, + "Expected pack msg length 256, got %d\n", rc); + + /* + * Clear the SNAT session. Without the session, an incoming pkt will + * hit the block firewall rule instead. + */ + dp_test_npf_clear_sessions(); + + dpt_udp("dp2T1", "aa:bb:cc:18:0:1", + "203.0.113.203", 60000, "203.0.113.2", 10000, + "203.0.113.203", 60000, "192.0.2.103", 10000, + "aa:bb:cc:16:0:20", "dp1T0", + DP_TEST_FWD_DROPPED); + + /* + * Unpack and restore session from buffer + */ + enum session_pack_type spt = SESSION_PACK_NONE; + + rc = dp_session_restore(&buf, buf.hdr.pmh_len, &spt); + dp_test_fail_unless(rc == 0 && spt == SESSION_PACK_FULL, + "dp_session_restore failed\n"); + + /* Verify restored session */ + session_suite_ssync3_verify_sess2(); + + /* + * With the SNAT session restored, a backwards packet should now be + * translated and forwarded. + */ + dpt_udp("dp2T1", "aa:bb:cc:18:0:1", + "203.0.113.203", 60000, "203.0.113.2", 10000, + "203.0.113.203", 60000, "192.0.2.103", 10000, + "aa:bb:cc:16:0:20", "dp1T0", + DP_TEST_FWD_FORWARDED); + + /* + * Cleanup + */ + dp_test_npf_fw_del(&rset, false); + dp_test_npf_snat_del(snat.ifname, snat.rule, true); + dp_test_npf_cleanup(); + + dp_test_netlink_del_neigh("dp1T0", "192.0.2.103", + "aa:bb:cc:16:0:20"); + dp_test_netlink_del_neigh("dp2T1", "203.0.113.203", + "aa:bb:cc:18:0:1"); + + dp_test_nl_del_ip_addr_and_connected("dp1T0", "192.0.2.1/24"); + dp_test_nl_del_ip_addr_and_connected("dp2T1", "203.0.113.1/24"); + +} DP_END_TEST; diff --git a/tests/whole_dp/src/dp_test_session_internal_lib.c b/tests/whole_dp/src/dp_test_session_internal_lib.c index bf67ec31..def12bbc 100644 --- a/tests/whole_dp/src/dp_test_session_internal_lib.c +++ b/tests/whole_dp/src/dp_test_session_internal_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, AT&T Intellectual Property. All rights reserved. + * Copyright (c) 2020-2021, AT&T Intellectual Property. All rights reserved. * Copyright (c) 2017 by Brocade Communications Systems, Inc. * All rights reserved. * @@ -202,6 +202,11 @@ void _dp_test_session_reset(const char *file, int line) "session table counts: sessions: %lu\n", se); } +void dp_test_session_reset_session_id(void) +{ + session_reset_session_id(); +} + int _dp_test_session_feature_add(struct session *s, uint32_t if_index, enum session_feature_type type, void *data, const char *file, int line) diff --git a/tests/whole_dp/src/dp_test_session_internal_lib.h b/tests/whole_dp/src/dp_test_session_internal_lib.h index 2ed07bb9..9d5673fd 100644 --- a/tests/whole_dp/src/dp_test_session_internal_lib.h +++ b/tests/whole_dp/src/dp_test_session_internal_lib.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, AT&T Intellectual Property. All rights reserved. + * Copyright (c) 2018-2021, AT&T Intellectual Property. All rights reserved. * Copyright (c) 2015 by Brocade Communications Systems, Inc. * All rights reserved. * @@ -62,6 +62,8 @@ void _dp_test_session_reset(const char *file, int line); #define dp_test_session_reset() \ _dp_test_session_reset(__FILE__, __LINE__) +void dp_test_session_reset_session_id(void); + int _dp_test_session_feature_add(struct session *se, uint32_t if_index, enum session_feature_type type, void *data, const char *file, int line);