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 Connected(i *memif.Interface) error {
51 fmt.Println("Connected: ", i.GetName())
53 data, ok := i.GetPrivateData().(*interfaceData)
55 return fmt.Errorf("Invalid private data")
57 data.errChan = make(chan error, 1)
58 data.quitChan = make(chan struct{}, 1)
61 go func(errChan chan<- error, quitChan <-chan struct{}, wg *sync.WaitGroup) {
63 // allocate packet buffer
64 pkt := make([]byte, 2048)
66 rxq0, err := i.GetRxQueue(0)
72 txq0, err := i.GetTxQueue(0)
79 case <-quitChan: // channel closed
82 // read packet from shared memory
83 pktLen, err := rxq0.ReadPacket(pkt)
85 fmt.Printf("pktLen: %d\n", pktLen)
86 gopkt := gopacket.NewPacket(pkt[:pktLen], layers.LayerTypeEthernet, gopacket.NoCopy)
87 etherLayer := gopkt.Layer(layers.LayerTypeEthernet)
88 if etherLayer.(*layers.Ethernet).EthernetType == layers.EthernetTypeARP {
90 rEth := layers.Ethernet{
91 SrcMAC: net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
92 DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
93 EthernetType: layers.EthernetTypeARP,
96 AddrType: layers.LinkTypeEthernet,
97 Protocol: layers.EthernetTypeIPv4,
100 Operation: layers.ARPReply,
101 SourceHwAddress: []byte(net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}),
102 SourceProtAddress: []byte("\xc0\xa8\x01\x01"),
103 DstHwAddress: []byte(net.HardwareAddr{0x02, 0xfe, 0x08, 0x88, 0x45, 0x7f}),
104 DstProtAddress: []byte("\xc0\xa8\x01\x02"),
106 buf := gopacket.NewSerializeBuffer()
107 opts := gopacket.SerializeOptions{
109 ComputeChecksums: true,
111 gopacket.SerializeLayers(buf, opts, &rEth, &rArp)
112 // write packet to shared memory
113 txq0.WritePacket(buf.Bytes())
116 if etherLayer.(*layers.Ethernet).EthernetType == layers.EthernetTypeIPv4 {
117 ipLayer := gopkt.Layer(layers.LayerTypeIPv4)
119 fmt.Println("Missing IPv4 layer.")
122 ipv4, _ := ipLayer.(*layers.IPv4)
123 if ipv4.Protocol != layers.IPProtocolICMPv4 {
124 fmt.Println("Not ICMPv4 protocol.")
126 icmpLayer := gopkt.Layer(layers.LayerTypeICMPv4)
127 if icmpLayer == nil {
128 fmt.Println("Missing ICMPv4 layer.")
130 icmp, _ := icmpLayer.(*layers.ICMPv4)
131 if icmp.TypeCode.Type() != layers.ICMPv4TypeEchoRequest {
132 fmt.Println("Not ICMPv4 echo request.")
134 fmt.Println("Received an ICMPv4 echo request.")
136 // Build packet layers.
137 ethResp := layers.Ethernet{
138 DstMAC: net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
139 //DstMAC: net.HardwareAddr{0x02, 0xfe, 0xa8, 0x77, 0xaf, 0x20},
140 SrcMAC: []byte(net.HardwareAddr{0x02, 0xfe, 0x08, 0x88, 0x45, 0x7f}),
142 EthernetType: layers.EthernetTypeIPv4,
144 ipv4Resp := layers.IPv4{
152 Protocol: layers.IPProtocolICMPv4,
153 SrcIP: []byte("\xc0\xa8\x01\x01"),
154 DstIP: []byte("\xc0\xa8\x01\x02"),
156 icmpResp := layers.ICMPv4{
157 TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeEchoReply, 0),
162 // Set up buffer and options for serialization.
163 buf := gopacket.NewSerializeBuffer()
164 opts := gopacket.SerializeOptions{
166 ComputeChecksums: true,
168 gopacket.SerializeLayers(buf, opts, ðResp, &ipv4Resp, &icmpResp,
169 gopacket.Payload(icmp.Payload))
170 // write packet to shared memory
171 txq0.WritePacket(buf.Bytes())
173 } else if err != nil {
179 }(data.errChan, data.quitChan, &data.wg)
184 type interfaceData struct {
186 quitChan chan struct{}
190 func interractiveHelp() {
191 fmt.Println("help - print this help")
192 fmt.Println("start - start connecting loop")
193 fmt.Println("show - print interface details")
194 fmt.Println("exit - exit the application")
198 cpuprof := flag.String("cpuprof", "", "cpu profiling output file")
199 memprof := flag.String("memprof", "", "mem profiling output file")
200 role := flag.String("role", "slave", "interface role")
201 name := flag.String("name", "gomemif", "interface name")
202 socketName := flag.String("socket", "", "control socket filename")
207 defer profile.Start(profile.CPUProfile, profile.ProfilePath(*cpuprof)).Stop()
210 defer profile.Start(profile.MemProfile, profile.ProfilePath(*memprof)).Stop()
213 memifErrChan := make(chan error)
214 exitChan := make(chan struct{})
223 fmt.Println("Invalid role")
227 fmt.Println("GoMemif: Responder")
228 fmt.Println("-----------------------")
230 socket, err := memif.NewSocket("gomemif_example", *socketName)
232 fmt.Println("Failed to create socket: ", err)
236 data := interfaceData{}
237 args := &memif.Arguments{
239 ConnectedFunc: Connected,
240 DisconnectedFunc: Disconnected,
245 i, err := socket.NewInterface(args)
247 fmt.Println("Failed to create interface on socket %s: %s", socket.GetFilename(), err)
251 // slave attempts to connect to control socket
252 // to handle control communication call socket.StartPolling()
254 fmt.Println(args.Name, ": Connecting to control socket...")
255 for !i.IsConnecting() {
256 err = i.RequestConnection()
258 /* TODO: check for ECONNREFUSED errno
259 * if error is ECONNREFUSED it may simply mean that master
260 * interface is not up yet, use i.RequestConnection()
262 fmt.Println("Faild to connect: ", err)
268 go func(exitChan chan<- struct{}) {
269 reader := bufio.NewReader(os.Stdin)
271 fmt.Print("gomemif# ")
272 text, _ := reader.ReadString('\n')
273 // convert CRLF to LF
274 text = strings.Replace(text, "\n", "", -1)
279 // start polling for events on this socket
280 socket.StartPolling(memifErrChan)
282 fmt.Println("remote: ", i.GetRemoteName())
283 fmt.Println("peer: ", i.GetPeerName())
285 err = socket.StopPolling()
287 fmt.Println("Failed to stop polling: ", err)
292 fmt.Println("Unknown input")
301 case err, ok := <-memifErrChan:
305 case err, ok := <-data.errChan: