@@ -64,6 +64,7 @@ struct ovn_extend_table;
OVNACT(CT_CLEAR, ovnact_null) \
OVNACT(CLONE, ovnact_nest) \
OVNACT(ARP, ovnact_nest) \
+ OVNACT(ICMP, ovnact_nest) \
OVNACT(ND_NA, ovnact_nest) \
OVNACT(GET_ARP, ovnact_get_mac_bind) \
OVNACT(PUT_ARP, ovnact_put_mac_bind) \
@@ -429,6 +430,12 @@ enum action_opcode {
* The actions, in OpenFlow 1.3 format, follow the action_header.
*/
ACTION_OPCODE_ND_NS,
+
+ /* "icmp4 { ...actions... }".
+ *
+ * The actions, in OpenFlow 1.3 format, follow the action_header.
+ */
+ ACTION_OPCODE_ICMP,
};
/* Header. */
@@ -217,6 +217,53 @@ pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md,
dp_packet_uninit(&packet);
}
+static void
+pinctrl_handle_icmp(const struct flow *ip_flow, const struct match *md,
+ struct ofpbuf *userdata)
+{
+ /* This action only works for IP packets, and the switch should only send
+ * us IP packets this way, but check here just to be sure. */
+ if (ip_flow->dl_type != htons(ETH_TYPE_IP)) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ VLOG_WARN_RL(&rl, "ICMP action on non-IP packet (Ethertype %"PRIx16")",
+ ntohs(ip_flow->dl_type));
+ return;
+ }
+
+ uint64_t packet_stub[128 / 8];
+ struct dp_packet packet;
+
+ dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
+ dp_packet_clear(&packet);
+ packet.packet_type = htonl(PT_ETH);
+
+ struct eth_header *eh = dp_packet_put_zeros(&packet, sizeof *eh);
+ eh->eth_dst = ip_flow->dl_dst;
+ eh->eth_src = ip_flow->dl_src;
+ eh->eth_type = htons(ETH_TYPE_IP);
+
+ struct ip_header *nh = dp_packet_put_zeros(&packet, sizeof *nh);
+ dp_packet_set_l3(&packet, nh);
+ nh->ip_ihl_ver = IP_IHL_VER(5, 4);
+ nh->ip_tot_len = htons(sizeof(struct ip_header) +
+ sizeof(struct icmp_header));
+ nh->ip_proto = IPPROTO_ICMP;
+ nh->ip_frag_off = htons(IP_DF);
+ packet_set_ipv4(&packet, ip_flow->nw_src, ip_flow->nw_dst, 0, 255);
+
+ struct icmp_header *ih = dp_packet_put_zeros(&packet, sizeof *ih);
+ dp_packet_set_l4(&packet, ih);
+ packet_set_icmp(&packet, ICMP4_DST_UNREACH, 1);
+
+ if (ip_flow->vlans[0].tci & htons(VLAN_CFI)) {
+ eth_push_vlan(&packet, htons(ETH_TYPE_VLAN_8021Q),
+ ip_flow->vlans[0].tci);
+ }
+
+ set_actions_and_enqueue_msg(&packet, md, userdata);
+ dp_packet_uninit(&packet);
+}
+
static void
pinctrl_handle_put_dhcp_opts(
struct dp_packet *pkt_in, struct ofputil_packet_in *pin,
@@ -1020,6 +1067,10 @@ process_packet_in(const struct ofp_header *msg, struct controller_ctx *ctx)
pinctrl_handle_nd_ns(&headers, &pin.flow_metadata, &userdata);
break;
+ case ACTION_OPCODE_ICMP:
+ pinctrl_handle_icmp(&headers, &pin.flow_metadata, &userdata);
+ break;
+
default:
VLOG_WARN_RL(&rl, "unrecognized packet-in opcode %"PRIu32,
ntohl(ah->opcode));
@@ -1141,6 +1141,12 @@ parse_ARP(struct action_context *ctx)
parse_nested_action(ctx, OVNACT_ARP, "ip4");
}
+static void
+parse_ICMP(struct action_context *ctx)
+{
+ parse_nested_action(ctx, OVNACT_ICMP, "ip4");
+}
+
static void
parse_ND_NA(struct action_context *ctx)
{
@@ -1174,6 +1180,12 @@ format_ARP(const struct ovnact_nest *nest, struct ds *s)
format_nested_action(nest, "arp", s);
}
+static void
+format_ICMP(const struct ovnact_nest *nest, struct ds *s)
+{
+ format_nested_action(nest, "icmp4", s);
+}
+
static void
format_ND_NA(const struct ovnact_nest *nest, struct ds *s)
{
@@ -1224,6 +1236,14 @@ encode_ARP(const struct ovnact_nest *on,
encode_nested_actions(on, ep, ACTION_OPCODE_ARP, ofpacts);
}
+static void
+encode_ICMP(const struct ovnact_nest *on,
+ const struct ovnact_encode_params *ep,
+ struct ofpbuf *ofpacts)
+{
+ encode_nested_actions(on, ep, ACTION_OPCODE_ICMP, ofpacts);
+}
+
static void
encode_ND_NA(const struct ovnact_nest *on,
const struct ovnact_encode_params *ep,
@@ -2247,6 +2267,8 @@ parse_action(struct action_context *ctx)
parse_CLONE(ctx);
} else if (lexer_match_id(ctx->lexer, "arp")) {
parse_ARP(ctx);
+ } else if (lexer_match_id(ctx->lexer, "icmp4")) {
+ parse_ICMP(ctx);
} else if (lexer_match_id(ctx->lexer, "nd_na")) {
parse_ND_NA(ctx);
} else if (lexer_match_id(ctx->lexer, "nd_ns")) {
@@ -1729,10 +1729,6 @@
<li><code>icmp4.code = 1</code> (host unreachable)</li>
</ul>
- <p>
- Details TBD.
- </p>
-
<p><b>Prerequisite:</b> <code>ip4</code></p>
</dd>
@@ -1534,6 +1534,29 @@ execute_nd_ns(const struct ovnact_nest *on, const struct ovntrace_datapath *dp,
table_id, pipeline, &node->subs);
}
+static void
+execute_icmp(const struct ovnact_nest *on, const struct ovntrace_datapath *dp,
+ const struct flow *uflow, uint8_t table_id,
+ enum ovnact_pipeline pipeline, struct ovs_list *super)
+{
+ struct flow icmp_flow = *uflow;
+
+ /* Update fields for ICMP. */
+ icmp_flow.dl_dst = uflow->dl_dst;
+ icmp_flow.dl_src = uflow->dl_src;
+ icmp_flow.nw_dst = uflow->nw_dst;
+ icmp_flow.nw_src = uflow->nw_src;
+ icmp_flow.nw_proto = IPPROTO_ICMP;
+ icmp_flow.tp_src = htons(ICMP4_DST_UNREACH); /* icmp type */
+ icmp_flow.tp_dst = htons(1); /* icmp code */
+
+ struct ovntrace_node *node = ovntrace_node_append(
+ super, OVNTRACE_NODE_TRANSFORMATION, "icmp4");
+
+ trace_actions(on->nested, on->nested_len, dp, &icmp_flow,
+ table_id, pipeline, &node->subs);
+}
+
static void
execute_get_mac_bind(const struct ovnact_get_mac_bind *bind,
const struct ovntrace_datapath *dp,
@@ -1892,6 +1915,11 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
case OVNACT_SET_METER:
/* Nothing to do. */
break;
+
+ case OVNACT_ICMP:
+ execute_icmp(ovnact_get_ICMP(a), dp, uflow, table_id, pipeline,
+ super);
+ break;
}
}
icmp4 action is used to replace the IPv4 packet been processed with an ICMPv4 packet initialized based on incoming IPv4 one. Ethernet and IPv4 fields not listed are not changed: - ip.proto = 1 (ICMPv4) - ip.frag = 0 (not a fragment) - icmp4.type = 3 (destination unreachable) - icmp4.code = 1 (host unreachable) Prerequisite: ip4 Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com> --- include/ovn/actions.h | 7 +++++++ ovn/controller/pinctrl.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ ovn/lib/actions.c | 22 ++++++++++++++++++++ ovn/ovn-sb.xml | 4 ---- ovn/utilities/ovn-trace.c | 28 ++++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 4 deletions(-)