---
controller/pinctrl.c | 5 +++
include/ovn/actions.h | 7 ++++
lib/actions.c | 22 +++++++++++
northd/ovn-northd.8.xml | 5 ++-
northd/ovn-northd.c | 28 +++++++++++++-
tests/ovn.at <http://ovn.at> | 84
++++++++++++++++++++++++++++++++++++++++-
utilities/ovn-trace.c | 5 +++
7 files changed, 150 insertions(+), 6 deletions(-)
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index ce11aa365..b9880e257 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -3057,6 +3057,11 @@ process_packet_in(struct rconn *swconn, const
struct ofp_header *msg)
&userdata, false);
break;
+ case ACTION_OPCODE_SCTP_ABORT:
+ pinctrl_handle_sctp_abort(swconn, &headers, &packet,
+ &pin.flow_metadata, &userdata,
false);
+ break;
+
case ACTION_OPCODE_REJECT:
pinctrl_handle_reject(swconn, &headers, &packet,
&pin.flow_metadata,
&userdata);
diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index d104d4d64..be87e6135 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -106,6 +106,7 @@ struct ovn_extend_table;
OVNACT(CHK_LB_HAIRPIN_REPLY, ovnact_result) \
OVNACT(CT_SNAT_TO_VIP, ovnact_null) \
OVNACT(BFD_MSG, ovnact_null) \
+ OVNACT(SCTP_ABORT, ovnact_nest) \
/* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
enum OVS_PACKED_ENUM ovnact_type {
@@ -634,6 +635,12 @@ enum action_opcode {
* The actions, in OpenFlow 1.3 format, follow the action_header.
*/
ACTION_OPCODE_BFD_MSG,
+
+ /* "sctp_abort { ...actions... }".
+ *
+ * The actions, in OpenFlow 1.3 format, follow the action_header.
+ */
+ ACTION_OPCODE_SCTP_ABORT,
};
/* Header. */
diff --git a/lib/actions.c b/lib/actions.c
index 86be97f44..56b8fab62 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -1490,6 +1490,12 @@ parse_TCP_RESET(struct action_context *ctx)
parse_nested_action(ctx, OVNACT_TCP_RESET, "tcp", ctx->scope);
}
+static void
+parse_SCTP_ABORT(struct action_context *ctx)
+{
+ parse_nested_action(ctx, OVNACT_SCTP_ABORT, "sctp", ctx->scope);
+}
+
static void
parse_ND_NA(struct action_context *ctx)
{
@@ -1571,6 +1577,12 @@ format_TCP_RESET(const struct ovnact_nest
*nest, struct ds *s)
format_nested_action(nest, "tcp_reset", s);
}
+static void
+format_SCTP_ABORT(const struct ovnact_nest *nest, struct ds *s)
+{
+ format_nested_action(nest, "sctp_abort", s);
+}
+
static void
format_ND_NA(const struct ovnact_nest *nest, struct ds *s)
{
@@ -1700,6 +1712,14 @@ encode_TCP_RESET(const struct ovnact_nest *on,
encode_nested_actions(on, ep, ACTION_OPCODE_TCP_RESET, ofpacts);
}
+static void
+encode_SCTP_ABORT(const struct ovnact_nest *on,
+ const struct ovnact_encode_params *ep,
+ struct ofpbuf *ofpacts)
+{
+ encode_nested_actions(on, ep, ACTION_OPCODE_SCTP_ABORT, ofpacts);
+}
+
static void
encode_REJECT(const struct ovnact_nest *on,
const struct ovnact_encode_params *ep,
@@ -3837,6 +3857,8 @@ parse_action(struct action_context *ctx)
ovnact_put_IGMP(ctx->ovnacts);
} else if (lexer_match_id(ctx->lexer, "tcp_reset")) {
parse_TCP_RESET(ctx);
+ } else if (lexer_match_id(ctx->lexer, "sctp_abort")) {
+ parse_SCTP_ABORT(ctx);
} else if (lexer_match_id(ctx->lexer, "nd_na")) {
parse_ND_NA(ctx);
} else if (lexer_match_id(ctx->lexer, "nd_na_router")) {
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 398a3452e..70065a36d 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -518,8 +518,9 @@
flows with the
<code>tcp_reset { output <-> inport;
next(pipeline=egress,table=5);}</code>
- action for TCP connections and <code>icmp4/icmp6</code> action
- for UDP connections.
+ action for TCP connections,<code>icmp4/icmp6</code> action
+ for UDP connections, and <code>sctp_abort {output <-%gt;
inport;
+ next(pipeline=egress,table=5);}</code> action for SCTP
associations.
</li>
<li>
Other ACLs translate to <code>drop;</code> for new or
untracked
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 50507685b..332dbc112 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -10529,7 +10529,7 @@ build_ipv6_input_flows_for_lrouter_port(
&op->nbrp->header_, lflows);
}
- /* UDP/TCP port unreachable */
+ /* UDP/TCP/SCTP port unreachable */
if (!smap_get(&op->od->nbr->options, "chassis")
&& !op->od->l3dgw_port) {
for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
@@ -10545,6 +10545,18 @@ build_ipv6_input_flows_for_lrouter_port(
80, ds_cstr(match), action,
&op->nbrp->header_);
+ ds_clear(match);
+ ds_put_format(match,
+ "ip6 && ip6.dst == %s &&
!ip.later_frag && sctp",
+ op->lrp_networks.ipv6_addrs[i].addr_s);
+ action = "sctp_abort {"
+ "eth.dst <-> eth.src; "
+ "ip6.dst <-> ip6.src; "
+ "next; };";
+ ovn_lflow_add_with_hint(lflows, op->od,
S_ROUTER_IN_IP_INPUT,
+ 80, ds_cstr(match), action,
+ &op->nbrp->header_);
+
ds_clear(match);
ds_put_format(match,
"ip6 && ip6.dst == %s &&
!ip.later_frag && udp",
@@ -10806,7 +10818,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
if (!smap_get(&op->od->nbr->options, "chassis")
&& !op->od->l3dgw_port) {
- /* UDP/TCP port unreachable. */
+ /* UDP/TCP/SCTP port unreachable. */
for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
ds_clear(match);
ds_put_format(match,
@@ -10835,6 +10847,18 @@ build_lrouter_ipv4_ip_input(struct ovn_port
*op,
80, ds_cstr(match), action,
&op->nbrp->header_);
+ ds_clear(match);
+ ds_put_format(match,
+ "ip4 && ip4.dst == %s &&
!ip.later_frag && sctp",
+ op->lrp_networks.ipv4_addrs[i].addr_s);
+ action = "sctp_abort {"
+ "eth.dst <-> eth.src; "
+ "ip4.dst <-> ip4.src; "
+ "next; };";
+ ovn_lflow_add_with_hint(lflows, op->od,
S_ROUTER_IN_IP_INPUT,
+ 80, ds_cstr(match), action,
+ &op->nbrp->header_);
+
ds_clear(match);
ds_put_format(match,
"ip4 && ip4.dst == %s &&
!ip.later_frag",
diff --git a/tests/ovn.at <http://ovn.at> b/tests/ovn.at <http://ovn.at>
index c71e81822..f575eecb5 100644
--- a/tests/ovn.at <http://ovn.at>
+++ b/tests/ovn.at <http://ovn.at>
@@ -1637,6 +1637,17 @@ tcp_reset { };
encodes as controller(userdata=00.00.00.0b.00.00.00.00)
has prereqs tcp
+# sctp_abort
+sctp_abort {eth.dst = ff:ff:ff:ff:ff:ff; output; }; output;
+ formats as sctp_abort { eth.dst = ff:ff:ff:ff:ff:ff; output; };
output;
+ encodes as
controller(userdata=00.00.00.18.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00),resubmit(,64)
+ has prereqs sctp
+
+sctp_abort { };
+ formats as sctp_abort { drop; };
+ encodes as controller(userdata=00.00.00.18.00.00.00.00)
+ has prereqs sctp
+
# reject
reject { eth.dst = ff:ff:ff:ff:ff:ff; output; }; output;
encodes as
controller(userdata=00.00.00.16.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00),resubmit(,64)
@@ -14354,6 +14365,45 @@ test_tcp_syn_packet() {
as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
}
+# test_sctp_init_packet INPORT HV ETH_SRC ETH_DST IPV4_SRC IPV4_DST
IP_CHKSUM SCTP_SPORT SCTP_DPORT SCTP_INIT_TAG SCTP_CHKSUM
EXP_IP_CHKSUM EXP_SCTP_ABORT_CHKSUM
+#
+# Causes a packet to be received on INPORT of the hypervisor HV.
The packet is an SCTP INIT chunk with
+# ETH_SRC, ETH_DST, IPV4_SRC, IPV4_DST, IP_CHKSUM, SCTP_SPORT,
SCTP_DPORT, and SCTP_CHKSUM as specified.
+# The INIT "initiate_tag" will be set to SCTP_INIT_TAG.
+# EXP_IP_CHKSUM and EXP_SCTP_CHKSUM are the ip and sctp checksums
of the SCTP ABORT chunk generated by OVN logical router
+#
+# INPORT is an lport number, e.g. 1 for vif1.
+# HV is a hypervisor number.
+# ETH_SRC and ETH_DST are each 12 hex digits.
+# IPV4_SRC and IPV4_DST are each 8 hex digits.
+# SCTP_SPORT and SCTP_DPORT are 4 hex digits.
+# IP_CHKSUM and EXP_IP_CHKSUM are 4 hex digits.
+# SCTP_CHKSUM and EXP_SCTP_CHKSUM are 8 hex digits.
+test_sctp_init_packet() {
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv4_src=$5
ipv4_dst=$6 ip_chksum=$7
+ local sctp_sport=$8 sctp_dport=$9 sctp_init_tag=${10}
sctp_chksum=${11}
+ local exp_ip_chksum=${12} exp_sctp_abort_chksum=${13}
+
+ local ip_ttl=ff
+ local eth_hdr=${eth_dst}${eth_src}0800
+ local
ip_hdr=4500002500004000${ip_ttl}84${ip_chksum}${ipv4_src}${ipv4_dst}
+ local sctp_hdr=${sctp_sport}${sctp_dport}00000000${sctp_chksum}
+ local
sctp_init=01000014${sctp_init_tag}0000000000010001${sctp_init_tag}
+
+ local packet=${eth_hdr}${ip_hdr}${sctp_hdr}${sctp_init}
+
+ local sctp_abort_ttl=3e
+ local reply_eth_hdr=${eth_src}${eth_dst}0800
+ local
reply_ip_hdr=4500002400004000${sctp_abort_ttl}84${exp_ip_chksum}${ipv4_dst}${ipv4_src}
+ local
reply_sctp_hdr=${sctp_dport}${sctp_sport}${sctp_init_tag}${exp_sctp_abort_chksum}
+ local reply_sctp_abort=06000004
+
+ local
reply=${reply_eth_hdr}${reply_ip_hdr}${reply_sctp_hdr}${reply_sctp_abort}
+ echo $reply >> vif$inport.expected
+
+ check as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+}
+
# test_tcp6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_ROUTER
TCP_SPORT TCP_DPORT TCP_CHKSUM EXP_TCP_RST_CHKSUM
#
# Causes a packet to be received on INPORT of the hypervisor HV.
The packet is a TCP syn segment with
@@ -14374,6 +14424,36 @@ test_tcp6_packet() {
as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
}
+# test_tcp6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_ROUTER
SCTP_SPORT SCTP_DPORT SCTP_INIT_TAG SCTP_CHKSUM EXP_SCTP_ABORT_CHKSUM
+#
+# Causes a packet to be received on INPORT of the hypervisor HV.
The packet is an SCTP INIT chunk with
+# ETH_SRC, ETH_DST, IPV6_SRC, IPV6_ROUTER, SCTP_SPORT, SCTP_DPORT
and SCTP_CHKSUM as specified.
+# The INIT "initiate_tag" will be set to SCTP_INIT_TAG.
+# EXP_SCTP_CHKSUM is the sctp checksum of the SCTP ABORT chunk
generated by OVN logical router
+test_sctp6_packet() {
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5
ipv6_router=$6
+ local sctp_sport=$7 sctp_dport=$8 sctp_init_tag=$9
sctp_chksum=${10}
+ local exp_sctp_abort_chksum=${11}
+ shift 11
+
+ local eth_hdr=${eth_dst}${eth_src}86dd
+ local ip_hdr=60000000002084ff${ipv6_src}${ipv6_router}
+ local sctp_hdr=${sctp_sport}${sctp_dport}00000000${sctp_chksum}
+ local
sctp_init=01000014${sctp_init_tag}0000000000010001${sctp_init_tag}
+
+ local packet=${eth_hdr}${ip_hdr}${sctp_hdr}${sctp_init}
+
+ local reply_eth_hdr=${eth_src}${eth_dst}86dd
+ local reply_ip_hdr=600000000010843e${ipv6_router}${ipv6_src}
+ local
reply_sctp_hdr=${sctp_dport}${sctp_sport}${sctp_init_tag}${exp_sctp_abort_chksum}
+ local reply_sctp_abort=06000004
+
+ local
reply=${reply_eth_hdr}${reply_ip_hdr}${reply_sctp_hdr}${reply_sctp_abort}
+ echo $reply >> vif$inport.expected
+
+ check as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+}
+
# test_ip6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_DST
IPV6_PROTO IPV6_LEN DATA EXP_ICMP_CODE EXP_ICMP_CHKSUM
#
# Causes a packet to be received on INPORT of the hypervisor HV.
The packet is an IPv6
@@ -14428,13 +14508,13 @@ OVN_POPULATE_ARP
ovn-nbctl --wait=hv sync
test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1
1) $(ip_to_hex 192 168 1 254) 11 0000 f87c f485 0303
-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1
1) $(ip_to_hex 192 168 1 254) 84 0000 f87c f413 0302
test_ip6_packet 1 1 000000000001 00000000ff01
20010db8000100000000000000000011 20010db8000100000000000000000001 11
0015 dbb8303900155bac6b646f65206676676e6d66720a 0104 1d31
OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
test_tcp_syn_packet 2 2 000000000002 00000000ff02 $(ip_to_hex 192
168 2 1) $(ip_to_hex 192 168 2 254) 0000 8b40 3039 0000 b680 6e05
-test_ip6_packet 2 2 000000000002 00000000ff02
20010db8000200000000000000000011 20010db8000200000000000000000001 84
0004 01020304 0103 5e74
+test_sctp_init_packet 2 2 000000000002 00000000ff02 $(ip_to_hex 192
168 2 1) $(ip_to_hex 192 168 2 254) 0000 8b40 3039 00000001 82112601
b606 10fe95b6
test_tcp6_packet 2 2 000000000002 00000000ff02
20010db8000200000000000000000011 20010db8000200000000000000000001
8b40 3039 0000 98cd
+test_sctp6_packet 2 2 000000000002 00000000ff02
20010db8000200000000000000000011 20010db8000200000000000000000001
8b40 3039 00000002 C0379D5A 39f23aaf
OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [vif2.expected])
OVN_CLEANUP([hv1], [hv2])
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
index d54ffbcd9..c0a0edc0a 100644
--- a/utilities/ovn-trace.c
+++ b/utilities/ovn-trace.c
@@ -2594,6 +2594,11 @@ trace_actions(const struct ovnact *ovnacts,
size_t ovnacts_len,
false, pipeline, super);
break;
+ case OVNACT_SCTP_ABORT:
+ execute_sctp_abort(ovnact_get_SCTP_ABORT(a), dp, uflow,
table_id,
+ false, pipeline, super);
+ break;
+
case OVNACT_OVNFIELD_LOAD:
execute_ovnfield_load(ovnact_get_OVNFIELD_LOAD(a), super);
break;
--
2.29.2
_______________________________________________
dev mailing list
[email protected] <mailto:[email protected]>
https://mail.openvswitch.org/mailman/listinfo/ovs-dev
<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>