OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
icmp_error_handler.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 #include <stdint.h>
5 #include "base/os.h"
6 #include <vr_defs.h>
7 #include <cmn/agent_cmn.h>
9 #include <oper/vn.h>
10 
11 #include <pkt/pkt_init.h>
12 #include <pkt/flow_table.h>
15 
17  boost::shared_ptr<PktInfo> info,
18  boost::asio::io_context *io) :
19  ProtoHandler(agent, info, *io), proto_(proto) {
20 }
21 
23 }
24 
26  if (pkt_info_->len < (sizeof(struct ether_header) + sizeof(struct ip)))
27  return false;
28  return true;
29 }
30 
32  if (ValidatePacket() == false) {
34  return true;
35  }
36 
37  VmInterface *vm_itf = dynamic_cast<VmInterface *>
39  if (vm_itf == NULL || vm_itf->layer3_forwarding() == false ||
40  vm_itf->vn() == NULL) {
42  return true;
43  }
44 
45  return SendIcmpError(vm_itf);
46 }
47 
48 // Generate ICMP error
50  char data[ICMP_PAYLOAD_LEN];
51  uint16_t data_len = ntohs(pkt_info_->ip->ip_len);
52  if (data_len > ICMP_PAYLOAD_LEN)
53  data_len = ICMP_PAYLOAD_LEN;
54  memcpy(data, pkt_info_->ip, data_len);
55 
56  uint32_t src_ip = 0;
57  FlowKey key;
58  bool is_nat_flow = false;
59 
60  if (pkt_info_->agent_hdr.flow_index == (uint32_t)-1) {
61  // flow index is -1 for 255.255.255.255
62  if (pkt_info_->ip_daddr.to_v4().to_ulong() != 0xFFFFFFFF) {
64  return true;
65  }
66  src_ip = pkt_info_->ip_saddr.to_v4().to_ulong();
67  } else {
68  if (proto_->FlowIndexToKey(pkt_info_->agent_hdr.flow_index, &key, &is_nat_flow)
69  == false ||
70  key.family != Address::INET ||
71  ((!is_nat_flow) &&
72  (key.src_addr != pkt_info_->ip_saddr ||
73  key.dst_addr != pkt_info_->ip_daddr ||
74  key.protocol != pkt_info_->ip_proto ||
75  key.src_port != pkt_info_->sport ||
76  key.dst_port != pkt_info_->dport))) {
78  return true;
79  }
80 
81  src_ip = key.src_addr.to_v4().to_ulong();
82  }
83 
84  // Get IPAM to find default gateway
85  const VnIpam *ipam = intf->vn()->GetIpam(Ip4Address(src_ip));
86  if (ipam == NULL || ipam->default_gw.is_v4() == false) {
88  return true;
89  }
90 
91  // Retain the agent-header before ethernet header
92  uint16_t len = (char *)pkt_info_->eth - (char *)pkt_info_->pkt;
93  uint16_t buf_len = pkt_info_->max_pkt_len;
94 
95  // Form ICMP Packet with following
96  // EthHdr - IP Header - ICMP Header - User IP Packet(max 128 bytes)
97  char *ptr = (char *)pkt_info_->pkt;
98  len += EthHdr(ptr + len, buf_len - len,
99  agent()->vhost_interface()->mac(),
100  MacAddress(pkt_info_->eth->ether_shost),
101  ETHERTYPE_IP, intf->tx_vlan_id());
102 
103  uint16_t icmp_len = ICMP_UNREACH_HDR_LEN;
104  uint16_t ip_len = sizeof(struct ip) + icmp_len + data_len;
105  len += IpHdr(ptr + len, buf_len - len, ip_len,
106  htonl(ipam->default_gw.to_v4().to_ulong()),
107  htonl(src_ip), IPPROTO_ICMP, DEFAULT_IP_ID, DEFAULT_IP_TTL);
108 
109  char *icmp = ptr + len;
110  len += IcmpHdr(ptr + len, buf_len - len, ICMP_UNREACH,
111  ICMP_UNREACH_NEEDFRAG, 0, pkt_info_->agent_hdr.mtu);
112 
113  if (pkt_info_->agent_hdr.flow_index != (uint32_t)-1) {
114  // Its possible that user payload has gone thru NAT processing already.
115  // Restore the original fields from flow_key
116  struct ip *ip = (struct ip *)data;
117  uint16_t ip_hlen = ip->ip_hl * 4;
118 
119  ip->ip_src.s_addr = htonl(key.src_addr.to_v4().to_ulong());
120  ip->ip_dst.s_addr = htonl(key.dst_addr.to_v4().to_ulong());
121  ip->ip_sum = 0;
122  ip->ip_sum = Csum((uint16_t *)data, ip_hlen, 0);
123  if (ip->ip_p == IPPROTO_UDP) {
124  udphdr *udp = (udphdr *)(data + ip_hlen);
125  udp->uh_sport = ntohs(key.src_port);
126  udp->uh_dport = ntohs(key.dst_port);
127  } else if (ip->ip_p == IPPROTO_TCP) {
128  tcphdr *tcp = (tcphdr *)(data + ip_hlen);
129  tcp->th_sport = ntohs(key.src_port);
130  tcp->th_dport = ntohs(key.dst_port);
131  }
132  }
133  memcpy(ptr + len, data, data_len);
134  len += data_len;
135  IcmpChecksum(icmp, icmp_len + data_len);
136  pkt_info_->set_len(len);
137 
140  return true;
141 }
IpAddress src_addr
Definition: flow_entry.h:213
#define DEFAULT_IP_TTL
Definition: pkt_handler.h:44
bool SendIcmpError(VmInterface *intf)
const VnIpam * GetIpam(const IpAddress &ip) const
Definition: vn.cc:651
Definition: vn.h:28
IpAddress dst_addr
Definition: flow_entry.h:214
const Interface * vhost_interface() const
Definition: agent.h:935
#define DEFAULT_IP_ID
Definition: pkt_handler.h:48
static const int ICMP_PAYLOAD_LEN
InterfaceTable * interface_table() const
Definition: agent.h:465
uint16_t Csum(uint16_t *, std::size_t, uint32_t) const
const MacAddress & mac() const
Definition: interface.h:131
uint8_t protocol
Definition: flow_entry.h:215
Agent * agent() const
Definition: proto_handler.h:80
boost::shared_ptr< PktInfo > pkt_info_
Definition: proto_handler.h:92
IcmpErrorProto * proto_
uint16_t tx_vlan_id() const
int EthHdr(const MacAddress &src, const MacAddress &dest, const uint16_t proto)
IpAddress default_gw
Definition: vn.h:31
Definition: agent.h:358
uint32_t GetInterfaceIndex() const
Definition: proto_handler.h:82
void Send(uint32_t itf, uint32_t vrf, uint16_t, PktHandler::PktModuleName)
bool layer3_forwarding() const
const VnEntry * vn() const
boost::asio::ip::address_v4 Ip4Address
Definition: address.h:14
IcmpErrorHandler(Agent *agent, IcmpErrorProto *proto, boost::shared_ptr< PktInfo > info, boost::asio::io_context *io)
uint16_t src_port
Definition: flow_entry.h:216
void IcmpChecksum(char *buff, uint16_t buf_len)
#define ICMP_UNREACH_HDR_LEN
Definition: pkt_handler.h:51
Address::Family family
Definition: flow_entry.h:211
void increment_interface_errors()
uint16_t dst_port
Definition: flow_entry.h:217
void increment_invalid_flow_index()
const Interface * FindInterface(size_t index) const
Definition: interface.cc:323
bool FlowIndexToKey(uint32_t index, FlowKey *key, bool *is_nat_flow)
uint16_t IcmpHdr(char *buff, uint16_t buf_len, uint8_t type, uint8_t code, uint16_t word1, uint16_t word2)
void IpHdr(uint16_t len, in_addr_t src, in_addr_t dest, uint8_t protocol, uint16_t id, uint8_t ttl)