//FindAll finds the MTU for each connection specified in the //configuration. Use Find() if you're only looking for a specific MTU. func FindAll() { if !initalized { log.Println("Please make sure that the MTU package was configured with mtu.Init(.., ..)") return } c := conf //Setup a mtuOK channel for each config var mtuOkChannels = make(map[int]chan int) for conf := range c.MTUConfList { mtuOkChannels[conf] = make(chan int, 100) } var quitDistribute = make(chan bool) go distributeMtuOkPackets(icmpPacketsStage2, mtuOkChannels, quitDistribute) var wg sync.WaitGroup for conf := range c.MTUConfList { logging.InfoLog("Starting MTU Discovery " + strconv.Itoa(conf+1) + "/" + strconv.Itoa(len(c.MTUConfList)) + " between " + c.MTUConfList[conf].SourceIP + " and " + c.MTUConfList[conf].DestinationIP + ". Reported by AppID " + strconv.Itoa(c.ApplicationID) + ".") wg.Add(1) go find( c.MTUConfList[conf], c.ApplicationID, conf, mtuOkChannels[conf], &wg) } //Wait until all MTU's have been detected wg.Wait() quitDistribute <- true }
//find finds the ideal MTU between two nodes by sending batches of packets with varying sizes //to a remote node. The remote nodes is requires to respond to those packets if it received them. //so it can determine the largest packet that was received on the remote node and the smallest packet that //went missing. In a next step FastMTU sends again a batch of packets with sizes between the largest successful //and smallest unsuccessful packet. This behaviour is continued until the size-difference between individual //packets is no larger then 1Byte. Once that happens the largest successful packet is reported as MTU. func find(mtuConf config.MTUConfig, appID int, chanID int, mtuOK chan int, wg *sync.WaitGroup) int { if !initalized { log.Println("Please make sure that the MTU package was configured with mtu.Init(.., ..)") return 0 } var rangeStart = mtuConf.MTURangeStart var rangeEnd = mtuConf.MTURangeEnd var itStep = ((rangeEnd - rangeStart) / mtuConf.ConcurrentPackets) var roughMTU = 0 var mtuDetected = false var retries = 0 for !mtuDetected { if itStep == 0 { itStep = 1 mtuDetected = true } roughMTU = sendBatch(mtuConf.SourceIP, mtuConf.DestinationIP, rangeStart, rangeEnd, itStep, mtuConf.Timeout, appID, chanID, mtuOK) if roughMTU == rangeEnd { //If all packets are successful there's a chance that our range is too small. This could be because of packet loss //in a earlier iteration or because the range in the configuration was chosen too small. So we double the //range and reset mtuDetected to make sure it runs once more. We also recalculate the itStep to prevent //a packet flood if the range is suddenly big and we had a small itstep before. mtuDetected = false rangeStart = rangeEnd rangeEnd = 2 * rangeEnd itStep = ((rangeEnd - rangeStart) / mtuConf.ConcurrentPackets) } else if roughMTU == 0 { //If no packet is successful we run 1 retry. if retries < 1 { retries++ log.Println("ERROR: Reported 0.. trying again.") } else { log.Println("ERROR: Reported MTU 0.. ") mtuDetected = true } } else { //This is the normal case. We had some successful and some unsuccessful packets. The range is set between //the last successful and the first unsuccessful packet. Then the itStep is recalculated. rangeStart = roughMTU rangeEnd = roughMTU + itStep itStep = ((rangeEnd - rangeStart) / mtuConf.ConcurrentPackets) } } report := "MTU between " + mtuConf.SourceIP + " and " + mtuConf.DestinationIP + " is " + strconv.Itoa(roughMTU) + ". Reported by AppID " + strconv.Itoa(conf.ApplicationID) + "." logging.InfoLog(report) wg.Done() return roughMTU }