@@ -32,6 +32,8 @@ v3.1.0 - xx xxx xxxx
- OpenFlow:
* New OpenFlow extension NXT_CT_FLUSH to flush connections matching
the specified fields.
+ * New OpenFlow extension NXT_CT_SET_ZONE_LIMIT to set conntrack table
+ limit at zone level.
- ovs-ctl:
* New option '--dump-hugepages' to include hugepages in core dumps. This
can assist with postmortem analysis involving DPDK, but may also produce
@@ -1101,4 +1101,14 @@ struct nx_ct_flush {
};
OFP_ASSERT(sizeof(struct nx_ct_flush) == 8);
+/* NXT_CT_SET_ZONE_LIMIT.
+ *
+ * Sets connection tracking table zone limit. */
+struct nx_ct_zone_limit {
+ uint8_t zero[2]; /* Must be zero. */
+ ovs_be16 zone_id; /* Connection tracking zone. */
+ ovs_be32 limit; /* Drop limit. */
+};
+OFP_ASSERT(sizeof(struct nx_ct_zone_limit) == 8);
+
#endif /* openflow/nicira-ext.h */
@@ -518,6 +518,9 @@ enum ofpraw {
/* NXT 1.0+ (32): struct nx_ct_flush, uint8_t[8][]. */
OFPRAW_NXT_CT_FLUSH,
+ /* NXT 1.0+ (35): struct nx_ct_zone_limit. */
+ OFPRAW_NXT_CT_SET_ZONE_LIMIT,
+
/* NXST 1.0+ (3): void. */
OFPRAW_NXST_IPFIX_BRIDGE_REQUEST,
@@ -776,6 +779,7 @@ enum ofptype {
OFPTYPE_IPFIX_FLOW_STATS_REPLY, /* OFPRAW_NXST_IPFIX_FLOW_REPLY */
OFPTYPE_CT_FLUSH_ZONE, /* OFPRAW_NXT_CT_FLUSH_ZONE. */
OFPTYPE_CT_FLUSH, /* OFPRAW_NXT_CT_FLUSH. */
+ OFPTYPE_CT_SET_ZONE_LIMIT, /* OFPRAW_NXT_CT_SET_ZONE_LIMIT. */
/* Flow monitor extension. */
OFPTYPE_FLOW_MONITOR_CANCEL, /* OFPRAW_NXT_FLOW_MONITOR_CANCEL.
@@ -293,6 +293,7 @@ ofputil_is_bundlable(enum ofptype type)
case OFPTYPE_IPFIX_FLOW_STATS_REPLY:
case OFPTYPE_CT_FLUSH_ZONE:
case OFPTYPE_CT_FLUSH:
+ case OFPTYPE_CT_SET_ZONE_LIMIT:
break;
}
@@ -967,6 +967,15 @@ ofp_print_nxt_ct_flush(struct ds *string, const struct ofp_header *oh)
return 0;
}
+static enum ofperr
+ofp_print_nxt_ct_set_zone_limit(struct ds *string,
+ const struct nx_ct_zone_limit *nzl)
+{
+ ds_put_format(string, " zone_id=%"PRIu16, ntohs(nzl->zone_id));
+ ds_put_format(string, " limit=%"PRIu32, ntohl(nzl->limit));
+ return 0;
+}
+
static enum ofperr
ofp_to_string__(const struct ofp_header *oh,
const struct ofputil_port_map *port_map,
@@ -1204,6 +1213,8 @@ ofp_to_string__(const struct ofp_header *oh,
return ofp_print_nxt_ct_flush_zone(string, ofpmsg_body(oh));
case OFPTYPE_CT_FLUSH:
return ofp_print_nxt_ct_flush(string, oh);
+ case OFPTYPE_CT_SET_ZONE_LIMIT:
+ return ofp_print_nxt_ct_set_zone_limit(string, ofpmsg_body(oh));
}
return 0;
@@ -1427,6 +1427,7 @@ is_admitted_msg(const struct ofpbuf *b)
case OFPTYPE_IPFIX_FLOW_STATS_REPLY:
case OFPTYPE_CT_FLUSH_ZONE:
case OFPTYPE_CT_FLUSH:
+ case OFPTYPE_CT_SET_ZONE_LIMIT:
default:
return true;
}
@@ -5631,6 +5631,26 @@ ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id)
}
}
+static void
+ct_set_zone_limit(const struct ofproto *ofproto_, const uint16_t zone_id,
+ const uint32_t limit)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+ struct ovs_list zone_limits = OVS_LIST_INITIALIZER(&zone_limits);
+
+ ct_dpif_push_zone_limit(&zone_limits, zone_id, limit, 0);
+ int err = ct_dpif_set_limits(ofproto->backer->dpif, NULL, &zone_limits);
+ if (err) {
+ VLOG_ERR_RL(&rl, "failed to set zone limit id=%"PRIu16", "
+ "limit=%"PRIu32" (%s)", zone_id, limit,
+ ovs_strerror(err));
+ } else {
+ VLOG_DBG("configured zone limit for zone=%"PRIu16", limit=%"PRIu32"",
+ zone_id, limit);
+ }
+ ct_dpif_free_zone_limits(&zone_limits);
+}
+
static void
get_datapath_cap(const char *datapath_type, struct smap *cap)
{
@@ -6920,4 +6940,5 @@ const struct ofproto_class ofproto_dpif_class = {
ct_flush, /* ct_flush */
ct_set_zone_timeout_policy,
ct_del_zone_timeout_policy,
+ ct_set_zone_limit, /* ct_set_zone_limit */
};
@@ -1916,6 +1916,10 @@ struct ofproto_class {
/* Deletes the timeout policy associated with 'zone' in datapath type
* 'dp_type'. */
void (*ct_del_zone_timeout_policy)(const char *dp_type, uint16_t zone);
+
+ /* Sets conntrack zone limit */
+ void (*ct_set_zone_limit)(const struct ofproto *, const uint16_t zone,
+ const uint32_t limit);
};
extern const struct ofproto_class ofproto_dpif_class;
@@ -966,6 +966,28 @@ handle_nxt_ct_flush(struct ofconn *ofconn, const struct ofp_header *oh)
return 0;
}
+static enum ofperr
+handle_nxt_ct_set_zone_limit(struct ofconn *ofconn,
+ const struct ofp_header *oh)
+{
+ struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+ const struct nx_ct_zone_limit *nzl = ofpmsg_body(oh);
+
+ if (!is_all_zeros(nzl->zero, sizeof nzl->zero)) {
+ return OFPERR_NXBRC_MUST_BE_ZERO;
+ }
+
+ uint16_t zone_id = ntohs(nzl->zone_id);
+ uint32_t limit = ntohl(nzl->limit);
+ if (ofproto->ofproto_class->ct_set_zone_limit) {
+ ofproto->ofproto_class->ct_set_zone_limit(ofproto, zone_id, limit);
+ } else {
+ return EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
void
ofproto_set_flow_restore_wait(bool flow_restore_wait_db)
{
@@ -8814,6 +8836,9 @@ handle_single_part_openflow(struct ofconn *ofconn, const struct ofp_header *oh,
case OFPTYPE_CT_FLUSH:
return handle_nxt_ct_flush(ofconn, oh);
+ case OFPTYPE_CT_SET_ZONE_LIMIT:
+ return handle_nxt_ct_set_zone_limit(ofconn, oh);
+
case OFPTYPE_HELLO:
case OFPTYPE_ERROR:
case OFPTYPE_FEATURES_REPLY:
@@ -4181,3 +4181,13 @@ AT_CHECK([ovs-ofctl ofp-print "\
00 00 00 14 00 00 00 00 00 00 00 00 00 00 ff ff 0a 0a 00 02 00 00 00 00 \
" | grep -q OFPBPC_BAD_VALUE], [0])
AT_CLEANUP
+
+AT_SETUP([NXT_CT_SET_ZONE_LIMIT])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+01 04 00 18 00 00 00 03 00 00 23 20 00 00 00 23 \
+00 00 00 12 00 01 86 a0 \
+"], [0], [dnl
+NXT_CT_SET_ZONE_LIMIT (xid=0x3): zone_id=18 limit=100000
+])
+AT_CLEANUP
@@ -3309,3 +3309,15 @@ AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: <all>" ovs-vswitchd.log])
OVS_VSWITCHD_STOP
AT_CLEANUP
+
+
+AT_SETUP([ovs-ofctl ct-set-zone-limit])
+OVS_VSWITCHD_START
+
+AT_CHECK([ovs-appctl vlog/set ct_dpif:dbg])
+AT_CHECK([ovs-ofctl ct-set-zone-limit br0 1 200000])
+
+OVS_WAIT_UNTIL([grep -q "ofproto_dpif|DBG|.*zone=1.*limit=200000" ovs-vswitchd.log])
+AT_CHECK([grep -q "ofproto_dpif|DBG|.*zone=1.*limit=200000" ovs-vswitchd.log])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
@@ -326,6 +326,11 @@ An example of an IPv6 TCP \fIct-[orig|reply]-tuple\fR:
.IP
This command uses an Open vSwitch extension that is only in Open vSwitch 3.1
and later.
+.IP "\fBct\-set\-zone\-limit \fIswitch zone limit\fR
+Set the connection tracking entries limit in \fIzone\fR on \fIswitch\fR.
+.IP
+This command uses an Open vSwitch extension that is only in Open
+vSwitch 3.1 and later.
.
.SS "OpenFlow Switch Flow Table Commands"
.
@@ -489,6 +489,8 @@ usage(void)
" ct-flush SWITCH [ZONE] [CT_ORIG_TUPLE [CT_REPLY_TUPLE]]\n"
" flush conntrack entries specified\n"
" by CT_ORIG/REPLY_TUPLE and ZONE\n"
+ " ct-set-zone-limit SWITCH ZONE LIMIT set conntrack entries\n"
+ " limit for the ZONE\n"
"\nFor OpenFlow switches and controllers:\n"
" probe TARGET probe whether TARGET is up\n"
" ping TARGET [N] latency of N-byte echos\n"
@@ -3098,6 +3100,35 @@ ofctl_ct_flush(struct ovs_cmdl_context *ctx)
vconn_close(vconn);
}
+static void
+ofctl_ct_set_zone_limit(struct ovs_cmdl_context *ctx)
+{
+ uint16_t zone_id;
+ uint32_t limit;
+
+ char *error = str_to_u16(ctx->argv[2], "zone_id", &zone_id);
+ if (error) {
+ ovs_fatal(0, "%s", error);
+ }
+ error = str_to_u32(ctx->argv[3], &limit);
+ if (error) {
+ ovs_fatal(0, "%s", error);
+ }
+
+ struct vconn *vconn;
+ open_vconn(ctx->argv[1], &vconn);
+ enum ofp_version version = vconn_get_version(vconn);
+
+ struct ofpbuf *msg = ofpraw_alloc(OFPRAW_NXT_CT_SET_ZONE_LIMIT, version,
+ 0);
+ struct nx_ct_zone_limit *nzl = ofpbuf_put_zeros(msg, sizeof *nzl);
+ nzl->zone_id = htons(zone_id);
+ nzl->limit = htonl(limit);
+
+ transact_noreply(vconn, msg);
+ vconn_close(vconn);
+}
+
static void
ofctl_dump_ipfix_flow(struct ovs_cmdl_context *ctx)
{
@@ -5114,6 +5145,9 @@ static const struct ovs_cmdl_command all_commands[] = {
{ "ct-flush", "switch [zone=N] [ct-orig-tuple [ct-reply-tuple]]",
1, 4, ofctl_ct_flush, OVS_RO },
+ { "ct-set-zone-limit", "switch zone limit",
+ 3, 3, ofctl_ct_set_zone_limit, OVS_RO },
+
{ "ofp-parse", "file",
1, 1, ofctl_ofp_parse, OVS_RW },
{ "ofp-parse-pcap", "pcap",