summaryrefslogtreecommitdiff
path: root/ovn/controller/pinctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'ovn/controller/pinctrl.c')
-rw-r--r--ovn/controller/pinctrl.c53
1 files changed, 53 insertions, 0 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));