Пример #1
0
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
}