Skip to content

Instantly share code, notes, and snippets.

@mkfsn
Created April 16, 2018 08:58
Show Gist options
  • Save mkfsn/139274a9d0368c76c86f13ea0aa41fcc to your computer and use it in GitHub Desktop.
Save mkfsn/139274a9d0368c76c86f13ea0aa41fcc to your computer and use it in GitHub Desktop.
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