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