Beispiel #1
0
// Send a packet, creating a corresponding ODP flow rule if possible
func (fastdp *FastDatapath) send(fops FlowOp, frame []byte, lock *fastDatapathLock) {
	// Gather the actions from actionFlowOps, execute any others
	var dec *EthernetDecoder
	flow := odp.NewFlowSpec()
	createFlow := true

	for _, xfop := range FlattenFlowOp(fops) {
		switch fop := xfop.(type) {
		case interface {
			updateFlowSpec(*odp.FlowSpec)
		}:
			fop.updateFlowSpec(&flow)
		case vetoFlowCreationFlowOp:
			createFlow = false
		default:
			// A foreign FlowOp (e.g. a sleeve forwarding
			// FlowOp), so send the packet through the
			// FlowOp interface, decoding the packet
			// lazily.
			if dec == nil {
				dec = fastdp.takeDecoder(lock)
				dec.DecodeLayers(frame)

				// If we are sending the packet
				// through the FlowOp interface, we
				// mustn't create a flow, as that
				// could prevent the proper handling
				// of similar packets in the future.
				createFlow = false
			}

			if len(dec.decoded) != 0 {
				lock.unlock()
				fop.Process(frame, dec, false)
			}
		}
	}

	if dec != nil {
		// put the decoder back
		lock.relock()
		fastdp.dec = dec
	}

	if len(flow.Actions) != 0 {
		lock.relock()
		checkWarn(fastdp.dp.Execute(frame, nil, flow.Actions))
	}

	if createFlow {
		lock.relock()
		// if the fastdp's deleteFlowsCount changed since we
		// initially locked it, then we might have created a
		// flow on the basis of stale information.  It's fine
		// to handle one packet like that, but it would be bad
		// to introduce a stale flow.
		if lock.deleteFlowsCount == fastdp.deleteFlowsCount {
			log.Debug("Creating ODP flow ", flow)
			checkWarn(fastdp.dp.CreateFlow(flow))
		}
	}
}
Beispiel #2
0
func flagsToFlowSpec(f Flags, dpif *odp.Dpif) (dp odp.DatapathHandle, flow odp.FlowSpec, ok bool) {
	flow = odp.NewFlowSpec()

	var inPort string
	f.StringVar(&inPort, "in-port", "", "key: incoming vport")

	var ethSrc, ethDst string
	f.StringVar(&ethSrc, "eth-src", "", "key: ethernet source MAC")
	f.StringVar(&ethDst, "eth-dst", "", "key: ethernet destination MAC")

	var tun tunnelFlags
	addTunnelFlags(f, &tun, "tunnel-", "tunnel ")

	var setTun tunnelFlags
	addTunnelFlags(f, &setTun, "set-tunnel-", "action: set tunnel ")

	var output string
	f.StringVar(&output, "output", "", "action: output to vports")

	args := f.Parse(1, 1)
	dpp, _ := lookupDatapath(dpif, args[0])
	if dpp == nil {
		return
	}

	if inPort != "" {
		vport, err := dpp.LookupVportByName(inPort)
		if err != nil {
			printErr("%s", err)
			return
		}
		flow.AddKey(odp.NewInPortFlowKey(vport.ID))
	}

	// The ethernet flow key is mandatory
	err := handleEthernetFlowKeyOptions(flow, ethSrc, ethDst)
	if err != nil {
		printErr("%s", err)
		return
	}

	flowKey, err := parseTunnelFlags(&tun)
	if err != nil {
		printErr("%s", err)
		return
	}

	if !flowKey.Ignored() {
		flow.AddKey(flowKey)
	}

	// Actions are ordered, but flags aren't.  As a temporary
	// hack, we already put SET actions before an OUTPUT action.

	setTunAttrs, err := parseSetTunnelFlags(&setTun)
	if err != nil {
		printErr("%s", err)
		return
	}

	if setTunAttrs != nil {
		flow.AddAction(*setTunAttrs)
	}

	if output != "" {
		for _, vpname := range strings.Split(output, ",") {
			vport, err := dpp.LookupVportByName(vpname)
			if err != nil {
				printErr("%s", err)
				return
			}
			flow.AddAction(odp.NewOutputAction(vport.ID))
		}
	}

	return *dpp, flow, true
}