func (fastdp *FastDatapath) makeBridgeVport(vport odp.Vport) { // Set up a bridge port for netdev and internal vports. vxlan // vports are handled separately, as they do not correspond to // bridge ports (we set up the miss handler for them in // getVxlanVportID). typ := vport.Spec.TypeName() if typ != "netdev" && typ != "internal" { return } vportID := vport.ID // Sending to the bridge port outputs on the vport: fastdp.addSendToPort(bridgePortID{vport: vportID}, func(_ PacketKey, _ *fastDatapathLock) FlowOp { return fastdp.odpActions(odp.NewOutputAction(vportID)) }) // Delete flows, in order to recalculate flows for broadcasts // on the bridge. checkWarn(fastdp.deleteFlows()) // Packets coming from the netdev are processed by the bridge fastdp.missHandlers[vportID] = func(flowKeys odp.FlowKeys, lock *fastDatapathLock) FlowOp { return fastdp.bridge(bridgePortID{vport: vportID}, flowKeysToPacketKey(flowKeys), lock) } }
func (fwd *fastDatapathForwarder) Forward(key ForwardPacketKey) FlowOp { if !key.SrcPeer.HasShortID || !key.DstPeer.HasShortID { return nil } fwd.lock.RLock() defer fwd.lock.RUnlock() if fwd.remoteAddr == nil { // Returning nil would discard the packet, but also // result in a flow rule, which we would have to // invalidate when we learn the remote IP. So for // now, just prevent flows. return vetoFlowCreationFlowOp{} } remoteIP, err := ipv4Bytes(fwd.remoteAddr.IP) if err != nil { log.Error(err) return DiscardingFlowOp{} } var sta odp.SetTunnelAction sta.SetTunnelId(tunnelIDFor(key)) sta.SetIpv4Src(fwd.localIP) sta.SetIpv4Dst(remoteIP) sta.SetTos(0) sta.SetTtl(64) sta.SetDf(true) sta.SetCsum(false) return fwd.fastdp.odpActions(sta, odp.NewOutputAction(fwd.vxlanVportID)) }
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(ðSrc, "eth-src", "", "key: ethernet source MAC") f.StringVar(ðDst, "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 }