1 // raw-data is a basic example showing how to create a memif interface, handle
2 // events through callbacks and perform Rx/Tx of raw data. Before handling
3 // an actual packets it is important to understand the skeleton of libmemif-based
6 // Since VPP expects proper packet data, it is not very useful to connect
7 // raw-data example with VPP, even though it will work, since all the received
8 // data will get dropped on the VPP side.
10 // To create a connection of two raw-data instances, run two processes
15 // $ ./raw-data --slave
17 // Every 3 seconds both sides send 3 raw-data packets to the opposite end through
18 // each queue. The received packets are printed to stdout.
20 // Stop an instance of raw-data with an interrupt signal.
31 "go.fd.io/govpp/extras/libmemif"
35 // Socket through which the opposite memifs will establish the connection.
36 Socket = "/tmp/raw-data-example"
38 // Secret used to authenticate the memif connection.
41 // ConnectionID is an identifier used to match opposite memifs.
44 // NumQueues is the (configured!) number of queues for both Rx & Tx.
45 // The actual number agreed during connection establishment may be smaller!
49 // For management of go routines.
51 var stopCh chan struct{}
53 // OnConnect is called when a memif connection gets established.
54 func OnConnect(memif *libmemif.Memif) (err error) {
55 details, err := memif.GetDetails()
57 fmt.Printf("libmemif.GetDetails() error: %v\n", err)
59 fmt.Printf("memif %s has been connected: %+v\n", memif.IfName, details)
61 stopCh = make(chan struct{})
62 // Start a separate go routine for each queue.
63 // (memif queue is a unit of parallelism for Rx/Tx)
64 // Beware: the number of queues created may be lower than what was requested
65 // in MemifConfiguration (the master makes the final decision).
66 // Use Memif.GetDetails to get the number of queues.
68 for i = 0; i < uint8(len(details.RxQueues)); i++ {
70 go ReadAndPrintPackets(memif, i)
72 for i = 0; i < uint8(len(details.TxQueues)); i++ {
74 go SendPackets(memif, i)
79 // OnDisconnect is called when a memif connection is lost.
80 func OnDisconnect(memif *libmemif.Memif) (err error) {
81 fmt.Printf("memif %s has been disconnected\n", memif.IfName)
82 // Stop all packet producers and consumers.
88 // ReadAndPrintPackets keeps receiving raw packet data from a selected queue
89 // and prints them to stdout.
90 func ReadAndPrintPackets(memif *libmemif.Memif, queueID uint8) {
93 // Get channel which fires every time there are packets to read on the queue.
94 interruptCh, err := memif.GetQueueInterruptChan(queueID)
96 // Example of libmemif error handling code:
98 case libmemif.ErrQueueID:
99 fmt.Printf("libmemif.Memif.GetQueueInterruptChan() complains about invalid queue id!?")
100 // Here you would put all the errors that need to be handled individually...
102 fmt.Printf("libmemif.Memif.GetQueueInterruptChan() error: %v\n", err)
110 // Read all packets from the queue but at most 10 at once.
111 // Since there is only one interrupt signal sent for an entire burst
112 // of packets, an interrupt handling routine should repeatedly call
113 // RxBurst() until the function returns an empty slice of packets.
114 // This way it is ensured that there are no packets left
115 // on the queue unread when the interrupt signal is cleared.
117 packets, err := memif.RxBurst(queueID, 10)
119 fmt.Printf("libmemif.Memif.RxBurst() error: %v\n", err)
120 // Skip this burst, continue with the next one 3secs later...
122 if len(packets) == 0 {
123 // No more packets to read until the next interrupt.
126 for _, packet := range packets {
127 fmt.Printf("Received packet queue=%d: %v\n", queueID, string(packet[:]))
137 // SendPackets keeps sending bursts of 3 raw-data packets every 3 seconds into
138 // the selected queue.
139 func SendPackets(memif *libmemif.Memif, queueID uint8) {
145 case <-time.After(3 * time.Second):
147 // Prepare fake packets.
148 packets := []libmemif.RawPacketData{
149 libmemif.RawPacketData("Packet #1 in burst number " + strconv.Itoa(counter)),
150 libmemif.RawPacketData("Packet #2 in burst number " + strconv.Itoa(counter)),
151 libmemif.RawPacketData("Packet #3 in burst number " + strconv.Itoa(counter)),
153 // Send the packets. We may not be able to do it in one burst if the ring
154 // is (almost) full or the internal buffer cannot contain it.
157 count, err := memif.TxBurst(queueID, packets[sent:])
159 fmt.Printf("libmemif.Memif.TxBurst() error: %v\n", err)
162 fmt.Printf("libmemif.Memif.TxBurst() has sent %d packets.\n", count)
164 if sent == len(packets) {
176 fmt.Println("Starting 'raw-data' example...")
178 // If run with the "--slave" option, create memif in the slave mode.
181 if len(os.Args) > 1 && (os.Args[1] == "--slave" || os.Args[1] == "-slave") {
186 // Initialize libmemif first.
187 appName := "Raw-Data" + appSuffix
188 fmt.Println("Initializing libmemif as ", appName)
189 err := libmemif.Init(appName)
191 fmt.Printf("libmemif.Init() error: %v\n", err)
194 // Schedule automatic cleanup.
195 defer libmemif.Cleanup()
197 // Prepare callbacks to use with the memif.
198 // The same callbacks could be used with multiple memifs.
199 // The first input argument (*libmemif.Memif) can be used to tell which
200 // memif the callback was triggered for.
201 memifCallbacks := &libmemif.MemifCallbacks{
202 OnConnect: OnConnect,
203 OnDisconnect: OnDisconnect,
206 // Prepare memif1 configuration.
207 memifConfig := &libmemif.MemifConfig{
208 MemifMeta: libmemif.MemifMeta{
210 ConnID: ConnectionID,
211 SocketFilename: Socket,
214 Mode: libmemif.IfModeEthernet,
216 MemifShmSpecs: libmemif.MemifShmSpecs{
217 NumRxQueues: NumQueues,
218 NumTxQueues: NumQueues,
224 fmt.Printf("Callbacks: %+v\n", memifCallbacks)
225 fmt.Printf("Config: %+v\n", memifConfig)
227 // Create memif1 interface.
228 memif, err := libmemif.CreateInterface(memifConfig, memifCallbacks)
230 fmt.Printf("libmemif.CreateInterface() error: %v\n", err)
233 // Schedule automatic cleanup of the interface.
236 // Wait until an interrupt signal is received.
237 sigChan := make(chan os.Signal, 1)
238 signal.Notify(sigChan, os.Interrupt)