static void fragment_reap(struct vr_btable *table, int start, unsigned int num_entries) { unsigned int i; struct vr_fragment *fe; unsigned long sec, nsec; vr_get_mono_time(&sec, &nsec); for (i = 0; i < ENTRIES_PER_SCAN; i++) { fe = vr_btable_get(table, (start + i) % num_entries); if (fe && fe->f_dip) { if (sec > fe->f_time + 1) vr_fragment_del(fe); } } return; }
unsigned int vr_flow_inet_input(struct vrouter *router, unsigned short vrf, struct vr_packet *pkt, unsigned short proto, struct vr_forwarding_md *fmd) { struct vr_flow_key key, *key_p = &key; struct vr_ip *ip, *icmp_pl_ip = NULL; struct vr_fragment *frag; unsigned int flow_parse_res; unsigned int trap_res = 0; unsigned int sip, dip; unsigned short *t_hdr, sport, dport; unsigned char ip_proto; struct vr_icmp *icmph; /* * interface is in a mode where it wants all packets to be received * without doing lookups to figure out whether packets were destined * to me or not */ if (pkt->vp_flags & VP_FLAG_TO_ME) return vr_ip_rcv(router, pkt, fmd); ip = (struct vr_ip *)pkt_network_header(pkt); ip_proto = ip->ip_proto; /* if the packet is not a fragment, we easily know the sport, and dport */ if (vr_ip_transport_header_valid(ip)) { t_hdr = (unsigned short *)((char *)ip + (ip->ip_hl * 4)); if (ip_proto == VR_IP_PROTO_ICMP) { icmph = (struct vr_icmp *)t_hdr; if (vr_icmp_error(icmph)) { icmp_pl_ip = (struct vr_ip *)(icmph + 1); ip_proto = icmp_pl_ip->ip_proto; t_hdr = (unsigned short *)((char *)icmp_pl_ip + (icmp_pl_ip->ip_hl * 4)); if (ip_proto == VR_IP_PROTO_ICMP) icmph = (struct vr_icmp *)t_hdr; } } if (ip_proto == VR_IP_PROTO_ICMP) { if (icmph->icmp_type == VR_ICMP_TYPE_ECHO || icmph->icmp_type == VR_ICMP_TYPE_ECHO_REPLY) { sport = icmph->icmp_eid; dport = VR_ICMP_TYPE_ECHO_REPLY; } else { sport = 0; dport = icmph->icmp_type; } } else { if (icmp_pl_ip) { sport = *(t_hdr + 1); dport = *t_hdr; } else { sport = *t_hdr; dport = *(t_hdr + 1); } } } else { /* ...else, we need to get it from somewhere */ flow_parse_res = vr_flow_parse(router, NULL, pkt, &trap_res); /* ...and it really matters only if we need to do a flow lookup */ if (flow_parse_res == VR_FLOW_LOOKUP) { frag = vr_fragment_get(router, vrf, ip); if (!frag) { vr_pfree(pkt, VP_DROP_FRAGMENTS); return 0; } sport = frag->f_sport; dport = frag->f_dport; if (vr_ip_fragment_tail(ip)) vr_fragment_del(frag); } else { /* * since there is no other way of deriving a key, set the * key_p to NULL, indicating to code below that there is * indeed no need for flow lookup */ key_p = NULL; } } if (key_p) { /* we have everything to make a key */ if (icmp_pl_ip) { sip = icmp_pl_ip->ip_daddr; dip = icmp_pl_ip->ip_saddr; } else { sip = ip->ip_saddr; dip = ip->ip_daddr; } vr_get_flow_key(key_p, fmd->fmd_vlan, pkt, sip, dip, ip_proto, sport, dport); flow_parse_res = vr_flow_parse(router, key_p, pkt, &trap_res); if (flow_parse_res == VR_FLOW_LOOKUP && vr_ip_fragment_head(ip)) vr_fragment_add(router, vrf, ip, key_p->key_src_port, key_p->key_dst_port); if (flow_parse_res == VR_FLOW_BYPASS) { return vr_flow_forward(vrf, pkt, proto, fmd); } else if (flow_parse_res == VR_FLOW_TRAP) { return vr_trap(pkt, vrf, trap_res, NULL); } return vr_flow_lookup(router, vrf, key_p, pkt, proto, fmd); } /* * ...come here, when there is not enough information to do a * flow lookup */ return vr_flow_forward(vrf, pkt, proto, fmd); }