From: Florent Kermarrec Date: Thu, 29 Jan 2015 18:17:45 +0000 (+0100) Subject: model: add arp skeleton X-Git-Tag: 24jan2021_ls180~2604^2~109 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=dcbfdcab44c956689daf57f091b556258efac232;p=litex.git model: add arp skeleton --- diff --git a/liteeth/common.py b/liteeth/common.py index d66e7c19..e68e4c49 100644 --- a/liteeth/common.py +++ b/liteeth/common.py @@ -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 = { diff --git a/liteeth/test/common.py b/liteeth/test/common.py index 844584b9..684be80a 100644 --- a/liteeth/test/common.py +++ b/liteeth/test/common.py @@ -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 index 00000000..e0a80f2c --- /dev/null +++ b/liteeth/test/model/arp.py @@ -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 diff --git a/liteeth/test/model/mac.py b/liteeth/test/model/mac.py index 72656af4..7af991be 100644 --- a/liteeth/test/model/mac.py +++ b/liteeth/test/model/mac.py @@ -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]")