Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <stdint.h>
6 : #include "base/os.h"
7 : #include "vr_defs.h"
8 : #include "pkt/proto_handler.h"
9 : #include "pkt/pkt_init.h"
10 : #include "pkt/packet_buffer.h"
11 :
12 : ///////////////////////////////////////////////////////////////////////////////
13 :
14 0 : ProtoHandler::ProtoHandler(Agent *agent, boost::shared_ptr<PktInfo> info,
15 0 : boost::asio::io_context &io)
16 0 : : agent_(agent), pkt_info_(info), io_(io) {}
17 :
18 0 : ProtoHandler::~ProtoHandler() {
19 0 : }
20 :
21 0 : uint32_t ProtoHandler::EncapHeaderLen() const {
22 0 : return agent_->pkt()->pkt_handler()->EncapHeaderLen();
23 : }
24 :
25 : // send packet to the pkt0 interface
26 0 : void ProtoHandler::Send(uint32_t itf, uint32_t vrf, uint16_t cmd,
27 : PktHandler::PktModuleName mod) {
28 0 : Send(itf, vrf, cmd, 0, 0, mod);
29 0 : }
30 :
31 0 : void ProtoHandler::Send(uint32_t itf, uint32_t vrf, uint16_t cmd,
32 : uint32_t param1, uint32_t param2,
33 : PktHandler::PktModuleName mod) {
34 : // If pkt_info_->pkt is non-NULL, pkt is freed in destructor of pkt_info_
35 0 : if (agent_->pkt()->pkt_handler() == NULL) {
36 0 : return;
37 : }
38 :
39 0 : AgentHdr hdr(itf, vrf, cmd, param1, param2);
40 0 : agent_->pkt()->pkt_handler()->Send(hdr, pkt_info_->packet_buffer_ptr());
41 0 : }
42 :
43 0 : int ProtoHandler::EthHdr(char *buff, uint16_t len, const MacAddress &src,
44 : const MacAddress &dest, const uint16_t proto,
45 : uint16_t vlan_id) {
46 0 : struct ether_header *eth = (struct ether_header *)buff;
47 0 : uint16_t encap_len = sizeof(struct ether_header);
48 :
49 0 : if (vlan_id != VmInterface::kInvalidVlanId) {
50 0 : encap_len += 4;
51 : }
52 :
53 0 : if (len < encap_len) {
54 0 : return 0;
55 : }
56 :
57 0 : dest.ToArray(eth->ether_dhost, sizeof(eth->ether_dhost));
58 0 : src.ToArray(eth->ether_shost, sizeof(eth->ether_shost));
59 :
60 0 : uint16_t *ptr = (uint16_t *) (buff + ETHER_ADDR_LEN * 2);
61 0 : if (vlan_id != VmInterface::kInvalidVlanId) {
62 0 : *ptr = htons(ETHERTYPE_VLAN);
63 0 : ptr++;
64 0 : *ptr = htons(vlan_id & 0xFFF);
65 0 : ptr++;
66 : }
67 :
68 0 : *ptr = htons(proto);
69 0 : return encap_len;
70 : }
71 :
72 0 : int ProtoHandler::EthHdr(const MacAddress &src, const MacAddress &dest,
73 : const uint16_t proto) {
74 0 : return EthHdr((char *)pkt_info_->eth, sizeof(struct ether_header), src,
75 0 : dest, proto, VmInterface::kInvalidVlanId);
76 : }
77 :
78 0 : int ProtoHandler::EthHdr(char *buff, uint16_t len, const Interface *intrface,
79 : const MacAddress &src, const MacAddress &dest,
80 : const uint16_t proto) {
81 0 : uint16_t vlan_id = VmInterface::kInvalidVlanId;
82 0 : if (intrface && intrface->type() == Interface::VM_INTERFACE &&
83 0 : !(agent_->tsn_enabled())) {
84 0 : vlan_id = static_cast<const VmInterface *>(intrface)->tx_vlan_id();
85 : }
86 :
87 0 : return EthHdr(buff, len, src, dest, proto, vlan_id);
88 : }
89 :
90 0 : int ProtoHandler::EthHdr(char *buff, uint16_t len, uint32_t ifindex,
91 : const MacAddress &src, const MacAddress &dest,
92 : const uint16_t proto) {
93 0 : const Interface *intf = agent()->interface_table()->FindInterface(ifindex);
94 0 : return EthHdr(buff, len, intf, src, dest, proto);
95 : }
96 :
97 0 : void ProtoHandler::VlanHdr(uint8_t *ptr, uint16_t tci) {
98 0 : vlanhdr *vlan = reinterpret_cast<vlanhdr *>(ptr);
99 0 : vlan->tpid = htons(0x8100);
100 0 : vlan->tci = htons(tci);
101 0 : vlan += 1;
102 0 : vlan->tpid = htons(0x800);
103 0 : return;
104 : }
105 :
106 0 : uint16_t ProtoHandler::IpHdr(char *buff, uint16_t buf_len, uint16_t len,
107 : in_addr_t src, in_addr_t dest, uint8_t protocol,
108 : uint16_t id, uint8_t ttl) {
109 0 : struct ip *ip = (struct ip *)buff;
110 0 : if (buf_len < sizeof(struct ip))
111 0 : return 0;
112 :
113 0 : ip->ip_hl = 5;
114 0 : ip->ip_v = 4;
115 0 : ip->ip_tos = 0;
116 0 : ip->ip_len = htons(len);
117 0 : ip->ip_id = htons(id);
118 0 : ip->ip_off = 0;
119 0 : ip->ip_ttl = ttl;
120 0 : ip->ip_p = protocol;
121 0 : ip->ip_sum = 0;
122 0 : ip->ip_src.s_addr = src;
123 0 : ip->ip_dst.s_addr = dest;
124 :
125 0 : ip->ip_sum = Csum((uint16_t *)ip, ip->ip_hl * 4, 0);
126 0 : return sizeof(struct ip);
127 : }
128 :
129 0 : void ProtoHandler::IpHdr(uint16_t len, in_addr_t src, in_addr_t dest,
130 : uint8_t protocol, uint16_t id, uint8_t ttl) {
131 :
132 0 : IpHdr((char *)pkt_info_->ip, sizeof(struct ip), len,
133 : src, dest, protocol, id, ttl);
134 0 : }
135 :
136 0 : void ProtoHandler::Ip6Hdr(ip6_hdr *ip, uint16_t plen, uint8_t next_header,
137 : uint8_t hlim, uint8_t *src, uint8_t *dest) {
138 0 : ip->ip6_flow = htonl(0x60000000); // version 6, TC and Flow set to 0
139 0 : ip->ip6_plen = htons(plen);
140 0 : ip->ip6_nxt = next_header;
141 0 : ip->ip6_hlim= hlim;
142 0 : memcpy(ip->ip6_src.s6_addr, src, 16);
143 0 : memcpy(ip->ip6_dst.s6_addr, dest, 16);
144 0 : }
145 :
146 0 : void ProtoHandler::FillUdpHdr(udphdr *udp, uint16_t len,
147 : uint16_t src_port, uint16_t dest_port) {
148 0 : udp->uh_sport = htons(src_port);
149 0 : udp->uh_dport = htons(dest_port);
150 0 : udp->uh_ulen = htons(len);
151 0 : udp->uh_sum = 0;
152 0 : }
153 :
154 0 : uint16_t ProtoHandler::UdpHdr(udphdr *udp, uint16_t buf_len, uint16_t len,
155 : in_addr_t src, uint16_t src_port, in_addr_t dest,
156 : uint16_t dest_port) {
157 0 : if (buf_len < sizeof(udphdr))
158 0 : return 0;
159 :
160 0 : FillUdpHdr(udp, len, src_port, dest_port);
161 : #ifdef VNSW_AGENT_UDP_CSUM
162 : udp->uh_sum = UdpCsum(src, dest, len, udp);
163 : #endif
164 :
165 0 : return sizeof(udphdr);
166 : }
167 :
168 0 : void ProtoHandler::UdpHdr(uint16_t len, in_addr_t src, uint16_t src_port,
169 : in_addr_t dest, uint16_t dest_port) {
170 0 : UdpHdr(pkt_info_->transp.udp, sizeof(udphdr), len, src, src_port,
171 : dest, dest_port);
172 0 : }
173 :
174 0 : uint16_t ProtoHandler::IcmpHdr(char *buff, uint16_t buf_len, uint8_t type,
175 : uint8_t code, uint16_t word1, uint16_t word2) {
176 0 : struct icmp *hdr = ((struct icmp *)buff);
177 0 : if (buf_len < sizeof(hdr))
178 0 : return 0;
179 :
180 0 : memset(hdr, 0, sizeof(struct icmp));
181 :
182 0 : hdr->icmp_type = type;
183 0 : hdr->icmp_code = code;
184 0 : if(type != ICMP_UNREACH) {
185 0 : LOG(ERROR,
186 : "Error type != ICMP_UNREACH. BackTrace: " << AgentBackTrace(1));
187 0 : return 0;
188 : }
189 0 : hdr->icmp_nextmtu = htons(word2);
190 0 : hdr->icmp_cksum = 0;
191 0 : if (type == ICMP_UNREACH)
192 0 : return ICMP_UNREACH_HDR_LEN;
193 0 : return 0;
194 : }
195 :
196 0 : void ProtoHandler::IcmpChecksum(char *buff, uint16_t buf_len) {
197 0 : struct icmp *hdr = ((struct icmp *)buff);
198 0 : hdr->icmp_cksum = Csum((uint16_t *)buff, buf_len, 0);
199 0 : }
200 :
201 0 : void ProtoHandler::IgmpChecksum(char *buff, uint16_t buf_len) {
202 0 : struct igmp *hdr = ((struct igmp *)buff);
203 0 : hdr->igmp_cksum = Csum((uint16_t *)buff, buf_len, 0);
204 0 : }
205 :
206 0 : void ProtoHandler::UdpHdr(udphdr *udp ,uint16_t len, const uint8_t *src,
207 : uint16_t src_port, const uint8_t *dest,
208 : uint16_t dest_port, uint8_t next_hdr) {
209 0 : FillUdpHdr(udp, len, src_port, dest_port);
210 0 : pkt_info_->transp.udp->uh_sum = Ipv6Csum(src, dest, len, next_hdr,
211 0 : (uint16_t *)pkt_info_->transp.udp);
212 0 : }
213 :
214 0 : void ProtoHandler::UdpHdr(uint16_t len, const uint8_t *src, uint16_t src_port,
215 : const uint8_t *dest, uint16_t dest_port,
216 : uint8_t next_hdr) {
217 0 : FillUdpHdr(pkt_info_->transp.udp, len, src_port, dest_port);
218 0 : pkt_info_->transp.udp->uh_sum = Ipv6Csum(src, dest, len, next_hdr,
219 0 : (uint16_t *)pkt_info_->transp.udp);
220 0 : }
221 :
222 0 : uint32_t ProtoHandler::Sum(uint16_t *ptr, std::size_t len, uint32_t sum) const {
223 0 : while (len > 1) {
224 0 : sum += *ptr++;
225 0 : len -= 2;
226 0 : if (sum & 0x80000000)
227 0 : sum = (sum & 0xFFFF) + (sum >> 16);
228 : }
229 :
230 0 : if (len > 0)
231 0 : sum += *(uint8_t *)ptr;
232 :
233 0 : return sum;
234 : }
235 :
236 0 : uint16_t ProtoHandler::Csum(uint16_t *ptr, std::size_t len, uint32_t sum) const{
237 0 : sum = Sum(ptr, len, sum);
238 :
239 0 : while (sum >> 16)
240 0 : sum = (sum & 0xFFFF) + (sum >> 16);
241 :
242 0 : return ~sum;
243 : }
244 :
245 0 : uint16_t ProtoHandler::UdpCsum(in_addr_t src, in_addr_t dest,
246 : std::size_t len, udphdr *udp) const {
247 0 : uint32_t sum = 0;
248 0 : PseudoUdpHdr phdr(src, dest, IPPROTO_UDP, htons(len));
249 0 : sum = Sum((uint16_t *)&phdr, sizeof(PseudoUdpHdr), sum);
250 0 : return Csum((uint16_t *)udp, len, sum);
251 : }
252 :
253 0 : uint16_t ProtoHandler::Ipv6Csum(const uint8_t *src, const uint8_t *dest,
254 : uint16_t plen, uint8_t next_hdr,
255 : uint16_t *hdr) const {
256 0 : uint32_t len = htonl((uint32_t)plen);
257 0 : uint32_t next = htonl((uint32_t)next_hdr);
258 :
259 0 : uint32_t pseudo = 0;
260 0 : pseudo = Sum((uint16_t *)src, 16, 0);
261 0 : pseudo = Sum((uint16_t *)dest, 16, pseudo);
262 0 : pseudo = Sum((uint16_t *)&len, 4, pseudo);
263 0 : pseudo = Sum((uint16_t *)&next, 4, pseudo);
264 0 : return Csum(hdr, plen, pseudo);
265 : }
266 :
267 0 : uint16_t ProtoHandler::Icmpv6Csum(const uint8_t *src, const uint8_t *dest,
268 : icmp6_hdr *icmp, uint16_t plen) const {
269 0 : return Ipv6Csum(src, dest, plen, IPPROTO_ICMPV6, (uint16_t *)icmp);
270 : }
271 :
272 : ///////////////////////////////////////////////////////////////////////////////
|