Line data Source code
1 : /*
2 : * vr_packet.c -- packet handling helpers
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : */
6 : #include <vr_os.h>
7 : #include <vr_packet.h>
8 :
9 : struct vr_packet *
10 0 : pkt_copy(struct vr_packet *pkt, unsigned short off, unsigned short len)
11 : {
12 : struct vr_packet *pkt_c;
13 : unsigned short head_space;
14 :
15 : /*
16 : * one eth header for agent, and one more for packets from
17 : * tun interfaces
18 : */
19 0 : head_space = (2 * sizeof(struct vr_eth)) + sizeof(struct agent_hdr);
20 0 : pkt_c = vr_palloc(head_space + len);
21 0 : if (!pkt_c)
22 0 : return pkt_c;
23 :
24 0 : pkt_c->vp_data += head_space;
25 0 : pkt_c->vp_tail += head_space;
26 0 : if (vr_pcopy(pkt_data(pkt_c), pkt, off, len) < 0) {
27 0 : PKT_LOG(VP_DROP_MISC, pkt, 0, VR_PACKET_C, __LINE__);
28 0 : vr_pfree(pkt_c, VP_DROP_MISC);
29 0 : return NULL;
30 : }
31 0 : pkt_pull_tail(pkt_c, len);
32 :
33 0 : pkt_c->vp_if = pkt->vp_if;
34 0 : pkt_c->vp_flags = pkt->vp_flags;
35 0 : pkt_c->vp_cpu = pkt->vp_cpu;
36 0 : pkt_c->vp_network_h = 0;
37 :
38 0 : return pkt_c;
39 : }
40 :
41 : struct vr_packet *
42 2 : pkt_cow(struct vr_packet *pkt, unsigned short head_room)
43 : {
44 : struct vr_packet *clone_pkt;
45 :
46 : /* Clone the packet */
47 2 : clone_pkt = vr_pclone(pkt);
48 2 : if (!clone_pkt) {
49 0 : return NULL;
50 : }
51 :
52 : /* Increase the head space by the head_room */
53 2 : if (vr_pcow(&clone_pkt, head_room)) {
54 0 : PKT_LOG(VP_DROP_PCOW_FAIL, pkt, 0, VR_PACKET_C, __LINE__);
55 0 : vr_pfree(clone_pkt, VP_DROP_PCOW_FAIL);
56 0 : return NULL;
57 : }
58 :
59 : /* Copy the ttl from old packet */
60 2 : clone_pkt->vp_ttl = pkt->vp_ttl;
61 :
62 2 : return clone_pkt;
63 : }
64 :
65 : bool
66 0 : vr_ip_proto_pull(struct vr_ip *iph)
67 : {
68 0 : unsigned char proto = iph->ip_proto;
69 :
70 0 : if ((proto == VR_IP_PROTO_TCP) || (proto == VR_IP_PROTO_UDP) ||
71 0 : (proto == VR_IP_PROTO_ICMP) || (proto == VR_IP_PROTO_SCTP)) {
72 0 : return true;
73 : }
74 :
75 0 : return false;
76 : }
77 :
78 : bool
79 0 : vr_ip6_proto_pull(struct vr_ip6 *ip6h)
80 : {
81 0 : unsigned char proto = ip6h->ip6_nxt;
82 :
83 0 : if ((proto == VR_IP_PROTO_TCP) || (proto == VR_IP_PROTO_UDP) ||
84 0 : (proto == VR_IP_PROTO_ICMP6) || (proto == VR_IP_PROTO_SCTP) ||
85 : (proto == VR_IP6_PROTO_FRAG)) {
86 0 : return true;
87 : }
88 :
89 0 : return false;
90 : }
91 :
92 : /**
93 : * vr_ip_transport_parse - parse IP packet to reach the L4 header
94 : */
95 : int
96 0 : vr_ip_transport_parse(struct vr_ip *iph, struct vr_ip6 *ip6h,
97 : void **thp, unsigned int frag_size,
98 : void (do_tcp_mss_adj)(struct tcphdr *, unsigned short,
99 : unsigned char),
100 : unsigned int *hlenp,
101 : unsigned short *th_csump,
102 : unsigned int *tcph_pull_lenp,
103 : unsigned int *pull_lenp)
104 : {
105 : unsigned char *thdr;
106 : unsigned short ip_proto;
107 0 : bool thdr_valid = false, icmp_pl_frag_hdr = false;
108 0 : unsigned int hlen = 0, tcph_pull_len = 0;
109 0 : unsigned int pull_len = *pull_lenp;
110 0 : struct vr_tcp *tcph = NULL;
111 0 : unsigned short th_csum = 0;
112 0 : struct vr_icmp *icmph = NULL;
113 0 : struct vr_ip *icmp_pl_iph = NULL;
114 0 : struct vr_ip6 *icmp_pl_ip6h = NULL;
115 : struct vr_ip6_frag *v6_frag;
116 :
117 :
118 : /* Note: iph is set for both ipv4 and ipv6 cases */
119 0 : if (iph) {
120 0 : if (vr_ip_is_ip6(iph)) {
121 0 : if (ip6h) {
122 0 : ip_proto = ip6h->ip6_nxt;
123 0 : hlen = sizeof(struct vr_ip6);
124 0 : if (ip_proto == VR_IP6_PROTO_FRAG) {
125 0 : pull_len += sizeof(struct vr_ip6_frag);
126 0 : if (frag_size < pull_len) {
127 0 : return PKT_RET_SLOW_PATH;
128 : }
129 :
130 0 : v6_frag = (struct vr_ip6_frag *)((char *)ip6h + hlen);
131 0 : ip_proto = v6_frag->ip6_frag_nxt;
132 0 : hlen += sizeof(struct vr_ip6_frag);
133 : }
134 0 : thdr_valid = vr_ip6_transport_header_valid(ip6h);
135 : } else {
136 0 : return PKT_RET_UNHANDLED;
137 : }
138 0 : } else if (vr_ip_is_ip4(iph)) {
139 0 : ip_proto = iph->ip_proto;
140 : /*
141 : * Account for IP options
142 : */
143 0 : thdr_valid = vr_ip_transport_header_valid(iph);
144 0 : if (thdr_valid) {
145 0 : hlen = iph->ip_hl * 4;
146 0 : pull_len += (hlen - sizeof(struct vr_ip));
147 : }
148 : } else {
149 0 : return PKT_RET_UNHANDLED;
150 : }
151 :
152 0 : if (thdr_valid) {
153 0 : tcph_pull_len = pull_len;
154 0 : if (thp)
155 0 : *thp = (char *)iph + hlen;
156 :
157 0 : if (ip_proto == VR_IP_PROTO_TCP) {
158 0 : pull_len += sizeof(struct vr_tcp);
159 0 : } else if (ip_proto == VR_IP_PROTO_UDP) {
160 0 : pull_len += sizeof(struct vr_udp);
161 0 : } else if ((ip_proto == VR_IP_PROTO_ICMP) ||
162 : (ip_proto == VR_IP_PROTO_ICMP6)) {
163 0 : pull_len += sizeof(struct vr_icmp);
164 0 : } else if (ip_proto == VR_IP_PROTO_SCTP) {
165 0 : pull_len += sizeof(struct vr_sctp);
166 : }
167 :
168 0 : if (frag_size < pull_len) {
169 0 : return PKT_RET_SLOW_PATH;
170 : }
171 :
172 :
173 0 : if (ip_proto == VR_IP_PROTO_TCP) {
174 : /*
175 : * Account for TCP options
176 : */
177 0 : tcph = (struct vr_tcp *)((char *)iph + hlen);
178 :
179 : /*
180 : * If SYN, do TCP MSS adjust using passed callback, or send it
181 : * to the slow path.
182 : */
183 0 : if ((ntohs(tcph->tcp_offset_r_flags) & VR_TCP_FLAG_SYN) &&
184 : vr_to_vm_mss_adj) {
185 0 : if (do_tcp_mss_adj) {
186 : /* Kernel will never get here, it will return slow path */
187 0 : do_tcp_mss_adj((struct tcphdr *)tcph,
188 : VROUTER_L2_OVERLAY_LEN, hlen);
189 : } else {
190 0 : return PKT_RET_SLOW_PATH;
191 : }
192 : }
193 :
194 0 : if ((VR_TCP_OFFSET(tcph->tcp_offset_r_flags) * 4) >
195 : (sizeof(struct vr_tcp))) {
196 0 : pull_len += ((VR_TCP_OFFSET(tcph->tcp_offset_r_flags) * 4) -
197 : (sizeof(struct vr_tcp)));
198 :
199 0 : if (frag_size < pull_len) {
200 0 : return PKT_RET_SLOW_PATH;
201 : }
202 : }
203 0 : th_csum = tcph->tcp_csum;
204 0 : } else if (ip_proto == VR_IP_PROTO_ICMP) {
205 0 : icmph = (struct vr_icmp *)((unsigned char *)iph + hlen);
206 0 : th_csum = icmph->icmp_csum;
207 0 : if (vr_icmp_error(icmph)) {
208 0 : pull_len += sizeof(struct vr_ip);
209 0 : if (frag_size < pull_len)
210 0 : return PKT_RET_SLOW_PATH;
211 0 : icmp_pl_iph = (struct vr_ip *)(icmph + 1);
212 0 : pull_len += (icmp_pl_iph->ip_hl * 4) - sizeof(struct vr_ip);
213 0 : if (frag_size < pull_len)
214 0 : return PKT_RET_SLOW_PATH;
215 0 : if (vr_ip_proto_pull(icmp_pl_iph)) {
216 0 : if (icmp_pl_iph->ip_proto == VR_IP_PROTO_TCP)
217 0 : pull_len += sizeof(struct vr_tcp);
218 0 : else if (icmp_pl_iph->ip_proto == VR_IP_PROTO_UDP)
219 0 : pull_len += sizeof(struct vr_udp);
220 0 : else if (icmp_pl_iph->ip_proto == VR_IP_PROTO_SCTP)
221 0 : pull_len += sizeof(struct vr_sctp);
222 : else
223 0 : pull_len += sizeof(struct vr_icmp);
224 :
225 0 : if (frag_size < pull_len)
226 0 : return PKT_RET_SLOW_PATH;
227 :
228 0 : if (icmp_pl_iph->ip_proto == VR_IP_PROTO_TCP) {
229 0 : th_csum = ((struct vr_tcp *)
230 : ((unsigned char *)icmp_pl_iph +
231 0 : icmp_pl_iph->ip_hl * 4))->tcp_csum;
232 0 : } else if (icmp_pl_iph->ip_proto == VR_IP_PROTO_UDP) {
233 0 : th_csum = ((struct vr_udp *)
234 : ((unsigned char *)icmp_pl_iph +
235 0 : icmp_pl_iph->ip_hl * 4))->udp_csum;
236 0 : } else if (icmp_pl_iph->ip_proto == VR_IP_PROTO_ICMP) {
237 0 : th_csum = ((struct vr_icmp *)
238 : ((unsigned char *)icmp_pl_iph +
239 0 : icmp_pl_iph->ip_hl * 4))->icmp_csum;
240 : }
241 : }
242 : }
243 0 : } else if (iph->ip_proto == VR_IP_PROTO_UDP) {
244 0 : th_csum = ((struct vr_udp *)
245 : ((unsigned char *)iph + hlen))->udp_csum;
246 0 : } else if ((ip_proto == VR_IP_PROTO_ICMP6) && ip6h) {
247 0 : icmph = (struct vr_icmp *)((unsigned char *)ip6h + hlen);
248 0 : if (icmph->icmp_type == VR_ICMP6_TYPE_NEIGH_SOL) {
249 : /*
250 : * We do not know if neighbour option of length
251 : * VR_ETHER_ALEN is not at all there or not in this
252 : * frag. So we will calculate the length to
253 : * be inclusive of both Target address and neighbour
254 : * option. If option is not preset, slow path would
255 : * take care of it
256 : */
257 0 : pull_len += sizeof(struct vr_neighbor_option) +
258 : VR_IP6_ADDRESS_LEN + VR_ETHER_ALEN;
259 0 : } else if (icmph->icmp_type == VR_ICMP6_TYPE_ROUTER_SOL) {
260 0 : pull_len += 8;
261 0 : } else if (vr_icmp6_error(icmph)) {
262 0 : pull_len += sizeof(struct vr_ip6);
263 0 : if (frag_size < pull_len)
264 0 : return PKT_RET_SLOW_PATH;
265 0 : icmp_pl_ip6h = (struct vr_ip6 *)(icmph + 1);
266 0 : ip_proto = icmp_pl_ip6h->ip6_nxt;
267 0 : if (vr_ip6_proto_pull(icmp_pl_ip6h)) {
268 0 : if (icmp_pl_ip6h->ip6_nxt == VR_IP_PROTO_TCP)
269 0 : pull_len += sizeof(struct vr_tcp);
270 0 : else if (icmp_pl_ip6h->ip6_nxt == VR_IP_PROTO_UDP)
271 0 : pull_len += sizeof(struct vr_udp);
272 0 : else if (icmp_pl_ip6h->ip6_nxt == VR_IP_PROTO_SCTP)
273 0 : pull_len += sizeof(struct vr_sctp);
274 0 : else if (icmp_pl_ip6h->ip6_nxt == VR_IP6_PROTO_FRAG) {
275 0 : pull_len += sizeof(struct vr_ip6_frag);
276 0 : icmp_pl_frag_hdr = true;
277 : } else
278 0 : pull_len += sizeof(struct vr_icmp);
279 :
280 0 : if (frag_size < pull_len)
281 0 : return PKT_RET_SLOW_PATH;
282 :
283 0 : if (icmp_pl_frag_hdr) {
284 0 : v6_frag = (struct vr_ip6_frag *)
285 : ((unsigned char *)icmp_pl_ip6h +
286 : sizeof(struct vr_ip6));
287 0 : ip_proto = v6_frag->ip6_frag_nxt;
288 0 : thdr = (unsigned char *)v6_frag +
289 : sizeof(struct vr_ip6_frag);
290 : } else {
291 0 : thdr = (unsigned char *)icmp_pl_ip6h +
292 : sizeof(struct vr_ip6);
293 : }
294 :
295 0 : if (ip_proto == VR_IP_PROTO_TCP) {
296 0 : th_csum = ((struct vr_tcp *)thdr)->tcp_csum;
297 0 : if (icmp_pl_frag_hdr)
298 0 : pull_len += sizeof(struct vr_tcp);
299 0 : } else if (ip_proto == VR_IP_PROTO_UDP) {
300 0 : th_csum = ((struct vr_udp *)thdr)->udp_csum;
301 0 : if (icmp_pl_frag_hdr)
302 0 : pull_len += sizeof(struct vr_udp);
303 0 : } else if (ip_proto == VR_IP_PROTO_ICMP6) {
304 0 : th_csum = ((struct vr_icmp *)thdr)->icmp_csum;
305 0 : if (icmp_pl_frag_hdr)
306 0 : pull_len += sizeof(struct vr_icmp);
307 0 : } else if (ip_proto == VR_IP_PROTO_SCTP) {
308 0 : if (icmp_pl_frag_hdr)
309 0 : pull_len += sizeof(struct vr_sctp);
310 : }
311 : }
312 : }
313 :
314 0 : if (frag_size < pull_len)
315 0 : return PKT_RET_SLOW_PATH;
316 : }
317 : }
318 : }
319 :
320 0 : if (hlenp)
321 0 : *hlenp = hlen;
322 0 : if (th_csump)
323 0 : *th_csump = th_csum;
324 0 : if (tcph_pull_lenp)
325 0 : *tcph_pull_lenp = tcph_pull_len;
326 0 : *pull_lenp = pull_len;
327 :
328 0 : return 0;
329 : }
330 :
331 : /**
332 : * vr_inner_pkt_parse - parse inner packet transported in MPLS-o-UDP, MPLS-o-GRE
333 : * or VXLAN tunnel.
334 : */
335 :
336 : int
337 0 : vr_inner_pkt_parse(unsigned char *va, int (*tunnel_type_cb)(unsigned int,
338 : unsigned int, unsigned short *), int *encap_type,
339 : int *pkt_typep, unsigned int *pull_lenp,
340 : unsigned int frag_size, struct vr_ip **iphp,
341 : struct vr_ip6 **ip6hp, unsigned short gre_udp_encap,
342 : unsigned char ip_proto)
343 : {
344 : unsigned short eth_proto;
345 0 : unsigned int pull_len = *pull_lenp;
346 : unsigned int label, control_data;
347 0 : int pkt_type = 0;
348 0 : struct vr_ip6 *ip6h = NULL;
349 0 : struct vr_ip *iph = NULL;
350 0 : struct vr_eth *eth = NULL;
351 0 : unsigned int mpls_label_len = VR_MPLS_HDR_LEN;
352 :
353 0 : if ((ip_proto == VR_IP_PROTO_GRE && gre_udp_encap == VR_GRE_PROTO_MPLS_NO) ||
354 0 : (ip_proto == VR_IP_PROTO_UDP && vr_mpls_udp_port(ntohs(gre_udp_encap)))) {
355 :
356 0 : *encap_type = PKT_ENCAP_MPLS;
357 : /* Take into consideration, the MPLS header and 4 bytes of
358 : * control information that might exist for L2 packet */
359 0 : if (frag_size < (pull_len + VR_MPLS_HDR_LEN +
360 : VR_L2_CTRL_DATA_LEN)) {
361 0 : return PKT_RET_SLOW_PATH;
362 : }
363 :
364 0 : label = ntohl(*(uint32_t *)(va + pull_len));
365 0 : if (!(label & VR_MPLS_LABEL_STACK_BIT_MASK)
366 0 : && ((label >> VR_MPLS_LABEL_SHIFT) == VR_MPLS_LABEL_MASK)) {
367 : // ignore outer label
368 0 : label = ntohl(*(uint32_t *)(va + pull_len + VR_MPLS_HDR_LEN));
369 0 : mpls_label_len = 2*VR_MPLS_HDR_LEN;
370 : }
371 :
372 0 : control_data = *(uint32_t *)(va + pull_len + mpls_label_len);
373 :
374 : /* Identify whether the packet is L2 or not using the label and
375 : * control data */
376 0 : pkt_type = tunnel_type_cb(label, control_data, NULL);
377 0 : if (pkt_type <= 0)
378 0 : return PKT_RET_UNHANDLED;
379 :
380 0 : if (pkt_type == PKT_MPLS_TUNNEL_L3) {
381 : /* L3 packet */
382 0 : iph = (struct vr_ip *) (va + pull_len + mpls_label_len);
383 0 : if (vr_ip_is_ip6(iph)) {
384 0 : ip6h = (struct vr_ip6 *)iph;
385 0 : pull_len += mpls_label_len + sizeof(struct vr_ip6);
386 0 : } else if (vr_ip_is_ip4(iph)) {
387 0 : pull_len += mpls_label_len + sizeof(struct vr_ip);
388 : } else {
389 0 : return PKT_RET_UNHANDLED;
390 : }
391 0 : } else if (pkt_type == PKT_MPLS_TUNNEL_L2_MCAST) {
392 : /* L2 Multicast packet with control information and
393 : * Vxlan header. Vxlan header contains IP + UDP + Vxlan */
394 0 : eth = (struct vr_eth *)(va + pull_len + mpls_label_len +
395 0 : VR_L2_CTRL_DATA_LEN + VR_VXLAN_HDR_LEN);
396 0 : pull_len += mpls_label_len + VR_L2_CTRL_DATA_LEN +
397 : VR_VXLAN_HDR_LEN + sizeof(struct vr_eth);
398 0 : } else if (pkt_type == PKT_MPLS_TUNNEL_L2_CONTROL_DATA) {
399 : /* L2 packet with control information */
400 0 : eth = (struct vr_eth *)(va + pull_len + mpls_label_len +
401 : VR_L2_CTRL_DATA_LEN);
402 0 : pull_len += mpls_label_len + VR_L2_CTRL_DATA_LEN +
403 : sizeof(struct vr_eth);
404 0 : } else if (pkt_type == PKT_MPLS_TUNNEL_L2_UCAST) {
405 : /* L2 packet with no control information */
406 0 : eth = (struct vr_eth *)(va + pull_len + mpls_label_len);
407 0 : pull_len += mpls_label_len + sizeof(struct vr_eth);
408 : } else {
409 0 : return PKT_RET_UNHANDLED;
410 : }
411 :
412 0 : if (frag_size < pull_len)
413 0 : return PKT_RET_SLOW_PATH;
414 :
415 0 : } else if (ip_proto == VR_IP_PROTO_UDP &&
416 0 : ntohs(gre_udp_encap) == VR_VXLAN_UDP_DST_PORT) {
417 0 : *encap_type = PKT_ENCAP_VXLAN;
418 0 : pull_len += sizeof(struct vr_vxlan);
419 :
420 : /* Take into consideration, the VXLAN header ethernet header */
421 0 : if (frag_size < pull_len + VR_ETHER_HLEN)
422 0 : return PKT_RET_SLOW_PATH;
423 :
424 0 : eth = (struct vr_eth *)(va + pull_len);
425 :
426 0 : pull_len += VR_ETHER_HLEN;
427 : } else {
428 0 : return PKT_RET_UNHANDLED;
429 : }
430 :
431 0 : if (eth) {
432 :
433 0 : eth_proto = eth->eth_proto;
434 0 : if (ntohs(eth_proto) == VR_ETH_PROTO_PBB) {
435 0 : pull_len += sizeof(struct vr_pbb_itag);
436 0 : if (frag_size < pull_len)
437 0 : return PKT_RET_SLOW_PATH;
438 :
439 0 : eth = (struct vr_eth *)(va + pull_len);
440 0 : pull_len += VR_ETHER_HLEN;
441 0 : if (frag_size < pull_len)
442 0 : return PKT_RET_SLOW_PATH;
443 0 : eth_proto = eth->eth_proto;
444 : }
445 :
446 0 : while (ntohs(eth_proto) == VR_ETH_PROTO_VLAN) {
447 0 : eth_proto = ((struct vr_vlan_hdr *)(va + pull_len))->vlan_proto;
448 0 : pull_len += sizeof(struct vr_vlan_hdr);
449 0 : if (frag_size < pull_len)
450 0 : return PKT_RET_SLOW_PATH;
451 : }
452 :
453 0 : if (ntohs(eth_proto) == VR_ETH_PROTO_IP) {
454 0 : iph = (struct vr_ip *)(va + pull_len);
455 0 : pull_len += sizeof(struct vr_ip);
456 0 : if (frag_size < pull_len)
457 0 : return PKT_RET_SLOW_PATH;
458 0 : } else if (ntohs(eth_proto) == VR_ETH_PROTO_IP6) {
459 0 : ip6h = (struct vr_ip6 *)(va + pull_len);
460 0 : iph = (struct vr_ip *)ip6h;
461 0 : pull_len += sizeof(struct vr_ip6);
462 0 : if (frag_size < pull_len)
463 0 : return PKT_RET_SLOW_PATH;
464 0 : } else if (ntohs(eth_proto) == VR_ETH_PROTO_ARP) {
465 0 : pull_len += sizeof(struct vr_arp);
466 0 : if (frag_size < pull_len)
467 0 : return PKT_RET_SLOW_PATH;
468 : }
469 : }
470 :
471 0 : *pull_lenp = pull_len;
472 0 : *iphp = iph;
473 0 : *ip6hp = ip6h;
474 0 : if (pkt_typep)
475 0 : *pkt_typep = pkt_type;
476 :
477 0 : return 0;
478 : }
479 :
480 : bool
481 0 : __vr_adjust_tcp_mss(struct vr_tcp *tcph, uint16_t len_overhead, uint16_t eth_mtu, uint16_t *old_mss, uint16_t *new_mss)
482 : {
483 0 : int opt_off = sizeof(struct vr_tcp);
484 0 : uint8_t *opt_ptr = (uint8_t *) tcph;
485 : uint16_t pkt_mss, max_mss;
486 :
487 0 : if ((tcph == NULL) || (!tcph->tcp_flag_syn)) {
488 0 : return false;
489 : }
490 :
491 0 : while (opt_off < (tcph->tcp_doff*4)) {
492 0 : switch (opt_ptr[opt_off]) {
493 0 : case VR_TCP_OPT_EOL:
494 0 : return false;
495 :
496 0 : case VR_TCP_OPT_NOP:
497 0 : opt_off++;
498 0 : continue;
499 :
500 0 : case VR_TCP_OPT_MSS:
501 0 : if ((opt_off + VR_TCP_OLEN_MSS) > (tcph->tcp_doff*4)) {
502 0 : return false;
503 : }
504 :
505 0 : if (opt_ptr[opt_off+1] != VR_TCP_OLEN_MSS) {
506 0 : return false;
507 : }
508 :
509 0 : pkt_mss = (opt_ptr[opt_off+2] << 8) | opt_ptr[opt_off+3];
510 0 : max_mss = eth_mtu - (len_overhead + sizeof(struct vr_tcp));
511 :
512 0 : if (pkt_mss > max_mss) {
513 0 : *old_mss = pkt_mss;
514 0 : *new_mss = max_mss;
515 0 : opt_ptr[opt_off+2] = (max_mss & 0xff00) >> 8;
516 0 : opt_ptr[opt_off+3] = max_mss & 0xff;
517 :
518 0 : return true;
519 : }
520 :
521 0 : return false;
522 :
523 0 : default:
524 :
525 0 : if ((opt_off + 1) == (tcph->tcp_doff*4)) {
526 0 : return false;
527 : }
528 :
529 0 : if (opt_ptr[opt_off+1]) {
530 0 : opt_off += opt_ptr[opt_off+1];
531 : } else {
532 0 : opt_off++;
533 : }
534 :
535 0 : continue;
536 : }
537 : }
538 :
539 0 : return false;
540 : }
541 :
542 :
543 : /*
544 : * vr_adjust_tcp_mss - adjust the TCP MSS in the given packet based on
545 : * vrouter physical interface MTU. If MSS was changed return true and sets
546 : * old_mss and new_mss args, returns false otherwise.
547 : */
548 : bool
549 0 : vr_adjust_tcp_mss(struct vr_tcp *tcph, uint16_t len_overhead, uint16_t *old_mss, uint16_t *new_mss)
550 : {
551 0 : uint16_t eth_mtu = VR_INVALID_MTU;
552 0 : struct vrouter *router = vrouter_get(0);
553 : int i;
554 :
555 0 : if (router == NULL) {
556 0 : return false;
557 : }
558 :
559 0 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
560 0 : if (router->vr_eth_if[i]) {
561 0 : uint16_t mtu = vif_get_mtu(router->vr_eth_if[i]);
562 0 : if (mtu < eth_mtu)
563 0 : eth_mtu = mtu;
564 : }
565 : }
566 0 : if (eth_mtu == VR_INVALID_MTU)
567 0 : return false;
568 :
569 0 : return __vr_adjust_tcp_mss(tcph, len_overhead, eth_mtu, old_mss, new_mss);
570 : }
571 :
572 : /*
573 : * calculate a 5 tuple hash for ipv4 and ipv6 packets
574 : * and smac, dmac and proto based hash for other packets
575 : */
576 7 : unsigned int vr_get_pkt_hash(struct vr_packet * pkt)
577 : {
578 : struct vr_tcp *tcp;
579 : struct vr_udp *udp;
580 : unsigned short sport, dport;
581 7 : int proto, flag = 0;
582 7 : struct vr_eth *eth = NULL;
583 7 : struct vr_ip *ip = NULL;
584 7 : struct vr_ip6 *ip6 = NULL;
585 7 : char *hdr = NULL;
586 : char key[38];
587 : uint32_t hash;
588 :
589 7 : if (!pkt)
590 0 : return 0;
591 :
592 7 : if (pkt->vp_type == VP_TYPE_IP6) {
593 1 : ip6 = (struct vr_ip6 *) pkt_network_header(pkt);
594 1 : hdr = (char *) ip6;
595 1 : if (vr_ip6_fragment(ip6)) {
596 0 : flag = 1;
597 0 : sport = dport = 0;
598 0 : proto = 0;
599 : } else
600 1 : proto = ip6->ip6_nxt;
601 6 : } else if(pkt->vp_type == VP_TYPE_IP) {
602 6 : ip = (struct vr_ip *) pkt_network_header(pkt);
603 6 : hdr = (char *) ip;
604 6 : if (vr_ip_fragment(ip)) {
605 0 : flag = 1;
606 0 : sport = dport = 0;
607 : }
608 6 : proto = ip->ip_proto;
609 : } else {
610 0 : eth = (struct vr_eth *) pkt_data(pkt);
611 0 : proto = -1;
612 : }
613 :
614 7 : if (flag == 0) {
615 7 : if (proto == VR_IP_PROTO_TCP) {
616 0 : if (pkt->vp_type == VP_TYPE_IP6)
617 0 : tcp = (struct vr_tcp *) (hdr + sizeof(*ip6));
618 : else
619 0 : tcp = (struct vr_tcp *) (hdr + ip->ip_hl*4);
620 0 : sport = ntohs(tcp->tcp_sport);
621 0 : dport = ntohs(tcp->tcp_dport);
622 7 : } else if (proto == VR_IP_PROTO_UDP) {
623 6 : if (pkt->vp_type == VP_TYPE_IP6)
624 0 : udp = (struct vr_udp *) (hdr + sizeof(*ip6));
625 : else
626 6 : udp = (struct vr_udp *) (hdr + ip->ip_hl*4);
627 6 : sport = ntohs(udp->udp_sport);
628 6 : dport = ntohs(udp->udp_dport);
629 : } else {
630 1 : sport = dport = 0;
631 : }
632 : }
633 :
634 7 : if (pkt->vp_type == VP_TYPE_IP6) {
635 1 : memcpy(key, &ip6->ip6_src, 16);
636 1 : memcpy(key+16, &ip6->ip6_dst, 16);
637 1 : memcpy(key+32, &proto, 1);
638 1 : memcpy(key+33, &sport, 2);
639 1 : memcpy(key+35, &dport, 2);
640 1 : hash = vr_hash(key, 37, 0);
641 6 : } else if (pkt->vp_type == VP_TYPE_IP) {
642 6 : memcpy(key, &ip->ip_saddr, 4);
643 6 : memcpy(key+4, &ip->ip_daddr, 4);
644 6 : memcpy(key+8, &proto, 1);
645 6 : memcpy(key+9, &sport, 2);
646 6 : memcpy(key+11, &dport, 2);
647 6 : hash = vr_hash(key, 13, 0);
648 : } else {
649 0 : memcpy(key, ð->eth_smac, 6);
650 0 : memcpy(key+6, ð->eth_dmac, 6);
651 0 : memcpy(key+12, ð->eth_proto, 1);
652 0 : hash = vr_hash(key, 13, 0);
653 : }
654 :
655 7 : return hash;
656 : }
|