Esempio n. 1
0
// SetPort sets a port in a specified portNo. To unset the port, pass nil as port argument.
func (self *Pipeline) AddPort(port gopenflow.Port) error {
	self.lock.Lock()
	defer self.lock.Unlock()

	portNo := uint32(1)
	for idx, p := range self.ports {
		if p == port {
			return fmt.Errorf("port already registered")
		}
		if idx >= portNo {
			portNo = idx + 1
		}
	}
	if portNo > ofp4.OFPP_MAX {
		return fmt.Errorf("no port number available")
		// we may reuse the port number
	}
	self.ports[portNo] = port
	self.portAlive[portNo] = watchTimer{}
	updateTimer := func(ofpPort []byte) {
		wt := self.portAlive[portNo]
		if ofp4.Port(ofpPort).State()&ofp4.OFPPS_LIVE != 0 {
			if wt.Active == nil {
				save := time.Now()
				wt.Active = &save
				self.portAlive[portNo] = wt
			}
		} else {
			if wt.Active != nil {
				wt.Past += time.Now().Sub(*wt.Active)
				wt.Active = nil
				self.portAlive[portNo] = wt
			}
		}
	}

	// add port first.
	ofpPort := makePort(portNo, port)
	self.portSnapshot[portNo] = ofpPort
	updateTimer(ofpPort)
	for _, ch := range self.channels {
		ch.Notify(ofp4.MakePortStatus(ofp4.OFPPR_ADD, ofpPort))
	}

	pktIngress := make(chan bool)
	go func() {
		for pkt := range port.Ingress() {
			oob := match(make(map[OxmKey]OxmPayload))
			if err := oob.UnmarshalBinary(pkt.Oob); err != nil {
				log.Print(err)
			} else {
				self.datapath <- &flowTask{
					Frame: Frame{
						serialized: pkt.Data,
						inPort:     portNo,
						inPhyPort:  port.PhysicalPort(),
						Oob:        oob,
					},
					pipe: self,
				}
			}
		}
		pktIngress <- true
	}()
	go func() {
		for _ = range port.Monitor() {
			ofpPort := makePort(portNo, port)
			if bytes.Equal(ofpPort, self.portSnapshot[portNo]) {
				continue
			} else {
				self.portSnapshot[portNo] = ofpPort
			}
			for _, ch := range self.channels {
				ch.Notify(ofp4.MakePortStatus(ofp4.OFPPR_MODIFY, ofpPort))
			}
			updateTimer(ofpPort)
		}
		for _, ch := range self.channels {
			ch.Notify(ofp4.MakePortStatus(ofp4.OFPPR_DELETE, self.portSnapshot[portNo]))
		}
		<-pktIngress
		delete(self.ports, portNo)
		delete(self.portSnapshot, portNo)
		delete(self.portAlive, portNo)
	}()
	return nil
}