func newFlowEntry(req ofp4.FlowMod) (*flowEntry, error) { reqMatch := match{} if err := reqMatch.UnmarshalBinary(req.Match().OxmFields()); err != nil { return nil, err } entry := &flowEntry{ lock: &sync.RWMutex{}, fields: reqMatch, cookie: req.Cookie(), created: time.Now(), idleTimeout: req.IdleTimeout(), hardTimeout: req.HardTimeout(), instWrite: makeActionSet(), instExp: make(map[int][]instExperimenter), } if err := entry.importInstructions(req.Instructions()); err != nil { return nil, err } return entry, nil }
func (pipe Pipeline) addFlowEntry(req ofp4.FlowMod) error { tableId := req.TableId() if tableId > ofp4.OFPTT_MAX { return ofp4.MakeErrorMsg( ofp4.OFPET_FLOW_MOD_FAILED, ofp4.OFPFMFC_BAD_TABLE_ID, ) } pipe.lock.Lock() defer pipe.lock.Unlock() var table *flowTable if trial, ok := pipe.flows[tableId]; ok { table = trial } else { table = &flowTable{ lock: &sync.RWMutex{}, feature: makeFlowTableFeature(), } pipe.flows[tableId] = table } return table.addFlowEntry(req, pipe) }
func (self *flowTable) addFlowEntry(req ofp4.FlowMod, pipe Pipeline) error { flow, e1 := newFlowEntry(req) if e1 != nil { return e1 } if err := self.feature.accepts(flow, req.Priority()); err != nil { return err } self.lock.Lock() defer self.lock.Unlock() var priority *flowPriority i := sort.Search(len(self.priorities), func(k int) bool { return self.priorities[k].priority <= req.Priority() // descending order }) if i == len(self.priorities) || self.priorities[i].priority != req.Priority() { priority = &flowPriority{ lock: &sync.RWMutex{}, priority: req.Priority(), flows: make(map[uint32][]*flowEntry), } self.priorities = append(self.priorities, nil) copy(self.priorities[i+1:], self.priorities[i:]) self.priorities[i] = priority } else { priority = self.priorities[i] } priority.lock.Lock() defer priority.lock.Unlock() key := priority.hash.Key(matchHash(flow.fields)) flows := []*flowEntry{flow} // prepare for rebuild for k, fs := range priority.flows { if k == key { for _, f := range fs { if conflict, err := flow.fields.Conflict(f.fields); err != nil { return err } else if req.Flags()&ofp4.OFPFF_CHECK_OVERLAP != 0 && !conflict { return ofp4.MakeErrorMsg(ofp4.OFPET_FLOW_MOD_FAILED, ofp4.OFPFMFC_OVERLAP) } if isEqual, err := flow.fields.Equal(f.fields); err != nil { return err } else if isEqual { // old entry will be cleared if req.Flags()&ofp4.OFPFF_RESET_COUNTS == 0 { // counters should be copied flow.packetCount = f.packetCount flow.byteCount = f.byteCount } } else { flows = append(flows, f) } } } else { flows = append(flows, fs...) } } if portNo, act := hookDot11Action(req.Match().OxmFields()); portNo != 0 && len(act) != 0 { if port := pipe.getPort(portNo); port != nil { if err := port.Vendor(gopenflow.MgmtFrameAdd(act)).(error); err != nil { return err } } } priority.rebuildIndex(flows) self.activeCount = uint32(len(flows)) return nil }