model: add arp skeleton
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 29 Jan 2015 18:17:45 +0000 (19:17 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 29 Jan 2015 18:17:45 +0000 (19:17 +0100)
liteeth/common.py
liteeth/test/common.py
liteeth/test/model/arp.py [new file with mode: 0644]
liteeth/test/model/mac.py

index d66e7c190aca2d3969a916183be9aa8cbc0a1ef5..e68e4c49826b332d82ba30bcc7ecaebcc898e1c0 100644 (file)
@@ -1,3 +1,4 @@
+import math
 from collections import OrderedDict
 
 from migen.fhdl.std import *
@@ -22,6 +23,9 @@ class HField():
                self.offset = offset
                self.width = width
 
+ethernet_type_ip = 0x800
+ethernet_type_arp = 0x806
+
 mac_header_len = 14
 mac_header = {
        "destination_mac_address":      HField(0,  0, 48),
@@ -29,8 +33,11 @@ mac_header = {
        "ethernet_type":                        HField(12, 0, 16)
 }
 
-ethernet_type_ip = 0x800
-ethernet_type_arp = 0x806
+arp_packet_length = 60
+arp_hwtype_ethernet = 0x0001
+arp_proto_ip = 0x0800
+arp_opcode_request = 0x0001
+arp_opcode_reply = 0x0002
 
 arp_header_len = 28
 arp_header = {
index 844584b98fcb32d132bf10605d2555ff4075ec20..684be80aae2693a82467b79e806752b22d9a1b81 100644 (file)
@@ -19,6 +19,20 @@ def seed_to_data(seed, random=True):
        else:
                return seed
 
+def split_bytes(v, n):
+       r = []
+       r_bytes = v.to_bytes(n, byteorder="little")
+       for byte in r_bytes:
+               r.append(int(byte))
+       return r
+
+def merge_bytes(b):
+       return int.from_bytes(bytes(b), "little")
+
+def get_field_data(field, datas):
+       v = merge_bytes(datas[field.byte:field.byte+math.ceil(field.width/8)])
+       return (v >> field.offset) & (2**field.width-1)
+
 def comp(p1, p2):
        r = True
        for x, y in zip(p1, p2):
@@ -58,7 +72,7 @@ class Packet(list):
                        self.append(data)
 
 class PacketStreamer(Module):
-       def __init__(self, description, last_be=None):
+       def __init__(self, description, last_be=1):
                self.source = Source(description)
                self.last_be = last_be
                ###
diff --git a/liteeth/test/model/arp.py b/liteeth/test/model/arp.py
new file mode 100644 (file)
index 0000000..e0a80f2
--- /dev/null
@@ -0,0 +1,111 @@
+import math, binascii
+
+from liteeth.common import *
+from liteeth.mac.common import *
+from liteeth.test.common import *
+from liteeth.test.mac import *
+
+def print_arp(s):
+       print_with_prefix(s, "[ARP]")
+
+preamble = split_bytes(eth_preamble, 8)
+
+# ARP model
+class ARPPacket(Packet):
+       def __init__(self, init=[]):
+               Packet.__init__(self, init)
+
+       def decode(self):
+               header = []
+               for byte in self[:arp_header_len]:
+                       header.append(self.pop(0))
+               for k, v in sorted(arp_header.items()):
+                       setattr(self, k, get_field_data(v, header))
+
+       def encode(self):
+               header = 0
+               for k, v in sorted(arp_header.items()):
+                       header |= (getattr(self, k) << (v.byte*8+v.offset))
+               for d in reversed(split_bytes(header, arp_header_len)):
+                       self.insert(0, d)
+
+       def __repr__(self):
+               r = "--------\n"
+               for k in sorted(arp_header.keys()):
+                       r += k + " : 0x%x" %getattr(self,k) + "\n"
+               r += "payload: "
+               for d in self:
+                       r += "%02x" %d
+               return r
+
+class ARP(Module):
+       def  __init__(self, mac, ip_address, mac_address, debug=False):
+               self.mac = mac
+               self.ip_address = ip_address
+               self.mac_address = mac_addres
+               self.debug = debug
+               self.tx_packets = []
+               self.tx_packet = ARPPacket()
+               self.rx_packet = ARPPacket()
+               self.table = {}
+               self.request_pending = False
+
+               self.mac.set_arp_callback(self.callback)
+
+       def send(self, packet):
+               if self.debug:
+                       print_arp(">>>>>>>>")
+                       print_arp(packet)
+               packet.encode()
+               self.mac.send(MACPacket(packet))
+
+       def callback(self, packet):
+               packet = ARPPacket(datas)
+               packet.decode()
+               if self.debug:
+                       print_arp("<<<<<<<<")
+                       print_arp(packet)
+               self.process_packet()
+
+       def process(self, packet):
+               if len(packet) != arp_packet_length-arp_header_length:
+                       raise ValueError
+               if packet.hardware_type != arp_hwtype_ethernet:
+                       raise ValueError
+               if packet.protocol_type != arp_proto_ip:
+                       raise ValueError
+               if packet.hardware_address_length != 6:
+                       raise ValueError
+               if packet.protocol_address_length != 4:
+                       raise ValueError
+               if packet.operation == arp_opcode_request:
+                       self.process_request(packet)
+               elif packet.operation == arp_opcode_reply:
+                       self.process_reply(packet)
+       
+       def process_request(self, request):
+               if request.destination_ip_address = self.ip_address:
+                       reply = ARPPacket([0]*(arp_packet_length-arp_header_length))
+                       reply.hardware_type = arp_hwtype_ethernet
+                       reply.protocol_type = arp_proto_ip
+                       reply.hardware_address_length = 6
+                       reply.protocol_address_length = 4
+                       reply.source_mac_address = self.mac_address
+                       reply.source_ip_address = self.ip_address
+                       reply.destination_mac_address = request.source_mac_address
+                       reply.destination_ip_address = request.source_ip_address
+                       self.send(reply)
+
+       def process_reply(self, reply):
+               self.table[reply.source_ip_address] = reply.source_mac_address
+
+       def request(self, ip_address):
+               request = ARPPacket([0]*(arp_packet_length-arp_header_length))
+               request.hardware_type = arp_hwtype_ethernet
+               request.protocol_type = arp_proto_ip
+               request.hardware_address_length = 6
+               request.protocol_address_length = 4
+               request.source_mac_address = self.mac_address
+               request.source_ip_address = self.ip_address
+               request.destination_mac_address = 0xffffffffffff
+               request.destination_ip_address = ip_address
index 72656af4ff700e06c562c830900e98dd192bfe87..7af991be827fb9535d103139ffb73b440693795b 100644 (file)
@@ -4,20 +4,6 @@ from liteeth.common import *
 from liteeth.mac.common import *
 from liteeth.test.common import *
 
-def split_bytes(v, n):
-       r = []
-       r_bytes = v.to_bytes(n, byteorder="little")
-       for byte in r_bytes:
-               r.append(int(byte))
-       return r
-
-def merge_bytes(b):
-       return int.from_bytes(bytes(b), "little")
-
-def get_field_data(field, datas):
-       v = merge_bytes(datas[field.byte:field.byte+math.ceil(field.width/8)])
-       return (v >> field.offset) & (2**field.width-1)
-
 def print_mac(s):
        print_with_prefix(s, "[MAC]")