Пример #1
0
func parseLabeledValue(txt string) (label, value string, eatLen int) {
	feed := txt
	if idx := strings.IndexFunc(txt, oxm.IsSeparator); idx > 0 {
		feed = txt[:idx]
	}
	trail := []rune{}
	for _, c := range txt[len(feed):] {
		if oxm.IsSeparator(c) {
			trail = append(trail, c)
		} else {
			break
		}
	}
	kv := strings.SplitN(feed, "=", 2)
	if len(kv) > 1 {
		return kv[0], kv[1], len(feed) + len(string(trail))
	} else {
		return kv[0], "", len(feed) + len(string(trail))
	}
}
Пример #2
0
func (self *flowRule) Parse(txt string) error {
	var actions []byte
	var delayed func() = nil
	phase := PHASE_MATCH
	for len(txt) > 0 {
		// in case value would include separator, don't use these value and just recalculate
		label, value, step := parseLabeledValue(txt)
		if label[0] == '@' && delayed != nil {
			delayed()
			delayed = nil
		}
		switch label {
		case "@meter":
			phase = PHASE_METER
			var meterId uint32
			if err := parseInt(value, &meterId); err != nil {
				return err
			}
			var inst [8]byte
			binary.BigEndian.PutUint16(inst[:], OFPIT_METER)
			binary.BigEndian.PutUint16(inst[2:], 8)
			binary.BigEndian.PutUint32(inst[4:], meterId)
			self.Instructions = append(self.Instructions, inst[:]...)
		case "@apply", "@apply_actions":
			phase = PHASE_APPLY
			delayed = func() {
				var inst [8]byte
				binary.BigEndian.PutUint16(inst[:], OFPIT_APPLY_ACTIONS)
				binary.BigEndian.PutUint16(inst[2:], uint16(len(actions)+8))
				self.Instructions = append(self.Instructions, inst[:]...)
				self.Instructions = append(self.Instructions, actions...)
				actions = actions[:0]
			}
		case "@clear", "@clear_actions":
			phase = PHASE_CLEAR
			var inst [8]byte
			binary.BigEndian.PutUint16(inst[:], OFPIT_CLEAR_ACTIONS)
			binary.BigEndian.PutUint16(inst[2:], 8)
			self.Instructions = append(self.Instructions, inst[:]...)
		case "@write", "@write_actions":
			phase = PHASE_WRITE
			delayed = func() {
				var inst [8]byte
				binary.BigEndian.PutUint16(inst[:], OFPIT_WRITE_ACTIONS)
				binary.BigEndian.PutUint16(inst[2:], uint16(len(actions)+8))
				self.Instructions = append(self.Instructions, inst[:]...)
				self.Instructions = append(self.Instructions, actions...)
				actions = actions[:0]
			}
		case "@metadata", "@write_metadata":
			phase = PHASE_META

			var v, m uint64
			vm := strings.SplitN(value, "/", 2)
			if err := parseInt(vm[0], &v); err != nil {
				return err
			}
			if len(vm) == 2 {
				if err := parseInt(vm[1], &m); err != nil {
					return err
				}
			} else {
				m = 0xFFFFFFFFFFFFFFFF
			}

			var inst [24]byte
			binary.BigEndian.PutUint16(inst[0:], OFPIT_WRITE_METADATA)
			binary.BigEndian.PutUint16(inst[2:], 24)
			binary.BigEndian.PutUint64(inst[8:], v)
			binary.BigEndian.PutUint64(inst[16:], m)
			self.Instructions = append(self.Instructions, inst[:]...)
		case "@goto", "@goto_table":
			phase = PHASE_GOTO
			var tableId uint8
			if err := parseInt(value, &tableId); err != nil {
				return err
			}
			var inst [8]byte
			binary.BigEndian.PutUint16(inst[:], OFPIT_GOTO_TABLE)
			binary.BigEndian.PutUint16(inst[2:], uint16(len(inst)))
			inst[4] = tableId
			self.Instructions = append(self.Instructions, inst[:]...)
		default:
			switch phase {
			case PHASE_MATCH:
				switch label {
				case "table":
					var v uint8
					if err := parseInt(value, &v); err != nil {
						return err
					}
					self.TableId = v
				case "priority", "idle_timeout", "hard_timeout":
					var v uint16
					if err := parseInt(value, &v); err != nil {
						return err
					}
					switch label {
					case "idle_timeout":
						self.IdleTimeout = v
					case "hard_timeout":
						self.HardTimeout = v
					case "priority":
						self.Priority = v
					}
				case "cookie":
					var v, m uint64
					vm := strings.SplitN(value, "/", 2)
					if err := parseInt(vm[0], &v); err != nil {
						return err
					}
					if len(vm) == 2 {
						if err := parseInt(vm[1], &m); err != nil {
							return err
						}
					}
					self.Cookie = v
					self.CookieMask = m
				case "out_port":
					var v uint32
					if err := parseInt(value, &v); err != nil {
						return err
					}
					self.OutPort = v
				case "out_group", "group":
					var v uint32
					if err := parseInt(value, &v); err != nil {
						return err
					}
					self.OutGroup = v
				default:
					if buf, n, err := oxm.ParseOne(txt); err != nil {
						return err
					} else {
						self.Match = append(self.Match, buf...)
						step = n
					}
				}
			case PHASE_APPLY, PHASE_WRITE:
				if buf, n, err := ParseAction(txt); err != nil {
					break
				} else {
					actions = append(actions, buf...)
					step = n
				}
			}
		}
		for i, c := range txt[step:] {
			if !oxm.IsSeparator(c) {
				step += i
				break
			}
		}
		txt = txt[step:]
	}
	if delayed != nil {
		delayed()
	}
	return nil
}