func makePort(portNo uint32, port gopenflow.Port) ofp4.Port { var config uint32 for _, conf := range port.GetConfig() { switch c := conf.(type) { case gopenflow.PortConfigPortDown: if bool(c) { config |= ofp4.OFPPC_PORT_DOWN } case gopenflow.PortConfigNoRecv: if bool(c) { config |= ofp4.OFPPC_NO_RECV } case gopenflow.PortConfigNoFwd: if bool(c) { config |= ofp4.OFPPC_NO_FWD } case gopenflow.PortConfigNoPacketIn: if bool(c) { config |= ofp4.OFPPC_NO_PACKET_IN } } } var state uint32 for _, st := range port.State() { switch s := st.(type) { case gopenflow.PortStateLinkDown: if bool(s) { state |= ofp4.OFPPS_LINK_DOWN } case gopenflow.PortStateBlocked: if bool(s) { state |= ofp4.OFPPS_BLOCKED } case gopenflow.PortStateLive: if bool(s) { state |= ofp4.OFPPS_LIVE } } } eth, err := port.Ethernet() if err != nil { log.Print(err) } return ofp4.MakePort(portNo, port.HwAddr(), []byte(port.Name()), config, state, eth.Curr, eth.Advertised, eth.Supported, eth.Peer, eth.CurrSpeed, eth.MaxSpeed) }
// 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 }