2 *------------------------------------------------------------------
3 * Copyright (c) 2020 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *------------------------------------------------------------------
31 "github.com/google/gopacket"
32 "github.com/google/gopacket/layers"
33 "github.com/pkg/profile"
36 func Disconnected(i *memif.Interface) error {
37 fmt.Println("Disconnected: ", i.GetName())
39 data, ok := i.GetPrivateData().(*interfaceData)
41 return fmt.Errorf("Invalid private data")
43 close(data.quitChan) // stop polling
45 data.wg.Wait() // wait until polling stops, then continue disconnect
50 func Responder(i *memif.Interface) error {
51 data, ok := i.GetPrivateData().(*interfaceData)
53 return fmt.Errorf("Invalid private data")
55 data.errChan = make(chan error, 1)
56 data.quitChan = make(chan struct{}, 1)
59 // allocate packet buffer
60 pkt := make([]byte, 2048)
62 rxq0, err := i.GetRxQueue(0)
67 txq0, err := i.GetTxQueue(0)
73 // read packet from shared memory
74 pktLen, err := rxq0.ReadPacket(pkt)
77 fmt.Printf("pktLen: %d\n", pktLen)
78 gopkt := gopacket.NewPacket(pkt[:pktLen], layers.LayerTypeEthernet, gopacket.NoCopy)
79 etherLayer := gopkt.Layer(layers.LayerTypeEthernet)
80 if etherLayer.(*layers.Ethernet).EthernetType == layers.EthernetTypeARP {
81 rEth := layers.Ethernet{
82 SrcMAC: net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
83 DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
85 EthernetType: layers.EthernetTypeARP,
88 AddrType: layers.LinkTypeEthernet,
89 Protocol: layers.EthernetTypeIPv4,
92 Operation: layers.ARPReply,
93 SourceHwAddress: []byte(net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}),
94 SourceProtAddress: []byte("\xc0\xa8\x01\x01"),
95 DstHwAddress: []byte(net.HardwareAddr{0x02, 0xfe, 0x08, 0x88, 0x45, 0x7f}),
96 DstProtAddress: []byte("\xc0\xa8\x01\x02"),
98 buf := gopacket.NewSerializeBuffer()
99 opts := gopacket.SerializeOptions{
101 ComputeChecksums: true,
103 gopacket.SerializeLayers(buf, opts, &rEth, &rArp)
104 // write packet to shared memory
105 txq0.WritePacket(buf.Bytes())
108 if etherLayer.(*layers.Ethernet).EthernetType == layers.EthernetTypeIPv4 {
109 ipLayer := gopkt.Layer(layers.LayerTypeIPv4)
111 fmt.Println("Missing IPv4 layer.")
114 ipv4, _ := ipLayer.(*layers.IPv4)
115 if ipv4.Protocol != layers.IPProtocolICMPv4 {
116 fmt.Println("Not ICMPv4 protocol.")
118 icmpLayer := gopkt.Layer(layers.LayerTypeICMPv4)
119 if icmpLayer == nil {
120 fmt.Println("Missing ICMPv4 layer.")
122 icmp, _ := icmpLayer.(*layers.ICMPv4)
123 if icmp.TypeCode.Type() != layers.ICMPv4TypeEchoRequest {
124 fmt.Println("Not ICMPv4 echo request.")
126 fmt.Println("Received an ICMPv4 echo request.")
128 // Build packet layers.
129 ethResp := layers.Ethernet{
130 DstMAC: net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
131 //DstMAC: net.HardwareAddr{0x02, 0xfe, 0xa8, 0x77, 0xaf, 0x20},
132 SrcMAC: []byte(net.HardwareAddr{0x02, 0xfe, 0x08, 0x88, 0x45, 0x7f}),
134 EthernetType: layers.EthernetTypeIPv4,
136 ipv4Resp := layers.IPv4{
144 Protocol: layers.IPProtocolICMPv4,
145 SrcIP: []byte("\xc0\xa8\x01\x01"),
146 DstIP: []byte("\xc0\xa8\x01\x02"),
148 icmpResp := layers.ICMPv4{
149 TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeEchoReply, 0),
154 // Set up buffer and options for serialization.
155 buf := gopacket.NewSerializeBuffer()
156 opts := gopacket.SerializeOptions{
158 ComputeChecksums: true,
160 gopacket.SerializeLayers(buf, opts, ðResp, &ipv4Resp, &icmpResp,
161 gopacket.Payload(icmp.Payload))
162 // write packet to shared memory
163 txq0.WritePacket(buf.Bytes())
172 func Connected(i *memif.Interface) error {
173 data, ok := i.GetPrivateData().(*interfaceData)
175 return fmt.Errorf("Invalid private data")
179 // allocate packet buffer
180 pkt := make([]byte, 2048)
182 rxq0, err := i.GetRxQueue(0)
185 // read packet from shared memory
186 pktLen, err := rxq0.ReadPacket(pkt)
192 type interfaceData struct {
194 quitChan chan struct{}
198 func interractiveHelp() {
199 fmt.Println("help - print this help")
200 fmt.Println("start - start connecting loop")
201 fmt.Println("show - print interface details")
202 fmt.Println("exit - exit the application")
206 cpuprof := flag.String("cpuprof", "", "cpu profiling output file")
207 memprof := flag.String("memprof", "", "mem profiling output file")
208 role := flag.String("role", "slave", "interface role")
209 name := flag.String("name", "gomemif", "interface name")
210 socketName := flag.String("socket", "/run/vpp/memif.sock", "control socket filename")
215 defer profile.Start(profile.CPUProfile, profile.ProfilePath(*cpuprof)).Stop()
218 defer profile.Start(profile.MemProfile, profile.ProfilePath(*memprof)).Stop()
221 memifErrChan := make(chan error)
222 exitChan := make(chan struct{})
231 fmt.Println("Invalid role")
235 fmt.Println("GoMemif: Responder")
236 fmt.Println("-----------------------")
238 socket, err := memif.NewSocket("gomemif_example", *socketName)
240 fmt.Println("Failed to create socket: ", err)
244 data := interfaceData{}
245 args := &memif.Arguments{
247 ConnectedFunc: Connected,
248 DisconnectedFunc: Disconnected,
251 InterruptFunc: Responder,
254 i, err := socket.NewInterface(args)
256 fmt.Println("Failed to create interface on socket %s: %s", socket.GetFilename(), err)
260 // slave attempts to connect to control socket
261 // to handle control communication call socket.StartPolling()
263 fmt.Println(args.Name, ": Connecting to control socket...")
264 for !i.IsConnecting() {
265 err = i.RequestConnection()
267 /* TODO: check for ECONNREFUSED errno
268 * if error is ECONNREFUSED it may simply mean that master
269 * interface is not up yet, use i.RequestConnection()
271 fmt.Println("Failed to connect: ", err)
277 go func(exitChan chan<- struct{}) {
278 reader := bufio.NewReader(os.Stdin)
280 fmt.Print("gomemif# ")
281 text, _ := reader.ReadString('\n')
282 // convert CRLF to LF
283 text = strings.Replace(text, "\n", "", -1)
288 // start polling for events on this socket
289 socket.StartPolling(memifErrChan)
291 fmt.Println("remote: ", i.GetRemoteName())
292 fmt.Println("peer: ", i.GetPeerName())
294 err = socket.StopPolling()
296 fmt.Println("Failed to stop polling: ", err)
301 fmt.Println("Unknown input")
310 case err, ok := <-memifErrChan:
314 case err, ok := <-data.errChan: