From: chas w. <ch...@us...> - 2004-02-21 15:43:39
|
Update of /cvsroot/linux-atm/linux-atm/src/oamd In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10452/src/oamd Added Files: Tag: V2_5_0 Makefile.am atmoamd.c crc10.c crc10.h io.c io.h oam.c oam.h Log Message: import preliminary OAM support from Jorge Boncompte [DTI2] <jo...@dt...> --- NEW FILE: Makefile.am --- sbin_PROGRAMS = atmoamd atmoamd_SOURCES = atmoamd.c io.c io.h oam.c oam.h crc10.c crc10.h atmoamd_LDADD = $(top_builddir)/src/lib/libatm.la atmoamd_DEPENDENCIES = $(zeppelin_LDADD) --- NEW FILE: atmoamd.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <signal.h> #include <atm.h> #include "io.h" #define COMPONENT "OAMD" int timer, run_fsm, debug; static void usage(const char *name) { fprintf(stderr, "usage: %s [-b] [-d]\n", name); fprintf(stderr, "%6s %s -V\n", "", name); exit(1); } static void sig_handler(int signo) { if (signo == SIGALRM) { timer++; run_fsm = 1; signal(SIGALRM, sig_handler); alarm(1); } } int main(int argc, char **argv) { int c, background = 0; set_application("atmoamd"); set_verbosity(NULL,DIAG_INFO); while ((c = getopt(argc,argv,"bdV")) != EOF) switch (c) { case 'b': background = 1; break; case 'd': set_verbosity(NULL,DIAG_DEBUG); debug = 1; break; case 'V': printf("%s\n",VERSION); return 0; default: usage(argv[0]); } if (argc != optind) usage(argv[0]); diag(COMPONENT,DIAG_INFO,"Linux ATM OAM, version " VERSION); open_kernel(); /* run in background */ if (background) { pid_t pid; pid = fork(); if (pid < 0) diag(COMPONENT,DIAG_FATAL,"fork: %s",strerror(errno)); if (pid) { diag(COMPONENT,DIAG_DEBUG,"Backgrounding (PID %d)",pid); exit(0); } } signal(SIGALRM, sig_handler); alarm(1); poll_loop(); close_kernel(); return 0; } --- NEW FILE: crc10.c --- #include <atm.h> #include "crc10.h" static unsigned short byte_crc10_table[256] = { 0x0000, 0x0233, 0x0255, 0x0066, 0x0299, 0x00aa, 0x00cc, 0x02ff, 0x0301, 0x0132, 0x0154, 0x0367, 0x0198, 0x03ab, 0x03cd, 0x01fe, 0x0031, 0x0202, 0x0264, 0x0057, 0x02a8, 0x009b, 0x00fd, 0x02ce, 0x0330, 0x0103, 0x0165, 0x0356, 0x01a9, 0x039a, 0x03fc, 0x01cf, 0x0062, 0x0251, 0x0237, 0x0004, 0x02fb, 0x00c8, 0x00ae, 0x029d, 0x0363, 0x0150, 0x0136, 0x0305, 0x01fa, 0x03c9, 0x03af, 0x019c, 0x0053, 0x0260, 0x0206, 0x0035, 0x02ca, 0x00f9, 0x009f, 0x02ac, 0x0352, 0x0161, 0x0107, 0x0334, 0x01cb, 0x03f8, 0x039e, 0x01ad, 0x00c4, 0x02f7, 0x0291, 0x00a2, 0x025d, 0x006e, 0x0008, 0x023b, 0x03c5, 0x01f6, 0x0190, 0x03a3, 0x015c, 0x036f, 0x0309, 0x013a, 0x00f5, 0x02c6, 0x02a0, 0x0093, 0x026c, 0x005f, 0x0039, 0x020a, 0x03f4, 0x01c7, 0x01a1, 0x0392, 0x016d, 0x035e, 0x0338, 0x010b, 0x00a6, 0x0295, 0x02f3, 0x00c0, 0x023f, 0x000c, 0x006a, 0x0259, 0x03a7, 0x0194, 0x01f2, 0x03c1, 0x013e, 0x030d, 0x036b, 0x0158, 0x0097, 0x02a4, 0x02c2, 0x00f1, 0x020e, 0x003d, 0x005b, 0x0268, 0x0396, 0x01a5, 0x01c3, 0x03f0, 0x010f, 0x033c, 0x035a, 0x0169, 0x0188, 0x03bb, 0x03dd, 0x01ee, 0x0311, 0x0122, 0x0144, 0x0377, 0x0289, 0x00ba, 0x00dc, 0x02ef, 0x0010, 0x0223, 0x0245, 0x0076, 0x01b9, 0x038a, 0x03ec, 0x01df, 0x0320, 0x0113, 0x0175, 0x0346, 0x02b8, 0x008b, 0x00ed, 0x02de, 0x0021, 0x0212, 0x0274, 0x0047, 0x01ea, 0x03d9, 0x03bf, 0x018c, 0x0373, 0x0140, 0x0126, 0x0315, 0x02eb, 0x00d8, 0x00be, 0x028d, 0x0072, 0x0241, 0x0227, 0x0014, 0x01db, 0x03e8, 0x038e, 0x01bd, 0x0342, 0x0171, 0x0117, 0x0324, 0x02da, 0x00e9, 0x008f, 0x02bc, 0x0043, 0x0270, 0x0216, 0x0025, 0x014c, 0x037f, 0x0319, 0x012a, 0x03d5, 0x01e6, 0x0180, 0x03b3, 0x024d, 0x007e, 0x0018, 0x022b, 0x00d4, 0x02e7, 0x0281, 0x00b2, 0x017d, 0x034e, 0x0328, 0x011b, 0x03e4, 0x01d7, 0x01b1, 0x0382, 0x027c, 0x004f, 0x0029, 0x021a, 0x00e5, 0x02d6, 0x02b0, 0x0083, 0x012e, 0x031d, 0x037b, 0x0148, 0x03b7, 0x0184, 0x01e2, 0x03d1, 0x022f, 0x001c, 0x007a, 0x0249, 0x00b6, 0x0285, 0x02e3, 0x00d0, 0x011f, 0x032c, 0x034a, 0x0179, 0x0386, 0x01b5, 0x01d3, 0x03e0, 0x021e, 0x002d, 0x004b, 0x0278, 0x0087, 0x02b4, 0x02d2, 0x00e1, }; unsigned short update_crc10_by_bytes(unsigned short crc10_accum, unsigned char *data_blk_ptr, int data_blk_size) { register int i; for (i = 0; i < data_blk_size; i++) { crc10_accum = ((crc10_accum << 8) & 0x3ff) ^ byte_crc10_table[(crc10_accum >> 2) & 0xff] ^ *data_blk_ptr++; } return crc10_accum; } unsigned short crc10(unsigned char *payload) { unsigned short crc; payload[46] = payload[47] = 0; crc = update_crc10_by_bytes(0, payload, ATM_CELL_PAYLOAD); payload[46] ^= crc >> 8; payload[47] ^= crc & 0xff; return crc; } int crc10_check(unsigned char *payload) { unsigned short old_crc, crc; old_crc = payload[47]; old_crc += payload[46] << 8; crc = crc10(payload); if (crc != old_crc) return -1; /* Failed CRC10 check */ else return 0; /* CRC10 correct */ } --- NEW FILE: crc10.h --- /* * crc10.h CRC10 * * Written 2003 by Jorge Boncompte, DTI2 * * The CRC10 table and sum routine are from the f4loopbackd.c source */ #ifndef CRC10_H #define CRC10_H #define POLYNOMIAL 0x633 unsigned short crc10(unsigned char *payload); int crc10_check(unsigned char *payload); #endif --- NEW FILE: io.c --- /* io.c - I/O operations */ /* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <stdint.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/poll.h> #include <net/if.h> #include <netinet/in.h> #include <atm.h> #define _LINUX_NETDEVICE_H /* glibc2 */ #include <linux/if_arp.h> #include "atmd.h" #include "io.h" #include "oam.h" #define COMPONENT "IO" static int kernel; extern int run_fsm; /* ----- kernel interface -------------------------------------------------- */ void open_kernel(void) { if ((kernel = socket(PF_ATMSVC, SOCK_DGRAM, 0)) < 0) diag(COMPONENT, DIAG_FATAL, "socket: %s", strerror(errno)); if (ioctl(kernel, ATMOAMD_CTRL, 0) < 0) diag(COMPONENT, DIAG_FATAL, "ioctl ATMOAMD_CTRL: %s", strerror(errno)); } int send_kernel(struct atmoam_ctrl *ctrl) { int size; size = write(kernel, ctrl, sizeof (struct atmoam_ctrl)); if (size < 0) { diag(COMPONENT, DIAG_DEBUG, "write kernel: %s", strerror(errno)); return -errno; } return size; } void recv_kernel(void) { struct atmoam_ctrl ctrl; int size; size = read(kernel, &ctrl, sizeof (ctrl)); if (size < 0) { diag(COMPONENT, DIAG_ERROR, "read kernel: %s", strerror(errno)); return; } diag(COMPONENT, DIAG_DEBUG, "OAM %s Cell received on Intf %d VPI/VCI %d/%d (Vcc %p)", ctrl.pti == 5 ? "F5-E2E" : (ctrl.pti == 4 ? "F5-SEG" : "UNK"), ctrl.number, ctrl.vpi, ctrl.vci, *(struct atm_vcc **) &ctrl.vcc); oam_process(&ctrl); } void close_kernel(void) { close(kernel); } void poll_loop(void) { struct pollfd pollfds; pollfds.fd = kernel; pollfds.events = POLLIN; /* Que eventos queremos, solo entradas */ for (;;) { oam_state_print(); if (run_fsm) { oam_fsm(); run_fsm = 0; } switch (poll(&pollfds, 1, 10000)) { case 0: break; case -1: if (errno != EINTR) diag(COMPONENT, DIAG_ERROR, "poll loop...%s", strerror(errno)); break; default: if (pollfds.revents && POLLIN) recv_kernel(); } } } --- NEW FILE: io.h --- /* io.h - I/O operations */ /* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #ifndef IO_H #define IO_H #include <stdint.h> #include <sys/socket.h> /* for struct sockaddr */ #include <atm.h> /* for struct sockaddr_atmsvc */ #include <atmd.h> #include <linux/atmoam.h> void open_kernel(void); void recv_kernel(void); int send_kernel(struct atmoam_ctrl *); void close_kernel(void); void poll_loop(void); #endif --- NEW FILE: oam.c --- #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <errno.h> #include <atm.h> #include <linux/atmoam.h> #include "oam.h" #include "io.h" #include "crc10.h" #define COMPONENT "OAM" extern int timer; struct oamfsm fsm; struct oamvcc vcc; void handle_circuit_state(int state) { vcc.state = state; diag(COMPONENT, DIAG_DEBUG, "VCC STATE CHANGE: %s", vcc.state ? "DOWN" : "UP"); if (vcc.state == VCC_UP) { system("backuprdsi stop&"); } else if (vcc.state == VCC_DOWN) { system("backuprdsi start&"); } } void oam_state_print(void) { return; printf ("-------------------------------------------------------------------\n"); printf("T: %d UP: %d DOWN: %d STATE: %d VCCSTATE %d CTag: %lx\n", timer, fsm.upretry, fsm.downretry, fsm.state, vcc.state, vcc.CTag); printf("InOAM: %lu OutOAM: %lu CrcErrors: %lu CTagErrors: %lu\n", vcc.stats.InOAM, vcc.stats.OutOAM, vcc.stats.CrcErrors, vcc.stats.CTagErrors); printf("InEndLoop: %lu OutEndLoop: %lu\n", vcc.stats.F5.InEndLoop, vcc.stats.F5.OutEndLoop); printf ("-------------------------------------------------------------------\n"); } static int put_ctag(unsigned char *pdu, unsigned long ctag) { if (pdu == NULL) return -1; pdu[2] = (unsigned char) (ctag >> 24); pdu[3] = (unsigned char) (ctag >> 16); pdu[4] = (unsigned char) (ctag >> 8); pdu[5] = (unsigned char) ctag; return 0; } static unsigned long get_ctag(unsigned char *pdu) { unsigned long ctag; if (pdu == NULL) return -1; ctag = (unsigned long) pdu[5]; ctag += (unsigned long) (pdu[4] << 8); ctag += (unsigned long) (pdu[3] << 16); ctag += (unsigned long) (pdu[2] << 24); return ctag; } void oam_send(struct atmoam_ctrl *ctrl) { int error; error = send_kernel(ctrl); if (error > 0) { fsm.state = OAM_SENT; vcc.stats.OutOAM++; vcc.stats.F5.OutEndLoop++; } else if (error == -EUNATCH) { OAM_WAIT_10_S; vcc.stats.OutDrops++; } } static unsigned long oam_build_lb_cell(struct atmoam_ctrl *ctrl) { unsigned char *oamcell = (unsigned char *) &ctrl->cell; static unsigned long tag = 0; const unsigned char lpBackLocId[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; const unsigned char srcId[] = { 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A }; unsigned char *pdu = oamcell + 4; unsigned char *hdr = oamcell; unsigned short crc; // fill vpi hdr[0] = ctrl->vpi >> 4; hdr[1] = (ctrl->vpi & 0x0F) << 4; // fill vci hdr[1] |= ctrl->vci >> 12; hdr[2] = (ctrl->vci >> 4) & 0xFF; hdr[3] = 0x0A; hdr[3] |= (ctrl->vci & 0x0F) << 4; // updates the HEC // loopback function pdu[0] = 0x18; pdu[1] = 0x01; put_ctag(pdu, tag); tag++; // fill the loopback id memcpy(pdu + 6, lpBackLocId, 16); // fill the Src Id memcpy(pdu + 22, (unsigned char *) srcId, 16); // fill the unused bytes memcpy(pdu + 38, (unsigned char *) srcId, 8); // computes the CRC pdu[ATM_CELL_PAYLOAD - 2] = 0; pdu[ATM_CELL_PAYLOAD - 1] = 0; crc = crc10(pdu); pdu[ATM_CELL_PAYLOAD - 1] = (unsigned char) crc; pdu[ATM_CELL_PAYLOAD - 2] = (unsigned char) (crc >> 8); return tag - 1; } static int oam_fault(unsigned char *pdu) { struct oampayload *oampayload = (struct oampayload *) pdu; unsigned long ctag; if (OAM_FUNC(pdu) == ATM_OAM_F_LOOP) { ctag = get_ctag(pdu); diag(COMPONENT, DIAG_DEBUG, "\tReceived Fault-Mgmnt (%s) cell, CTag: 0x%lX", oampayload->LoopBackInd == 1 ? "Loopback" : "Loopback reply", ctag); if (pdu[1] == 1) { /* Celda de Loopback */ vcc.stats.F5.InEndLoop++; pdu[1] = 0; /* Clear Loopback but */ /* Recalculate CRC10 */ crc10(pdu); /* Volvemos a enviar la celda */ return 1; } if (pdu[1] == 0) { /* Loopback reply */ if (ctag == vcc.CTag) { vcc.stats.F5.InEndLoop++; OAM_INC_UPRETRY; if (fsm.upretry >= OAM_UPRETRY) { if (vcc.state == VCC_DOWN) handle_circuit_state(VCC_UP); } else { if (vcc.state == VCC_DOWN) { vcc.CTag = oam_build_lb_cell(&vcc. ctrl); oam_send(&vcc.ctrl); return 0; } } /* Desde aqui deberiamos ir a ESPERAR a 10 */ OAM_WAIT_10_S; return 0; } else { printf("Wrong Correlation Tag\n"); vcc.stats.CTagErrors++; OAM_INC_DOWNRETRY; if (fsm.downretry >= OAM_DOWNRETRY) { if (vcc.state == VCC_UP) handle_circuit_state(VCC_DOWN); } else { if (vcc.state == VCC_UP) { vcc.CTag = oam_build_lb_cell(&vcc. ctrl); oam_send(&vcc.ctrl); return 0; } } /* Desde aqui deberiamos ir a ESPERAR a 10 */ OAM_WAIT_10_S; return 0; } } } return 0; } void oam_process(struct atmoam_ctrl *ctrl) { vcc.stats.InOAM++; if (crc10_check(ctrl->cell.payload) != 0) { diag(COMPONENT, DIAG_ERROR, "Received OAM cell, failed CRC-10 check"); vcc.stats.CrcErrors++; OAM_INC_DOWNRETRY; if (fsm.downretry >= OAM_DOWNRETRY) { if (vcc.state == VCC_UP) handle_circuit_state(VCC_DOWN); } else { if (vcc.state == VCC_UP) { vcc.CTag = oam_build_lb_cell(&vcc.ctrl); oam_send(&vcc.ctrl); return; } } /* Desde aqui deberiamos ir a ESPERAR a 10 */ OAM_WAIT_10_S; return; } switch (OAM_TYPE(ctrl->cell.payload)) { case ATM_OAM_T_FAULT: if (oam_fault(ctrl->cell.payload)) send_kernel(ctrl); break; case ATM_OAM_T_PERF: break; case ATM_OAM_T_ACTDEACT: break; } } void oam_fsm(void) { switch (fsm.state) { case OAM_INIT: timer = 0; vcc.ctrl.number = 0; vcc.ctrl.vpi = 8; vcc.ctrl.vci = 32; vcc.ctrl.pti = 5; vcc.CTag = oam_build_lb_cell(&vcc.ctrl); oam_send(&vcc.ctrl); break; case OAM_SENT: OAM_INC_DOWNRETRY; if (fsm.downretry >= OAM_DOWNRETRY) { if (vcc.state == VCC_UP) handle_circuit_state(VCC_DOWN); } else { if (vcc.state == VCC_UP) { vcc.CTag = oam_build_lb_cell(&vcc.ctrl); oam_send(&vcc.ctrl); return; } } /* Desde aqui deberiamos ir a ESPERAR a 10 */ OAM_WAIT_10_S; break; case OAM_WAIT10: if (timer != 10) return; else { fsm.state = OAM_INIT; return; } } } --- NEW FILE: oam.h --- /* * oam.h - OAM cell processing * * Written 2003 by Jorge Boncompte, DTI2 * */ #ifndef OAM_H #define OAM_H #define OAM_UPRETRY 3 #define OAM_DOWNRETRY 5 #define OAM_WAITRETRY 1 #define OAM_INIT 0 #define OAM_SENT 2 #define OAM_REPLY 3 #define OAM_WAIT10 4 #define VCC_UP 0 #define VCC_DOWN 1 #define OAM_INC_UPRETRY fsm.upretry++; fsm.downretry=0 #define OAM_INC_DOWNRETRY fsm.downretry++; fsm.upretry=0 #define OAM_WAIT_10_S timer = 0; fsm.state = OAM_WAIT10 struct oamfsm { int state; short upretry; short downretry; }; struct oamvcc { struct atmoam_ctrl ctrl; int state; unsigned long CTag; struct { unsigned long InOAM; unsigned long OutOAM; unsigned long CrcErrors; unsigned long CTagErrors; unsigned long OutDrops; struct { unsigned long InEndLoop; unsigned long InSegLoop; // unsigned long InAIS; // unsigned long InRDI; unsigned long OutEndLoop; unsigned long OutSegLoop; // unsigned long OutRDI; } F5; } stats; }; void oam_process(struct atmoam_ctrl *ctrl); void oam_fsm(void); void oam_state_print(void); #endif |