- 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 (get_dl_type(ip_flow) == htons(ETH_TYPE_IP)) {
+ struct ip_header *nh = dp_packet_put_zeros(&packet, sizeof *nh);
+
+ eh->eth_type = htons(ETH_TYPE_IP);
+ 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);
+ } else {
+ struct ip6_hdr *nh = dp_packet_put_zeros(&packet, sizeof *nh);
+ struct icmp6_error_header *ih;
+ uint32_t icmpv6_csum;
+
+ eh->eth_type = htons(ETH_TYPE_IPV6);
+ dp_packet_set_l3(&packet, nh);
+ nh->ip6_vfc = 0x60;
+ nh->ip6_nxt = IPPROTO_ICMPV6;
+ nh->ip6_plen = htons(sizeof(*nh) + ICMP6_ERROR_HEADER_LEN);
+ packet_set_ipv6(&packet, &ip_flow->ipv6_src, &ip_flow->ipv6_dst,
+ ip_flow->nw_tos, ip_flow->ipv6_label, 255);
+
+ ih = dp_packet_put_zeros(&packet, sizeof *ih);
+ dp_packet_set_l4(&packet, ih);
+ ih->icmp6_base.icmp6_type = ICMP6_DST_UNREACH;
+ ih->icmp6_base.icmp6_code = 1;
+ ih->icmp6_base.icmp6_cksum = 0;
+
+ uint8_t *data = dp_packet_put_zeros(&packet, sizeof *nh);
+ memcpy(data, dp_packet_l3(pkt_in), sizeof(*nh));
+
+ icmpv6_csum = packet_csum_pseudoheader6(dp_packet_l3(&packet));
+ ih->icmp6_base.icmp6_cksum = csum_finish(
+ csum_continue(icmpv6_csum, ih,
+ sizeof(*nh) + ICMP6_ERROR_HEADER_LEN));
+ }