Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : #include "base/os.h" 5 : #include <netinet/icmp6.h> 6 : #include <vr_defs.h> 7 : #include <cmn/agent_cmn.h> 8 : #include <oper/interface_common.h> 9 : #include <oper/vn.h> 10 : #include <pkt/pkt_init.h> 11 : #include <services/icmpv6_error_proto.h> 12 : #include <services/icmpv6_error_handler.h> 13 : #include <services/icmpv6_handler.h> 14 : #include <services/services_init.h> 15 : #include <services/icmpv6_proto.h> 16 : 17 : 18 : extern SandeshTraceBufferPtr Icmpv6TraceBuf; 19 : 20 0 : Icmpv6ErrorHandler::Icmpv6ErrorHandler(Agent *agent, Icmpv6ErrorProto *proto, 21 : boost::shared_ptr<PktInfo> info, 22 0 : boost::asio::io_context *io) : 23 0 : ProtoHandler(agent, info, *io), proto_(proto) { 24 0 : } 25 : 26 0 : Icmpv6ErrorHandler::~Icmpv6ErrorHandler() { 27 0 : } 28 : 29 0 : bool Icmpv6ErrorHandler::ValidatePacket() { 30 0 : if (pkt_info_->len < (sizeof(struct ether_header) + sizeof(struct ip6_hdr))) 31 0 : return false; 32 0 : return true; 33 : } 34 : 35 0 : bool Icmpv6ErrorHandler::Run() { 36 : 37 0 : if (ValidatePacket() == false) { 38 0 : proto_->increment_drops(); 39 0 : return true; 40 : } 41 : 42 0 : VmInterface *vm_itf = dynamic_cast<VmInterface *> 43 0 : (agent()->interface_table()->FindInterface(GetInterfaceIndex())); 44 0 : if (vm_itf == NULL || vm_itf->layer3_forwarding() == false || 45 0 : vm_itf->IsActive() == false) { 46 0 : proto_->increment_interface_errors(); 47 0 : return true; 48 : } 49 0 : return SendIcmpv6Error(vm_itf); 50 : } 51 : 52 : // Generate ICMP error 53 0 : bool Icmpv6ErrorHandler::SendIcmpv6Error(VmInterface *intf) { 54 : 55 0 : char *buff = (char *)pkt_info_->pkt; 56 0 : uint16_t buff_len = pkt_info_->packet_buffer()->data_len(); 57 : char data[ICMPV6_PAYLOAD_LEN]; 58 0 : int len = ntohs(pkt_info_->ip6->ip6_plen); 59 : 60 0 : if (len > ICMPV6_PAYLOAD_LEN) 61 0 : len = ICMPV6_PAYLOAD_LEN; 62 : 63 0 : memcpy(data, pkt_info_->ip6, len); 64 : 65 0 : Ip6Address source_address; 66 0 : boost::system::error_code ec; 67 0 : const VnIpam *ipam = intf->vn()->GetIpam(pkt_info_->ip_saddr.to_v6()); 68 0 : if (ipam != NULL) { 69 0 : if (ipam->default_gw.is_v6()) 70 0 : source_address = ipam->default_gw.to_v6(); 71 : } 72 : // If source address is not found, use vhost address mapped v6 address. 73 : // vrouter forwards the icmp error packets as part of the original flow. 74 0 : if (source_address.is_unspecified()) 75 0 : source_address = Ip6Address::v4_mapped(agent()->router_id()); 76 : 77 : uint32_t interface = 78 0 : (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? 79 0 : pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex(); 80 : 81 0 : uint16_t eth_len = EthHdr(buff, buff_len, interface, 82 : agent()->vhost_interface()->mac(), 83 0 : MacAddress(pkt_info_->eth->ether_shost), 84 0 : ETHERTYPE_IPV6); 85 : 86 0 : pkt_info_->ip6 = (struct ip6_hdr *)(buff + eth_len); 87 0 : Ip6Hdr(pkt_info_->ip6, len+ICMP_UNREACH_HDR_LEN, IPV6_ICMP_NEXT_HEADER, 88 0 : 255, source_address.to_bytes().data(), 89 0 : pkt_info_->ip_saddr.to_v6().to_bytes().data()); 90 : 91 0 : icmp6_hdr *icmp = pkt_info_->transp.icmp6 = 92 0 : (icmp6_hdr *)(pkt_info_->pkt + eth_len 93 0 : + sizeof(ip6_hdr)); 94 0 : icmp->icmp6_type = ICMP6_PACKET_TOO_BIG; 95 0 : icmp->icmp6_code = 0; 96 0 : icmp->icmp6_mtu = htonl(pkt_info_->agent_hdr.mtu); 97 0 : icmp->icmp6_cksum = 0; 98 0 : memcpy(buff + sizeof(ip6_hdr) + eth_len+ICMP_UNREACH_HDR_LEN, data, len); 99 0 : icmp->icmp6_cksum = 100 0 : Icmpv6Csum(source_address.to_bytes().data(), 101 0 : pkt_info_->ip_saddr.to_v6().to_bytes().data(), 102 0 : icmp, len + ICMP_UNREACH_HDR_LEN); 103 0 : pkt_info_->set_len(len + sizeof(ip6_hdr) + eth_len+ICMP_UNREACH_HDR_LEN); 104 : 105 : uint16_t command = 106 0 : (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? 107 0 : (uint16_t)AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH; 108 : 109 0 : Send(GetInterfaceIndex(), pkt_info_->vrf, command, 110 : PktHandler::ICMPV6); 111 0 : return true; 112 : }