/* * trim to len bytes starting at offset */ struct block *trimblock(struct block *bp, int offset, int len) { uint32_t l, trim; int olen = len; QDEBUG checkb(bp, "trimblock 1"); if (blocklen(bp) < offset + len) { freeblist(bp); return NULL; } l =_pullblock(&bp, offset, 0); if (bp == NULL) return NULL; if (l != offset) { freeblist(bp); return NULL; } while ((l = BLEN(bp)) < len) { len -= l; bp = bp->next; } trim = BLEN(bp) - len; trim -= dropext(bp, trim); bp->wp -= trim; if (bp->next) { freeblist(bp->next); bp->next = NULL; } return bp; }
int qpass(struct queue *q, struct block *b) { int dlen, len, dowakeup; /* sync with qread */ dowakeup = 0; spin_lock_irqsave(&q->lock); if (q->len >= q->limit) { freeblist(b); spin_unlock_irqsave(&q->lock); return -1; } if (q->state & Qclosed) { len = blocklen(b); freeblist(b); spin_unlock_irqsave(&q->lock); return len; } /* add buffer to queue */ if (q->bfirst) q->blast->next = b; else q->bfirst = b; len = BALLOC(b); dlen = BLEN(b); QDEBUG checkb(b, "qpass"); while (b->next) { b = b->next; QDEBUG checkb(b, "qpass"); len += BALLOC(b); dlen += BLEN(b); } q->blast = b; q->len += len; q->dlen += dlen; if (q->len >= q->limit / 2) q->state |= Qflow; if (q->state & Qstarve) { q->state &= ~Qstarve; dowakeup = 1; } spin_unlock_irqsave(&q->lock); if (dowakeup) { rendez_wakeup(&q->rr); qwake_cb(q, FDTAP_FILT_READABLE); } return len; }
int qpass(Queue *q, Block *b) { int dlen, len, dowakeup; /* sync with qread */ dowakeup = 0; lock(&q->l); if(q->len >= q->limit){ unlock(&q->l); freeblist(b); return -1; } if(q->state & Qclosed){ unlock(&q->l); len = blocklen(b); freeblist(b); return len; } /* add buffer to queue */ if(q->bfirst) q->blast->next = b; else q->bfirst = b; len = BALLOC(b); dlen = BLEN(b); QDEBUG checkb(b, "qpass"); while(b->next){ b = b->next; QDEBUG checkb(b, "qpass"); len += BALLOC(b); dlen += BLEN(b); } q->blast = b; q->len += len; q->dlen += dlen; if(q->len >= q->limit/2) q->state |= Qflow; if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } unlock(&q->l); if(dowakeup) Wakeup(&q->rr); return len; }
/* * add a block list to a queue */ void qaddlist(Queue *q, Block *b) { /* queue the block */ if(q->bfirst) q->blast->next = b; else q->bfirst = b; q->len += blockalloclen(b); q->dlen += blocklen(b); while(b->next) b = b->next; q->blast = b; }
/* * add a block list to a queue */ void qaddlist(struct queue *q, struct block *b) { /* TODO: q lock? */ /* queue the block */ if (q->bfirst) q->blast->next = b; else q->bfirst = b; q->len += blockalloclen(b); q->dlen += blocklen(b); while (b->next) b = b->next; q->blast = b; }
/* * Enqueue a copy of an unacked block for possible retransmissions */ void relackq(Reliable *r, Block *bp) { Block *np; np = copyblock(bp, blocklen(bp)); if(r->unacked) r->unackedtail->list = np; else { /* restart timer */ r->timeout = 0; r->xmits = 1; r->unacked = np; } r->unackedtail = np; np->list = nil; }
/* * copy the string of blocks into * a single block and free the string */ Block* concatblock(Block *bp) { int len; Block *nb, *f; if(bp->next == 0) return bp; nb = allocb(blocklen(bp)); for(f = bp; f; f = f->next) { len = BLEN(f); memmove(nb->wp, f->rp, len); nb->wp += len; } freeblist(bp); return nb; }
/* * called with ucb locked */ void relrexmit(Conv *c, Reliable *r) { Rudppriv *upriv; Block *np; Fs *f; upriv = c->p->priv; f = c->p->f; r->timeout = 0; if(r->xmits++ > Rudpmaxxmit){ relhangup(c, r); return; } upriv->rxmits++; np = copyblock(r->unacked, blocklen(r->unacked)); DPRINT("rxmit r->ackrvcd+1 = %lud\n", r->ackrcvd+1); doipoput(c, f, np, 0, c->ttl, c->tos); }
/* * copy the string of blocks into * a single block and free the string */ Block* concatblock(Block *bp) { int len; Block *nb, *f; if(bp->next == nil) return bp; nb = allocb(blocklen(bp)); for(f = bp; f != nil; f = f->next) { len = BLEN(f); memmove(nb->wp, f->rp, len); nb->wp += len; } concatblockcnt += BLEN(nb); freeblist(bp); QDEBUG checkb(nb, "concatblock 1"); return nb; }
/* * copy the string of blocks into * a single block and free the string */ struct block *concatblock(struct block *bp) { int len; struct block *nb, *f; if (bp->next == 0) return bp; /* probably use parts of qclone */ PANIC_EXTRA(bp); nb = block_alloc(blocklen(bp), MEM_WAIT); for (f = bp; f; f = f->next) { len = BLEN(f); memmove(nb->wp, f->rp, len); nb->wp += len; } concatblockcnt += BLEN(nb); freeblist(bp); QDEBUG checkb(nb, "concatblock 1"); return nb; }
/* * trim to len bytes starting at offset */ Block * trimblock(Block *bp, int offset, int len) { ulong l; Block *nb, *startb; QDEBUG checkb(bp, "trimblock 1"); if(blocklen(bp) < offset+len) { freeblist(bp); return nil; } while((l = BLEN(bp)) < offset) { offset -= l; nb = bp->next; bp->next = nil; freeb(bp); bp = nb; } startb = bp; bp->rp += offset; while((l = BLEN(bp)) < len) { len -= l; bp = bp->next; } bp->wp -= (BLEN(bp) - len); if(bp->next) { freeblist(bp->next); bp->next = nil; } return startb; }
void udpkick(void *x, struct block *bp) { struct conv *c = x; Udp4hdr *uh4; Udp6hdr *uh6; uint16_t rport; uint8_t laddr[IPaddrlen], raddr[IPaddrlen]; Udpcb *ucb; int dlen, ptcllen; Udppriv *upriv; struct Fs *f; int version; struct conv *rc; upriv = c->p->priv; assert(upriv); f = c->p->f; netlog(c->p->f, Logudp, "udp: kick\n"); if (bp == NULL) return; ucb = (Udpcb *) c->ptcl; switch (ucb->headers) { case 7: /* get user specified addresses */ bp = pullupblock(bp, UDP_USEAD7); if (bp == NULL) return; ipmove(raddr, bp->rp); bp->rp += IPaddrlen; ipmove(laddr, bp->rp); bp->rp += IPaddrlen; /* pick interface closest to dest */ if (ipforme(f, laddr) != Runi) findlocalip(f, laddr, raddr); bp->rp += IPaddrlen; /* Ignore ifc address */ rport = nhgets(bp->rp); bp->rp += 2 + 2; /* Ignore local port */ break; case 6: /* get user specified addresses */ bp = pullupblock(bp, UDP_USEAD6); if (bp == NULL) return; ipmove(raddr, bp->rp); bp->rp += IPaddrlen; ipmove(laddr, bp->rp); bp->rp += IPaddrlen; /* pick interface closest to dest */ if (ipforme(f, laddr) != Runi) findlocalip(f, laddr, raddr); rport = nhgets(bp->rp); bp->rp += 2 + 2; /* Ignore local port */ break; default: rport = 0; break; } if (ucb->headers) { if (memcmp(laddr, v4prefix, IPv4off) == 0 || ipcmp(laddr, IPnoaddr) == 0) version = V4; else version = V6; } else { if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 && memcmp(c->laddr, v4prefix, IPv4off) == 0) || ipcmp(c->raddr, IPnoaddr) == 0) version = V4; else version = V6; } dlen = blocklen(bp); /* fill in pseudo header and compute checksum */ switch (version) { case V4: bp = padblock(bp, UDP4_IPHDR_SZ + UDP_UDPHDR_SZ); if (bp == NULL) return; uh4 = (Udp4hdr *) (bp->rp); ptcllen = dlen + UDP_UDPHDR_SZ; uh4->Unused = 0; uh4->udpproto = IP_UDPPROTO; uh4->frag[0] = 0; uh4->frag[1] = 0; hnputs(uh4->udpplen, ptcllen); if (ucb->headers) { v6tov4(uh4->udpdst, raddr); hnputs(uh4->udpdport, rport); v6tov4(uh4->udpsrc, laddr); rc = NULL; } else { v6tov4(uh4->udpdst, c->raddr); hnputs(uh4->udpdport, c->rport); if (ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(f, c->laddr, c->raddr); v6tov4(uh4->udpsrc, c->laddr); rc = c; } hnputs(uh4->udpsport, c->lport); hnputs(uh4->udplen, ptcllen); uh4->udpcksum[0] = 0; uh4->udpcksum[1] = 0; hnputs(uh4->udpcksum, ~ptclcsum(bp, UDP4_PHDR_OFF, UDP4_PHDR_SZ)); bp->checksum_start = UDP4_IPHDR_SZ; bp->checksum_offset = uh4->udpcksum - uh4->udpsport; bp->flag |= Budpck; uh4->vihl = IP_VER4; ipoput4(f, bp, 0, c->ttl, c->tos, rc); break; case V6: bp = padblock(bp, UDP6_IPHDR_SZ + UDP_UDPHDR_SZ); if (bp == NULL) return; // using the v6 ip header to create pseudo header // first then reset it to the normal ip header uh6 = (Udp6hdr *) (bp->rp); memset(uh6, 0, 8); ptcllen = dlen + UDP_UDPHDR_SZ; hnputl(uh6->viclfl, ptcllen); uh6->hoplimit = IP_UDPPROTO; if (ucb->headers) { ipmove(uh6->udpdst, raddr); hnputs(uh6->udpdport, rport); ipmove(uh6->udpsrc, laddr); rc = NULL; } else { ipmove(uh6->udpdst, c->raddr); hnputs(uh6->udpdport, c->rport); if (ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(f, c->laddr, c->raddr); ipmove(uh6->udpsrc, c->laddr); rc = c; } hnputs(uh6->udpsport, c->lport); hnputs(uh6->udplen, ptcllen); uh6->udpcksum[0] = 0; uh6->udpcksum[1] = 0; hnputs(uh6->udpcksum, ptclcsum(bp, UDP6_PHDR_OFF, dlen + UDP_UDPHDR_SZ + UDP6_PHDR_SZ)); memset(uh6, 0, 8); uh6->viclfl[0] = IP_VER6; hnputs(uh6->len, ptcllen); uh6->nextheader = IP_UDPPROTO; ipoput6(f, bp, 0, c->ttl, c->tos, rc); break; default: panic("udpkick: version %d", version); } upriv->ustats.udpOutDatagrams++; }
ParallelDofs :: ParallelDofs (MPI_Comm acomm, Table<int> && adist_procs, int dim, bool iscomplex) : comm(acomm), dist_procs(adist_procs) { int ntasks = MyMPI_GetNTasks(comm); int id = MyMPI_GetId(comm); ndof = dist_procs.Size(); if (ntasks == 1) { Array<int> nexdofs(ntasks), ndistprocs(ndof); nexdofs = 0; ndistprocs = 0; exchangedofs = Table<int> (nexdofs); dist_procs = Table<int> (ndistprocs); ismasterdof.SetSize(ndof); ismasterdof.Set(); global_ndof = ndof; return; } // transpose table Array<int> nexdofs(ntasks); nexdofs = 0; for (int i = 0; i < ndof; i++) for (int d : dist_procs[i]) nexdofs[d]++; exchangedofs = Table<int>(nexdofs); nexdofs = 0; for (int i = 0; i < ndof; i++) for (int d : dist_procs[i]) exchangedofs[d][nexdofs[d]++] = i; ismasterdof.SetSize (ndof); ismasterdof.Set(); for (int i = 0; i < id; i++) for (int ex : exchangedofs[i]) ismasterdof.Clear (ex); mpi_t.SetSize (ntasks); MPI_Datatype mpi_type; mpi_type = iscomplex ? MyGetMPIType<Complex>() : MyGetMPIType<double>(); if (dim != 1) { MPI_Datatype htype; MPI_Type_contiguous (dim, mpi_type, &htype); mpi_type = htype; } for (int dest = 0; dest < ntasks; dest++ ) { if ( !IsExchangeProc(dest) ) continue; FlatArray<int> exdofs = GetExchangeDofs(dest); int len_vec = exdofs.Size(); if (len_vec == 0) continue; Array<int> blocklen(len_vec); blocklen = 1; MPI_Type_indexed (len_vec, &blocklen[0], &exdofs[0], mpi_type, &mpi_t[dest]); MPI_Type_commit (&mpi_t[dest]); } for (int i = 0; i < ntasks; i++) if (IsExchangeProc (i)) all_dist_procs.Append (i); size_t nlocal = 0; for (int i = 0; i < ndof; i++) if (ismasterdof.Test(i)) nlocal++; global_ndof = MyMPI_AllReduce (nlocal, MPI_SUM, comm); }
/* Adds block (which can be a list of blocks) to the queue, subject to * qio_flags. Returns the length written on success or -1 on non-throwable * error. Adjust qio_flags to control the value-added features!. */ static ssize_t __qbwrite(struct queue *q, struct block *b, int qio_flags) { ssize_t ret; bool dowakeup = FALSE; bool was_empty; if (q->bypass) { ret = blocklen(b); (*q->bypass) (q->arg, b); return ret; } spin_lock_irqsave(&q->lock); was_empty = q->len == 0; if (q->state & Qclosed) { spin_unlock_irqsave(&q->lock); freeblist(b); if (!(qio_flags & QIO_CAN_ERR_SLEEP)) return -1; if (q->err[0]) error(EFAIL, q->err); else error(EFAIL, "connection closed"); } if ((qio_flags & QIO_LIMIT) && (q->len >= q->limit)) { /* drop overflow takes priority over regular non-blocking */ if ((qio_flags & QIO_DROP_OVERFLOW) || (q->state & Qdropoverflow)) { spin_unlock_irqsave(&q->lock); freeb(b); return -1; } /* People shouldn't set NON_BLOCK without CAN_ERR, but we can be nice * and catch it. */ if ((qio_flags & QIO_CAN_ERR_SLEEP) && (qio_flags & QIO_NON_BLOCK)) { spin_unlock_irqsave(&q->lock); freeb(b); error(EAGAIN, "queue full"); } } ret = enqueue_blist(q, b); QDEBUG checkb(b, "__qbwrite"); /* make sure other end gets awakened */ if (q->state & Qstarve) { q->state &= ~Qstarve; dowakeup = TRUE; } spin_unlock_irqsave(&q->lock); /* TODO: not sure if the usage of a kick is mutually exclusive with a * wakeup, meaning that actual users either want a kick or have qreaders. */ if (q->kick && (dowakeup || (q->state & Qkick))) q->kick(q->arg); if (dowakeup) rendez_wakeup(&q->rr); if (was_empty) qwake_cb(q, FDTAP_FILT_READABLE); /* * flow control, wait for queue to get below the limit * before allowing the process to continue and queue * more. We do this here so that postnote can only * interrupt us after the data has been queued. This * means that things like 9p flushes and ssl messages * will not be disrupted by software interrupts. * * Note - this is moderately dangerous since a process * that keeps getting interrupted and rewriting will * queue infinite crud. */ if ((qio_flags & QIO_CAN_ERR_SLEEP) && !(q->state & Qdropoverflow) && !(qio_flags & QIO_NON_BLOCK)) { /* This is a racy peek at the q status. If we accidentally block, we * set Qflow, so someone should wake us. If we accidentally don't * block, we just returned to the user and let them slip a block past * flow control. */ while (!qnotfull(q)) { spin_lock_irqsave(&q->lock); q->state |= Qflow; spin_unlock_irqsave(&q->lock); rendez_sleep(&q->wr, qnotfull, q); } } return ret; }
int ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c) { Proc *up = externup(); int medialen, len, chunk, uflen, flen, seglen, lid, offset, fragoff; int morefrags, blklen, rv = 0, tentative; uint8_t *gate, nexthdr; Block *xp, *nb; Fraghdr6 fraghdr; IP *ip; Ip6hdr *eh; Ipifc *ifc; Route *r, *sr; ip = f->ip; /* Fill out the ip header */ eh = (Ip6hdr*)(bp->rp); ip->stats[OutRequests]++; /* Number of uint8_ts in data and ip header to write */ len = blocklen(bp); tentative = iptentative(f, eh->src); if(tentative){ netlog(f, Logip, "reject tx of packet with tentative src address %I\n", eh->src); goto free; } if(gating){ chunk = nhgets(eh->ploadlen); if(chunk > len){ ip->stats[OutDiscards]++; netlog(f, Logip, "short gated packet\n"); goto free; } if(chunk + IP6HDR < len) len = chunk + IP6HDR; } if(len >= IP_MAX){ ip->stats[OutDiscards]++; netlog(f, Logip, "exceeded ip max size %I\n", eh->dst); goto free; } r = v6lookup(f, eh->dst, c); if(r == nil){ // print("no route for %I, src %I free\n", eh->dst, eh->src); ip->stats[OutNoRoutes]++; netlog(f, Logip, "no interface %I\n", eh->dst); rv = -1; goto free; } ifc = r->RouteTree.ifc; if(r->RouteTree.type & (Rifc|Runi)) gate = eh->dst; else if(r->RouteTree.type & (Rbcast|Rmulti)) { gate = eh->dst; sr = v6lookup(f, eh->src, nil); if(sr && (sr->RouteTree.type & Runi)) ifc = sr->RouteTree.ifc; } else gate = r->v6.gate; if(!gating) eh->vcf[0] = IP_VER6; eh->ttl = ttl; if(!gating) { eh->vcf[0] |= tos >> 4; eh->vcf[1] = tos << 4; }
void igmpiput(Medium *m, Ipifc *, Block *bp) { int n; IGMPpkt *ghp; Ipaddr group; IGMPrep *rp, **lrp; Multicast *mp, **lmp; ghp = (IGMPpkt*)(bp->rp); netlog(Logigmp, "igmpiput: %d %I\n", ghp->vertype, ghp->group); n = blocklen(bp); if(n < IGMP_IPHDRSIZE+IGMP_HDRSIZE){ netlog(Logigmp, "igmpiput: bad len\n"); goto error; } if((ghp->vertype>>4) != 1){ netlog(Logigmp, "igmpiput: bad igmp type\n"); goto error; } if(ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE)){ netlog(Logigmp, "igmpiput: checksum error %I\n", ghp->src); goto error; } group = nhgetl(ghp->group); lock(&igmpalloc); switch(ghp->vertype & 0xf){ case IGMPquery: /* * start reporting groups that we're a member of. */ stats.inqueries++; for(rp = igmpalloc.reports; rp; rp = rp->next) if(rp->m == m) break; if(rp != nil) break; /* already reporting */ mp = Mediumcopymulti(m); if(mp == nil) break; rp = malloc(sizeof(*rp)); if(rp == nil) break; rp->m = m; rp->multi = mp; rp->ticks = 0; for(; mp; mp = mp->next) mp->timeout = nrand(MAXTIMEOUT); rp->next = igmpalloc.reports; igmpalloc.reports = rp; wakeup(&igmpalloc.r); break; case IGMPreport: /* * find report list for this medium */ stats.inreports++; lrp = &igmpalloc.reports; for(rp = *lrp; rp; rp = *lrp){ if(rp->m == m) break; lrp = &rp->next; } if(rp == nil) break; /* * if someone else has reported a group, * we don't have to. */ lmp = &rp->multi; for(mp = *lmp; mp; mp = *lmp){ if(mp->addr == group){ *lmp = mp->next; free(mp); break; } lmp = &mp->next; } break; } unlock(&igmpalloc); error: freeb(bp); }
void rudpkick(void *x) { Proc *up = externup(); Conv *c = x; Udphdr *uh; uint16_t rport; uint8_t laddr[IPaddrlen], raddr[IPaddrlen]; Block *bp; Rudpcb *ucb; Rudphdr *rh; Reliable *r; int dlen, ptcllen; Rudppriv *upriv; Fs *f; upriv = c->p->priv; f = c->p->f; netlog(c->p->f, Logrudp, "rudp: kick\n"); bp = qget(c->wq); if(bp == nil) return; ucb = (Rudpcb*)c->ptcl; switch(ucb->headers) { case 7: /* get user specified addresses */ bp = pullupblock(bp, UDP_USEAD7); if(bp == nil) return; ipmove(raddr, bp->rp); bp->rp += IPaddrlen; ipmove(laddr, bp->rp); bp->rp += IPaddrlen; /* pick interface closest to dest */ if(ipforme(f, laddr) != Runi) findlocalip(f, laddr, raddr); bp->rp += IPaddrlen; /* Ignore ifc address */ rport = nhgets(bp->rp); bp->rp += 2+2; /* Ignore local port */ break; default: ipmove(raddr, c->raddr); ipmove(laddr, c->laddr); rport = c->rport; break; } dlen = blocklen(bp); /* Make space to fit rudp & ip header */ bp = padblock(bp, UDP_IPHDR+UDP_RHDRSIZE); if(bp == nil) return; uh = (Udphdr *)(bp->rp); uh->vihl = IP_VER4; rh = (Rudphdr*)uh; ptcllen = dlen + (UDP_RHDRSIZE-UDP_PHDRSIZE); uh->Unused = 0; uh->udpproto = IP_UDPPROTO; uh->frag[0] = 0; uh->frag[1] = 0; hnputs(uh->udpplen, ptcllen); switch(ucb->headers){ case 7: v6tov4(uh->udpdst, raddr); hnputs(uh->udpdport, rport); v6tov4(uh->udpsrc, laddr); break; default: v6tov4(uh->udpdst, c->raddr); hnputs(uh->udpdport, c->rport); if(ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(f, c->laddr, c->raddr); v6tov4(uh->udpsrc, c->laddr); break; } hnputs(uh->udpsport, c->lport); hnputs(uh->udplen, ptcllen); uh->udpcksum[0] = 0; uh->udpcksum[1] = 0; qlock(&ucb->ql); r = relstate(ucb, raddr, rport, "kick"); r->sndseq = NEXTSEQ(r->sndseq); hnputl(rh->relseq, r->sndseq); hnputl(rh->relsgen, r->sndgen); hnputl(rh->relack, r->rcvseq); /* ACK last rcvd packet */ hnputl(rh->relagen, r->rcvgen); if(r->rcvseq != r->acksent) r->acksent = r->rcvseq; hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_RHDRSIZE)); relackq(r, bp); qunlock(&ucb->ql); upriv->ustats.rudpOutDatagrams++; DPRINT("sent: %lud/%lud, %lud/%lud\n", r->sndseq, r->sndgen, r->rcvseq, r->rcvgen); doipoput(c, f, bp, 0, c->ttl, c->tos); if(waserror()) { relput(r); qunlock(&r->lock); nexterror(); } /* flow control of sorts */ qlock(&r->lock); if(UNACKED(r) > Maxunacked){ r->blocked = 1; sleep(&r->vous, flow, r); r->blocked = 0; } qunlock(&r->lock); relput(r); poperror(); }