Created
April 16, 2018 08:58
-
-
Save mkfsn/139274a9d0368c76c86f13ea0aa41fcc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"os/exec" | |
"sync" | |
"os" | |
"flag" | |
"os/signal" | |
"syscall" | |
// "XXXXXXXX/devices" | |
"github.com/intel-go/nff-go/flow" | |
"github.com/intel-go/nff-go/packet" | |
) | |
const ( | |
PacketDrop = false | |
PacketAccept = true | |
defaultPort uint8 = 0 | |
) | |
type nff struct { | |
stop chan struct{} | |
incomming chan *packet.Packet | |
verdict chan bool | |
port uint8 | |
device *devices.DeviceInfo | |
ifName string | |
driver string | |
*sync.WaitGroup | |
} | |
func NewNFF(ifName string) (*nff, error) { | |
nffInstance := &nff{ | |
stop: make(chan struct{}), | |
port: defaultPort, | |
incomming: make(chan *packet.Packet), | |
verdict: make(chan bool), | |
ifName: ifName, | |
WaitGroup: &sync.WaitGroup{}, | |
} | |
if err := nffInstance.register(ifName); err != nil { | |
return nil, err | |
} | |
if err := nffInstance.init(); err != nil { | |
return nil, err | |
} | |
return nffInstance, nil | |
} | |
func (n *nff) Run() { | |
go func() { | |
n.Add(1) | |
defer n.Done() | |
for { | |
select { | |
case <-n.stop: | |
return | |
case pkt := <-n.incomming: | |
// Handle packet | |
log.Println(pkt) | |
n.verdict <- PacketAccept | |
} | |
} | |
}() | |
} | |
func (n *nff) Close() error { | |
close(n.stop) | |
n.Wait() | |
if err := n.unregister(); err != nil { | |
return err | |
} | |
return nil | |
} | |
func (n *nff) register(ifName string) error { | |
// 1. Get interface information | |
ifInfo, err := devices.GetInterfaceInfo(ifName) | |
if err != nil { | |
return err | |
} | |
n.device = ifInfo.Device | |
n.driver = n.device.Driver | |
// 2. Unbind current driver | |
// sudo ./devbind -u 0000:00:04.0 | |
if err := n.device.Unbind(); err != nil { | |
return err | |
} | |
// 3. Bind PMD Driver | |
err = n.device.Bind(devices.DefaultDpdkDriver) | |
if err != nil { | |
return err | |
} | |
return nil | |
} | |
func (n *nff) unregister() error { | |
// 1. Unbind device | |
// devbind -u 0000:00:04.0 | |
if err := n.device.Unbind(); err != nil { | |
return fmt.Errorf("Failed to unbind device: %s", err.Error()) | |
} | |
// 2. Bind original driver | |
// devbind -b virtio-pci 0000:00:04.0 | |
if err := n.device.Bind(n.driver); err != nil { | |
return fmt.Errorf("Failed to bind device: %s", err.Error()) | |
} | |
// 3. Bring interface up | |
cmd := exec.Command("ip", "link", "set", "dev", n.ifName, "up") | |
if _, err := cmd.Output(); err != nil { | |
return fmt.Errorf("Failed to bring interface %s up: %s", n.ifName, err.Error()) | |
} | |
return nil | |
} | |
func (n *nff) init() error { | |
config := &flow.Config{ | |
HWTXChecksum: true, | |
} | |
flow.SystemInit(config) | |
// NOTE: Must be called after flow.SystemInit | |
n.port = defaultPort | |
// Main flow from receiver (port 0) | |
mainFlow, err := flow.SetReceiver(n.port) | |
if err != nil { | |
return err | |
} | |
// Packet handler: rewrite and filter packet | |
if err := flow.SetHandlerDrop(mainFlow, n.handler, nil); err != nil { | |
return err | |
} | |
// Send packet back to port 0 | |
if err := flow.SetSender(mainFlow, n.port); err != nil { | |
return err | |
} | |
go func() { | |
if err := flow.SystemStart(); err != nil { | |
log.Fatal("Failed to start system:", err.Error()) | |
} | |
}() | |
return nil | |
} | |
func (n *nff) handler(pkt *packet.Packet, _ flow.UserContext) bool { | |
if pkt == nil { | |
return PacketDrop | |
} | |
n.incomming <- pkt | |
return <-n.verdict | |
} | |
func main() { | |
var iface string | |
flag.StringVar(&iface, "i", "eth0", "interface to run DPDK") | |
flag.Parse() | |
nff, err := NewNFF(iface) | |
if err != nil { | |
log.Fatal("Failed to construct nff:", err.Error()) | |
} | |
log.Println("NFF starting") | |
nff.Run() | |
log.Println("NFF started") | |
defer func() { | |
log.Println("NFF stopping") | |
if err := nff.Close(); err != nil { | |
log.Println("NFF failed to stop:", err.Error()) | |
} else { | |
log.Println("NFF stopped successfully") | |
} | |
}() | |
sig := make(chan os.Signal) | |
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) | |
<-sig | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment