summaryrefslogtreecommitdiff
path: root/ovn
diff options
context:
space:
mode:
authorLorenzo Bianconi <lorenzo.bianconi@redhat.com>2018-02-20 18:39:43 +0100
committerBen Pfaff <blp@ovn.org>2018-03-09 11:38:48 -0800
commitbc3d6a63688b0498bf72c0c24ee8471178d52f60 (patch)
treedf9f5b5f7226d00064044546b01941459a8efcef /ovn
parent980211b75d05789f2eb47b7c3db90e82bca78f29 (diff)
downloadopenvswitch-bc3d6a63688b0498bf72c0c24ee8471178d52f60.tar.gz
OVN: add icmp4{} action support
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) - ip.ttl = 255 - icmp4.type = 3 (destination unreachable) - icmp4.code = 1 (host unreachable) Prerequisite: ip4 Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com> Signed-off-by: Ben Pfaff <blp@ovn.org> Acked-By: Mark Michelson <mmichels@redhat.com>
Diffstat (limited to 'ovn')
-rw-r--r--ovn/controller/pinctrl.c53
-rw-r--r--ovn/lib/actions.c22
-rw-r--r--ovn/ovn-sb.xml5
-rw-r--r--ovn/utilities/ovn-trace.c30
4 files changed, 106 insertions, 4 deletions
diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
index 75516bf4e..b4dbd8c29 100644
--- a/ovn/controller/pinctrl.c
+++ b/ovn/controller/pinctrl.c
@@ -220,6 +220,55 @@ pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md,
}
static void
+pinctrl_handle_icmp4(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,
+ "ICMP4 action on non-IP packet (eth_type 0x%"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,
+ ip_flow->nw_tos, 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,
struct ofpbuf *userdata, struct ofpbuf *continuation)
@@ -1033,6 +1082,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_ICMP4:
+ pinctrl_handle_icmp4(&headers, &pin.flow_metadata, &userdata);
+ break;
+
default:
VLOG_WARN_RL(&rl, "unrecognized packet-in opcode %"PRIu32,
ntohl(ah->opcode));
diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
index fde3bff00..fc5ace1f6 100644
--- a/ovn/lib/actions.c
+++ b/ovn/lib/actions.c
@@ -1142,6 +1142,12 @@ parse_ARP(struct action_context *ctx)
}
static void
+parse_ICMP4(struct action_context *ctx)
+{
+ parse_nested_action(ctx, OVNACT_ICMP4, "ip4");
+}
+
+static void
parse_ND_NA(struct action_context *ctx)
{
parse_nested_action(ctx, OVNACT_ND_NA, "nd_ns");
@@ -1175,6 +1181,12 @@ format_ARP(const struct ovnact_nest *nest, struct ds *s)
}
static void
+format_ICMP4(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)
{
format_nested_action(nest, "nd_na", s);
@@ -1225,6 +1237,14 @@ encode_ARP(const struct ovnact_nest *on,
}
static void
+encode_ICMP4(const struct ovnact_nest *on,
+ const struct ovnact_encode_params *ep,
+ struct ofpbuf *ofpacts)
+{
+ encode_nested_actions(on, ep, ACTION_OPCODE_ICMP4, ofpacts);
+}
+
+static void
encode_ND_NA(const struct ovnact_nest *on,
const struct ovnact_encode_params *ep,
struct ofpbuf *ofpacts)
@@ -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_ICMP4(ctx);
} else if (lexer_match_id(ctx->lexer, "nd_na")) {
parse_ND_NA(ctx);
} else if (lexer_match_id(ctx->lexer, "nd_ns")) {
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
index f000b166c..6a8b818a3 100644
--- a/ovn/ovn-sb.xml
+++ b/ovn/ovn-sb.xml
@@ -1725,14 +1725,11 @@
<ul>
<li><code>ip.proto = 1</code> (ICMPv4)</li>
<li><code>ip.frag = 0</code> (not a fragment)</li>
+ <li><code>ip.ttl = 255</code></li>
<li><code>icmp4.type = 3</code> (destination unreachable)</li>
<li><code>icmp4.code = 1</code> (host unreachable)</li>
</ul>
- <p>
- Details TBD.
- </p>
-
<p><b>Prerequisite:</b> <code>ip4</code></p>
</dd>
diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c
index db39c4961..00e885a14 100644
--- a/ovn/utilities/ovn-trace.c
+++ b/ovn/utilities/ovn-trace.c
@@ -1536,6 +1536,31 @@ execute_nd_ns(const struct ovnact_nest *on, const struct ovntrace_datapath *dp,
}
static void
+execute_icmp4(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 icmp4_flow = *uflow;
+
+ /* Update fields for ICMP. */
+ icmp4_flow.dl_dst = uflow->dl_dst;
+ icmp4_flow.dl_src = uflow->dl_src;
+ icmp4_flow.nw_dst = uflow->nw_dst;
+ icmp4_flow.nw_src = uflow->nw_src;
+ icmp4_flow.nw_proto = IPPROTO_ICMP;
+ icmp4_flow.nw_ttl = 255;
+ icmp4_flow.tp_src = htons(ICMP4_DST_UNREACH); /* icmp type */
+ icmp4_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, &icmp4_flow,
+ table_id, pipeline, &node->subs);
+}
+
+static void
execute_get_mac_bind(const struct ovnact_get_mac_bind *bind,
const struct ovntrace_datapath *dp,
struct flow *uflow, struct ovs_list *super)
@@ -1893,6 +1918,11 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
case OVNACT_SET_METER:
/* Nothing to do. */
break;
+
+ case OVNACT_ICMP4:
+ execute_icmp4(ovnact_get_ICMP4(a), dp, uflow, table_id, pipeline,
+ super);
+ break;
}
}