int i;? ? ? struct ip_vs_offh_bucket *b;? ? ? struct list_head *p;? ? ? struct ip_vs_dest *dest;? ? ? ? b = tbl;? ? ? p = &svc->destinations;? ? ? for (i=0; i? ? ? ? if (list_empty(p)) {? ? ? ? ? ? ? b->dest = NULL;? ? ? ? ? } else {? ? ? ? ? ? ? if (p == &svc->destinations)? ? ? ? ? ? ? ? ? p = p->next;? ? ? ? ? ? ? ? dest = list_entry(p, struct ip_vs_dest, n_list);? ? ? ? ? ? ? atomic_inc(&dest->refcnt);? ? ? ? ? ? ? b->dest = dest;? ? ? ? ? ? ? ? p = p->next;? ? ? ? ? }? ? ? ? ? b++;? ? ? }? ? ? return 0;? }? ? static void ip_vs_offh_flush(struct ip_vs_offh_bucket *tbl)? {? ? ? int i;? ? ? struct ip_vs_offh_bucket *b;? ? ? ? b = tbl;? ? ? for (i=0; i? ? ? ? if (b->dest) {? ? ? ? ? ? ? atomic_dec(&b->dest->refcnt);? ? ? ? ? ? ? b->dest = NULL;? ? ? ? ? }? ? ? ? ? b++;? ? ? }? }? ? static int ip_vs_offh_init_svc(struct ip_vs_service *svc)? {? ? ? struct ip_vs_offh_data *pdata;? ? ? struct ip_vs_offh_bucket *tbl;? ? ? ? pdata = kmalloc(sizeof(struct ip_vs_offh_data), GFP_ATOMIC);? ? ? if (pdata == NULL) {? ? ? ? ? pr_err("%s(): no memory\n", __func__);? ? ? ? ? return -ENOMEM;? ? ? }? ? ? ? tbl = kmalloc(sizeof(struct ip_vs_offh_bucket)*IP_VS_OFFH_TAB_SIZE,? ? ? ? ? ? ? ? GFP_ATOMIC);? ? ? if (tbl == NULL) {? ? ? ? ? kfree(pdata);? ? ? ? ? pr_err("%s(): no memory\n", __func__);? ? ? ? ? return -ENOMEM;? ? ? }? ? ? ? pdata->tbl = tbl;? ? ? pdata->offset = 0;? ? ? pdata->offlen = 0;? ? ? ? svc->sched_data = pdata;? ? ? ? ip_vs_offh_assign(tbl, svc);? ? ? ? return 0;? }? ? static int ip_vs_offh_done_svc(struct ip_vs_service *svc)? {? ? ? struct ip_vs_offh_data *pdata = svc->sched_data;? ? ? struct ip_vs_offh_bucket *tbl = pdata->tbl;? ? ? ? ip_vs_offh_flush(tbl);? ? ? ? kfree(tbl);? ? ? kfree(pdata);? ? ? ? return 0;? }? ? static int ip_vs_offh_update_svc(struct ip_vs_service *svc)? {? ? ? struct ip_vs_offh_bucket *tbl = svc->sched_data;? ? ? ? ip_vs_offh_flush(tbl);? ? ? ip_vs_offh_assign(tbl, svc);? ? ? ? return 0;? }? ? static inline int is_overloaded(struct ip_vs_dest *dest)? {? ? ? return dest->flags & IP_VS_DEST_F_OVERLOAD;? }? ? static struct ip_vs_dest *? ip_vs_offh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)? {? ? ? struct ip_vs_dest *dest;? ? ? struct ip_vs_offh_data *pdata;? ? ? struct ip_vs_offh_bucket *tbl;? ? ? struct iphdr *iph;? ? ? void *transport_hdr;? ? ? char *payload;? ? ? u32 hdrlen = 0;? ? ? u32 _offset = 0;? ? ? u32 _offlen = 0;? ? ? ? iph = ip_hdr(skb);? ? ? hdrlen = iph->ihl*4;? ? ? if (hdrlen > skb->len) {? ? ? ? ? return NULL;? ? ? }? ? ? transport_hdr = (void *)iph + hdrlen;? ? ? ? switch (iph->protocol) {? ? ? ? ? case IPPROTO_TCP:? ? ? ? ? ? ? hdrlen += (((struct tcphdr*)transport_hdr)->doff)*4;? ? ? ? ? ? ? break;? ? ? ? ? case IPPROTO_UDP:? ? ? ? ? ? ? hdrlen += sizeof(struct udphdr);? ? ? ? ? ? ? break;? ? ? ? ? default:? ? ? ? ? ? ? return NULL;? ? ? }? #if 0? ? ? {? ? ? ? ? int i = 0;? ? ? ? ? _offset = offset;? ? ? ? ? _offlen = offlen;? ? ? ? ? payload = (char *)iph + hdrlen + _offset;? ? ? ? ? printk("begin:iplen:%d? \n", hdrlen);? ? ? ? ? for (i = 0; i < _offlen; i++) {? ? ? ? ? ? ? printk("%02X ", payload[i]);? ? ? ? ? }? ? ? ? ? printk("\nend\n");? ? ? ? ? return NULL;? ? ? ? }? #endif? ? ? ? pdata = (struct ip_vs_offh_datai *)svc->sched_data;? ? ? ? tbl = pdata->tbl;? ? ? _offset = offset;//pdata->offset;? ? ? _offlen = offlen;//pdata->offlen;? ? ? if (_offlen + _offset > skb->len - hdrlen) {? ? ? ? ? IP_VS_ERR_RL("OFFH: exceed\n");? ? ? ? ? return NULL;? ? ? }? ? ? ? payload = (char *)iph + hdrlen + _offset;? ? ? ? dest = ip_vs_offh_get(tbl, payload, _offlen);? ? ? if (!dest? ? ? ? ? || !(dest->flags & IP_VS_DEST_F_AVAILABLE)? ? ? ? ? || atomic_read(&dest->weight) <= 0? ? ? ? ? || is_overloaded(dest)) {? ? ? ? ? IP_VS_ERR_RL("OFFH: no destination a |