func (self match) UnmarshalBinary(msg []byte) error { exps := make(map[uint32]bool) for _, oxm := range ofp4.Oxm(msg).Iter() { hdr := oxm.Header() switch hdr.Class() { case ofp4.OFPXMC_OPENFLOW_BASIC: self[OxmKeyBasic(hdr.Type())] = OxmValueMask{ Value: oxm.Value(), Mask: oxm.Mask(), } case ofp4.OFPXMC_EXPERIMENTER: exps[ofp4.OxmExperimenterHeader(oxm).Experimenter()] = true default: return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBMC_BAD_TYPE, ) } } for exp, _ := range exps { if handle, ok := oxmHandlers[exp]; ok { for k, v := range handle.Parse(msg) { oxmKeys[k] = exp self[k] = v } } else { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBRC_BAD_LEN, ) } } return nil }
func (entry *flowEntry) importInstructions(instructions ofp4.Instruction) error { for _, inst := range instructions.Iter() { switch inst.Type() { default: return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_UNKNOWN_INST, ) case ofp4.OFPIT_GOTO_TABLE: entry.instGoto = ofp4.InstructionGotoTable(inst).TableId() case ofp4.OFPIT_WRITE_METADATA: i := ofp4.InstructionWriteMetadata(inst) if i.Metadata()&^i.MetadataMask() != 0 { return errors.New("invalid value/mask pair") } entry.instMetadata = &metadataInstruction{ i.Metadata(), i.MetadataMask(), } case ofp4.OFPIT_WRITE_ACTIONS, ofp4.OFPIT_APPLY_ACTIONS, ofp4.OFPIT_CLEAR_ACTIONS: i := ofp4.InstructionActions(inst) switch inst.Type() { case ofp4.OFPIT_WRITE_ACTIONS: var aset actionSet if err := aset.UnmarshalBinary(i.Actions()); err != nil { return err } entry.instWrite = aset case ofp4.OFPIT_APPLY_ACTIONS: var alist actionList if err := alist.UnmarshalBinary(i.Actions()); err != nil { return err } entry.instApply = alist case ofp4.OFPIT_CLEAR_ACTIONS: entry.instClear = true } case ofp4.OFPIT_METER: entry.instMeter = ofp4.InstructionMeter(inst).MeterId() case ofp4.OFPIT_EXPERIMENTER: experimenter := ofp4.InstructionExperimenter(inst).Experimenter() data := inst[8:] if handler, ok := instructionHandlers[experimenter]; ok { pos := handler.Order(data) entry.instExp[pos] = append(entry.instExp[pos], instExperimenter{ Experimenter: experimenter, Data: data, Handler: handler, }) } else { return ofp4.MakeErrorMsg(ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_UNSUP_INST) } } } return nil }
func (self *ofmMpPortStats) Map() Reducable { mpreq := ofp4.MultipartRequest(self.req) proc := func(portNo uint32, port gopenflow.Port) { var pstats gopenflow.PortStats var ethinfo gopenflow.PortStatsEthernet if p, err := port.Stats(); err != nil { log.Print(err) } else { pstats = p if p.Ethernet != nil { ethinfo = *p.Ethernet } } duration := self.pipe.portAlive[portNo].Total() chunk := ofp4.MakePortStats( portNo, pstats.RxPackets, pstats.TxPackets, pstats.RxBytes, pstats.TxBytes, pstats.RxDropped, pstats.TxDropped, pstats.RxErrors, pstats.TxErrors, ethinfo.RxFrameErr, ethinfo.RxOverErr, ethinfo.RxCrcErr, ethinfo.Collisions, uint32(duration.Seconds()), uint32(duration.Nanoseconds()%int64(time.Second)), ) self.chunks = append(self.chunks, chunk) } portNo := ofp4.PortStatsRequest(mpreq.Body()).PortNo() switch portNo { default: if portNo > 0 && portNo <= ofp4.OFPP_MAX { if port := self.pipe.getPort(portNo); port != nil { proc(portNo, port) } else { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_PORT_MOD_FAILED, ofp4.OFPPMFC_BAD_PORT)) } } else { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_PORT_MOD_FAILED, ofp4.OFPPMFC_BAD_PORT)) } case ofp4.OFPP_ALL, ofp4.OFPP_ANY: for portNo, port := range self.pipe.getAllPorts() { proc(portNo, port) } } return self }
func (self *ofmPortMod) Map() Reducable { pipe := self.pipe msg := ofp4.PortMod(self.req) var confs []gopenflow.PortConfig for _, config := range []uint32{ ofp4.OFPPC_PORT_DOWN, ofp4.OFPPC_NO_RECV, ofp4.OFPPC_NO_FWD, ofp4.OFPPC_NO_PACKET_IN, } { if msg.Mask()&config != 0 { switch config { case ofp4.OFPPC_PORT_DOWN: confs = append(confs, gopenflow.PortConfigPortDown(msg.Config()&config != 0)) case ofp4.OFPPC_NO_RECV: confs = append(confs, gopenflow.PortConfigNoRecv(msg.Config()&config != 0)) case ofp4.OFPPC_NO_FWD: confs = append(confs, gopenflow.PortConfigNoFwd(msg.Config()&config != 0)) case ofp4.OFPPC_NO_PACKET_IN: confs = append(confs, gopenflow.PortConfigNoPacketIn(msg.Config()&config != 0)) } } } // ofp_port_mod looks for normal port only. if port := pipe.getPort(msg.PortNo()); port != nil { port.SetConfig(confs) } else { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_PORT_MOD_FAILED, ofp4.OFPPMFC_BAD_PORT)) } return self }
func (self actionSetField) Process(data *Frame) (*outputToPort, *outputToGroup, error) { ms := match{} if err := ms.UnmarshalBinary(self.Field); err != nil { return nil, nil, err } else { for oxmKey, oxmPayload := range ms { var handler OxmHandler switch oxmKey.(type) { case OxmKeyBasic: handler = oxmBasicHandler default: handler = oxmHandlers[oxmKeys[oxmKey]] } if handler == nil { return nil, nil, ofp4.MakeErrorMsg( ofp4.OFPBAC_BAD_EXPERIMENTER, ofp4.OFPBAC_BAD_TYPE, ) } else if err := handler.SetField(data, oxmKey, oxmPayload); err != nil { return nil, nil, err } } } return nil, nil, nil }
func (self *ofmGroupMod) Map() Reducable { pipe := self.pipe req := ofp4.GroupMod(self.req) switch req.Command() { case ofp4.OFPGC_ADD: if err := pipe.addGroup(req); err != nil { if e, ok := err.(ofp4.ErrorMsg); ok { self.putError(e) } else { log.Print(err) } } case ofp4.OFPGC_MODIFY: func() { pipe.lock.Lock() defer pipe.lock.Unlock() if group, exists := pipe.groups[req.GroupId()]; exists { var buckets bucketList if err := buckets.UnmarshalBinary(req.Buckets()); err != nil { log.Print(err) } group.groupType = req.Type() group.buckets = buckets } else { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_GROUP_MOD_FAILED, ofp4.OFPGMFC_UNKNOWN_GROUP)) } }() case ofp4.OFPGC_DELETE: if err := func() error { pipe.lock.Lock() defer pipe.lock.Unlock() if req.GroupId() == ofp4.OFPG_ALL { for groupId, _ := range pipe.groups { if err := pipe.deleteGroupInside(groupId); err != nil { return err } } } else { return pipe.deleteGroupInside(req.GroupId()) } return nil }(); err != nil { if e, ok := err.(ofp4.ErrorMsg); ok { self.putError(e) } else { log.Print(err) } } } return self }
func (self *ofmPacketOut) Map() Reducable { msg := ofp4.PacketOut(self.req) var eth []byte if msg.BufferId() == ofp4.OFP_NO_BUFFER { eth = msg.Data() } else { func() { self.pipe.lock.Lock() defer self.pipe.lock.Unlock() if original, ok := self.pipe.buffer[msg.BufferId()]; ok { delete(self.pipe.buffer, msg.BufferId()) if data, err := original.Serialized(); err != nil { log.Print(err) } else { eth = data } } else { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_BAD_REQUEST, ofp4.OFPBRC_BUFFER_UNKNOWN)) } }() } if eth != nil { data := &Frame{ serialized: eth, inPort: msg.InPort(), } if data.inPort > 0 && data.inPort <= ofp4.OFPP_MAX { data.inPhyPort = self.pipe.getPort(msg.InPort()).PhysicalPort() } var actions actionList actions.UnmarshalBinary(msg.Actions()) var gouts []outputToGroup for _, act := range []action(actions) { if pout, gout, e := act.Process(data); e != nil { log.Print(e) } else { if pout != nil { self.outputs = append(self.outputs, *pout) } if gout != nil { gouts = append(gouts, *gout) } } } self.outputs = append(self.outputs, self.pipe.groupToOutput(gouts, nil)...) } return self }
func (self *ofmExperimenter) Map() Reducable { exp := ofp4.ExperimenterHeader(self.req) key := experimenterKey{ Experimenter: exp.Experimenter(), ExpType: exp.ExpType(), } if handler, ok := messageHandlers[key]; ok { for _, rep := range handler.Execute(exp[16:]) { msg := ofp4.MakeExperimenterHeader(exp.Experimenter(), exp.ExpType()).AppendData(rep).SetXid(self.req.Xid()) self.resps = append(self.resps, msg) } } else { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_BAD_REQUEST, ofp4.OFPBRC_BAD_EXPERIMENTER)) } return self }
func (pipe *Pipeline) deleteGroupInside(groupId uint32) error { if _, exists := pipe.groups[groupId]; exists { for _, chainId := range pipe.groupChains(groupId, nil) { if _, exists := pipe.groups[chainId]; exists { delete(pipe.groups, chainId) } pipe.filterFlowsInside(flowFilter{ opUnregister: true, outPort: ofp4.OFPP_ANY, outGroup: chainId, }) } } else { return ofp4.MakeErrorMsg(ofp4.OFPET_GROUP_MOD_FAILED, ofp4.OFPGMFC_GROUP_EXISTS) } return nil }
/* You should pass expanded match. */ func (self match) Conflict(target match) (bool, error) { uni := make(map[OxmKey]bool) for k, _ := range self { uni[k] = true } for k, _ := range target { uni[k] = true } for oxmKey, _ := range uni { if sPayload, ok := self[oxmKey]; !ok { continue } else if tPayload, ok := target[oxmKey]; !ok { continue } else { var handle OxmHandler switch k := oxmKey.(type) { case OxmKeyBasic: if oxm.Header(k).Class() == ofp4.OFPXMC_OPENFLOW_BASIC { handle = oxmBasicHandler } default: handle = oxmHandlers[oxmKeys[oxmKey]] } if handle == nil { return false, ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBMC_BAD_TYPE, ) } if result, err := handle.Conflict(oxmKey, sPayload, tPayload); err != nil { return false, err } else if result { return true, nil } } } return false, nil }
func (self match) Expand() (match, error) { var exps []uint32 ret := make(map[OxmKey]OxmPayload) for k, v := range self { oxm := ofp4.Oxm(k.Bytes(v)) if oxm.Header().Class() == ofp4.OFPXMC_EXPERIMENTER { exps = append(exps, ofp4.OxmExperimenterHeader(oxm).Experimenter()) } ret[k] = v } oxmBasicHandler.Expand(ret) for _, exp := range exps { if handle, ok := oxmHandlers[exp]; !ok { return nil, ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBMC_BAD_TYPE, ) } else if err := handle.Expand(ret); err != nil { return nil, err } } return ret, 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 (pipe *Pipeline) addGroup(req ofp4.GroupMod) error { var buckets []bucket for _, msg := range req.Buckets().Iter() { var b bucket if err := b.UnmarshalBinary(msg); err != nil { return err } buckets = append(buckets, b) } pipe.lock.Lock() defer pipe.lock.Unlock() if _, exists := pipe.groups[req.GroupId()]; exists { return ofp4.MakeErrorMsg(ofp4.OFPET_GROUP_MOD_FAILED, ofp4.OFPGMFC_GROUP_EXISTS) } else { pipe.groups[req.GroupId()] = &group{ lock: &sync.RWMutex{}, groupType: req.Type(), buckets: buckets, } } return nil }
func (self *ofmReply) createError(ofpet uint16, code uint16) { self.resps = append(self.resps, ofp4.Header(ofp4.MakeErrorMsg(ofpet, code)).AppendData(self.req).SetXid(self.req.Xid())) }
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 }
func (self *ofmFlowMod) Map() Reducable { msg := ofp4.FlowMod(self.req) bufferId := msg.BufferId() switch msg.Command() { case ofp4.OFPFC_ADD: if err := self.pipe.addFlowEntry(msg); err != nil { if e, ok := err.(ofp4.ErrorMsg); ok { self.putError(e) } else { log.Print(err) } } case ofp4.OFPFC_MODIFY, ofp4.OFPFC_MODIFY_STRICT: reqMatch := match{} if err := reqMatch.UnmarshalBinary(msg.Match().OxmFields()); err != nil { log.Print(err) } else if msg.TableId() > ofp4.OFPTT_MAX { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_FLOW_MOD_FAILED, ofp4.OFPFMFC_BAD_TABLE_ID)) } else { filter := flowFilter{ cookie: msg.Cookie(), cookieMask: msg.CookieMask(), tableId: msg.TableId(), outPort: ofp4.OFPP_ANY, outGroup: ofp4.OFPG_ANY, match: reqMatch, } if msg.Command() == ofp4.OFPFC_MODIFY_STRICT { filter.priority = msg.Priority() filter.opStrict = true } for _, stat := range self.pipe.filterFlows(filter) { flow := stat.flow if err := func() error { flow.lock.Lock() defer flow.lock.Unlock() if msg.Flags()&ofp4.OFPFF_RESET_COUNTS != 0 { flow.packetCount = 0 flow.byteCount = 0 } return flow.importInstructions(msg.Instructions()) }(); err != nil { if e, ok := err.(ofp4.ErrorMsg); ok { self.putError(e) } else { log.Print(err) } } } } case ofp4.OFPFC_DELETE, ofp4.OFPFC_DELETE_STRICT: reqMatch := match{} if err := reqMatch.UnmarshalBinary(msg.Match().OxmFields()); err != nil { log.Print(err) } else { filter := flowFilter{ opUnregister: true, cookie: msg.Cookie(), cookieMask: msg.CookieMask(), tableId: msg.TableId(), outPort: msg.OutPort(), outGroup: msg.OutGroup(), match: reqMatch, } if msg.Command() == ofp4.OFPFC_DELETE_STRICT { filter.priority = msg.Priority() filter.opStrict = true } for _, stat := range self.pipe.filterFlows(filter) { if hdr, err := stat.flow.fields.MarshalBinary(); err != nil { log.Print(err) } else if portNo, act := hookDot11Action(oxm.Oxm(hdr)); portNo != 0 && len(act) != 0 { if port := self.pipe.getPort(portNo); port != nil { if err := port.Vendor(gopenflow.MgmtFrameRemove(act)).(error); err != nil { log.Print(err) } } } if stat.flow.flags&ofp4.OFPFF_SEND_FLOW_REM != 0 { self.pipe.sendFlowRem(stat.tableId, stat.priority, stat.flow, ofp4.OFPRR_DELETE) } } } bufferId = ofp4.OFP_NO_BUFFER // nothing to do with buffer by specification. } if bufferId != ofp4.OFP_NO_BUFFER { original, ok := func() (outputToPort, bool) { self.pipe.lock.Lock() defer self.pipe.lock.Unlock() original, ok := self.pipe.buffer[bufferId] if ok { delete(self.pipe.buffer, bufferId) } return original, ok }() if ok { pipe := self.pipe pipe.datapath <- &flowTask{ Frame: original.Frame, pipe: self.pipe, tableId: 0, } } else { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_BAD_REQUEST, ofp4.OFPBRC_BUFFER_UNKNOWN)) } } return self }
func (self *flowTableFeature) importProps(props ofp4.TableFeaturePropHeader) error { for _, prop := range props.Iter() { switch prop.Type() { case ofp4.OFPTFPT_INSTRUCTIONS, ofp4.OFPTFPT_INSTRUCTIONS_MISS: var ids []instructionKey for _, inst := range ofp4.TableFeaturePropInstructions(prop).InstructionIds().Iter() { if inst.Type() == ofp4.OFPIT_EXPERIMENTER { ids = append(ids, ofp4.InstructionExperimenter(inst).Experimenter()) } else { ids = append(ids, inst.Type()) } } switch prop.Type() { case ofp4.OFPTFPT_INSTRUCTIONS: self.hit.inst = ids case ofp4.OFPTFPT_INSTRUCTIONS_MISS: self.miss.inst = ids } case ofp4.OFPTFPT_NEXT_TABLES: self.hit.next = ofp4.TableFeaturePropNextTables(prop).NextTableIds() case ofp4.OFPTFPT_NEXT_TABLES_MISS: self.miss.next = ofp4.TableFeaturePropNextTables(prop).NextTableIds() case ofp4.OFPTFPT_WRITE_ACTIONS, ofp4.OFPTFPT_WRITE_ACTIONS_MISS, ofp4.OFPTFPT_APPLY_ACTIONS, ofp4.OFPTFPT_APPLY_ACTIONS_MISS: var ids []actionKey for _, act := range ofp4.TableFeaturePropActions(prop).ActionIds().Iter() { if act.Type() == ofp4.OFPAT_EXPERIMENTER { ids = append(ids, ofp4.ActionExperimenterHeader(act).Experimenter()) } else { ids = append(ids, act.Type()) } } switch prop.Type() { case ofp4.OFPTFPT_WRITE_ACTIONS: self.hit.writeActions = ids case ofp4.OFPTFPT_WRITE_ACTIONS_MISS: self.miss.writeActions = ids case ofp4.OFPTFPT_APPLY_ACTIONS: self.hit.applyActions = ids case ofp4.OFPTFPT_APPLY_ACTIONS_MISS: self.miss.applyActions = ids } case ofp4.OFPTFPT_MATCH, ofp4.OFPTFPT_WILDCARDS, ofp4.OFPTFPT_WRITE_SETFIELD, ofp4.OFPTFPT_WRITE_SETFIELD_MISS, ofp4.OFPTFPT_APPLY_SETFIELD, ofp4.OFPTFPT_APPLY_SETFIELD_MISS: var ids []oxmId for _, oxm := range ofp4.TableFeaturePropOxm(prop).OxmIds().Iter() { hdr := oxm.Header() if hdr.Class() == ofp4.OFPXMC_EXPERIMENTER { exp := ofp4.OxmExperimenterHeader(oxm).Experimenter() ids = append(ids, [...]uint32{oxmHandlers[exp].OxmId(uint32(oxm.Header())), exp}) } else { ids = append(ids, hdr.Type()) } } switch prop.Type() { case ofp4.OFPTFPT_MATCH: self.match = ids case ofp4.OFPTFPT_WILDCARDS: self.wildcards = ids case ofp4.OFPTFPT_WRITE_SETFIELD: self.hit.writeSetfield = ids case ofp4.OFPTFPT_WRITE_SETFIELD_MISS: self.miss.writeSetfield = ids case ofp4.OFPTFPT_APPLY_SETFIELD: self.hit.applySetfield = ids case ofp4.OFPTFPT_APPLY_SETFIELD_MISS: self.miss.applySetfield = ids } case ofp4.OFPTFPT_EXPERIMENTER, ofp4.OFPTFPT_EXPERIMENTER_MISS: msg := ofp4.TableFeaturePropExperimenter(prop) eKey := experimenterKey{ Experimenter: msg.Experimenter(), ExpType: msg.ExpType(), } if _, ok := tableHandlers[eKey]; !ok { return ofp4.MakeErrorMsg( ofp4.OFPET_TABLE_FEATURES_FAILED, ofp4.OFPTFFC_BAD_ARGUMENT, ) } exp := experimenterProp{ experimenterKey: eKey, Data: msg.ExperimenterData(), } switch prop.Type() { case ofp4.OFPTFPT_EXPERIMENTER: self.hit.experimenter = append(self.hit.experimenter, exp) case ofp4.OFPTFPT_EXPERIMENTER_MISS: self.miss.experimenter = append(self.hit.experimenter, exp) } } } return nil }
// See openflow switch 1.3.4 spec "Flow Table Modification Messages" page 40 func (self flowTableFeature) accepts(entry *flowEntry, priority uint16) error { isTableMiss := false if len(entry.fields) == 0 && priority == 0 { isTableMiss = true } var instKeys instructionKeyList if isTableMiss && self.miss.inst != nil { instKeys = instructionKeyList(self.miss.inst) } else if self.hit.inst != nil { instKeys = instructionKeyList(self.hit.inst) } if entry.instGoto != 0 { if instKeys != nil && !instKeys.Have(uint16(ofp4.OFPIT_GOTO_TABLE)) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_UNSUP_INST, ) } var next []uint8 if isTableMiss && self.miss.next != nil { next = self.miss.next } else if self.hit.next != nil { next = self.hit.next } if next != nil { supported := false for _, tableId := range next { if entry.instGoto == tableId { supported = true } } if !supported { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_BAD_TABLE_ID, ) } } } if entry.instMetadata != nil { if instKeys != nil && !instKeys.Have(uint16(ofp4.OFPIT_WRITE_METADATA)) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_UNSUP_INST, ) } if entry.instMetadata.metadata&^self.metadataWrite != 0 { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_UNSUP_METADATA, ) } if entry.instMetadata.mask&^self.metadataWrite != 0 { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_UNSUP_METADATA_MASK, ) } } if !isTableMiss && self.match != nil { unavailable := func(id oxmId) bool { for _, k := range self.match { if k == id { return false } } return true } for k, p := range entry.fields { for _, oxm := range ofp4.Oxm(k.Bytes(p)).Iter() { var id oxmId hdr := oxm.Header() switch hdr.Type() { case ofp4.OFPXMC_OPENFLOW_BASIC: id = oxmBasicHandler.OxmId(uint32(hdr)) case ofp4.OFPXMC_EXPERIMENTER: exp := ofp4.OxmExperimenterHeader(oxm).Experimenter() id = [...]uint32{ oxmHandlers[exp].OxmId(uint32(hdr)), exp, } default: return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBMC_BAD_TYPE, ) } if unavailable(id) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBMC_BAD_FIELD, ) } } } for _, k := range self.wildcards { if unavailable(k) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBMC_BAD_WILDCARDS, ) } } } if len([]action(entry.instApply)) > 0 { if instKeys != nil && !instKeys.Have(uint16(ofp4.OFPIT_APPLY_ACTIONS)) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_UNSUP_INST, ) } var keys []actionKey if isTableMiss && self.miss.applyActions != nil { keys = self.miss.applyActions } else if self.hit.applyActions != nil { keys = self.hit.applyActions } if keys != nil { for _, act := range []action(entry.instApply) { aKey := act.Key() if !actionKeyList(keys).Have(aKey) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_ACTION, ofp4.OFPBAC_BAD_TYPE, ) } } // XXX: Experimenter } } if entry.instWrite.Len() > 0 { if instKeys != nil && !instKeys.Have(uint16(ofp4.OFPIT_WRITE_ACTIONS)) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_UNSUP_INST, ) } var keys []actionKey if isTableMiss && self.miss.writeActions != nil { keys = self.miss.writeActions } else if self.hit.writeActions != nil { keys = self.hit.writeActions } if keys != nil { for _, a := range entry.instWrite.hash { if !actionKeyList(keys).Have(a.Key()) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_ACTION, ofp4.OFPBAC_BAD_TYPE, ) } } for k, _ := range entry.instWrite.exp { if !actionKeyList(keys).Have(k) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_ACTION, ofp4.OFPBAC_BAD_TYPE, ) } } } } for _, insts := range entry.instExp { for _, inst := range insts { if instKeys != nil && !instKeys.Have(inst.Experimenter) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_UNSUP_INST, ) } } } if entry.instMeter != 0 { if instKeys != nil && !instKeys.Have(uint16(ofp4.OFPIT_METER)) { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_INSTRUCTION, ofp4.OFPBIC_UNSUP_INST, ) } } return nil }
func (self *Pipeline) AddChannel(conn io.ReadWriteCloser) error { self.lock.Lock() defer self.lock.Unlock() ch := &channel{ Conn: conn, } // process hello ch.Notify(ofp4.MakeHello(ofp4.MakeHelloElemVersionbitmap([]uint32{uint32(1 << 4)}))) head := make([]byte, 4) if msg, err := readOfpMessage(conn, head); err != nil { return err } else if ofp4.Header(msg).Type() != ofp4.OFPT_HELLO { return fmt.Errorf("The first message must be HELLO") } else { satisfied := false for _, element := range ofp4.Hello(msg).Elements().Iter() { switch element.Type() { case ofp4.OFPHET_VERSIONBITMAP: bitmaps := ofp4.HelloElemVersionbitmap(element).Bitmaps() if len(bitmaps) > 0 && (bitmaps[0]&(1<<4) != 0) { satisfied = true } // ensure there be no bits higher than ofp4 for i, b := range bitmaps { if i == 0 && (b&0xFFFFFFE0) != 0 { satisfied = false } if i > 0 && b != 0 { satisfied = false } } } } if !satisfied && ofp4.Header(msg).Version() == 4 { satisfied = true } if !satisfied { err := ofp4.MakeErrorMsg( ofp4.OFPET_HELLO_FAILED, ofp4.OFPHFC_INCOMPATIBLE, ) ch.Response(ofp4.Header(err).SetXid(ofp4.Header(msg).Xid())) return err } } self.channels = append(self.channels, ch) worker := make(chan MapReducable) go MapReduce(worker, 4) go func() { defer close(worker) defer conn.Close() multipartCollect := make(map[uint32][][]byte) for { msg, err := readOfpMessage(conn, head) if err != nil { log.Print(err) break } reply := ofmReply{pipe: self, channel: ch, req: msg} switch ofp4.Header(msg).Type() { case ofp4.OFPT_ERROR: log.Print("got unexpected OFPT_ERROR") case ofp4.OFPT_ECHO_REQUEST: worker <- &ofmEcho{reply} case ofp4.OFPT_ECHO_REPLY: log.Print("got unexpected OFPT_ECHO_REPLY") case ofp4.OFPT_EXPERIMENTER: worker <- &ofmExperimenter{reply} case ofp4.OFPT_FEATURES_REQUEST: worker <- &ofmFeaturesRequest{reply} case ofp4.OFPT_GET_CONFIG_REQUEST: worker <- &ofmGetConfigRequest{reply} case ofp4.OFPT_SET_CONFIG: worker <- &ofmSetConfig{reply} case ofp4.OFPT_PACKET_OUT: worker <- &ofmPacketOut{ofmOutput{reply, nil}} case ofp4.OFPT_FLOW_MOD: worker <- &ofmFlowMod{ofmOutput{reply, nil}} case ofp4.OFPT_GROUP_MOD: worker <- &ofmGroupMod{reply} case ofp4.OFPT_PORT_MOD: worker <- &ofmPortMod{reply} case ofp4.OFPT_TABLE_MOD: worker <- &ofmTableMod{reply} case ofp4.OFPT_MULTIPART_REQUEST: xid := ofp4.Header(msg).Xid() req := ofp4.MultipartRequest(msg) multipartCollect[xid] = append(multipartCollect[xid], req.Body()) if req.Flags()&ofp4.OFPMPF_REQ_MORE == 0 { reqs := multipartCollect[xid] delete(multipartCollect, xid) mreply := ofmMulti{ ofmReply: reply, reqs: reqs, chunks: nil, } // capture switch req.Type() { case ofp4.OFPMP_DESC: worker <- &ofmMpDesc{mreply} case ofp4.OFPMP_TABLE: worker <- &ofmMpTable{mreply} case ofp4.OFPMP_GROUP_DESC: worker <- &ofmMpGroupDesc{mreply} case ofp4.OFPMP_GROUP_FEATURES: worker <- &ofmMpGroupFeatures{mreply} case ofp4.OFPMP_METER_FEATURES: worker <- &ofmMpMeterFeatures{mreply} case ofp4.OFPMP_PORT_DESC: worker <- &ofmMpPortDesc{mreply} case ofp4.OFPMP_FLOW: worker <- &ofmMpFlow{mreply} case ofp4.OFPMP_AGGREGATE: worker <- &ofmMpAggregate{mreply} case ofp4.OFPMP_PORT_STATS: worker <- &ofmMpPortStats{mreply} case ofp4.OFPMP_QUEUE: worker <- &ofmMpQueue{mreply} case ofp4.OFPMP_GROUP: worker <- &ofmMpGroup{mreply} case ofp4.OFPMP_METER: worker <- &ofmMpMeter{mreply} case ofp4.OFPMP_METER_CONFIG: worker <- &ofmMpMeterConfig{mreply} case ofp4.OFPMP_TABLE_FEATURES: worker <- &ofmMpTableFeatures{mreply} case ofp4.OFPMP_EXPERIMENTER: worker <- &ofmMpExperimenter{mreply} default: panic("unknown ofp_multipart_request.type") } } case ofp4.OFPT_BARRIER_REQUEST: for xid, _ := range multipartCollect { buf := ofp4.Header(make([]byte, 8)) buf.SetXid(xid) rep := ofmReply{pipe: self, channel: ch, req: buf} rep.createError(ofp4.OFPET_BAD_REQUEST, ofp4.OFPBRC_BAD_MULTIPART) worker <- &rep delete(multipartCollect, xid) } worker <- &ofmBarrierRequest{reply} case ofp4.OFPT_QUEUE_GET_CONFIG_REQUEST: worker <- &ofmQueueGetConfigRequest{reply} case ofp4.OFPT_ROLE_REQUEST: worker <- &ofmRoleRequest{reply} case ofp4.OFPT_GET_ASYNC_REQUEST: worker <- &ofmGetAsyncRequest{reply} case ofp4.OFPT_SET_ASYNC: worker <- &ofmSetAsync{reply} case ofp4.OFPT_METER_MOD: worker <- &ofmMeterMod{reply} default: fmt.Printf("unknown ofp_header.type %v\n", msg) return } } }() return nil }
func (self actionGeneric) Process(data *Frame) (*outputToPort, *outputToGroup, error) { switch self.Type { default: return nil, nil, ofp4.MakeErrorMsg( ofp4.OFPET_BAD_ACTION, ofp4.OFPBAC_BAD_TYPE, ) case ofp4.OFPAT_COPY_TTL_OUT: var ttl uint8 found := 0 for _, layer := range data.Layers() { switch clayer := layer.(type) { case *layers.MPLS: ttl = clayer.TTL found++ case *layers.IPv4: ttl = clayer.TTL found++ case *layers.IPv6: ttl = clayer.HopLimit found++ } if found == 2 { break // capture the second value } } if found > 1 { func() { // for direct exit from switch for _, layer := range data.layers { switch clayer := layer.(type) { case *layers.MPLS: clayer.TTL = ttl return case *layers.IPv4: clayer.TTL = ttl return case *layers.IPv6: clayer.HopLimit = ttl return } } }() } case ofp4.OFPAT_COPY_TTL_IN: var ttl uint8 found := 0 func() { // for direct exit from switch for _, layer := range data.Layers() { switch clayer := layer.(type) { case *layers.MPLS: if found > 0 { clayer.TTL = ttl return } else { ttl = clayer.TTL found++ } case *layers.IPv4: if found > 0 { clayer.TTL = ttl return } else { ttl = clayer.TTL found++ } case *layers.IPv6: if found > 0 { clayer.HopLimit = ttl return } else { ttl = clayer.HopLimit found++ } } } }() case ofp4.OFPAT_DEC_MPLS_TTL: for _, layer := range data.layers { switch clayer := layer.(type) { case *layers.MPLS: if clayer.TTL > 0 { clayer.TTL-- } if clayer.TTL == 0 { pout := &outputToPort{ Frame: data.clone(), outPort: ofp4.OFPP_CONTROLLER, reason: ofp4.OFPR_INVALID_TTL, } // invalidate the frame data.serialized = data.serialized[:0] data.layers = nil return pout, nil, nil } } } case ofp4.OFPAT_POP_VLAN: var buf []gopacket.Layer found := false for i, layer := range data.Layers() { if found == false { var ethertype layers.EthernetType switch layer.LayerType() { case layers.LayerTypeDot1Q: ethertype = layer.(*layers.Dot1Q).Type found = true } if found { if i < 1 { return nil, nil, errors.New("bare vlan") } base := data.layers[i-1] if base.LayerType() == layers.LayerTypeEthernet { base.(*layers.Ethernet).EthernetType = ethertype } else { return nil, nil, errors.New("unsupported") } continue } } buf = append(buf, layer) } if found { data.layers = buf } else { return nil, nil, errors.New("pop vlan failed") } case ofp4.OFPAT_DEC_NW_TTL: func() { // for direct exit from switch for _, layer := range data.Layers() { switch clayer := layer.(type) { case *layers.IPv4: if clayer.TTL > 1 { clayer.TTL-- } else { // packet_in ? } return case *layers.IPv6: if clayer.HopLimit > 1 { clayer.HopLimit-- } else { // packet_in ? } return } } }() case ofp4.OFPAT_POP_PBB: var buf []gopacket.Layer found := false for i, layer := range data.Layers() { if found == false { switch pbb := layer.(type) { case *layers2.PBB: found = true if i < 1 { panic("bare pbb") } else if eth, ok := data.layers[i-1].(*layers.Ethernet); ok { eth.EthernetType = pbb.Type eth.SrcMAC = pbb.SrcMAC eth.DstMAC = pbb.DstMAC } else { panic("Unsupported") } continue } } buf = append(buf, layer) } if found { data.layers = buf } else { return nil, nil, errors.New("pop vlan failed") } } return nil, nil, nil }
func (self *actionList) UnmarshalBinary(data []byte) error { var actions []action for _, msg := range ofp4.ActionHeader(data).Iter() { var act action switch msg.Type() { default: return errors.New("unknown ofp4.Action type") case ofp4.OFPAT_COPY_TTL_OUT, ofp4.OFPAT_COPY_TTL_IN, ofp4.OFPAT_DEC_MPLS_TTL, ofp4.OFPAT_POP_VLAN, ofp4.OFPAT_DEC_NW_TTL, ofp4.OFPAT_POP_PBB: act = actionGeneric{ Type: msg.Type(), } case ofp4.OFPAT_OUTPUT: a := ofp4.ActionOutput(msg) act = actionOutput{ Port: a.Port(), MaxLen: a.MaxLen(), } case ofp4.OFPAT_SET_MPLS_TTL: act = actionMplsTtl{ MplsTtl: ofp4.ActionMplsTtl(msg).MplsTtl(), } case ofp4.OFPAT_PUSH_VLAN, ofp4.OFPAT_PUSH_MPLS, ofp4.OFPAT_PUSH_PBB: act = actionPush{ Type: msg.Type(), Ethertype: ofp4.ActionPush(msg).Ethertype(), } case ofp4.OFPAT_POP_MPLS: act = actionPopMpls{ Ethertype: ofp4.ActionPopMpls(msg).Ethertype(), } case ofp4.OFPAT_SET_QUEUE: act = actionSetQueue{ QueueId: ofp4.ActionSetQueue(msg).QueueId(), } case ofp4.OFPAT_GROUP: act = actionGroup{ GroupId: ofp4.ActionGroup(msg).GroupId(), } case ofp4.OFPAT_SET_NW_TTL: act = actionNwTtl{ NwTtl: ofp4.ActionNwTtl(msg).NwTtl(), } case ofp4.OFPAT_SET_FIELD: f := ofp4.ActionSetField(msg).Field() act = actionSetField{ Field: f[:f.Header().Length()+4], } case ofp4.OFPAT_EXPERIMENTER: a := ofp4.ActionExperimenterHeader(msg) if handler, ok := actionHandlers[a.Experimenter()]; ok { act = actionExperimenter{ Experimenter: a.Experimenter(), Data: msg[8:], Handler: handler, } } else { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_ACTION, ofp4.OFPBAC_BAD_EXPERIMENTER, ) } } actions = append(actions, act) } *self = actions return nil }
func (self *ofmMeterMod) Map() Reducable { pipe := self.pipe req := ofp4.MeterMod(self.req) switch req.Command() { case ofp4.OFPMC_ADD: meterId := req.MeterId() if meterId == 0 || (meterId > ofp4.OFPM_MAX && meterId != ofp4.OFPM_CONTROLLER) { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_METER_MOD_FAILED, ofp4.OFPMMFC_INVALID_METER)) } else { var bands bandList if err := bands.UnmarshalBinary(req.Bands()); err != nil { log.Print(err) } var highestBand band for _, b := range bands { if highestBand == nil || highestBand.getRate() < b.getRate() { highestBand = b } } newMeter := &meter{ lock: &sync.Mutex{}, created: time.Now(), bands: bands, highestBand: highestBand, } if req.Flags()&ofp4.OFPMF_PKTPS != 0 { newMeter.flagPkts = true } if req.Flags()&ofp4.OFPMF_BURST != 0 { newMeter.flagBurst = true } if req.Flags()&ofp4.OFPMF_STATS != 0 { newMeter.flagStats = true } if err := func() error { pipe.lock.Lock() defer pipe.lock.Unlock() if _, exists := pipe.meters[meterId]; exists { return ofp4.MakeErrorMsg( ofp4.OFPET_METER_MOD_FAILED, ofp4.OFPMMFC_METER_EXISTS, ) } else { pipe.meters[meterId] = newMeter } return nil }(); err != nil { if e, ok := err.(ofp4.ErrorMsg); ok { self.putError(e) } else { log.Print(err) } } } case ofp4.OFPMC_DELETE: meterId := req.MeterId() if err := func() error { pipe.lock.Lock() defer pipe.lock.Unlock() if meterId == ofp4.OFPM_ALL { for meterId, _ := range pipe.meters { pipe.deleteMeterInside(meterId) } } else { return pipe.deleteMeterInside(meterId) } return nil }(); err != nil { if e, ok := err.(ofp4.ErrorMsg); ok { self.putError(e) } else { log.Print(err) } } case ofp4.OFPMC_MODIFY: // XXX: } return self }
func (self actionPush) Process(data *Frame) (*outputToPort, *outputToGroup, error) { var buf []gopacket.Layer found := false switch self.Type { case ofp4.OFPAT_PUSH_VLAN: for i, layer := range data.Layers() { buf = append(buf, layer) if found == false { switch layer.LayerType() { case layers.LayerTypeEthernet: eth := layer.(*layers.Ethernet) ethertype := eth.EthernetType eth.EthernetType = layers.EthernetType(self.Ethertype) dot1q := &layers.Dot1Q{Type: ethertype} if d, ok := data.layers[i+1].(*layers.Dot1Q); ok { dot1q.Priority = d.Priority dot1q.DropEligible = d.DropEligible dot1q.VLANIdentifier = d.VLANIdentifier } buf = append(buf, dot1q) found = true } } } case ofp4.OFPAT_PUSH_MPLS: for i, layer := range data.Layers() { if found == false { var ttl uint8 var base gopacket.Layer var mpls *layers.MPLS switch t := layer.(type) { case *layers.MPLS: base = data.layers[i-1] ttl = t.TTL mpls = t case *layers.IPv4: base = data.layers[i-1] ttl = t.TTL case *layers.IPv6: base = data.layers[i-1] ttl = t.HopLimit case *layers.ARP: base = data.layers[i-1] } if base != nil { if base.LayerType() == layers.LayerTypeEthernet { base.(*layers.Ethernet).EthernetType = layers.EthernetType(self.Ethertype) } else if base.LayerType() == layers.LayerTypeDot1Q { base.(*layers.Dot1Q).Type = layers.EthernetType(self.Ethertype) } else { return nil, nil, errors.New("unsupported") } if mpls != nil { buf = append(buf, &layers.MPLS{ Label: mpls.Label, TrafficClass: mpls.TrafficClass, StackBottom: false, TTL: ttl, }) } else { buf = append(buf, &layers.MPLS{ StackBottom: true, TTL: ttl, }) } found = true } } buf = append(buf, layer) } case ofp4.OFPAT_PUSH_PBB: for _, layer := range data.Layers() { buf = append(buf, layer) if found == false { switch layer.LayerType() { case layers.LayerTypeEthernet: eth := layer.(*layers.Ethernet) ethertype := eth.EthernetType eth.EthernetType = layers.EthernetType(self.Ethertype) buf = append(buf, &layers2.PBB{ DstMAC: eth.DstMAC, SrcMAC: eth.SrcMAC, Type: ethertype, }) found = true } } } default: return nil, nil, ofp4.MakeErrorMsg( ofp4.OFPET_BAD_ACTION, ofp4.OFPBAC_BAD_TYPE, ) } if found { data.layers = buf } else { return nil, nil, errors.New("push vlan failed") } return nil, nil, nil }