📄 ethernet.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//***************************************************************** * ethernet.c - Routines to simulate an ethernet device. * * Ethernet interface emulation. * Created by: Ed Bugnion * Revised by: Dan Teodosiu, 07/96 * * NOTES: * This interface writes the data directly to memory (and doesn't * care about coherence). Should be changed to use DMA. * * Last modified by: $Author: bosch $ *****************************************************************/#include <stdio.h>#include <sys/types.h>#ifdef __alpha#include <sys/ioctl.h>#else#ifndef i386#include <sys/unistd.h>#endif#endif#ifdef i386#include <sys/ioctl.h>#endif#include <sys/mman.h>#include <sys/file.h>#include <sys/signal.h>#ifndef __alpha#ifndef linux#include <sys/ioccom.h>#include <sys/filio.h>#endif#endif#include <sys/time.h>#include <unistd.h>#include <string.h>#include <sys/socket.h>#include <net/if.h>#include <errno.h>#include <netinet/in.h>#include <stddef.h>#include <stdlib.h>#include <netdb.h>#ifndef linux#include <sys/uio.h>#include <netinet/if_ether.h>#include <poll.h>#endif#include "syslimits.h"#include "simtypes.h"#include "ethernet.h"#include "sim.h"#include "sim_error.h"#include "simutil.h"#include "cpu_interface.h"#include "checkpoint.h"#include "../../devices/network/cluster.h"#include "machine_params.h"#include "arch_specifics.h"#include "eventcallback.h"#include "list.h"#ifdef VCS_FAKE#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <netinet/in_systm.h>#include <netinet/in.h>#include <netinet/ip.h>void VcsFakeInit(void);#endifstatic int SimetherCheckpointCB(CptDescriptor *cptd);/* * Seems to be a bug in the SGI offsetof() at 6.2 */#if defined(sgi) && defined(_COMPILER_VERSION) && (_COMPILER_VERSION >= 400)#undef offsetof#define offsetof(s, m) (size_t)(&(((s *)0)->m))#endif/********************************************************************** * offset computation **********************************************************************/static int simetherIndex[sizeof(SimetherRegisters)];typedef enum { NONE,ETHER_ADDR, NUM_RCV,NUM_SND,NUM_CHUNKS, INTR_CPU, RCV_ADDR, RCV_MAXLEN,RCV_LEN,RCV_FLAG, SND_FIRST,SND_LAST,SND_FLAG, CHUNK_ADDR, CHUNK_LEN} RegisterNames ;char* simetherRegisterNamesStr[] = { "none","ether_addr", "num_rcv","num_snd","num_chunk", "intr_cpu", "rcv_addr", "rcv_maxLen","rcv_len", "rcv_flag", "snd_first", "snd_last", "snd_flag", "chunk_addr", "chunk_len" };static RegisterNames simetherOffset[sizeof(SimetherRegisters)];static voidSimetherAddEntry(int offset, RegisterNames n, int index){ simetherOffset[offset] = n; simetherIndex[offset] = index;}#define ADD_ENTRY(_f,_n,_i) \ SimetherAddEntry(offsetof(SimetherRegisters,_f),_n,_i)static void SimetherOffsetsInit(void){ int i; for(i=0;i<sizeof(SimetherRegisters);i++) { simetherOffset[i] = NONE; simetherIndex[i] = -1; } for(i=0;i<6;i++) { ADD_ENTRY(etheraddr[i],ETHER_ADDR,i); } ADD_ENTRY(intrCPU,INTR_CPU,0); ADD_ENTRY(numRcvEntries,NUM_RCV,0); ADD_ENTRY(numSndEntries,NUM_SND,0); ADD_ENTRY(numSndChunks,NUM_CHUNKS,0); for(i=0;i<ETHER_MAX_RCV_ENTRIES; i++) { ADD_ENTRY(rcvEntries[i].pAddr,RCV_ADDR,i); ADD_ENTRY(rcvEntries[i].maxLen,RCV_MAXLEN,i); ADD_ENTRY(rcvEntries[i].len,RCV_LEN,i); ADD_ENTRY(rcvEntries[i].flag,RCV_FLAG,i); } for(i=0;i<ETHER_MAX_SND_ENTRIES;i++) { ADD_ENTRY(sndEntries[i].firstChunk,SND_FIRST,i); ADD_ENTRY(sndEntries[i].lastChunk,SND_LAST,i); ADD_ENTRY(sndEntries[i].flag,SND_FLAG,i); } for( i=0;i<ETHER_MAX_SND_CHUNKS;i++) { ADD_ENTRY(sndChunks[i].pAddr,CHUNK_ADDR,i); ADD_ENTRY(sndChunks[i].len,CHUNK_LEN,i); }}/*************************************************************************** * * local cluster structures * ***************************************************************************/#define USE_LOCAL_CLUSTER 1#define LOCAL_CLUSTER_DMA_LATENCY 300 /* Nanoseconds per cache-line */#define LOCAL_CLUSTER_MBIT 10 /* Megabit-per-second */#define LOCAL_CLUSTER_MAX_MSGS 1024/* If broadcast is 0, if_num is the interface to send to. *//* If broadcast is 1, if_num is the only interface not to send to. */typedef struct LocalClusterMessage { EventCallbackHdr hdr; List_Links link; int if_num; int broadcast; int len; char data[SIMETHER_MAX_TRANSFER_SIZE];} LocalClusterMessage;#define CMSG_TO_LIST(_m) (&((_m)->link))#define LIST_TO_CMSG(_l) ((LocalClusterMessage *) (((char *)(_l)) - sizeof(EventCallbackHdr)))static int LocalClusterActive = 0;static LocalClusterMessage messageStorage[LOCAL_CLUSTER_MAX_MSGS];/* List of available LocalClusterMessage structures */static List_Links freeMessageList;static int LocalClusterSendPacket(int cpuNum, int src_if_num, struct iovec *iov, int io_len);static void LocalClusterMessageArrive(int cpuNum, EventCallbackHdr *hdr, void *arg);/*************************************************************************** * * simether internals * ***************************************************************************/static int disableEthernet = 0;static int numEtherInterfaces = 0;typedef struct SimetherState { /* ethersim/ UPD related stuff */ int fd; struct sockaddr_in toaddr; /* Address of ethernet simulator process. */ int toaddrlen; /* Length of the address. */ int ethernum; int machine; /* Machine that this controller is on */ /* ethersim/cluster synchronization */ char rcvLock[128]; /* Interaction with the interrupt architecture */ int intrPosted; EtherIntFunc int_f; /* function to call for raising/clearing an int */ /* Ring buffer managment */ int rcvPtr; int chunkOwner[ETHER_MAX_SND_CHUNKS]; int sndAcks[ETHER_MAX_SND_ENTRIES]; /* Kernel-visible state (through uncached accesses */ SimetherRegisters copy;} SimetherState;static SimetherState* simetherState = 0;/* parameters */char *EthersimHostname;char *EtherAddress;int EtherSendPort;int RestoreEthernet;intSimetherInit(int restore, EtherIntFunc int_f){ SimetherState *state; extern int errno; struct sockaddr_in sin; struct hostent *host; int if_num; int tmp[6]; int on,i; /* Initialize each configured board */ SimetherOffsetsInit(); if (!RestoreEthernet) { disableEthernet = 1; } Simcpt_Register("ether", SimetherCheckpointCB, ALL_CPUS); if (restore) { Simcpt_Restore("ether"); } else { numEtherInterfaces = TOTAL_ETHER_CONTROLLERS; simetherState = (SimetherState *) ZMALLOC(sizeof(SimetherState)*numEtherInterfaces,"SimetherState"); } if ((numEtherInterfaces > 1) && USE_LOCAL_CLUSTER) { ASSERT(!LocalClusterActive); LocalClusterActive = 1; List_Init(&freeMessageList); for (i = 0; i < LOCAL_CLUSTER_MAX_MSGS; i++) { LocalClusterMessage *cmsg = messageStorage + i; bzero((char *) (cmsg), sizeof(messageStorage[0])); List_InitElement(CMSG_TO_LIST(cmsg)); List_Insert(CMSG_TO_LIST(cmsg), LIST_ATREAR(&freeMessageList)); } } for (if_num=0; if_num<numEtherInterfaces; if_num++) { int j, machine; state = simetherState + if_num; state->ethernum = if_num; for (machine = 0; machine < NUM_MACHINES; machine++) { if ((FIRST_ETHER_CONTROLLER(machine) <= if_num) && (LAST_ETHER_CONTROLLER(machine) >= if_num)) { state->machine = machine; break; } } /* * hardcoded values for now */ if (!restore) { state->copy.numRcvEntries = 16; state->copy.numSndEntries = ETHER_MAX_SND_ENTRIES; state->copy.numSndChunks = ETHER_MAX_SND_CHUNKS; for(j=0;j<state->copy.numRcvEntries;j++) state->copy.rcvEntries[j].flag = OS_OWNED; for(j=0;j<state->copy.numSndEntries;j++) { state->copy.sndEntries[j].flag = OS_OWNED; state->sndAcks[j] = 1; } for(j=0;j<state->copy.numSndChunks;j++) state->chunkOwner[j] = OS_OWNED; } /* * Create the UDP socket that will be used to send and receive packets` * to and from the simulator. */ if( disableEthernet ) { state->fd = -1; if( sscanf(EtherAddress,"%i:%i:%i:%i:%i:%i", &tmp[0],&tmp[1],&tmp[2],&tmp[3],&tmp[4],&tmp[5])!=6) { CPUError("Simether: Parsing of '%'s failed \n", EtherAddress); } for(i=0;i<5;++i) state->copy.etheraddr[i] = tmp[i]; state->copy.etheraddr[5] = if_num + tmp[5]; state->int_f = int_f; } else { state->fd = socket(AF_INET, SOCK_DGRAM, 0); if (state->fd < 0) { perror("Simether_init:socket"); return -1; } bzero((char *)&sin, sizeof (sin)); sin.sin_port = htons(0); sin.sin_family = AF_INET; if (bind(state->fd, (struct sockaddr *) &sin, sizeof (sin)) < 0) { perror("Simether_init:bind"); return -1; } on = 1; if (ioctl(state->fd, FIONBIO, &on) < 0) { perror("Simether_init: FIOBIO"); } host = gethostbyname(EthersimHostname); if (!host) { Sim_Warning("EthersimHostname : %s\n", EthersimHostname); perror("Simether_init:gethostbyname EthersimHostname"); return -1; } state->toaddr.sin_family = host->h_addrtype; bcopy(host->h_addr, (char*)&state->toaddr.sin_addr, host->h_length); state->toaddr.sin_port = htons(EtherSendPort); state->toaddrlen = sizeof(state->toaddr); if( !restore ) /* note: this is currently unused */ state->copy.intrCPU = SIM_MAXCPUS; if( sscanf(EtherAddress,"%i:%i:%i:%i:%i:%i", &tmp[0],&tmp[1],&tmp[2],&tmp[3],&tmp[4],&tmp[5])!=6) { CPUError("Simether: Parsing of '%'s failed \n", EtherAddress); } for(i=0;i<5;++i) state->copy.etheraddr[i] = tmp[i]; state->copy.etheraddr[5] = if_num + tmp[5]; state->int_f = int_f; } } #ifdef VCS_FAKE VcsFakeInit();#endif return 0;}voidSimetherPoll(void){#ifndef linux static struct pollfd fds[ETHER_MAX_CONTROLLERS]; SimetherState *state; int i; for (i=0; i < numEtherInterfaces; i++) { state = &simetherState[i]; ASSERT(state->fd != 0); fds[i].fd = state->fd; fds[i].events = POLLRDNORM; fds[i].revents = 0; } poll(fds, numEtherInterfaces, 0); for (i = 0; i < numEtherInterfaces; i++) { SIM_DEBUG(('i', "SimetherPoll fd: 0x%x events: 0x%x revents: 0x%x\n", fds[i].fd, fds[i].events, fds[i].revents)); } for(i = 0; i < numEtherInterfaces; i++) if (fds[i].revents & POLLRDNORM) SimetherReceivePacket( i, 0 , 0 ) ;#else Sim_Warning("Uh oh... SimetherPoll called\n");#endif}void SimetherInitCluster(void){ int i, j; char etheraddr[6]; for (i = 0; i < numEtherInterfaces; i++) { for (j = 0; j < 6; j++) etheraddr[j] = simetherState[i].copy.etheraddr[j]; ClusterSetEtherAddr(etheraddr, i); }}char* SimetherAddr(int iface_num) { static char etheraddr[6]; int i; for (i = 0; i < 6; i++) etheraddr[i] = simetherState[iface_num].copy.etheraddr[i]; return etheraddr;}static void SimetherClearSlot(SimetherState *state) { int i; SimetherRegisters *regs = &state->copy; for(i=0;i<state->copy.numRcvEntries;i++) { if( regs->rcvEntries[i].flag == OS_OWNED ) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -