Index: rna/CHANGES.RNA diff -u /dev/null rna/CHANGES.RNA:1.2 --- /dev/null Tue Jul 1 09:16:48 2008 +++ rna/CHANGES.RNA Fri Jun 27 18:18:52 2008 @@ -0,0 +1,6 @@ + +Changes since v0.0 +------------------- + + Initial implementation + Index: rna/LICENSE.RNA diff -u /dev/null rna/LICENSE.RNA:1.1 --- /dev/null Tue Jul 1 09:16:48 2008 +++ rna/LICENSE.RNA Fri Jun 27 10:40:55 2008 @@ -0,0 +1,42 @@ +# +# ------------------------------------------------------------------- +# RNA +# +# http://www.isi.edu/rnd +# USC Information Sciences Institute (USC/ISI) +# Marina del Rey, California 90292, USA +# Copyright (c) 2007-2009 +# +# ------------------------------------------------------------------- +# +# Copyright (c) 2007-2009 by the University of Southern California. +# All rights reserved. +# +# Permission to use, copy, modify, and distribute this software and +# its documentation in source and binary forms for non-commercial +# purposes and without fee is hereby granted, provided that the above +# copyright notice appear in all copies and that both the copyright +# notice and this permission notice appear in supporting +# documentation, and that any documentation, advertising materials, +# and other materials related to such distribution and use acknowledge +# that the software was developed by the University of Southern +# California, Information Sciences Institute. The name of the +# University may not be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THE UNIVERSITY OF SOUTHERN CALIFORNIA MAKES NO REPRESENTATIONS ABOUT +# THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS +# PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +# ------------------------------------------------------------------- +# +# +# This work was partly supported by the NSF (Grant No. CNS-0626788) +# project. Any opinions, findings, and conclusions or recommendations +# expressed in this material are those of the authors and do not +# necessarily reflect the views of the National Science Foundation. +# +# Other copyrights might apply to parts of this software and are so +# noted when applicable. Index: rna/Makefile.RNA diff -u /dev/null rna/Makefile.RNA:1.2 --- /dev/null Tue Jul 1 09:16:48 2008 +++ rna/Makefile.RNA Fri Jun 27 13:07:20 2008 @@ -0,0 +1,51 @@ +#!/bin/sh + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +INCPATH=$(PWD)/include +PORTS=/usr/ports +MODULES=devel/p5-Parse-RecDescent + +RNADIR=elements/rna + +PATTERNS_FILE=${RNADIR}/metaprotocol_patterns_db.txt +PROCESSED_PATTERNS=${RNADIR}/metaprotocol_patterns_db.cc +MODULE_NAMESPACE=${RNADIR}/module_namespace.txt +PATTERNS_PARSER=${RNADIR}/patterns_parser.pl + +all: build + +help: + @echo "make [compile|clean|patch]" + +configure-rna: + sh configure --disable-analysis --enable-ppp --enable-gre \ + --enable-userlevel --disable-linuxmodule --enable-rna \ + --enable-local CPPFLAGS="-DRNA" LIBS="-lcrypto" \ + --disable-int64 + +# Compile twice to deal with Error **2 message +compile: ${PROCESSED_PATTERNS} + cd userlevel && gmake && gmake + +build: configure-rna compile + +clean: + make clean + +patterns: ${PROCESSED_PATTERNS} + +${PROCESSED_PATTERNS} : ${PATTERNS_FILE} ${MODULE_NAMESPACE} + perl ${PATTERNS_PARSER} ${PATTERNS_FILE} ${MODULE_NAMESPACE} ${PROCESSED_PATTERNS} + + +perl-modules: + for i in ${MODULES} do; \ + cd ${PORTS}/$i && make && make install;\ + done Index: rna/README.RNA diff -u /dev/null rna/README.RNA:1.8 --- /dev/null Tue Jul 1 09:16:48 2008 +++ rna/README.RNA Mon Jun 30 14:13:09 2008 @@ -0,0 +1,597 @@ +================================================================== + + RNA METAPROTOCOL (v0.9) + http://www.isi.edu/rna + + $Revision: 1.8 $ + $Date: 2008/06/30 21:13:09 $ + +================================================================== + +This is the README for the source release of RNA Metaprotocol +software. See http://www.isi.edu/rna for more information on RNA. + +RNA Metaprotocol is a stem cell-like protocol that adapts to a given +context of operation. The aim of RNA Metaprotocol software is to take +a step in that direction. This implementation of RNA Metaprotocol +extend Click modular router software with additional modules and +runtime composition capabilities. + +CONTENTS +========= + +1 DISTRIBUTION + Summary of the files that are part of this distribution +2 INSTALLATION + Instructions on installing RNA-extensions and execution +3 CONFIGURATION + Discusses configuration file format +4 CODE + 5.1 FILES + 5.2 DESCRIPTION OF MODULES + Summary of the code in the various files + 5.3 MODIFICATIONS TO CLICK + Changes made to Click router +5 METAPROTOCOL PATTERN LANGUAGE AND COMPILATION: + Description of the language of the metaprotocol template + and the parser written in Perl +6 BUGS/LIMITATIONS +7 FUTURE WORK + Possible extensions + +======================================================================= + +1. DISTRIBUTION +--------------- + +RNA is distributed a set of new files and modifications to Click +modular router (http://read.cs.ucla.edu/click). + +CLICKDIR/LICENSE.RNA USC/ISI Licence for RNA-specific code +CLICKDIR/Makefile.RNA Build Click to use RNA +CLICKDIR/README.RNA This file +CLICKDIR/CHANGES.RNA Changes since the last revision +CLICKDIR/elements/rna/ RNA elements and metaprotocol +CLICKDIR/conf/rna* Click configuration files that use + RNA capabilities + +This release has been tested only on FreeBSD though it should work +without minor modification on other UNIX platforms. + +======================================================================= + +2. INSTALLATION +---------------- + +Download the click source (version 1.5.0) and apply the metaprotocol +match. Click source may be downloaded from the cvs site or from the +standard distribution. + +$ fetch http://read.cs.ucla.edu/click/click-1.5.0.tar.gz +$ tar zxvf click-1.5.0.tar.gz + +The patch should applicable to 1.5.xxx series. In future this patch +will be migrated to the 1.6 version of Click. + +$ fetch http://www.isi.edu/rna/rna-metaprotocol-v0.9.patch +$cd +$patch -p1 < ../rna-metaprotocol-v0.9.patch + +$ make -f Makefile.RNA configure-rna +$ make -f Makefile.RNA compile + +Execution is simple: + +$cd +$./userlevel/click ./conf/ + +Often multiple configuration files may have to run to simulate +multiple stacks. + +======================================================================= + +3. CONFIGURATION FILE +--------------------- + +The configuration files use the same language as that of Click but +with minor modifications.A fragment of the configuration file is shown +below: + +~~~~~~~~~ +b1 :: Buffer(NAME 'B1 MODULE'); +b2 :: Buffer(NAME 'B2 MODULE'); +d1 :: Demultiplexor(NAME 'DEMUX 1'); +m1 :: Multiplexor(NAME 'MUX 1'); + +r1 :: Metaprotocol(NAME 'MP1', + ELEMENTS b1 b2 d1 m1, + CONN false, + PATTERN 'MIN', + AUTONEGOTIATE true); + +... -> [0] r1 [1] ->.... + +~~~~ + +Several modules of various kinds are instantiated and provided to the +Metaprotocol. The Metaprotocol may compose any subset or none of the +element provided. The elements are not explicitly connected using the +language provided by Click except the metaprotocol. + +The Metaprotocol has several parameters some of which are +module-independent. These parameters are supported by the base class +RNAElement and supported by all modules. They include: + + NAME : String - Human readable name for each module + DEBUG : Bool - Enable debug messages for this module + (default is true) + PROCESS: Bool - Should initiate the composition process + True by default with metaprotocol, false by + default for other modules + CONN : Bool - Mark this protocol as being connection-oriented + (helps mostly with testing) + ELEMENTS: Element list - Elements available for composition + UPSTREAM: Element list - Upstream elements + DOWNSTREAM: Element list- Downstream elements + Helpful when there are loops (caused by the + composition) and compound elements. + +Beyond these each module supports modules-specific parameters. Some of +these are listed below. + +>> Metaprotocol: Basic implementation of the metaprotocol + + PATTERN: String - Initial pattern + AUTONEGOTIATE: Bool - Enable automatic negotiation + +The PATTERN parameter specifies the initial pattern that must be +executed by the metaprotocol. It does not, however, specify a +particular final composition that must be reached. So this +metaprotocol instantiates a subset of patterns selected from the many +based on some internal strategy. The autonegotiate parameter tells the +metaprotocol to negotiate with the peer once the protocol is instantiated. + +>> Buffer: Multi-purpose buffering module + + COPIES Send packet copies repeated? + DELAY Enable delayed send + (default = false; each packet delayed for a random time < some max ) + MANAGEMENT Enable sending management packets + (default = false) + SKIP The number of packets between successive management packets + (default = 5) + +>> Crypt: Symmetric cryptographic module + + KEY Symmetric key (32 characters in Hex with optional + "0x" at the beginning) + +>> Multiplexor: Distribute incoming message from upstream into several streams + + STRATEGY Distribution algorithm + + +======================================================================= + +4 CODE +------ + +RNAElement is the base class from which most modules are +derived. RNAElement itself is derived from the Element class of +Click. In addition there are helper class to enable storage and +retrieval of link and node state, and track the status of the +composition. Metaprotocol and the modules that are composed by the +metaprotocol are subclasses of RNAElement. Metaprotocol uses a +template that consists of the pattern language and state objects. + +4.1 FILES + +This section lists various files in the elements/rna directory and +summarizes the content of each. + +// Basic RNA Element +rnaelement.hh - Specifies the RNAElement class (derived from + Click's Element class) +rnaelement.cc - Main file that includes other RNA Element files +rnaelement_links.cc - Management of creation and deletion of connections + between modules +rnaelement_messages.cc - Handle incoming messages (both data, control and + management) +rnaelement_neighbors.cc - Discover upstream and downstream elements +rnaelement_parse.cc - Parse the input parameters +rnaelement_handlers.cc - Call backs from Click router. +rnaelement_control.cc - Control interface between modules (effectively + between the protocol layers) +rnaelement_ctlmsg.cc - Data structure passed between module while performing + the control operations. +rnaelement_linkstate.cc - Stores state associated with each link from a + particular module instance has to other modules. + This is internal to each module. The link may + be intra-layer or cross layer. +rnalement_connstate.cc - Connection state that is exchanged between + layers and included in messages + +// Metaprotocol +metaprotocol.cc - Metaprotocol implemented as a class derived from + RNAElement class +metaprotocol_state.cc - Stores and retrieves patterns +metaprotocol_patterns.cc- Implementation of patterns +metaprotocol_patterns_db.txt - Stored patterns file +metaprotocol_patterns_db.cc - Output of the patterns file parser +patterns_parser.pl - Patterns file parser (written in perl) + + +// Modules that are composed by the metaprotocol +module_namespace.txt - Enum containing known module names (implementation of + the module namespace) +modules_crypt.cc - Implements a module that encrypts and decrypts + traffic. Assumes a symmetric key and key specified + using configuration interface. +modules_buffer.cc - Implements a simple buffer that can optionally delay + packets and generate management packets to the layers + below +modules_reorderbuffer.cc- Buffer extended with support for sequence numbers in header +modules_multiplexor.cc - Multiplexor and demultiplexor of packets based on the +modules_demultiplexor.cc packet header. Demultiplexor that supports registration + of the demux patterns from the downstream modules. Mux + can support multiple strategies for muxing (in theory) +modules_pktsrc.cc - Wrapper around the packet generator that adds a RNA + message header + +4.2 DESCRIPTION OF MODULES +-------------------------- + +This section summarizes the structure and function of various classes +in the elements/rna directory. + +RNAElement: +---------- + +The RNAElement is the base class from which the metaprotocol and other +modules are derived. It implements the shared +functionality. RNAElement is a wrapper around the basic element +structure provided by Click Element class. RNAElement adds: + +* Type - type of RNA element (e.g., BUFFER) + +* Configuration - parses commonly used parameters and arguments + +* Control interface - to communicate between RNAElements for discovery + and state modification + +* Link management - addition/deletion of the links on the fly + +* Message flow - default algorithms to move data across modules; do + pre and post processing of the messages. + +* Element management - maintain the list of elements + +* Template - the state and pattern management. Only metaprotocols use +this capability. + +RNAElement supports an explicit control interface within and across +protocols. The purpose is to allow discovery and coordination across +layers. The coordination could be locally driven or driven by an +entity performing the coordination. There are two control interfaces - +synchronous and asynchronous. The synchronous interface is useful when +the programming environment for the protocol is shared across +layers. The asynchronous interface based on messages is useful when +the programming environment is not shared. It provides a message based +abstraction. Both are equivalent. + +The synchronous control interface consists of a generic control() +function. Each control request consists of a message type (command and +reply), operation type (configuration, connection, discover etc.), +operation (link add, connection close etc.), and optional data. If the +default control handler in RNAElement cannot handle the request, the +request is handled by module-specific control handler. + +Link State: +---------- + +Each RNAElement, including the metaprotocol, maintains a list of links +to other elements. This is necessary to foward message within and +across protocols. A LinkState object is instantiated upon addition of +a link during initialization period or later. The datastructure +maintains information about the following: + +* Ports - the local and remote Click element ports + +* Element - a pointer to the element structure at the remote end of +the link + +* Direction - the direction of traffic flow because Click links are +unidirectional (they flow from the output port of a given element to +the input port of another element) + +* [Optional] Linktype - which tells whether the link from the module +goes to the metaprotocol element or another data processing element. + +* [Optional] Connection-orientedness : Whether the next layer is +connection-oriented or not and if yes, whether the connection state +has been obtained or not + +* Connection state - exported connection state from the next +layer. Ideally this should be per-connection and not per-link. May be +this should be an array. + +Messages: +-------- + +There are three kinds of messages - data, control and +management. Data messages flow between peers within the same +layer. Control messages also flow across hosts between endpoints +within the same layer but the data is intended for control and +coordination purposes. Management messages flow within a single host +between layers. The management messages are used to implement the +asynchronous control interface between layers. + +There is no explicit new class associated with the messages. The +Packet class of Click is reused. The header in the packet is used to +carry the message type information. The header of each metaprotcol +message includes the type of message (control, data or management), +the sub-type (e.g., test and normal for data messages), and sub-type +specific content such as length and pattern name. + +Packet annotation is used to convey connection state information +across layers. The connection state is structured as a set of +(variable, value) tuples that is discovered across layers. + +Metaprotocol: +------------ + +The Metaprotocol class is derived from RNAElement class and uses all +of its capabilities. The main code rests in two files +(metaprotocol.cc/hh). The metaprotocol implements: + +* Composition - execution of a selected pattern + +* Negotiation - exchange of control messages with a peer + +* Testing - testing the outcome of a composition + +The content of the negotiation (patterns) are managed by the +metaprotocol state object (metaprotocol_state.cc/hh). The pattern +functionality is implemented by a separate object +(metaprotocol_patterns.cc/hh). + +State: This should be rightly called pattern manager. This state +specifies: + +* Initial pattern + +* Possible next patterns given a position + +* Execute or cleanup an executed pattern + +* Tests the feasibility of a specific pattern + +The state is populated during compile time (for now). The patterns are +specified in a separate file (metaprotocol_patterns_db.txt) that are +precompiled (metaprotocol_patterns_db.cc) and incorporated into the +state object at compile time. + +The objective of the negotiation process is to enable two endpoint +within the same layer to agree upon a composition. This is achieved +incrementally adding one feature at a time. The patterns are organized +as DAG (directed acyclic graph) and the negotiation process walks down +the patterns DAG in a synchronized fashion. The negotiation might +result in backtracking as well. Undoing a pattern may be necessary in +addition to doing. This in general requires several round trips but a +production implementation may be able to make larger functional jumps. +The main file (metaprotocol.cc/hh) implements the negotiation +(initiate_negotiation(),negotiate_request(), and negotiate_reply()). + +In future the negotiation will be separated out because multiple +negotiation strategies may have to be supported over time. + +5.3 MODIFICATIONS TO CLICK +-------------------------- + +Click is a powerful framework and the modifications are minimal. They +are in two basic classes. First, click assumes that once the modules +are they remain that way. They have extra tools that are manipulate +compositions once made but do not have that support in the core +code. Minor changes were necessary to expose the 'disconnect' +interface. A second function was written that tries to update the +internal state of all the modules so that the modifications of the +composition are 'committed'. This poses an interesting problem in that +the composition is being modified by the composed elements. This +naturally creates recursion and potential problems. Ideally Click +should provide an interface to control the composition process but +until then this is a stop gap arrangement. + +The files modified include lib/router.cc, lib/element.cc, +include/click/element.hh and include/click/router.hh. + +Some changes to lib/* and elements/userlevel/* are intended to fix +compilation issues that arose when the Click code is compiled without +64-bit support. + +5 METAPROTOCOL PATTERN LANGUAGE AND COMPILATION +----------------------------------------------- + +A key challenge is to deal with the semantics of the inter-connection +between modules. This information is specified in the patterns file +provided to the meta-protocol. Why a certain protocol should be +connected a particular way is related to the question of function and +semantics that is beyond the scope of the pattern language. + +The pattern language specifies the patterns that are accepted by the +metaprotocol. : + +COMMAND: START_CMD | NAME_CMD | PATTERN_CMD | COMMENT +START_CMD: 'START' IDENTIFIER +NAME_CMD: 'NAMESPACE' IDENTIFIER +PATTERN_CMD: 'PATTERN' IDENTIFIER RULES +RULES: RULE(s?) +RULE: ( REQ_CMD | FOLLOWS_CMD | RENAME_CMD | CONF_CMD ) +REQ_CMD: 'REQ' ('MUST') IDENTIFIER VALUE(?) OP(?) +FOLLOWS_CMD: 'FOLLOWS' IDENTIFIER +CONF_CMD: ('CONFIG' | 'UNCONFIG') (ARG_CMD | LINK_CMD) +ARG_CMD: 'ARG' IDENTIFIER VALUE(?) TEXT TEXT +LINK_CMD: 'LINK' ('ADD'|'DEL') IDENTIFIER VALUE(?) VALUE(?) + IDENTIFIER VALUE(?) VALUE(?) KEYWORD(s?) +RENAME_CMD: 'RENAME' IDENTIFIER VALUE TEXT +TEXT: /\S+/ +VALUE: /\d+/ + +The perl script CLICKDIR/elements/rna/process_patterns.pl implements a +simple recursive descent parser for the pattern language. + +This process may be invoked through the Makefile.RNA + +$ make -f Makefile.RNA patterns + + module namespace + | + | + V +metaprotocol_patterns_db.txt ----> patterns_parser.pl---->metaprotocol_patterns_db.cc + +The output is included during the initialization process of the +metaprotocol template state. + +metaprotocol_state.cc: + ... + State::State(RNAElement *control_in, ....) { + ... + #include "metaprotocol_patterns_db.cc" + ... + } + ... + + + +======================================================================= + +6. BUGS/LIMITATIONS +---------------- + +>> Error message: ::class_name method malformed + +This warning is printed by click-buildtool that parses the files for +sanity check. It assumes that class_name() method returns a fixed +string. RNA elements call the default_class_name() function in the +base class. This is not a critical error. The work around is to +try compiling again. + +>> The compilation process terminates with "*** Error code 2" + +Workaround: Try compiling again. + +$make -f Makefile.RNA compile + +>> Only push interface supported + +Only push interface is supported right now. Pull interface is not +fundamentally different in terms of the functionality except the +RNAElement structure must be generalized a little more. + +>> When I execute ./click ./conf/ I see +>> messages like this: + +[MP2] RNAElement::push: 29 | b02000b0 2000b020 00080000 00b02000 b02000b0 2000aaaa aaaaaaaa aa +[MP2] Metaprotocol::push_data - received a data message +[MP2] Metaprotocol::push_data - Normal data. Pushing to intra-layer module. +[MP2] RNAElement::push_data(port = 1) +[LINK] <> [MP2 local, 1 port] <- [UNKNOWN remote, -1 port]] +[MP2] RNAElement::push_data inter-layer message +[MP2] RNAElement::select_outgoing_link (upstream, layer sensitive, intra-layer, agnostic remote, remote unknown, conn state not required) +[MP2] open_connection Entry +[LINK] <> [RNAElement::open_connection local, 3 port] -> [B2 MODULE remote, 1 port]] +[MP2] open_connection: Found 0 downstream elements +[MP2] open_connection Exit +[12] Sending packet to: +[LINK] <> [MP2 local, 3 port] -> [B2 MODULE remote, 1 port]] + +The current release has debug messages enabled mostly because the +runtime construction of the metaprotocol and message flow is being +debugged. This is not a "production" release in that sense. + +>> Static template + +Patterns are included during compilation. Future work will make the +patterns loadable at runtime. + +>> Explicit specification of upstream/downstream nodes + +The nodes may require an explicit specification of upstream and +downstream elements. This is useful because the metaprotocol may +create loops - depending on the programming framework. + +>> Limited wild card support + +Only one wild card is supported in any pattern. Support for multiple +wild cards will be added in future. For example if multiple buffers +must be incorporated into a mux-demux system, then the meaning of the +following line is that two buffers must be connected to the +multiplexor. + + CONFIG LINK ADD MULTIPLEXOR 0 BUFFER 0 2 + +On the other hand, the following instruction means that first two +buffers must be disconnected from the multiplexor. + + UNCONFIG LINK DEL MULTIPLEXOR 0 BUFFER 0 2 + +Fine grained control and multiple wildcards will be supported in +future. + +>> UNCONFIG ARG not effective + +UNCONFIG supports only LINK commands for now. UNCONFIG ARG will be +added in future. + +======================================================================= + +7. FUTURE WORK +-------------- + +1. Porting Click 1.6.0 + +The core functionality of 1.6.0 release of Click is similar to that of +1.5.0. Some of the 1.6.0 code is already incorporated due to +compilation issues mentioned above. The + +2. Runtime parsing. + +The parsing of the patterns is currently a compile-time operation. The +parser has been written in Perl. Making this process a runtime +operation by embedding a parser into the metaprotocol enables dynamic +loading of the patterns file and learning of the patterns across +hosts. + +3. Extensions to the language + +The language described above is still primitive. Possible extensions +include more expressive patterns with support for notions such as +atleast or atmost, a language for testing, + +4. Context-driven composition + +A decision process is required to bridge the information about the +context of operations and the final goal of the protocol. + +5. Multiple host configurations + +Multiple peers e.g., any kind of algorithm that involves multiple +parties such as routing, filtering etc. In this case the design point +is obtained from the peer and it is relatively fixed. New design +points may be propagated accounting for disruption. + +6. Check multiple possible compositions + +Exchange a set of possible next compositions instead of one at a +time. This is a simple extension and should be supported in future. + +7. Support for multiple negotiation strategies + +Currently the metaprotocol supports only one kind of negotiation style +(simple two-way negotiate + test). Others may be necessary/interesting +such as those with multilevel backtracking and with memory. + +8. Dynamic instantiation of modules + +This enables further simplification of the configuration files but +requires modifications to the Click core. Index: rna/conf/rna-muxdemux-left.click diff -u /dev/null rna/conf/rna-muxdemux-left.click:1.2 --- /dev/null Tue Jul 1 09:16:48 2008 +++ rna/conf/rna-muxdemux-left.click Mon Jun 30 12:42:10 2008 @@ -0,0 +1,76 @@ + +// RNA Test Configuration File: MuxDemux +// +// This script instantiates the left stack and the negotiation between +// the endpoints is supposed to result in a mux-demux like arrangement. +// Other patterns may be added but they do not succeed (failed +// prerequiresites). +// +// +// PktSrc PktSrc +// | | +// V V +// Buffer Buffer +// | | +// V V +// +----------------+ +------+---------+ +// | [Metaprotocol] | | [Metaprotocol] | +// | Mux | | Mux | +// | / \ | | / \ | +// | Buf1 Buf2 | | Buf1 Buf2 | +// | \ / | | \ / | +// | Demux | | Demux | +// | | | | | | +// +-------+--------+ +------+---------+ +// | | +// V V +// +-----------------+ +// Left stack Right stack +// +// Execute +// cd /userlevel +// ./click ../conf/rna-muxdemux-left.click +// + + +// Generate copies of the packets coming from above +// at regular intervals... +b1 :: Buffer(NAME 'B1 MODULE', + COPIES true, + PROCESS true); + +// Modules that must be composed +e1 :: Buffer(NAME 'E1 MODULE'); +e2 :: Buffer(NAME 'E2 MODULE'); +m1 :: Multiplexor(NAME 'MUX 1'); +d1 :: Demultiplexor(NAME 'DEMUX 1'); + +// Set the goal of the metaprotocol as muxdemux. Enable automatic +// negotiation between the endpoints. +r1 :: Metaprotocol(NAME 'MP1', + ELEMENTS e1 e2 d1 m1, + PROCESS true, + CONN false, + PATTERN 'MUXDEMUX', + AUTONEGOTIATE true); + +// Packet generator... +src :: InfiniteSource(\, 2) +p1 :: RNAPktSrc(NAME 'PKTSRC1', + PROCESS true); + +// Create a loopback on the machine to another instance of the +// metaprotocol +AddressInfo( + nik 128.9.168.58, +) + +elementclass loopback { + input[0] -> Socket(UDP, nik, 20001) + Socket(UDP, 0.0.0.0, 20000) -> [0] output +} + +l :: loopback + +src -> [0] p1 [0] -> [0] b1 [1] -> [0] r1 [1] -> Print -> [0] l +l[0] -> Print -> [1] r1 [0] -> [1] b1 [0] -> Print -> Discard Index: rna/conf/rna-muxdemux-right.click diff -u /dev/null rna/conf/rna-muxdemux-right.click:1.2 --- /dev/null Tue Jul 1 09:16:49 2008 +++ rna/conf/rna-muxdemux-right.click Mon Jun 30 12:42:10 2008 @@ -0,0 +1,76 @@ + +// RNA Test Configuration File: MuxDemux +// +// This script instantiates the right stack and the negotiation between +// the endpoints is supposed to result in a mux-demux like arrangement. +// Other patterns may be added but they do not succeed (failed +// prerequiresites). +// +// +// PktSrc PktSrc +// | | +// V V +// Buffer Buffer +// | | +// V V +// +----------------+ +------+---------+ +// | [Metaprotocol] | | [Metaprotocol] | +// | Mux | | Mux | +// | / \ | | / \ | +// | Buf1 Buf2 | | Buf1 Buf2 | +// | \ / | | \ / | +// | Demux | | Demux | +// | | | | | | +// +-------+--------+ +------+---------+ +// | | +// V V +// +-----------------+ +// Left stack Right stack +// +// Execute +// cd /userlevel +// ./click ../conf/rna-muxdemux-right.click +// + +// Generate copies of the packets coming from above +// at regular intervals... +//b1 :: Buffer(NAME 'B1 MODULE', +// COPIES true, +// PROCESS true); + +// Modules that must be composed +e1 :: Buffer(NAME 'E1 MODULE'); +e2 :: Buffer(NAME 'E2 MODULE'); +m1 :: Multiplexor(NAME 'MUX 1'); +d1 :: Demultiplexor(NAME 'DEMUX 1'); + +// Set the goal of the metaprotocol as muxdemux. +r1 :: Metaprotocol(NAME 'MP1', + ELEMENTS e1 e2 d1 m1, + PROCESS true, + CONN false, + PATTERN 'MUXDEMUX'); + +p1 :: RNAPktSrc(NAME 'PKTSRC2', + PROCESS true); + +AddressInfo( + nik 128.9.168.58, +) + +src :: InfiniteSource(\, 0) + +// Loopback the data that has been sent out. +elementclass loopback { + input[0] -> Socket(UDP, nik, 20000) + Socket(UDP, 0.0.0.0, 20001) -> [0] output +} + +l :: loopback + +// Create the minimal composition. Still looks like +// existing Click program but will be eventually simplified to +// just "r1" + +src -> Print -> [0] p1 [0] -> [0] r1 [1] -> Print -> [0] l +l[0] -> Print -> [1] r1 [0] -> Print -> Discard Index: rna/conf/rna-reorderbuffer-left.click diff -u /dev/null rna/conf/rna-reorderbuffer-left.click:1.1 --- /dev/null Tue Jul 1 09:16:49 2008 +++ rna/conf/rna-reorderbuffer-left.click Mon Jun 30 12:42:10 2008 @@ -0,0 +1,81 @@ +// +// The elements are specified such that pattern ORDERED_DELIVERY +// is supported (see elements/rna/metaprotocol_patterns_db.txt) +// +// Autonegotiate is necessary to enable execution of pattern MIN first +// followed by ORDERED_DELIVERY. Prerequisites are not satisfied for +// other patterns such as ENCRYPTED_ORDERED_DELIVERY, TUNNEL and +// MUXDEMUX to be executed. +// +// +// PKTSRC1 (RNAPktSrc) +// | +// V +// +------------------+ +// | \ MP1 | +// | \ | +// | | | +// | V | +// | REORDER1 (ReorderBuffer) +// | | | +// | V | +// | B1 MODULE (Buffer) +// | / | +// | / | +// | | | +// | V | +// +------------------+ +// | +// V +// +// To the rightstack +// +// Execute +// cd /userlevel +// ./click ../conf/rna-reorderbuffer-left.click +// + +e1 :: Buffer(NAME 'B1 MODULE'); + +e2 :: Demultiplexor(NAME 'DEMUX 1'); + +e3 :: ReorderBuffer(NAME 'REORDER 1'); + + +r1 :: Metaprotocol(NAME 'MP1', + ELEMENTS e1 e2 e3, + PROCESS true, + CONN false, + PATTERN 'MIN', + AUTONEGOTIATE true); + +p1 :: RNAPktSrc(NAME 'PKTSRC1', + PROCESS true); + +b1 :: Buffer(NAME 'PKTSRCBUF1', + PROCESS true, + COPIES true, + DELAY true); + +AddressInfo( + nik 128.9.168.58, +) + +src :: InfiniteSource(\, 2) + +// Loopback the data that has been sent out. +elementclass loopback { + input[0] -> Socket(UDP, nik, 20001) + Socket(UDP, 0.0.0.0, 20000) -> [0] output +} + +l :: loopback + +// WAIT!!!! + +// Make sure that Bufferelem has input ports 0/0 going upstream and +// 1/1 going downstream when being used as stand alone protocol +// module + +src -> [0] p1 [0] -> [0] b1 [1] -> [0] r1 [1] -> Print -> [0] l +l[0] -> Print -> [1] r1 [0] -> [1] b1 [0] -> Print -> Discard Index: rna/conf/rna-reorderbuffer-right.click diff -u /dev/null rna/conf/rna-reorderbuffer-right.click:1.1 --- /dev/null Tue Jul 1 09:16:49 2008 +++ rna/conf/rna-reorderbuffer-right.click Mon Jun 30 12:42:10 2008 @@ -0,0 +1,67 @@ +// +// The elements are specified such that pattern ORDERED_DELIVERY +// is supported (see elements/rna/metaprotocol_patterns_db.txt) +// +// Autonegotiate is necessary to enable execution of pattern MIN first +// followed by ORDERED_DELIVERY. Prerequisites are not satisfied for +// other patterns such as ENCRYPTED_ORDERED_DELIVERY, TUNNEL and +// MUXDEMUX to be executed. +// +// +// PKTSRC2 (RNAPktSrc) +// | +// V +// +------------------+ +// | \ MP2 | +// | \ | +// | | | +// | V | +// | REORDER2 (ReorderBuffer) +// | | | +// | V | +// | B2 MODULE (Buffer) +// | / | +// | / | +// | | | +// | V | +// +------------------+ +// | +// V +// To the left stack +// +// Execute +// cd /userlevel +// ./click ../conf/rna-reorderbuffer-right.click +// + +e1 :: Buffer(NAME 'B2 MODULE'); + +e2 :: Demultiplexor(NAME 'DEMUX 2'); + +e3 :: ReorderBuffer(NAME 'REORDER 2'); + +r1 :: Metaprotocol(NAME 'MP2', + ELEMENTS e1 e2 e3, + PROCESS true, + CONN false, + PATTERN 'MIN'); + +p1 :: RNAPktSrc(NAME 'PKTSRC2', + PROCESS true); + +AddressInfo( + nik 128.9.168.58, +) + +src :: InfiniteSource(\, 0) + +// Loopback the data that has been sent out. +elementclass loopback { + input[0] -> Socket(UDP, nik, 20000) + Socket(UDP, 0.0.0.0, 20001) -> [0] output +} + +l :: loopback + +src -> Print -> [0] p1 [0] -> [0] r1 [1] -> Print -> [0] l +l[0] -> Print -> [1] r1 [0] -> Print -> Discard Index: rna/elements/rna/metaprotocol.cc diff -u /dev/null rna/elements/rna/metaprotocol.cc:1.3 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/metaprotocol.cc Mon Jun 30 12:43:20 2008 @@ -0,0 +1,1128 @@ + +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "rnaelement.hh" +#include "metaprotocol.hh" + +class Handler; + +CLICK_DECLS + +// This is the main file that implements the metaprotocol. It is yet +// another RNA element, i.e., it is derived from the RNA element. Each +// RNA Metaprotcol turns into a single protocol which corresponds to a +// layer. The idea is to make the metaprotocol generic enough to +// customize to any protocol at runtime. + + + +// It alters the composition of self using Click interfaces. +// RNAElement provides a set of built in capabilities to alter the com + + +//========================================================= +// +// Initialize/destroy the object +// +//========================================================= + +Metaprotocol::Metaprotocol() +{ + + set_type(CONTROL); + connection_oriented = true; + _options = NULL; + instance = ""; + _start_pattern = ""; + + autonegotiate = false; + negotiation_ongoing = false; + negotiation_pattern = 0; + finished_negotiation = false; + test_ongoing = false; + finished_test = false; + initialized_protocol = false; + + +}; + +Metaprotocol::~Metaprotocol() +{ + //delete state; +}; + + +//========================================================= +// +// Element list processing... +// +// The configuration provides a list of elements for processing. This +// is a function that will extract one element of a given type. There +// are two versions - a version that is read only and another that +// deletes the element before returning. +// +//========================================================= + +// +// Find the options element... +// + +RNAElement * +Metaprotocol::find_one_element(RNAElementType t){ + + for (int i = 0; i < _elemlist.size(); i++){ + RNAElement *e = _elemlist[i]; + if (e && e->get_type() == t ){ + return e; + } + } + + return NULL; +}; + +// +// Find an element of a given type and return that element. Remove the +// element from the list. +// + +RNAElement * +Metaprotocol::find_one_element_erase(RNAElementType t){ + + int elemnum = -1,i; + + for (i = 0; i < _elemlist.size(); i++){ + RNAElement *e = _elemlist[i]; + if (e && e->get_type() == t ){ + elemnum = i; + click_chatter("[%s] Metaprotocol::find_one_element_erase: " + "found element %s \n", + instance_name(), e->instance_name()); + + break; + } + }; + + if (elemnum >= 0) { + RNAElement *e = _elemlist[i]; + _elemlist.erase(_elemlist.begin() + i); + return e; + } else { + return NULL; + }; +}; + +//========================================================= +// +// +// Select the next pattern - Given a list of possible pattern for the +// next step, how should we select one? This is a place where +// preferences and policy apply but there is is not support for them +// at the present. We simply return the first valid pattern. +// +//========================================================= + +Pattern * +Metaprotocol::select_pattern(Vector _patlist){ + + // Return the very first... + if (_patlist.size() > 0) + return _patlist[0]; + else + return NULL; +}; + + +// ############################################################# +// +// Handler for incoming test messages... +// +// ############################################################# + +// +// This is a function that tests the composition after execution by +// sending a message back and forth. Only when the message is +// received, the composition is assumed to complete and correct. +// +// Note: Metaprotocol does not allow concurrent testing of multiple +// compositions. + +//========================================================= +// +// Upon receiving a test request (after completion of negotiation and +// execution), the peer sends a test reply. Upon receiving a test +// reply, the negotiation process is assumed to be complete. If +// autonegotiation is enabled, the process continues until it can +// proceed no further. +// +//========================================================= + +void +Metaprotocol::test_reply(int port, Packet *p){ + + (void)port; + if (!p) + return; + + + unsigned char *data = (unsigned char *)p->data(); + + //========================================================= + // Sanity check.... + //========================================================= + if ((test_ongoing == false) || + (*(data + 1) != MESSAGE_DATA_TEST) || + (*(data + 2) != MESSAGE_DATA_TEST_ECHO_REPLY)) { + rna_click_chatter(FUNC_DEFAULT,"[%s] Metaprotocol::test_reply " + "reply %s \n", + instance_name(), + ((test_ongoing == false) ? "unexpected" : "wrong type") + ); + p->kill(); + return; + }; + + //========================================================= + // Process the reply + //========================================================= + if (*(data + 2) == MESSAGE_DATA_TEST_ECHO_REPLY){ + + rna_click_chatter(FUNC_DEFAULT,"[%s] Metaprotocol::test_reply " + "Handled reply; Dropping packet \n\n", + instance_name()); + + // update the flags + test_ongoing = false; + finished_test = true; + initialized_protocol = true; + + // Eliminate the packet... + p->kill(); + + // If autonegotiate is enabled, then extract the next feasible + // pattern and initiate the negotiation with that pattern. + if (autonegotiate){ + + if (negotiation_pattern->Name() == "NULL" && _start_pattern != ""){ + Pattern * startpat = state->find_pattern(_start_pattern); + initiate_negotiation(startpat); + } else { + Vector next_pats = state->find_next_verified_patterns(); + if (next_pats.size() > 0){ + Pattern *next_pat = select_pattern(next_pats); + initiate_negotiation(next_pat); + }; + }; + }; + + }; + + return; + +}; + +// +// This test request is typically sent by the peer initiating the +// negotiation. The test message is intended for exactly that - +// testing whether the composition has been successful or not. This +// involves generating a new message labeled as test in the header and +// sending it over the intra-layer outgoing links. + +void +Metaprotocol::test_request(int port, Packet *p){ + + click_chatter("[%s] Metaprotocol::test_request Entered", instance_name()); + + //--------------------------------------------------------- + // Sanity checks... + //--------------------------------------------------------- + if (!p){ + click_chatter("[%s] Metaprotocol::test_request Error - undefined message", + instance_name()); + return; + }; + + + LinkState *incoming_link = lookup_link(port); + if (! incoming_link ){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] Metaprotocol::test_request Dropping packet...\n", + instance_name()); + p->kill(); + return; + }; + + //--------------------------------------------------------- + // Make sure that the message has a known type + //--------------------------------------------------------- + unsigned char *data = (unsigned char *)p->data(); + + int data_message_type = *(data + 1); + if (data_message_type != MESSAGE_DATA_TEST) { + click_chatter("[%s] Metaprotocol::test_request Error - Wrong kind of message", + instance_name()); + p->kill(); + return; + }; + + + data_message_type = *(data + 2); + if (data_message_type != MESSAGE_DATA_TEST_ECHO_REQUEST){ + click_chatter("[%s] Metaprotocol::test_request Error - " + "Unknown test message type..", + instance_name()); + p->kill(); + return; + }; + + //--------------------------------------------------------- + // Send the reply... + //--------------------------------------------------------- + + // rewrite the first three bits of the header... + data = (unsigned char *)p->data(); + *data = MESSAGE_DATA; + *(data + 1) = MESSAGE_DATA_TEST; + *(data + 2) = MESSAGE_DATA_TEST_ECHO_REPLY; + + // Eventually we might have to send some more information e.g., a + // nonce. + + // Figure out where to send the message out. If the incoming message + // has come on a intra-layer link, then + + bool crosslayer = incoming_link->is_crosslayer(); + LinkState *l = select_outgoing_link(p, NULL, + true, /* headed downstream */ + false, /* not layer agnostic */ + crosslayer, /* cross layer */ + true, /* agnostic remote endpoint */ + /* of the cross-layer link */ + false /* doesnt matter */ + ); + + // Cant send the packet out... + if (!l) + p->kill(); + + // If an outgoing link exists, then send the packet along the link + if (l){ + + if (debug) { + click_chatter("[%s] Metaprotocol::test_request - Sending test REPLY\n", + instance_name()); + click_chatter("[M1] Sending packet to:\n"); + l->print(instance_name()); + }; + + Port port = output(l->local_port); + if (port.active()){ + click_chatter("Sending out on port"); + //process_outgoing_to_downstream(&p, l); + port.push(p); + } else { + rna_click_chatter(FUNC_DEFAULT,"output port is not active.\n"); + }; + }; + + click_chatter("[%s] Metaprotocol::test_request Exited", instance_name()); + + return; + +}; + +//========================================================= +// + +// Initiate a test message to the peer...This is typically executed at +// the end that initiated the negotiation process. + +// +//========================================================= + +int +Metaprotocol::initiate_test(bool crosslayer, String teststring, LinkState *l){ + + + if (teststring.length() > 255) { + click_chatter("[%s] Metaprotocol::initiate_test Error! " + "teststring greater than 255 bytes", + instance_name()); + return -1; + }; + + + //========================================================= + // Generate the test message... + //========================================================= + + // Create a new packet + WritablePacket *p = Packet::make(teststring.length() + 4); + unsigned char *data = (unsigned char *)p->data(); + + // Copy three bytes of header... + *data = MESSAGE_DATA; + *(data + 1) = MESSAGE_DATA_TEST; + *(data + 2) = MESSAGE_DATA_TEST_ECHO_REQUEST; + *(data + 3) = teststring.length(); + memcpy(data + 4, teststring.c_str(), teststring.length()); + + + //========================================================= + // Find the outgoing link and send it out... + //========================================================= + + if (!l) + l = select_outgoing_link(p, NULL, + true, /* headed downstream */ + false, /* not layer agnostic */ + crosslayer, /* cross layer */ + true, /* agnostic remote endpoint */ + /* of the cross-layer link */ + false /* doesnt matter */ + ); + + // If no link exists, then kill it and return... + if (!l) + p->kill(); + + // If an outgoing link exists, then send the packet along the link + if (l){ + + if (1) { + discover_connectionstate(l); + if (l->connection_oriented) { + ConnectionState *c = l->connstate_get(); + SET_CONN_ANNO(p, c); + }; + }; + + // print_links(); + + if (debug) + click_chatter("[%s] Metaprotocol::initiate_test\n" + "[M2] Sending packet to:\n", + instance_name()); + + l->print(instance_name()); + Port port = output(l->local_port); + if (port.active()){ + click_chatter("Sending out on port"); + //process_outgoing_to_downstream(&p, l); + port.push(p); + } else { + rna_click_chatter(FUNC_DEFAULT,"output port is not active.\n"); + p->kill(); + }; + }; + + test_ongoing = true; + return 0; + +}; + + +//========================================================= +// +// Initiate an exchange with the other endpoint regarding a potential +// composition. The process might result in a success of failure. The +// negotiation process must be modified to handle all possible +// errors. For now, this is a fragile process. +// +//========================================================= + +int +Metaprotocol::initiate_negotiation(Pattern *next_pattern){ + + + if (!next_pattern) { + click_chatter("[%s] Metaprotocol::initiate_negotiation(*) - Failed. " + "Pattern argument not found", + instance_name()); + return -1; + }; + + // Mostly useful only for printing purpose... + String s = next_pattern->Name(); + click_chatter("[%s] Metaprotocol::initiate_negotiation(%s) Entering", + instance_name(), s.printable().c_str()); + + // Check if we are in the middle of an exchange + if (negotiation_ongoing == true) { + click_chatter("[%s] Metaprotocol::initiate_negotiation(%s) - Terminated " + "Negotiation ongoing.", + instance_name(), s.printable().c_str()); + return -1; + } + + + //========================================================= + // Extract the pattern + //========================================================= + + int ret = next_pattern->Verify(); + if (ret < 0){ + click_chatter("[%s] Metaprotocol::initiate_negotiation(%s) - Failed. " + "Pattern not verified.", + instance_name(), s.printable().c_str()); + return -1; + }; + + click_chatter("[%s] Metaprotocol::initiate_negotiation(%s) - " + "verify successful", + instance_name(), s.printable().c_str()); + + //========================================================= + // Generate the negotiation packet.... + //========================================================= + + Packet *p = next_pattern->GenerateMessage(); + p->push(3); + unsigned char *data = (unsigned char *)p->data(); + *data = MESSAGE_CONTROL; + *(data + 1) = MESSAGE_CONTROL_NEGOTIATE; + *(data + 2) = MESSAGE_CONTROL_NEGOTIATE_REQUEST; + + LinkState *l = select_outgoing_link(p, NULL, + true, /* headed downstream */ + false, /* not layer agnostic */ + true, /* cross layer */ + true, /* agnostic remote endpoint */ + /* of the cross-layer link */ + false /* doesnt matter */ + ); + + // If an outgoing link exists, then send the packet along the link + + if (l){ + + if (0) { + discover_connectionstate(l); + if (l->connection_oriented) { + ConnectionState *c = l->connstate_get(); + SET_CONN_ANNO(p, c); + }; + }; + + // print_links(); + + click_chatter("[M3] Sending packet to:\n"); + l->print(instance_name()); + Port port = output(l->local_port); + if (port.active()){ + click_chatter("Sending out on port"); + //process_outgoing_to_downstream(&p, l); + port.push(p); + } else { + rna_click_chatter(FUNC_DEFAULT,"output port is not active.\n"); + }; + }; + + negotiation_ongoing = true; + negotiation_pattern = next_pattern; + + // rna_click_chatter(FUNC_DEFAULT,"[%s] Metaprotocol::initiate_negotiation()" + // "returning\n", instance_name()); + return 0; + +}; + + + +//========================================================= +// + +// Upon receiving a negotiation request, a reply is generated. This +// function is called at the initiator end of the neogitiation. + +// +//========================================================= + +void +Metaprotocol::negotiate_reply(Packet *p){ + + if (!p) + return; + + if (debug) + rna_click_chatter(FUNC_DEFAULT,"[%s] Metaprotocol::negotiate_reply " + "Entry\n", instance_name()); + + unsigned char *data = (unsigned char *)p->data(); + + //========================================================= + // Sanity check.... + //========================================================= + if ((negotiation_ongoing == false) || + (*(data + 1) != MESSAGE_CONTROL_NEGOTIATE)) { + rna_click_chatter(FUNC_DEFAULT,"[%s] Metaprotocol::negotiate_reply " + "Dropping packet...negotiation not in progress or wrong message type\n", + instance_name()); + p->kill(); + return; + }; + + //========================================================= + // Process the reply + //========================================================= + if (*(data + 2) == MESSAGE_CONTROL_NEGOTIATE_REPLY_SUCCESS){ + + rna_click_chatter(FUNC_DEFAULT,"[%s] Metaprotocol::negotiate_reply " + "process successful reply\n", instance_name()); + + // Execute the pattern + state->execute_pattern(negotiation_pattern); + + // Cleanup + negotiation_ongoing = false; + finished_negotiation = true; + p->kill(); + + // Now initiate testing... + String pattern_name = negotiation_pattern->Name(); + bool crosslayer = false; + if (pattern_name == "NULL") + crosslayer = true; + + String testpattern = negotiation_pattern->Name(); + initiate_test(crosslayer, testpattern, 0); + + }; + + if (*(data + 2) == MESSAGE_CONTROL_NEGOTIATE_REPLY_FAILURE){ + + rna_click_chatter(FUNC_DEFAULT,"[%s] Metaprotocol::negotiate_reply " + "Dropping packet - failure in reply\n"); + + // Cleanup + negotiation_ongoing = false; + finished_negotiation = true; + negotiation_pattern = 0; + p->kill(); + + }; + + + return; + +}; + + +//========================================================= +// +// Handle the request from the peer +// +//========================================================= +void +Metaprotocol::negotiate_request(Packet *p){ + + if (!p) + return; + + if (negotiation_ongoing == true){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] Metaprotocol::negotiate_request - Failure; " + "Dropping packet due to ongoing negotiation\n", + instance_name()); + return; + }; + + // Drop the negotiate flag and the type of negotiate message + p->pull(3); + + // Remove the header and update the pointer... + unsigned char *data = (unsigned char *)p->data(); + int length = *data; + Pattern *matched_pattern = 0; + + //========================================================= + // Sanity check.... + //========================================================= + if (!initialized_protocol) { + if ((length != 4) || (memcmp("NULL", data + 1, 4) != 0)){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] Not initialized and the pattern is " + "not NULL. So dropping packet...\n", + instance_name()); + p->kill(); + return; + }; + }; + + + Vector patlist = state->get_all_patterns(); + for (int i = 0; i < patlist.size(); i++){ + Pattern *pat = patlist[i]; + if (pat->ValidateMessage(p) >= 0){ + matched_pattern = pat; + break; + }; + }; + + if (!matched_pattern){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] Metaprotocol::negotiate_request " + "Didnt match any pattern; Dropping packet...\n", + instance_name()); + p->kill(); + return; + }; + + // Ok; Now obtained the matched pattern + String name = matched_pattern->Name(); + rna_click_chatter(FUNC_DEFAULT, + "[%s] Metaprotocol::negotiate_request Matched pattern %s \n", + instance_name(), name.c_str()); + + //========================================================= + // Generate a reply; use the incoming message. + //========================================================= + p->pull(length + 1); // Account for the string length... + p->push(3); + data = (unsigned char *)p->data(); + *(data + 0) = MESSAGE_CONTROL; + *(data + 1) = MESSAGE_CONTROL_NEGOTIATE; + + //========================================================= + // Can this pattern be instantiated? + //========================================================= + int ret = matched_pattern->Verify(); + //click_chatter("[%s] Metaprotocol::push_control() - verify ret = " + // "%d", instance_name(), ret); + + if (ret < 0){ + click_chatter("[%s] Metaprotocol::negotiate_request (%s) - Failed. " + "Pattern not verified.", + instance_name(), name.printable().c_str()); + *(data + 2) = MESSAGE_CONTROL_NEGOTIATE_REPLY_FAILURE; + } else { + *(data + 2) = MESSAGE_CONTROL_NEGOTIATE_REPLY_SUCCESS; + click_chatter("[%s] Metaprotocol::negotiate_request (%s) - Successful. " + "Pattern verified.", + instance_name(), name.printable().c_str()); + }; + + // Finish executing the pattern... + if (ret >= 0) + state->execute_pattern(matched_pattern); + + //========================================================= + // Send a reply back... + //========================================================= + // Extract the outgoing path/lnk + LinkState *l = select_outgoing_link(p, NULL, + true, /* headed downstream */ + false, /* not layer agnostic */ + true, /* cross layer */ + true, /* agnostic remote endpoint */ + /* of the cross-layer link */ + false /* doesnt matter */ + ); + // Send it out.... + if (l){ + + rna_click_chatter(FUNC_DEFAULT,"[%s] Metaprotocol::negotiate_request " + "sending reply\n", instance_name()); + + if (0) { + discover_connectionstate(l); + if (l->connection_oriented) { + ConnectionState *c = l->connstate_get(); + SET_CONN_ANNO(p, c); + }; + }; + + // print_links(); + + click_chatter("[M4] Sending packet to:\n"); + l->print(instance_name()); + Port port = output(l->local_port); + if (port.active()){ + click_chatter("Sending out on port"); + //process_outgoing_to_downstream(&p, l); + port.push(p); + } else { + rna_click_chatter(FUNC_DEFAULT,"output port is not active.\n"); + }; + }; + + finished_negotiation = true; + initialized_protocol = true; + + return; + +}; + +void +Metaprotocol::push_management(int port, Packet *p){ + + click_chatter("[%s] Metaprotocol::push_management - received a " + "management message", + instance_name()); + + LinkState *l = lookup_link (port); + if (!l) + return; + + // If I am downstream and I havent completed negotiation... + if (!l->is_downstream() || !l->is_crosslayer()){ + click_chatter("[%s] Metaprotocol::push_management - not downstream and " + "cross layer message \n", + instance_name()); + return; + }; + + unsigned char *data = (unsigned char *)p->data(); + if ((*( data + 0) != MESSAGE_MANAGEMENT) || + ((*(data + 1) != MESSAGE_MANAGEMENT_ADD_MODULE) && + (*(data + 1) != MESSAGE_MANAGEMENT_DEL_MODULE))){ + click_chatter("[%s] Metaprotocol::push_management - wrong message type \n", + instance_name()); + return; + }; + + if (negotiation_ongoing || test_ongoing ){ + + p->kill(); + click_chatter("[%s] Metaprotocol::push_management - " + "Killing packet. Negotiation/testing ongoing\n", + instance_name()); + return; + }; + + if (*(data + 1) == MESSAGE_MANAGEMENT_ADD_MODULE){ + + if (initialized_protocol == false){ + + Pattern * nullpat = state->find_pattern("NULL"); + initiate_negotiation(nullpat); + + } else { + + Vector next_pats = state->find_next_verified_patterns(); + if (next_pats.size() > 0){ + Pattern *next_pat = select_pattern(next_pats); + initiate_negotiation(next_pat); + }; + + }; + }; + + if (*(data + 1) == MESSAGE_MANAGEMENT_DEL_MODULE){ + // ... + }; + + return; +}; + +//========================================================= +// +// Handle the data from the other layers +// +//========================================================= + +void +Metaprotocol::push_data(int port, Packet *p){ + + (void)port; + (void)p; + + click_chatter("[%s] Metaprotocol::push_data - received a data message", + instance_name()); + + LinkState *l = lookup_link (port); + if (!l) + return; + + // If I am downstream and I havent completed negotiation... + if (l->is_downstream()){ + + if (initialized_protocol == false){ + + // I am not initialized, yet. So throw away the message from the + // layer above. + + p->kill(); + + click_chatter("[%s] Metaprotocol::push_data - " + "Killing packet. Protocol not initialized. \n", + instance_name()); + + if (autonegotiate) { + Pattern * nullpat = state->find_pattern("NULL"); + initiate_negotiation(nullpat); + }; + + } else { + + // ========================================================= + // See if there are any more patterns. If there are, then + // negotiate them. Otherwise simply send data... + // ========================================================= + + if (l->is_crosslayer() && + (negotiation_ongoing || test_ongoing )){ + + p->kill(); + click_chatter("[%s] Metaprotocol::push_data - " + "Killing packet. Negotiation/testing ongoing\n", + instance_name()); + + } else { + // + // Add a header saying this layer is not doing anything + // interesting... + // + + p->push(3); + unsigned char *data = (unsigned char *)p->data(); + *data = MESSAGE_DATA; + *(data + 1) = MESSAGE_DATA_NORMAL; + *(data + 2) = 0; + + if (debug) + RNAElement::print_packet("push_data", p, false); + + RNAElement::push_data(port, p); + } + + }; + + } else { + + // + // Coming from the lower layer... + // + + unsigned char *data = (unsigned char *)p->data(); + + if (*(data + 1) == MESSAGE_DATA_NORMAL){ + click_chatter("[%s] Metaprotocol::push_data - " + "Normal data. Pushing to intra-layer module.\n", + instance_name()); + p->pull(3); + RNAElement::push_data(port, p); + }; + + // Test message.... + if (*(data + 1) == MESSAGE_DATA_TEST){ + click_chatter("[%s] Metaprotocol::push_data - " + "received test (%d)%s \n", + instance_name(), + (int)(*(data + 2)), + ((*(data + 2) == MESSAGE_DATA_TEST_ECHO_REQUEST) ? + "REQUEST" : "REPLY")); + + if (*(data + 2) == MESSAGE_DATA_TEST_ECHO_REQUEST) + test_request(port, p); + else + test_reply(port, p); + }; + + }; + + return; +}; + +//========================================================= +// +// Handle control messages from the peer +// +//========================================================= + +void +Metaprotocol::push_control(int port, Packet *p){ + + click_chatter("[%s] Metaprotocol::push_control - received a " + "control message", + instance_name()); + + if (!p) + return; + + //========================================================= + // Extract Data/incoming link + //========================================================= + + LinkState *incoming_link = lookup_link(port); + if (! incoming_link ){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] Dropping packet...\n", + instance_name()); + p->kill(); + return; + }; + + //========================================================= + // Receive a control message from the peer.... + //========================================================= + + // *data MESSAGE_CONTROL is already been pulled. + unsigned char *data = (unsigned char *)p->data(); + if (*(data + 1) != MESSAGE_CONTROL_NEGOTIATE){ + + if (debug) + RNAElement::print_packet("push_control", p, false); + + if (debug) + rna_click_chatter(FUNC_DEFAULT, + "[%s] Dropping packet...Unknown control message (%d)\n", + *(data + 1), + instance_name()); + p->kill(); + return; + }; + + + if ( *(data + 2) == MESSAGE_CONTROL_NEGOTIATE_REQUEST) { + rna_click_chatter(FUNC_DEFAULT, + "[%s] Metaprotocol::push_control negotiation request\n", + instance_name()); + negotiate_request(p); + }; + + + //========================================================= + // Handle the reply.... + //========================================================= + if ((*(data + 2) == MESSAGE_CONTROL_NEGOTIATE_REPLY_FAILURE) || + (*(data + 2) == MESSAGE_CONTROL_NEGOTIATE_REPLY_SUCCESS)) { + + bool flag = (*(data + 1) == MESSAGE_CONTROL_NEGOTIATE_REPLY_FAILURE); + rna_click_chatter(FUNC_DEFAULT, + "[%s] Metaprotocol::push_control received negotiation " + "reply %s\n", + instance_name(), (flag? "FAILURE" : "SUCCESS")); + negotiate_reply(p); + }; + + return; + +}; + +//========================================================= +// +// Dont add any intra-protocol links. Simply ensure that the up and +// down inter-protocol links are added. +// +//========================================================= + +int +Metaprotocol::finish_configuration(){ + + //struct linkspec *link; + Vector linkspecs; + + click_chatter("[%s] Metaprotocol::finish_configuration() - " + "noutputs = %d ninputs = %d\n", + instance_name(), noutputs(), ninputs()); + +#ifdef COMMENT + if (noutputs() < 2 || _elemlist.size() < 2) { + rna_click_chatter(FUNC_DEFAULT, + "[%s] ERROR! Metaprotocol::finish_configuration() - " + "noutputs < 2 || element list < 2", + instance_name()); + return -1; + } + + + // Is this an independent initiator of the link creation? + + if (exec_finish_configuration) { + add_default_bidirectional_links(&linkspecs, true); + }; +#endif + + if (exec_finish_configuration) { + if (_preconfigured_element_list) + add_default_autodetect_links(&linkspecs, true); + else + add_default_bidirectional_links(&linkspecs, true); + }; + + //================================================== + + process_linkspecs(linkspecs); + + // print_links(); + + // Print out the table for the elements specified.... + if (0) + click_chatter("[%s] Element [myindex = %d, index = %d, inputs = %d, " + "outputs = %d] \n", + instance_name(), eindex(), this->eindex(), + this->ninputs(), this->noutputs()); + + for (int i = 0; i < _elemlist.size(); i++){ + Element *e = _elemlist[i]; + if (0) + click_chatter("[%s] Element [myindex = %d, index = %d, inputs = %d, " + "outputs = %d] \n", + instance_name(), eindex(), e->eindex(), + e->ninputs(), e->noutputs()); + }; + + // Test all the ports... + for (int i = 0; i < noutputs(); i++) { + Port p = output(i); + if (p.active()) { + Element *sender = p.element(); + if (0) + click_chatter("[%s] Metaprotocol::output port %d => %s\n", + instance_name(), i, sender->class_name()); + } else { + if (0) + click_chatter("[%s] Metaprotocol::output port %d => " + "inactive \n", instance_name(), i); + } + }; + + + return 0; +}; + +//=============================================================== +// +// Initial configuration of this module. Read the parameters from the +// configuration file.... +// +//=============================================================== + +int +Metaprotocol::configure(Vector &conf, ErrorHandler *errh) +{ + + RNAElement::configure(conf, errh); + + if (cp_va_parse(conf, this, errh, + cpKeywords, + "PATTERN", cpString, "Initial Pattern", &_start_pattern, + "AUTONEGOTIATE", cpBool, "Negotiate automatically", &autonegotiate, + cpEnd) < 0) + return -1; + + // Allocate state; Add the CONTROL element to element list provided + // to the state. + state = new State(this, _elemlist); + + if (exec_finish_configuration) + finish_configuration(); + + return 0; +}; + +ELEMENT_REQUIRES(State) +ELEMENT_REQUIRES(RNAElement) +EXPORT_ELEMENT(Metaprotocol) + +CLICK_ENDDECLS Index: rna/elements/rna/metaprotocol.hh diff -u /dev/null rna/elements/rna/metaprotocol.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/metaprotocol.hh Fri Jun 27 10:40:56 2008 @@ -0,0 +1,89 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_TEST_DYNCONTROLELEMENT_HH +#define CLICK_TEST_DYNCONTROLELEMENT_HH + +#include "rnaelement.hh" + +//================================================================ +// +// Core protocol - this will compose all other protocol modules +// +// A lot of work is done in the RNAElement class, state and pattern +// classes. So this appears a little more simpler than it is. +// +//================================================================ +class Metaprotocol : public RNAElement { +public: + + Metaprotocol(); + ~Metaprotocol(); + + static void static_initialize() { static_initialize_default(); }; + static void static_cleanup() { static_initialize_default(); }; + + // Click stuff... + const char *class_name() const { return default_class_name();} + const char *port_count() const { return "-/-"; } + const char *processing() const { return PUSH; } + int configuration_phase() { return CONFIGURE_PHASE_LAST; }; + int configure(Vector &, ErrorHandler *); + int finish_configuration(); + bool can_live_reconfigure() const { return true; } + + // Negotiation with the peer... + int initiate_negotiation(Pattern *); + void negotiate_request(Packet *p); + void negotiate_reply(Packet *p); + + // Message flow... + void push_control(int port, Packet *p); + void push_data(int port, Packet *p); + void push_management(int port, Packet *p); + + // Find element(s) that match a given type... + RNAElement *find_one_element(RNAElementType t); + RNAElement *find_one_element_erase(RNAElementType t); + + // + Pattern *select_pattern(Vector); + + // Test the constructed composition.... + int initiate_test(bool crosslayer, String teststring, LinkState *l = 0); + void test_reply(int port, Packet *p); + void test_request(int port, Packet *p); + + + private: + + Vector _processed_elemlist; + RNAElement *_options; + String _start_pattern; + bool client; + + // Negotiation related + bool autonegotiate; + bool finished_negotiation; + Pattern *negotiation_pattern; + bool negotiation_ongoing; + + // testing related. + bool finished_test; + bool test_ongoing; + + // Started exchange? + bool initialized_protocol; + +}; + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/metaprotocol_patterns.cc diff -u /dev/null rna/elements/rna/metaprotocol_patterns.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/metaprotocol_patterns.cc Fri Jun 27 10:40:56 2008 @@ -0,0 +1,743 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "metaprotocol_patterns.hh" + +//=================================================================== +// Class to store one pattern in each instance. A typical pattern +// looks like this (stored in metaprotocol_patterns.txt) +// +// PATTERN ENCRYPTED_ORDERED_DELIVERY +// FOLLOWS ORDERED_DELIVERY +// REQ MUST ENCRYPTION 1 +// REQ MUST REORDERBUFFER 1 +// REQ MUST DEMULTIPLEXOR 1 +// CONFIG ARG ENCRYPTION 1 algo des +// CONFIG ARG ENCRYPTION 1 keysize 512 +// CONFIG LINK ADD DEMULTIPLEXOR 1 REORDERBUFFER 1 +// CONFIG LINK ADD REORDERBUFFER 1 ENCRYPTION 1 +// UNCONFIG LINK DEL DEMULTIPLEXOR 1 REORDERBUFFER 1 +// UNCONFIG LINK DEL REORDERBUFFER 1 ENCRYPTION 1 +// +// Code for pattern ENCRYPTED_ORDERED_DELIVERY (generated by the patterns_parser.pl +// { +// parents.clear(); +// reqs.clear(); +// args.clear(); +// links.clear(); +// parents.push_back("ORDERED_DELIVERY"); +// r = new Req(CONSTRAINT_REQUIRE_MUST,ENCRYPTION,1); +// reqs.push_back(r); +// r = new Req(CONSTRAINT_REQUIRE_MUST,REORDERBUFFER,1); +// reqs.push_back(r); +// r = new Req(CONSTRAINT_REQUIRE_MUST,DEMULTIPLEXOR,1); +// reqs.push_back(r); +// a = new Arg(ENCRYPTION, 1, "algo", ""); +// args.push_back(a); +// a = new Arg(ENCRYPTION, 1, "keysize", ""); +// args.push_back(a); +// keywords.clear(); +// l = new Link(DEMULTIPLEXOR, 1, 1, REORDERBUFFER, 1, 1, OP_ADD, CONF_CONFIG, keywords); +// links.push_back(l); +// keywords.clear(); +// l = new Link(REORDERBUFFER, 1, 1, ENCRYPTION, 1, 1, OP_ADD, CONF_CONFIG, keywords); +// links.push_back(l); +// keywords.clear(); +// l = new Link(DEMULTIPLEXOR, 1, 1, REORDERBUFFER, 1, 1, OP_DEL, CONF_UNCONFIG, keywords); +// links.push_back(l); +// keywords.clear(); +// l = new Link(REORDERBUFFER, 1, 1, ENCRYPTION, 1, 1, OP_DEL, CONF_UNCONFIG, keywords); +// links.push_back(l); +// pat = new Pattern(this, "ENCRYPTED_ORDERED_DELIVERY", parents, reqs, args, links); +// }; +// .... +// +//=================================================================== + + +// +// Populate the class +// +Pattern::Pattern(State *s, + String name, + Vector parentlist, + Vector reqs, + Vector args, + Vector links){ + _s = s; + _name = name; + _parentlist = parentlist; + _reqs = reqs; + _args = args; + _links = links; + + // Result of the link create operations that are looked up + // during cleanup... + _lspecs.clear(); + +}; + + +//=================================================================== +// +// Cleanup the elements assigned to this pattern instance. Ideally +// this function should also check for 'active' patterns that is those +// that have been instantiated so that the pattern can be undone +// first. +// +//=================================================================== +Pattern::~Pattern(){ + + // Put the elements back in the shared state. Ideally this should be + // empty. + if (_s) { + while(_elemlist.size() > 0) { + _s->put_element(_elemlist.back()); + _elemlist.pop_back(); + }; + }; + +}; + +//=================================================================== +// +// Lookup a pattern by its name +// +//=================================================================== +bool +Pattern::Match(String name){ + return (_name == name); +}; + +//=================================================================== +// +// Return the name of this pattern +// +//=================================================================== +String +Pattern::Name(){ + return _name; +}; + +//=================================================================== +// +// Return the list of all the parent patterns which must be executed +// before this pattern can be. +// +//=================================================================== +Vector +Pattern::ParentNames(){ + return _parentlist; +}; + +//=================================================================== +// +// Return the prerequisites of this pattern. +// +//=================================================================== +Vector +Pattern::Requirements(){ + return _reqs; +}; + +//=================================================================== +// +// Test whether all the prerequisite previous patterns have been +// executed +// +//=================================================================== +bool +Pattern::MatchParentList(Vector completed_parent_list){ + + + // Go through each parent of the parent + for (int i = 0; i < _parentlist.size(); i++){ + bool found = false; + + // Look at the completed list of parents to see if they + // satisfy the parent requirements of the given pattern + // i.e., the follows requirement + for (int j = 0; j < completed_parent_list.size(); j++){ + if (completed_parent_list[j] == _parentlist[i]){ + found = true; + break; + } + }; + + // Well, is this parent requirement satisfied? + if (!found) + return false; + }; + + return true; +}; + +//=================================================================== +// +// Look at a list of patterns instead of one to determine the subset +// of patterns that are ready to be executed. One or more of them are +// selected for negotiation and execution later. +// +//=================================================================== +bool +Pattern::MatchParentList(Vector completed_parent_list){ + + bool found = false; + + // Debug + //click_chatter("Pattern::MatchParentList Looking for parents of %s \n", + //_name.c_str()); + // + //for (int j = 0; j < completed_parent_list.size(); j++){ + // String completed_parent_name = completed_parent_list[j]->Name(); + //click_chatter("Pattern::MatchParentList(%s): completed[%d] = %s\n", + // _name.c_str(), j, completed_parent_name.c_str()); + //}; + + + // Check if I am on the list of completed patterns. + for (int j = 0; j < completed_parent_list.size(); j++){ + String completed_parent_name = completed_parent_list[j]->Name(); + if (completed_parent_name == _name){ + found = true; + break; + }; + }; + + // If I am on the list, then skip self. + if (found) { + //click_chatter("Pattern::MatchParentList - Found %s on completed list\n", + // _name.c_str()); + return false; + }; + + + // Go through each parents to see if all of them are + // in the completed list... + for (int i = 0; i < _parentlist.size(); i++){ + found = false; + + //click_chatter("Pattern::MatchParentList Looking at %s - parent %s \n", + // _name.c_str(), _parentlist[i].c_str()); + + // Look at the completed list of parents to see if they + // satisfy the parent requirements of the given pattern + // i.e., the follows requirement + for (int j = 0; j < completed_parent_list.size(); j++){ + String completed_parent_name = completed_parent_list[j]->Name(); + int ret = String::compare(completed_parent_name, _parentlist[i]); + //click_chatter("Pattern::MatchParentList Looking at %s - " + // "parent \"%s\" current \"%s\" result = %d \n", + // _name.c_str(), _parentlist[i].c_str(), + // completed_parent_name.c_str(), ret); + if (ret == 0){ + found = true; + break; + } + }; + + // Well, is this parent requirement satisfied? + if (!found) { + //click_chatter("Pattern::MatchParentList %s - missed parent %s \n", + // _name.c_str(), _parentlist[i].c_str()); + + return false; + }; + }; + + + // click_chatter("Pattern::MatchParentList %s - parents are all satisfied\n", + // _name.c_str()); + + return true; +}; + + +//=================================================================== +// +// Among the elements 'owned' by this pattern (i.e., used for +// instantiation), find elements of a given type +// +//=================================================================== +RNAElement * +Pattern::FindElement(RNAElementType t, int n){ + + int c = -1; + + // Control is the metaprotocol. This is obtained from the state + // which obtains the same from the metaprotocol that instantiates + // the state. + if (t == CONTROL) { + RNAElement *control = _s->get_control(); + return control; + }; + + for (int j = 0; j < _elemlist.size(); j++){ + RNAElement *e = _elemlist[j]; + if (e->get_type() == t){ + c++; + if (c == n) { + return e; + }; + }; + }; + + return NULL; + +}; + +//======================================================== +// +// Generate the message corresponding to this pattern. This message +// will be sent to the peer. +// +//======================================================== + +Packet *Pattern::GenerateMessage(){ + + // Exchange the initial configuration - this pattern; once this + // accepted, then select one from the next few possible patterns. We + // could look ahead and exchange information on the other patterns + // as well. + + // Create a new packet + WritablePacket *p = Packet::make(0); + + int size = 1 + _name.length(); + p = p->push(size); + char *data = (char *)p->data(); + + // Add the header... + *(data + 0) = _name.length(); + strncpy(data + 1, _name.c_str(), _name.length()); + + return p; + +}; + +//======================================================== +// +// Check the incoming message to see if the incoming message matches +// this pattern. +// +//======================================================== + +int Pattern::ValidateMessage(Packet *p){ + + if (!p) + return -1; + + const char *data = (const char *)p->data(); + + int length = *(data + 0); + String iname (data + 1, length); + + if (_name.compare(iname)) + return -1; + + return 0; + +}; + +//======================================================== +// +// Verify if the requirements corresponding to this pattern can be +// met. +// +//======================================================== +int +Pattern::Verify(){ + + if (!_s) + return -1; + + //click_chatter("Pattern::Verify Requirements requirements size = %d\n", + // _reqs.size()); + + // Check if the prerequisits have been met. + for (int i = 0; i < _reqs.size(); i++){ + + Req *r = _reqs[i]; + if (!r){ + click_chatter("Pattern::Verify r is NULL\n"); + continue; + }; + + // Can I find the required number of elements of a given type? + if (r->c == CONSTRAINT_REQUIRE_MUST){ + int res = _s->check_elements(r->t, r->count); + if (res < 0){ + // r->print("FAILED"); + click_chatter("[Pattern::Verify] Failed to verify %s\n", + _name.c_str()); + return -1; + }; + }; + }; + + //click_chatter("Pattern::Verify Extracting the elements...\n"); + + return 0; +}; + + +//=================================================================== +// +// Helper function during execute. This function only looks at the +// LINK commands i.e., the subset of commands that alter the +// connections between modules. The caller can specify whether the +// execution must configure or deconfigure the pattern. The code for +// both is identical. This function calls the add/delete link +// functions of each RNA element so that the internal linkstate of the +// modules is also updated in the process. +// +//=================================================================== +int +Pattern::ExecuteHelper(ConfigType t){ + + // Sanity check... + if (t != CONF_CONFIG && t != CONF_UNCONFIG) + return -1; + + + // Add the links... + RNAElement *control = _s->get_control(); + Router *r = control->router(); + + Vector lspecs ; + struct linkspec *lspec; + + // Go through each of the LINK commands + for (int i = 0; i < _links.size(); i++){ + + Link *l = _links[i]; + + // Skip link commands that do not match... + if (l->conf != t) + continue; + + // Only one of the two elements can have the wildcard specification. + if ((l->count1 <= 0) || (l->count2 <= 0) || + (l->count1 > 1 && l->count2 > 1)){ + click_chatter("[%s] Pattern::Execute(): Invalid Link command \n"); + if (1) + click_chatter("[Pattern::Complete] Found a link %s " + "(type %d, instance %d num %d) -> (type %d, instance %d num %d) \n", + ((l->op == OP_ADD)? "ADD" : "DEL"), + l->t1, l->instance1, l->count1, l->t2, l->instance2, l->count2); + + continue; + }; + + // + // This is intended to handle the situation where + // + + int max_combinations = (l->count1 > l->count2) ? l->count1 : l->count2; + for (int c = 0; c < max_combinations; c++) { + + RNAElement *e0 = 0, *e1 = 0; + + if (l->count1 > 1) { + // First element is the wild card + e0 = _s->get_nth_element(l->t1, l->instance1 + c); + e1 = _s->get_nth_element(l->t2, l->instance2); + } else if (l->count1 > 1) { + // Second element is the wild card + e0 = _s->get_nth_element(l->t1, l->instance1); + e1 = _s->get_nth_element(l->t2, l->instance2 + c); + } else { + e0 = _s->get_nth_element(l->t1, l->instance1); + e1 = _s->get_nth_element(l->t2, l->instance2); + }; + + if (!e0 || !e1) { + click_chatter("[Pattern::Complete] Link cannot be executed.%s %s\n", + (e0 ? "": "e0 missing"), (e1 ? "": "e1 missing")); + continue; + }; + + if (l->op == OP_ADD){ + + if (1) + click_chatter("[Patterns::Execute] ADD before updated " + "connections %s (%d,%d) <-> %s(%d,%d)\n", + e0->instance_name(), e0->ninputs(), e0->noutputs(), + e1->instance_name(), e1->ninputs(), e1->noutputs()); + + //============================= + // + // Add bidirectional links between the modules identified. The + // pattern specified is assumed to go from the top to the bottom. + // The links are between intra-protocol modules, + //============================= + + lspecs.clear(); + + lspec = new linkspec; + lspec->local_elem = e0->eindex(); + lspec->local_out = e0->noutputs(); + lspec->remote_elem = e1->eindex(); + lspec->remote_in = e1->ninputs(); + lspec->local_is_upstream = true; + lspec->crosslayer = false; + lspecs.push_back(lspec); + + // Store the updated the lspec information including the linkcmds + // returned from the control element (metaprotocol) + _lspecs.push_back(lspec); + + lspec = new linkspec; + lspec->local_elem = e1->eindex(); + lspec->local_out = e1->noutputs(); + lspec->remote_elem = e0->eindex(); + lspec->remote_in = e0->ninputs(); + lspec->local_is_upstream = false; + lspec->crosslayer = false; + lspecs.push_back(lspec); + + // Store the updated the lspec information including the linkcmds + // returned from the control element (metaprotocol) + _lspecs.push_back(lspec); + + // Now process the links. + control->process_linkspecs(lspecs); + + // Add this bidirectional link and update the internal router + // datastructure... + r->update_connections(); + + if (1) + click_chatter("[Patterns::Execute] after updated connections " + "%s (%d,%d) <-> %s (%d,%d)\n", + e0->instance_name(), e0->ninputs(), e0->noutputs(), + e1->instance_name(), e1->ninputs(), e1->noutputs()); + + }; + + if (l->op == OP_DEL) { + + + click_chatter("[Patterns::Execute] DEL before updated " + "connections %s (%d,%d) <-> %s(%d,%d)\n", + e0->instance_name(), e0->ninputs(), e0->noutputs(), + e1->instance_name(), e1->ninputs(), e1->noutputs()); + + int e0idx = e0->eindex(); + int e1idx = e1->eindex(); + + // Find the right lspec that corresponds to the downstream and + // upstream links. + int down_link = -1, up_link = -1; + + Vector allpatterns = _s->get_all_patterns(); + for (int p = 0; p < allpatterns.size(); p++){ + + Pattern *pat = allpatterns[p]; + Vector& pat_lspecs = pat->GetLinkspecs(); + + for (int i = 0; i < pat_lspecs.size() ; i++){ + + struct linkspec *lspec = pat_lspecs[i]; + + if ((down_link < 0) && + (lspec->local_elem == e0idx) && + (lspec->remote_elem == e1idx) && + (lspec->local_is_upstream == true)){ + // link going downstream...delete this + + click_chatter("[Patterns::Execute] Found the down link in " + "pattern %s\n", pat->Name().c_str()); + + r->disconnect_rna(e0, lspec->local_out, + e1, lspec->remote_in); + down_link = i; + + // Update the state of the rna element... + e0->delete_link(lspec->l0); + e1->delete_link(lspec->l1); + + continue; + }; + + if ((up_link < 0) && + (lspec->local_elem == e1idx) && + (lspec->remote_elem == e0idx) && + (lspec->local_is_upstream == false)){ + + click_chatter("[Patterns::Execute] Found the uplink in " + "pattern %s\n", pat->Name().c_str()); + + // link going upstream....delete this + r->disconnect_rna(e1, lspec->local_out, + e0, lspec->remote_in); + up_link = i; + + // Update the state of the rna element... + e1->delete_link(lspec->l0); + e0->delete_link(lspec->l1); + + continue; + }; + + }; // all linkspecs for a given pattern... + + if (up_link >= 0 && down_link >= 0) { + + // Found a pattern at which this link delete can be performed. + + // Commit the changes + r->update_connections(); + + // Delete the two link information for the two links... + pat_lspecs[down_link] = pat_lspecs.back(); + pat_lspecs.pop_back(); + pat_lspecs[up_link] = pat_lspecs.back(); + pat_lspecs.pop_back(); + + break; + }; + + }; // for each pattern... + + if (up_link < 0 || down_link < 0) { + if (1) + click_chatter("[Patterns::Execute] ERROR! Cannot find a link " + "that can be deleted...\n"); + }; + + if (1){ + click_chatter("[Patterns::Execute] after updated connections " + "%s (%d,%d) <-> %s (%d,%d)\n", + e0->instance_name(), e0->ninputs(), e0->noutputs(), + e1->instance_name(), e1->ninputs(), e1->noutputs()); + + click_chatter("\n\n\n"); + click_chatter("\n\n\n"); + }; + + }; + + }; // For all possible combinations... + + // What is the status after processing each link? + if (1) { + click_chatter("\n\n"); + control->print_allelements_links(); + click_chatter("\n\n"); + }; + + }; // For all links... + + return 0; + +}; + +//======================================================== +// +// Execute the pattern. First check the prerequisites, gather the +// elements required to execute the commands, pass new configuration +// to each of the elements, and execute the helper function that +// completes the establishment of links etc. +// +//======================================================== +int +Pattern::Execute(){ + + + if (Verify() < 0){ + click_chatter("[Pattern::Execute] Pattern %s " + "cannot be verified \n", _name.c_str()); + return -1; + }; + + // Extract those elements from the state and store them in the + // pattern instance. This is potentially a problem because a pattern + // might be used repeatedly in a given composition. + + for (int i = 0; i < _reqs.size(); i++){ + Req *r = _reqs[i]; + if (r->c == CONSTRAINT_REQUIRE_MUST){ + // Obtain a count number of elements specified in the requirements... + Vector list = _s->get_elements(r->t, r->count); + + if (list.size() < r->count){ + click_chatter("[Pattern::Execute] Returned element list size (%d) " + "is less than expected (%d)\n", + list.size(), r->count); + return -1; + }; + for (int j = 0; j < r->count; j++) { + RNAElement *e = list[j]; + click_chatter("[Pattern::Execute] Obtained element name %s \n", + e->instance_name()); + _elemlist.push_back(e); + }; + list.clear(); + }; + }; + + click_chatter("[Pattern::Complete] Acquired the elements \n"); + + + // Identify the arguments for each module and configure them + // appropriately... + for (int i = 0; i < _args.size(); i++){ + click_chatter("[Pattern::Complete] Passing args...\n"); + Arg *a = _args[i]; + RNAElement *e = FindElement(a->t, a->c); + if (e){ + // Call the configure command with the appropriate var/arg + Vector conf; + conf.push_back(a->var + " " + a->arg); + e->configure(conf, (ErrorHandler *)NULL); + }; + }; + + ExecuteHelper(CONF_CONFIG); + + return 0; + +}; + +//======================================================== +// +// Undo the executed pattern. Essentially this involves calling the +// execute helper that executes all the UNCONFIG LINK commands. The +// elements are put back. +// +//======================================================== +int +Pattern::Unexecute(){ + + // UNCONFIG ARG commands must be eventually processed. + + // XXX: This should add a check for whether this pattern has been + // executed to begin with. + + ExecuteHelper(CONF_UNCONFIG); + + // Free up the elements to be added to the list.... + RNAElement *e; + while ((e = _elemlist.back())){ + _s->put_element(e); + _elemlist.pop_back(); + }; + + return 0; + +}; + +ELEMENT_PROVIDES(Pattern) +ELEMENT_REQUIRES(RNAElement) + +CLICK_ENDDECLS Index: rna/elements/rna/metaprotocol_patterns.hh diff -u /dev/null rna/elements/rna/metaprotocol_patterns.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/metaprotocol_patterns.hh Fri Jun 27 10:40:56 2008 @@ -0,0 +1,366 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef PATTERNS_HH +#define PATTERNS_HH + +#include "rnaelement_common.hh" + +//=================================================================== +// Class to store one pattern in each instance. A typical pattern +// looks like this (stored in metaprotocol_patterns.txt) +// +// PATTERN ENCRYPTED_ORDERED_DELIVERY +// FOLLOWS ORDERED_DELIVERY +// REQ MUST ENCRYPTION 1 +// REQ MUST REORDERBUFFER 1 +// REQ MUST DEMULTIPLEXOR 1 +// CONFIG ARG ENCRYPTION 1 algo des +// CONFIG ARG ENCRYPTION 1 keysize 512 +// CONFIG LINK ADD DEMULTIPLEXOR 1 REORDERBUFFER 1 +// CONFIG LINK ADD REORDERBUFFER 1 ENCRYPTION 1 +// UNCONFIG LINK DEL DEMULTIPLEXOR 1 REORDERBUFFER 1 +// UNCONFIG LINK DEL REORDERBUFFER 1 ENCRYPTION 1 +// +// Code for pattern ENCRYPTED_ORDERED_DELIVERY (generated by the patterns_parser.pl +// { +// parents.clear(); +// reqs.clear(); +// args.clear(); +// links.clear(); +// parents.push_back("ORDERED_DELIVERY"); +// r = new Req(CONSTRAINT_REQUIRE_MUST,ENCRYPTION,1); +// reqs.push_back(r); +// r = new Req(CONSTRAINT_REQUIRE_MUST,REORDERBUFFER,1); +// reqs.push_back(r); +// r = new Req(CONSTRAINT_REQUIRE_MUST,DEMULTIPLEXOR,1); +// reqs.push_back(r); +// a = new Arg(ENCRYPTION, 1, "algo", ""); +// args.push_back(a); +// a = new Arg(ENCRYPTION, 1, "keysize", ""); +// args.push_back(a); +// keywords.clear(); +// l = new Link(DEMULTIPLEXOR, 1, 1, REORDERBUFFER, 1, 1, OP_ADD, CONF_CONFIG, keywords); +// links.push_back(l); +// keywords.clear(); +// l = new Link(REORDERBUFFER, 1, 1, ENCRYPTION, 1, 1, OP_ADD, CONF_CONFIG, keywords); +// links.push_back(l); +// keywords.clear(); +// l = new Link(DEMULTIPLEXOR, 1, 1, REORDERBUFFER, 1, 1, OP_DEL, CONF_UNCONFIG, keywords); +// links.push_back(l); +// keywords.clear(); +// l = new Link(REORDERBUFFER, 1, 1, ENCRYPTION, 1, 1, OP_DEL, CONF_UNCONFIG, keywords); +// links.push_back(l); +// pat = new Pattern(this, "ENCRYPTED_ORDERED_DELIVERY", parents, reqs, args, links); +// }; +// .... +// +// Notes: +// +// Note that the namespace and semantics of the patterns is shared by +// both the endpoints. This is important because otherwise there may +// be functionality mismatch +// +// Patterns have to be checked for feasibility because we may not have +// modules that correspond to the pattern of operation. +// +// The LINK commands are hints for the composition program to +// indiciate where this module should go. The composition program may +// ignore the link command and use internal knowledge - which ofcourse +// makes it hard to reuse across layers etc. +// +// Patterns are specified in a particular order; A reference to +// another pattern in the form of FOLLOWs command. +// +// It can be seen as a tree of possible decisions and the negotiation +// process essentially walks the tree down during composition and +// walks up when the composition is terminated. The trees supported by +// each endpoint may be different and the endpoints walk only down the +// shared paths. +// +// +//=================================================================== + + +class State; +class Pattern; + +#include "rnaelement.hh" +#include "metaprotocol_state.hh" + +// Only a small number of commands are supported. +typedef enum { + PATTERN_BEGIN, + PATTERN_FOLLOWS, // Follows pattern X + PATTERN_REQ, // Requires n instances of module + PATTERN_ARG, // Pass variable X with value Y to module X + PATTERN_END +} PatternRuleType; + +// What is the nature of constraint? +typedef enum { + CONSTRAINT_BEGIN, + CONSTRAINT_REQUIRE_MUST, // A requirement must be followed + // There may be others e.g., MAY, PREFERABLY + CONSTRAINT_END, +} ConstraintType; + +//What is the nature of the LINK configuration operation? +typedef enum { + OP_BEGIN, + OP_ADD, // Add a link + OP_DEL, // Delete a link + OP_END +} OP; + +// When should the configuration command be executed? +typedef enum { + CONF_BEGIN, + CONF_CONFIG, // During instantiation of the composition + CONF_UNCONFIG, // During cleanup of a composition + CONF_END +} ConfigType; + + +//=================================================================== +// +// Requirement: +// For now only MUST is supported +// +// Eventually we should be able to send a pattern across to the peers +// at the other end too. There is some initial code to encode an +// instance of the class. +// +//=================================================================== +class Req { + +public: + + ConstraintType c; + int count; + RNAElementType t; + + void print(char *s = NULL){ + if (s) + click_chatter("[%s] Req [type=(%d,%s),c = %d,count=%d]\n", + s, t, str_elementtype[t], count, (int)c); + else + click_chatter("Req [type=(%d,%s),c = %d,count=%d]\n", + t, str_elementtype[t], count, (int)c); + }; + + static int encoded_size(){ + return 4; + }; + + + // Encode is pattern. + int encode(char *data){ + + if (!data) + return -1; + + *(data + 0) = (char) PATTERN_REQ; + *(data + 1) = (char) c; + *(data + 2) = (char) t; + *(data + 3) = (char) count; + + }; + + // Decode a pattern (provided probably by a peer) + int decode(const unsigned char *data){ + + if (!data || *data != PATTERN_REQ) + return -1; + + c = (ConstraintType) *(data + 1); + t = (RNAElementType) *(data + 2); + count = (int)*(data + 3); + + return 0; + + }; + + // Initialize the Requirement object + Req(ConstraintType c_in, RNAElementType t_in, int count_in) { + c = c_in; + t = t_in; + count = count_in; + }; + + Req(){ + + c = CONSTRAINT_END; + count = 0; + t = UNKNOWN; + + } + +}; + + +//=================================================================== +// +// Object that is used to store the LINK command +// Link: [number of instances] +// [number of instances] +// +// Only one of two modules can have number of instances > 1. This is a +// limited form of wildcard. Ideally this should support regular +// expressions and relative names, i.e., instead of using an absolute +// instance number, a relative instance number must be used. +// +// This does not yet support encoding/decoding like Req module +// +//=================================================================== + +class Link { + +public: + + RNAElementType t1, t2; + int instance1, instance2; + int count1, count2; + OP op; + ConfigType conf; + Vector keywords; + + Link(RNAElementType t1_in, int i1_in, int c1_in, + RNAElementType t2_in, int i2_in, int c2_in, + OP op_in, ConfigType conf_in, + Vector keywords_in + ){ + t1 = t1_in; + t2 = t2_in; + instance1 = i1_in; + instance2 = i2_in; + count1 = c1_in; + count2 = c2_in; + op = op_in; + conf = conf_in; + keywords = keywords_in; + }; + +}; + +//=================================================================== +// +// Object that is used to store the ARG command +// Arg: +// +// Both the variable and value are strings. They are interpreted by +// the modules to which this is presented upon inclusion into some +// composition by the metaprotocol. Ideally this should also have +// config/unconfig option. +// +// This does not yet support encoding/decoding. + +//=================================================================== + +class Arg { + +public: + String var; + String arg; + RNAElementType t; + int c; // Instance of this type + + void print(char *s = NULL){ + + if (s) + click_chatter("[%s] Arg [type=(%d,%s),instance=%d,var=%s,arg=%s]\n", + s, t, str_elementtype[t], (int)c,var.c_str(), arg.c_str()); + else + click_chatter("Arg [type=(%d,%s),instance=%d,var=%s,arg=%s]\n", + t, str_elementtype[t], c,var.c_str(), arg.c_str()); + + }; + + Arg(RNAElementType t_in, int c_in, String v_in, String a_in){ + c = c_in; + t = t_in; + arg = a_in; + var = v_in; + }; +}; + + +//=================================================================== +// +// This class stores a single pattern that consists of a set of +// follows, req, arg and link command objects. In addition the +// elements used during the instantiation process is also +// included. The class also stores information on the links that have +// been created. this stored information is used during cleanup. The +// follows is a list of the parent patterns upon which this pattern +// depends. The parent list is simply stored as a vector of strings. +// +//=================================================================== + +class Pattern { + + private: + State *_s; + String _name; + Vector _parentlist; + Vector _elemlist; + Vector _reqs; + Vector _args; + Vector _links; + Vector _lspecs; + + public: + Pattern(State *s, + String name, + Vector parentlist, + Vector reqs, + Vector args, + Vector links); + + virtual ~Pattern(); + + // Return the name of a given pattern or its parents + virtual String Name(); + virtual Vector ParentNames(); + + // + virtual bool Match(String s); + + // Check to see all parents are satisfied for a given pattern or a + // set of patterns. + virtual bool MatchParentList(Vector completed_parent_list); + virtual bool MatchParentList(Vector completed_parent_list); + + // Check to see if pattern's prerequisites are satisfied. + virtual int Verify(); + + // Add the links and complete the composition + virtual int ExecuteHelper(ConfigType); + virtual int Execute(); + virtual int Unexecute(); + + // Generate and receive a message containing a specification of a + // pattern. + virtual Packet *GenerateMessage(); + virtual int ValidateMessage(Packet *p); + + //Look at the list of the elements + RNAElement *FindElement(RNAElementType t, int c); + + // Extract the requirements + Vector Requirements(); + + // Extract the links created by this pattern + Vector& GetLinkspecs() { return _lspecs; } + +}; + +#endif Index: rna/elements/rna/metaprotocol_patterns_db.cc diff -u /dev/null rna/elements/rna/metaprotocol_patterns_db.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/metaprotocol_patterns_db.cc Fri Jun 27 10:40:56 2008 @@ -0,0 +1,183 @@ + Vector patternlist; + Pattern *pat; + Vector parents; + Vector reqs; + Vector args; + Vector links; + Req *r; + Arg *a; + Link *l; + Vector keywords; + +// Code for pattern MIN +{ + parents.clear(); + reqs.clear(); + args.clear(); + links.clear(); + r = new Req(CONSTRAINT_REQUIRE_MUST,BUFFER,1); + reqs.push_back(r); + keywords.clear(); + l = new Link(CONTROL, 0, 1, BUFFER, 0, 1, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(BUFFER, 0, 1, CONTROL, 0, 1, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + pat = new Pattern(this, "MIN", parents, reqs, args, links); + patternlist.push_back(pat); +}; +//Completed pattern MIN + +// Code for pattern ORDERED_DELIVERY +{ + parents.clear(); + reqs.clear(); + args.clear(); + links.clear(); + parents.push_back("MIN"); + r = new Req(CONSTRAINT_REQUIRE_MUST,REORDERBUFFER,1); + reqs.push_back(r); + keywords.clear(); + l = new Link(CONTROL, 0, 1, BUFFER, 0, 1, OP_DEL, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(CONTROL, 0, 1, REORDERBUFFER, 0, 1, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(REORDERBUFFER, 0, 1, BUFFER, 0, 1, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(CONTROL, 0, 1, REORDERBUFFER, 0, 1, OP_DEL, CONF_UNCONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(REORDERBUFFER, 0, 1, BUFFER, 0, 1, OP_DEL, CONF_UNCONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(CONTROL, 0, 1, BUFFER, 0, 1, OP_ADD, CONF_UNCONFIG, keywords); + links.push_back(l); + pat = new Pattern(this, "ORDERED_DELIVERY", parents, reqs, args, links); + patternlist.push_back(pat); +}; +//Completed pattern ORDERED_DELIVERY + +// Code for pattern NULL +{ + parents.clear(); + reqs.clear(); + args.clear(); + links.clear(); + pat = new Pattern(this, "NULL", parents, reqs, args, links); + patternlist.push_back(pat); +}; +//Completed pattern NULL + +// Code for pattern TUNNEL +{ + parents.clear(); + reqs.clear(); + args.clear(); + links.clear(); + parents.push_back("NULL"); + r = new Req(CONSTRAINT_REQUIRE_MUST,MULTITUNNEL,1); + reqs.push_back(r); + keywords.clear(); + keywords.push_back("BIDIRECTIONAL"); + keywords.push_back("ALL"); + l = new Link(CONTROL, 1, 1, MULTITUNNEL, 1, 1, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + keywords.push_back("BIDIRECTIONAL"); + keywords.push_back("ALL"); + l = new Link(CONTROL, 1, 1, MULTITUNNEL, 1, 1, OP_DEL, CONF_UNCONFIG, keywords); + links.push_back(l); + pat = new Pattern(this, "TUNNEL", parents, reqs, args, links); + patternlist.push_back(pat); +}; +//Completed pattern TUNNEL + +// Code for pattern ENCRYPTED_ORDERED_DELIVERY +{ + parents.clear(); + reqs.clear(); + args.clear(); + links.clear(); + parents.push_back("ORDERED_DELIVERY"); + r = new Req(CONSTRAINT_REQUIRE_MUST,ENCRYPTION,1); + reqs.push_back(r); + r = new Req(CONSTRAINT_REQUIRE_MUST,REORDERBUFFER,1); + reqs.push_back(r); + r = new Req(CONSTRAINT_REQUIRE_MUST,DEMULTIPLEXOR,1); + reqs.push_back(r); + a = new Arg(ENCRYPTION, 1, "algo", ""); + args.push_back(a); + a = new Arg(ENCRYPTION, 1, "keysize", ""); + args.push_back(a); + keywords.clear(); + l = new Link(DEMULTIPLEXOR, 1, 1, REORDERBUFFER, 1, 1, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(REORDERBUFFER, 1, 1, ENCRYPTION, 1, 1, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(DEMULTIPLEXOR, 1, 1, REORDERBUFFER, 1, 1, OP_DEL, CONF_UNCONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(REORDERBUFFER, 1, 1, ENCRYPTION, 1, 1, OP_DEL, CONF_UNCONFIG, keywords); + links.push_back(l); + pat = new Pattern(this, "ENCRYPTED_ORDERED_DELIVERY", parents, reqs, args, links); + patternlist.push_back(pat); +}; +//Completed pattern ENCRYPTED_ORDERED_DELIVERY + +// Code for pattern MUXDEMUX +{ + parents.clear(); + reqs.clear(); + args.clear(); + links.clear(); + parents.push_back("NULL"); + r = new Req(CONSTRAINT_REQUIRE_MUST,MULTIPLEXOR,1); + reqs.push_back(r); + r = new Req(CONSTRAINT_REQUIRE_MUST,DEMULTIPLEXOR,1); + reqs.push_back(r); + r = new Req(CONSTRAINT_REQUIRE_MUST,BUFFER,2); + reqs.push_back(r); + keywords.clear(); + l = new Link(CONTROL, 0, 1, MULTIPLEXOR, 0, 1, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(DEMULTIPLEXOR, 0, 1, CONTROL, 0, 1, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(MULTIPLEXOR, 0, 1, BUFFER, 0, 2, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(BUFFER, 0, 2, DEMULTIPLEXOR, 0, 1, OP_ADD, CONF_CONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(CONTROL, 0, 1, MULTIPLEXOR, 0, 1, OP_DEL, CONF_UNCONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(DEMULTIPLEXOR, 0, 1, CONTROL, 0, 1, OP_DEL, CONF_UNCONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(MULTIPLEXOR, 0, 1, BUFFER, 0, 2, OP_DEL, CONF_UNCONFIG, keywords); + links.push_back(l); + keywords.clear(); + l = new Link(BUFFER, 0, 2, DEMULTIPLEXOR, 0, 1, OP_DEL, CONF_UNCONFIG, keywords); + links.push_back(l); + pat = new Pattern(this, "MUXDEMUX", parents, reqs, args, links); + patternlist.push_back(pat); +}; +//Completed pattern MUXDEMUX + +// Code for NULL +{ + parents.clear(); + reqs.clear(); + args.clear(); + links.clear(); + pat = new Pattern(this, "NULL", parents, reqs, args, links); + patternlist.push_back(pat); +}; +//Completed pattern NULL Index: rna/elements/rna/metaprotocol_patterns_db.txt diff -u /dev/null rna/elements/rna/metaprotocol_patterns_db.txt:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/metaprotocol_patterns_db.txt Fri Jun 27 10:40:57 2008 @@ -0,0 +1,66 @@ +#------------------------------------- +# Patterns +#------------------------------------- + +# The default namespace... +NAMESPACE DEFAULT_NAMES + +START MIN + +PATTERN NULL + +# This simply specifies a buffer. no reodering etc. +PATTERN MIN + REQ MUST BUFFER 1 + CONFIG LINK ADD CONTROL 0 BUFFER 0 + CONFIG LINK ADD BUFFER 0 CONTROL 0 + +# Next use this pattern in MIN is successful +PATTERN ORDERED_DELIVERY + FOLLOWS MIN + REQ MUST REORDERBUFFER 1 + CONFIG LINK DEL CONTROL 0 BUFFER 0 + CONFIG LINK ADD CONTROL 0 REORDERBUFFER 0 + CONFIG LINK ADD REORDERBUFFER 0 BUFFER 0 + UNCONFIG LINK DEL CONTROL 0 REORDERBUFFER 0 + UNCONFIG LINK DEL REORDERBUFFER 0 BUFFER 0 + UNCONFIG LINK ADD CONTROL 0 BUFFER 0 + +PATTERN ENCRYPTED_ORDERED_DELIVERY + FOLLOWS ORDERED_DELIVERY + REQ MUST ENCRYPTION 1 + REQ MUST REORDERBUFFER 1 + REQ MUST DEMULTIPLEXOR 1 + CONFIG ARG ENCRYPTION 1 algo des + CONFIG ARG ENCRYPTION 1 keysize 512 + CONFIG LINK ADD DEMULTIPLEXOR 1 REORDERBUFFER 1 + CONFIG LINK ADD REORDERBUFFER 1 ENCRYPTION 1 + UNCONFIG LINK DEL DEMULTIPLEXOR 1 REORDERBUFFER 1 + UNCONFIG LINK DEL REORDERBUFFER 1 ENCRYPTION 1 + +PATTERN TUNNEL + FOLLOWS NULL + REQ MUST MULTITUNNEL 1 + CONFIG LINK ADD CONTROL 1 MULTITUNNEL 1 BIDIRECTIONAL ALL + UNCONFIG LINK DEL CONTROL 1 MULTITUNNEL 1 BIDIRECTIONAL ALL + +# Illustrates the problem of matching arbitrary patterns of +# composition. + +PATTERN MUXDEMUX + FOLLOWS NULL + REQ MUST MULTIPLEXOR 1 + REQ MUST DEMULTIPLEXOR 1 + REQ MUST BUFFER 2 + CONFIG LINK ADD CONTROL 0 MULTIPLEXOR 0 + CONFIG LINK ADD DEMULTIPLEXOR 0 CONTROL 0 + # The -1 indicates a varible. the language must be ideally + # extended to specify a variable. For now we use -1 as a stand in + # for the variable. + CONFIG LINK ADD MULTIPLEXOR 0 BUFFER 0 2 + CONFIG LINK ADD BUFFER 0 2 DEMULTIPLEXOR 0 + UNCONFIG LINK DEL CONTROL 0 MULTIPLEXOR 0 + UNCONFIG LINK DEL DEMULTIPLEXOR 0 CONTROL 0 + #This again uses a variable BUFFER (0, 2) + UNCONFIG LINK DEL MULTIPLEXOR 0 BUFFER 0 2 + UNCONFIG LINK DEL BUFFER 0 2 DEMULTIPLEXOR 0 Index: rna/elements/rna/metaprotocol_state.cc diff -u /dev/null rna/elements/rna/metaprotocol_state.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/metaprotocol_state.cc Fri Jun 27 10:40:57 2008 @@ -0,0 +1,386 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "metaprotocol_state.hh" + +//######################################################## +//# # +//# State Management # +//# # +//######################################################## + + +//======================================================== +// +// Constructor and destructor... +// +//======================================================== + +State::State(RNAElement *control_in, Vector &list) { + + control = control_in; + _elemlist = list; + _available_elemlist = list; + _used_elemlist.clear(); + + // Debug message + if (0) { + click_chatter("[State::State] element list size = %d \n", list.size()); + for (int i = 0; i < list.size(); i++){ + RNAElement *e = list[i]; + click_chatter("[State::State] Element[%d] = %d \n", + i, e->get_type()); + } + }; + +#include PROCESSED_PATTERNS + + _patternlist = patternlist; + +}; + +State::~State(){ + // Do nothing... +}; + + +//======================================================== +// +// Return a given number of elements of a given type; +// +//======================================================== +Vector +State::get_elements(RNAElementType t, int count = 1){ + + Vector list; + + // Debug messages + if (0) { + click_chatter("[State::get_elements] Require elements of type %d " + "(count = %d)\n", + t, count); + click_chatter("[State::get_elements] element list size = %d \n", + _available_elemlist.size()); + for (int i = 0; i < _available_elemlist.size(); i++){ + RNAElement *e = _available_elemlist[i]; + click_chatter("[State::get_elements] Element[%d] = %d \n", + i, e->get_type()); + } + }; + + if (count <= 0) + return list; + + // Check to ensure that we do have count number of elements of the + // given type. + if (check_elements(t, count) < 0) + return list; + + if (t == CONTROL){ + list.push_back(control); + return list; + }; + + Vector::iterator iter; + for (iter = _available_elemlist.begin(); + iter != _available_elemlist.end(); ){ + + RNAElement *e = *iter; + if (e && e->get_type() == t){ + iter = _available_elemlist.erase(iter); + _used_elemlist.push_back(e); + list.push_back(e); + count--; + } else { + iter++; + } + + if (count == 0) + break; + }; + + return list; +}; + +//======================================================== +// +// Get the Nth element of a given type. Dont add or delete anything. +// the count starts from 0; +// +//======================================================== + +RNAElement * +State::get_nth_element(RNAElementType t, int count){ + + if (count < 0) + return NULL; + + if (t == CONTROL) { + return control; + }; + + Vector::iterator iter; + for (iter = _elemlist.begin(); iter != _elemlist.end(); iter++){ + + RNAElement *e = *iter; + if (e && + (((t != ANY) && (e->get_type() == t)) || + (t == ANY))){ + count--; + if (count < 0) + return e; + }; + + }; + + return NULL; +}; + + + +//======================================================== +// +// Add an element back to the list of the composable elements +// +//======================================================== + +void +State::put_element(RNAElement *e){ + + if (!e) + return; + + // Ignore CONTROL (metaprotocol) element... + RNAElementType t = e->get_type(); + if (t == CONTROL) + return; + + Vector::iterator iter; + for (iter = _used_elemlist.begin(); iter != _used_elemlist.end(); iter++){ + RNAElement *e0 = *iter; + if (e == e0) { + + //Move it back to the available list... + _used_elemlist.erase(iter); + _available_elemlist.push_back(e); + + break; + }; + }; + +}; + +//======================================================== +// +// Can a composition be supported? This function checks whether a +// required number of elements of a given type are available. +// +//======================================================== + +int +State::check_elements(RNAElementType t, int count){ + + int c = 0; + + // Check is for control element... + if (t == CONTROL){ + if (count > 1 || count == 0) + return -1; + + return 0; + }; + + // Go through the available list to see if the + for (Vector::iterator iter = _available_elemlist.begin(); + iter != _available_elemlist.end(); iter++){ + + RNAElement *e = *iter; + + if (!e) { + continue; + }; + + const char *classname = e->class_name(); + + if (strcmp(classname, "RNAElement") != 0) + continue; + + //click_chatter("State::check_elements classname = %s type = (%d, %s)\n", + // classname, e->get_type(), str_elementtype[e->get_type()]); + + if (e->get_type() == t) + c++; + }; + + // click_chatter("State::check_elements found %d/%d of type %s \n", + // c,count, str_elementtype[t]); + + if (c >= count) + return 0; + else + return -1; + +}; + +//######################################################### +//# # +//# Pattern management # +//# # +//######################################################### + + +//======================================================== +// +// Return the list of patterns +// +//======================================================== + +Vector +State::get_all_patterns() { + return _patternlist; +} + +RNAElement * +State::get_control() { + return control; +} + +//======================================================== +// +// Find a pattern of a given name. This name may be specified by the +// peer or my metaprotocol (which parsed configuration file +// +//======================================================== +Pattern * +State::find_pattern(String name) { + + for (int i = 0; i < _patternlist.size(); i++){ + Pattern *p = _patternlist[i]; + if (p->Match(name)){ + return p; + }; + }; + + return NULL; + +}; + +//======================================================== +// +// Execute a given pattern - allocate the resourcees and assign them +// to the given pattern. +// +//======================================================== + +int +State::execute_pattern(Pattern *p){ + + if (!p) + return -1; + + String name = p->Name(); + + click_chatter("State::execute_pattern Adding %s to completed list\n", + name.c_str()); + + p->Execute(); + + // We have to complete this... + _completed_patterns.push_back(p); + + return 0; +}; + +//======================================================== +// +// Unexecute a given pattern - deallocate the resources and reset the +// protocol structure to the old way. +// +//======================================================== + +int +State::unexecute_pattern(Pattern *p){ + + if (!p) + return -1; + + String name = p->Name(); + + click_chatter("State::unexecute_pattern Adding %s to completed list\n", + name.c_str()); + + p->Unexecute(); + + // We have to complete this... + //_completed_patterns.push_back(p); + + return 0; +}; + +//======================================================== +// +// Execute a given pattern - allocate the resourcees and assign them +// to the given pattern. +// +//======================================================== + +Vector +State::find_next_patterns(){ + + Vector patlist; + for (int i = 0; i < _patternlist.size(); i++){ + Pattern *p = _patternlist[i]; + String patname = p->Name(); + + if (p->MatchParentList(_completed_patterns) == true){ + click_chatter("State::find_next_patterns Adding %s to the next " + "possible patterns \n", patname.c_str()); + patlist.push_back(p); + }; + }; + + + return patlist; +}; + +//======================================================== +// +// Find the executable patterns. +// +//======================================================== + +Vector +State::find_next_verified_patterns(){ + + Vector patlist; + for (int i = 0; i < _patternlist.size(); i++){ + Pattern *p = _patternlist[i]; + String patname = p->Name(); + + if ((p->MatchParentList(_completed_patterns) == true) && + (p->Verify() >= 0)){ + click_chatter("State::find_next_patterns Adding %s to the next " + "possible patterns \n", patname.c_str()); + patlist.push_back(p); + }; + }; + + click_chatter("State::find_next_patterns Found %d entries \n", + patlist.size()); + + return patlist; +}; + + + +ELEMENT_PROVIDES(State) +CLICK_ENDDECLS Index: rna/elements/rna/metaprotocol_state.hh diff -u /dev/null rna/elements/rna/metaprotocol_state.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/metaprotocol_state.hh Fri Jun 27 10:40:57 2008 @@ -0,0 +1,67 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef STATE_HH +#define STATE_HH + +#include "rnaelement.hh" +#include "metaprotocol_patterns.hh" + +//================================================================ +// State management; +// +// State stores the list of patterns, instantiates them, handles the +// message handling part of the negotiation etc. +// +// The patterns effectively store the "knowledge" that is specific to +// the individual protocol. +// +//================================================================ + +#define PROCESSED_PATTERNS "metaprotocol_patterns_db.cc" + +class State { + + private: + RNAElement *control; + Vector _elemlist; + Vector _available_elemlist; + Vector _used_elemlist; + Vector _patternlist; + Vector _completed_patterns; + + public: + State(RNAElement *, Vector &list); + virtual ~State(); + + // Element management + virtual int check_elements(RNAElementType t, int count); + virtual RNAElement * get_nth_element(RNAElementType t,int count); + virtual Vector get_elements (RNAElementType t, int count); + virtual void put_element(RNAElement *e); + + //Return the patterns stored... + virtual Vector get_all_patterns(); + + // Find the matching pattern... + Pattern * find_pattern(String name); + Vector find_next_patterns(); + Vector find_next_verified_patterns(); + + // Do/undo a pattern. This reorganizes the protocol composition. + int execute_pattern(Pattern *p); + int unexecute_pattern(Pattern *p); + + // Get a pointer to the metaprotocol module + RNAElement * get_control(); +}; + +#endif Index: rna/elements/rna/module_namespace.txt diff -u /dev/null rna/elements/rna/module_namespace.txt:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/module_namespace.txt Fri Jun 27 10:40:57 2008 @@ -0,0 +1,27 @@ +#ifndef __MODULE_NAMESPACE_HH +#define __MODULE_NAMESPACE_HH + +enum RNAElementType { + ELEMTYPE_BEGIN, + UNKNOWN, + ANY, + ROOT, + DISCOVERY, + BUFFER, + CONTROL, + CRYPT, + ENCRYPTION, + MULTITUNNEL, + MULTIPLEXOR, + DEMULTIPLEXOR, + MUXDEMUX, + NEGOTIATE, + OPTIONS, + REORDERBUFFER, + NETSTACK, + RINGBUFFER, + PKTSRC, + ELEMTYPE_END +}; + +#endif Index: rna/elements/rna/modules_buffer.cc diff -u /dev/null rna/elements/rna/modules_buffer.cc:1.2 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_buffer.cc Mon Jun 30 12:43:20 2008 @@ -0,0 +1,365 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "modules_buffer.hh" + +// +//=================================================================== +// + +Buffer::BufferedPacket::BufferedPacket(int port, Packet *p) { + assert(p); + _p = p; + _port = port; + click_gettimeofday(&_time_added); + delay = static_cast + (RNABUFFER_MAX_DELAY * + (static_cast(rand())/static_cast(RAND_MAX))); + //click_chatter("[BufferedPacket] delay = %ums, time_added = %ld %ld \n", + // delay, _time_added.tv_sec, _time_added.tv_usec); +}; + +bool +Buffer::BufferedPacket::expired(timeval *now) { + if (!now || delay == 0) + return false; + + unsigned long time_elapsed = + Buffer::diff_in_ms(*now,_time_added); + return (time_elapsed > delay); +}; + +bool +Buffer::BufferedPacket::expired() { + timeval curr_time; + click_gettimeofday(&curr_time); + return expired(&curr_time); +}; + +void +Buffer::BufferedPacket::print() { + //click_chatter("[BUFFER] delay = %u\n", delay); + return; +}; + + +// +//=================================================================== +// + +Buffer::Buffer() : + _rnabuffer_timer(static_rnabuffer_timer_hook, this) +{ + // Set the seed... + srand(0x2322311); + set_type(BUFFER); + copies = false; + delay = false; + snd_count = 0; + + // Send a management packet very fifth time or so... + management = false; + skip = 5; +} + +Buffer::~Buffer() +{ + // Do nothing... +} + +// +// Buffer code cannibalized from grid/dsrroutetable.[hh|cc] +// +unsigned long +Buffer::diff_in_ms(timeval t1, timeval t2) +{ + unsigned long s, us, ms; + + //click_chatter ("diff_in_ms: t1 %ld %ld; t2 %ld %ld\n", t1.tv_sec, + //t1.tv_usec, t2.tv_sec, t2.tv_usec); + + while (t1.tv_usec < t2.tv_usec) { + t1.tv_usec += 1000000; + t1.tv_sec -= 1; + } + + assert(t1.tv_sec >= t2.tv_sec); + + s = t1.tv_sec - t2.tv_sec; + assert(s < ((unsigned long)(1<<31))/1000); + + us = t1.tv_usec - t2.tv_usec; + ms = s * 1000L + us / 1000L; + +// click_chatter ("diff_in_ms: difference is %ld %ld -> %ld\n", s, +// us, ms); + + return ms; +} + + +int +Buffer::finish_configuration(){ + + //struct linkspec *link; + Vector linkspecs; + + click_chatter("[%s] Buffer::finish_configuration() - " + "noutputs = %d ninputs = %d\n", + instance_name(), noutputs(), ninputs()); + + if (exec_finish_configuration) { + add_default_bidirectional_links(&linkspecs, true); + process_linkspecs(linkspecs); + }; + + return 0; + +}; +int +Buffer::rna_finish_configuration() { + + + return 0; +}; + + +int +Buffer::initialize(ErrorHandler *) { + + // click_chatter("[%s] Buffer::initialize \n", instance_name()); + _rnabuffer_timer.initialize(this); + _rnabuffer_timer.schedule_after_msec(RNABUFFER_TIMER_INTERVAL); + + return 0; +}; + + +void +Buffer::static_rnabuffer_timer_hook(Timer *, void *v) +{ + // click_chatter("[Buffer::static_rnabuffer_timer_hook] \n"); + Buffer *buf = (Buffer *)v; + buf->rnabuffer_timer_hook(); +} + +void +Buffer::rnabuffer_timer_hook() +{ + + Vector retained, dropped; + + //click_chatter("[Buffer::rnabuffer_timer_hook] \n"); + + + timeval curr_time; + click_gettimeofday(&curr_time); + + if (rnabuffer.size() > 0){ + for (int i = 0; i < rnabuffer.size(); i++){ + BufferedPacket *p = rnabuffer[i]; + if (p->expired(&curr_time)){ + //click_chatter("[%s] Resending data? \n", instance_name()); + + if (copies == false) { + + // Here there is a 1:1 mapping between the packets that are + // coming in from above and those that go out. However every + // 'th packet is replaced by a management packet... + + click_chatter("\n[%s] Buffer::rnabuffer_timer_hook 1 " + "snd_count = %d skip = %d management = %s \n", + instance_name(), snd_count, skip, + ((management == false) ? "NONE" : "YES")); + + if ((management == true) && ((snd_count % skip) == 0)){ + send_management(p->_port); + } else { + RNAElement::push_data(p->_port, p->_p); + dropped.push_back(p); + snd_count++; + }; + + } else { + + click_chatter("[%s] Buffer::rnabuffer_timer_hook 2 " + "snd_count = %d skip = %d management = %d \n", + instance_name(), snd_count, skip, + (management == false)); + + // If this buffering module is supposed to send management + // packets from to time to trigger action at the next lower + // layer, then skip the current packet. + if ((management == true) && ((snd_count % skip) == 0)){ + send_management(p->_port); + } else { + RNAElement::push_data(p->_port, p->_p->clone()); + }; + snd_count++; + }; // send copies... + + } else { + // has not expired.... + retained.push_back(p); + }; + }; + + if (copies == false) { + rnabuffer.swap(retained); + }; + //delete dropped; + }; + _rnabuffer_timer.schedule_after_msec(RNABUFFER_TIMER_INTERVAL); + +}; + +//################################################################ +// Send a management message to the layer below...This will trigger +// composition and testing... +//################################################################ + +void +Buffer::send_management(int i){ + + LinkState *incoming_link = lookup_link(i); + if (! incoming_link || !incoming_link->is_downstream()){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] Buffer::send_management Dropping packet...Wrong incoming link\n", + instance_name()); + return; + }; + + WritablePacket *p = Packet::make(3); + char *data = (char *)p->data(); + + // For now only an add message. Later this should be expanded to del + // as well. + *data = MESSAGE_MANAGEMENT; + *(data + 1) = MESSAGE_MANAGEMENT_ADD_MODULE; + *(data + 2) = 0; + + rna_click_chatter(FUNC_DEFAULT, + "[%s] Buffer::send_management (port %d)\n", + instance_name(), i); + if (debug) + RNAElement::print_packet("send_management", p, false); + + RNAElement::push_data(i, p); + +}; + +//################################################################ +// +// Main data message handler from above and below... +// +//################################################################ + +void +Buffer::push_data(int i, Packet *p){ + + (void) i; + + //click_chatter("[%s] Got a new packet on port %d \n", + // instance_name(), i); + // click_chatter("[%s] Storing the packet in the rnabuffer \n", + // instance_name()); + + LinkState *incoming_link = lookup_link(i); + if (! incoming_link ){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] Buffer::push_data Dropping packet...\n", + instance_name()); + p->kill(); + return; + }; + + if (incoming_link->is_downstream()) { + + // Coming from upstream... + p->push(3); + char *data = (char *)p->data(); + *(data + 0) = MESSAGE_DATA; + *(data + 1) = MESSAGE_DATA_NORMAL; + *(data + 2) = 0; + + } else { + + // Coming from downstream...Remove the header... + p->pull(3); + + }; + + // Buffer only if the message is coming from upstream. + if ((delay == true) && (incoming_link->is_downstream())){ + + click_chatter("[%s] Storing the packet in the rnabuffer \n", + instance_name()); + BufferedPacket *b = new BufferedPacket(i, p); + rnabuffer.push_back(b); + } else { + + if (debug) + RNAElement::print_packet("push_data", p, false); + + // Copy the integer at the end... + if (0){ + String snd_str(snd_count); + int currlen = p->length(); + WritablePacket *p1 = p->put(snd_str.length()); + char *data = (char *)p1->data(); + memcpy(data + currlen, snd_str.c_str(), snd_str.length()); + }; + + RNAElement::push_data(i, p); + snd_count++; + }; +}; + +//################################################################ +// +// Handle arguments passed to this module during configuration phase +// of Click. It does not yet require RNA-specific configuration +// function (rna_finish_configuration); +// +//################################################################ +int +Buffer::configure(Vector &conf, ErrorHandler *errh) +{ + + // click_chatter("Configuring Buffer... %s \n", class_name()); + + RNAElement::configure(conf, errh); + + if (cp_va_parse(conf, this, errh, + cpKeywords, + "COPIES", cpBool, "Send packet copies repeated?", &copies, + "DELAY", cpBool, "Enable delayed send", &delay, + "MANAGEMENT", cpBool, "Enable sending management packets",&management, + "SKIP", cpInteger, "#packets between successive management packets",&skip, + + cpEnd) < 0) + return -1; + + if (exec_finish_configuration) + finish_configuration(); + + return 0; +} + +ELEMENT_REQUIRES(RNAElement) +EXPORT_ELEMENT(Buffer) +ELEMENT_MT_SAFE(Buffer) + +CLICK_ENDDECLS + + + Index: rna/elements/rna/modules_buffer.hh diff -u /dev/null rna/elements/rna/modules_buffer.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_buffer.hh Fri Jun 27 10:40:57 2008 @@ -0,0 +1,106 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_BUFFERELEMENT_HH +#define CLICK_BUFFERELEMENT_HH + +//########################################################## +// +// +// This is a multi-purpose buffering module stores the elements delayed +// by some time (possibly zero), generate management trigger messages, +// make copies of packets etc. +// +// +// Buffer code cannibalized from grid/dsrroutetable.[hh|cc] +//########################################################## + +#include "rnaelement.hh" + +#define RNABUFFER_TIMER_INTERVAL 1000 // Every second +#define RNABUFFER_MAX_DELAY 1000 // Delay + +class Buffer : public RNAElement { +public: + + // Packets buffered while waiting for route replies + class BufferedPacket + { + public: + Packet *_p; + int _port; + struct timeval _time_added; + unsigned long delay; + + BufferedPacket(int port, Packet *p); + + bool expired(timeval *now); + bool expired(); + + void print(); + }; + + // Constructor/destructor + Buffer(); + ~Buffer(); + + // Click related maintenance code... + int initialize(ErrorHandler *); + static void static_initialize() { RNAElement::static_initialize_default(); }; + static void static_cleanup() { RNAElement::static_initialize_default(); }; + const char *class_name() const { return default_class_name(); } + const char *port_count() const { return "-/-"; } + const char *processing() const { return PUSH; } + + // Configuration + // + // COPIES Send packet copies repeated? + // DELAY Enable delayed send + // (default = false; each packet delayed for a random time < some max ) + // MANAGEMENT Enable sending management packets + // SKIP The number of packets between successive management packets + // (default = 5) + + int configure(Vector &, ErrorHandler *); + int rna_finish_configuration(); // Complete the configuration step... + int finish_configuration(); + bool can_live_reconfigure() const { return true; } + + // The buffer can also generate management messages from time to + // time. + void push_data(int i, Packet *p); + void send_management(int port); + + // Timer management + static unsigned long diff_in_ms(timeval t1, timeval t2); + static void static_rnabuffer_timer_hook(Timer *, void *); + void rnabuffer_timer_hook(); + + private: + + // Buffered packets + Vector rnabuffer; + + // Internal timer object... + Timer _rnabuffer_timer; + + bool copies; // should I make copies of the incoming packet from above and send them? + bool delay; // should I delay the packets coming from above? + int snd_count; // how many packets have I sent? + + // Should I send management packets from time to time; how frequently? + bool management; + int skip; + +}; + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/modules_crypt.cc diff -u /dev/null rna/elements/rna/modules_crypt.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_crypt.cc Fri Jun 27 10:40:57 2008 @@ -0,0 +1,342 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "modules_crypt.hh" + +//################################################################# +// +// This is a simple symmetric key encryption. It assumes that the key +// is already shared and it generates the initialization vector +// randomly and embeds it in the message. +// +//################################################################# + +Crypt::Crypt() +{ + set_type(CRYPT); + + // This is packet source. Dont check for connection state. + set_skip_conn_check(true); + + +} + +Crypt::~Crypt() +{ +} + +//################################################################# +// +// Assume a two way path and assume a default configuration. +// +// ^ | +// | V +// Crypt +// | ^ +// V | +// +//################################################################# + +int +Crypt::finish_configuration() { + + rna_click_chatter(FUNC_ENTRY, + "[%s] Crypt finish_configuration \n", + instance_name()); + + // Add the links to begin with... + Vector links; + add_default_bidirectional_links(&links, true); // cross layer... + rna_click_chatter(FUNC_DEFAULT, + "[%s] linkspecs size = %d \n", + instance_name(), links.size()); + process_linkspecs(links); + print_links(); + + return 0; +}; + + +//##################################################### +// Acknowledgement: This code has been copied from +// http://linuxgazette.net/issue87/vinayak.html +// +// Copyright (c) 2003 by Vinayak Hegde. This material may be +// distributed only subject to the terms and conditions set forth in +// the Open Publication License, v1.0 or later (the latest version is +// presently available at http://www.opencontent.org/openpub/). +// +// The code has been edited to suit the need of RNA by Venkata Pingali +// (USC/ISI) - April 2008 USC/ISI copyright applies to the modified +// code. +// +//#################################################### + +Packet * +Crypt::encrypt (Packet *p) +{ + + int olen = 0, tlen = 0; + + // Reinitialize the initialization vector... + unsigned char iv[8]; + for (int i = 0; i < 8; i++) + iv[i] = random () & 0x0ff; + + // Make a clone and write the data.... + Packet *p0 = p->clone(); + + // Key question. What will be the resulting size of the message? + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init (& ctx); + EVP_EncryptInit (& ctx, EVP_bf_cbc (), + (const unsigned char *)key, + (const unsigned char *)iv); + + int cipher_blk_size = EVP_CIPHER_CTX_block_size(&ctx); + int iv_length = EVP_CIPHER_CTX_iv_length(&ctx); + p = p->push(cipher_blk_size); + + click_chatter("[%s] encrypt: cipher_blk_size = %d pkt len = %d \n", + instance_name(), cipher_blk_size, p->length()); + + // Get the beginning of the data + unsigned char *data_out = (unsigned char *)p->data(); + + // + if (EVP_EncryptUpdate (&ctx, data_out, &olen,p0->data(),p0->length()) != 1){ + printf ("error in encrypt update\n"); + return 0; + } + + if (EVP_EncryptFinal (& ctx, data_out + olen, &tlen) != 1){ + printf ("error in encrypt final\n"); + return 0; + } + + int diff = (p->length() - (olen + tlen)); + click_chatter("[%s] pkt len = %d olen = %d tlen = %d diff = %d \n", + instance_name(), p->length(), olen, tlen, diff); + if (diff > 0) + p->take(diff); + + olen += tlen; + + print_packet("encrypt", p); + + // Push the initialization vector... + p = p->push(iv_length); + data_out = (unsigned char *)p->data(); + memcpy (data_out, iv, 8); + + EVP_CIPHER_CTX_cleanup (& ctx); + + p0->kill(); + + return p; +} + +Packet * +Crypt::decrypt (Packet *p) +{ + + int olen = 0, tlen = 0; + + // Remove the nonce from the header... + Packet *p0 = p->clone(); + + // Extract the initialization vector.... + unsigned char iv[8]; + unsigned char *data_in = (unsigned char *)p0->data(); + memcpy (iv, data_in, sizeof(iv)); + + // Use the new IV to initialize the packet... + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init (& ctx); + EVP_DecryptInit (& ctx, EVP_bf_cbc (), key, iv); + + // over-write the clone... + if (EVP_DecryptUpdate (& ctx, + (unsigned char *)p->data(), & olen, + ((unsigned char *)p0->data() + sizeof(iv)), + (p->length() - sizeof(iv))) != 1){ + printf ("error in decrypt update\n"); + return 0; + } + + if (EVP_DecryptFinal (& ctx, ((unsigned char *)p->data()+olen),&tlen) != 1){ + printf ("error in decrypt final\n"); + return 0; + } + + olen += tlen; + + int diff = (p->length() - olen); + if (diff > 0) + p->take(diff); + + print_packet("decrypt", p); + + EVP_CIPHER_CTX_cleanup (& ctx); + + p0->kill(); + + return p; + +}; + +//################################################################# +// +// End included the code... +// +//################################################################# + +void +Crypt::push_data(int port, Packet *p){ + + LinkState *incoming_link = lookup_link(port); + if (! incoming_link ){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] Crypt::push_data Dropping packet...\n", + instance_name()); + p->kill(); + return; + }; + + + // Encrypt the packet if coming from above and decrypt in case the + // packet is coming from below. + if (incoming_link->is_downstream()) { + + p = encrypt(p); + + if (!p) + return; + + // Coming from upstream... + p = p->push(3); + + // insert the normal header... + char *data = (char *)p->data(); + *(data + 0) = MESSAGE_DATA; + *(data + 1) = MESSAGE_DATA_NORMAL; + *(data + 2) = 0; + + } else { + + // Coming from downstream...Remove the header... + p->pull(3); + + p = decrypt(p); + if (!p) + return; + + }; + + if (debug) + RNAElement::print_packet("Crypt::push_data", p, false); + + RNAElement::push_data(port, p); + + return; +}; + +// Read the key in from the configuration file. In case the key is not +// specified, a pre-defined key is used. + +int +Crypt::configure(Vector &conf, ErrorHandler *errh) +{ + + String key_in; + + RNAElement::configure(conf, errh); + + if (cp_va_parse(conf, this, errh, + cpKeywords, + "KEY", cpString, "Symmetric Key", &key_in, + cpEnd) < 0) + return -1; + + if (debug) + rna_click_chatter(FUNC_DEFAULT, + "[%s] Configuring Crypt. \n", + instance_name()); + + // + if (key_in.length() == 0) { + unsigned char key_static[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + memcpy(key, key_static, sizeof(key)); + } else { + unsigned char *key_in_c = (unsigned char *)key_in.c_str(); + + if ( + ((key_in.length() != 32) && (key_in.length() != 34)) || + ((key_in.length() == 34) && + ((key_in_c[0] != '0') && (key_in_c[1] != 'x'))) || + ((key_in.length() == 32) && + ((key_in_c[0] == '0') && (key_in_c[1] == 'x'))) + ){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] Configuring Crypt. Invalid key. \n", + instance_name()); + return -1; + }; + + if (key_in.length() == 34) + key_in_c += 2; + + // Convert the 32 character string into a 16 byte binary + // string. + // 0xabcd12341 processed as ab => ('a' - '0') + // + if (debug) { + rna_click_chatter(FUNC_DEFAULT, + "[%s] Configure(): Parsing Key = \"%s\" (length = %d)\n", + instance_name(), key_in_c, key_in.length()); + + rna_click_chatter(FUNC_DEFAULT, + "[%s] Configure(): Processed Key = ", + instance_name()); + }; + + for (int i = 0; i < 4; i++){ + unsigned char c[9]; + unsigned long x; + + // Copy 8 characters at a time + memcpy((void *)c, (void *)&key_in_c[i << 3], 8); + c[9] = '\0'; + + x = strtoul((const char *)c, 0, 16); + *((unsigned long *)&key[i << 2]) = x; + + if (debug) rna_click_chatter(FUNC_DEFAULT, "[%8.8x]:", x); + + }; + if (debug) rna_click_chatter(FUNC_DEFAULT, "\n"); + + } + + // Finally add all the links and discover peers + if (exec_finish_configuration) + finish_configuration(); + + return 0; + +}; + + +ELEMENT_REQUIRES(RNAElement) +EXPORT_ELEMENT(Crypt) + +CLICK_ENDDECLS Index: rna/elements/rna/modules_crypt.hh diff -u /dev/null rna/elements/rna/modules_crypt.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_crypt.hh Fri Jun 27 10:40:57 2008 @@ -0,0 +1,74 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_CRYPT_HH +#define CLICK_CRYPT_HH + +#include "rnaelement.hh" + +#include "openssl/evp.h" +#include +#include +#include + +#ifndef NO_RSA +#include +#endif + +#ifndef NO_DSA +#include +#endif + +#define IP_SIZE 128 +#define OP_SIZE 136 + +//############################################ +// +// Simple symmetric key encryption module... +// +//############################################ + + +class Crypt : public RNAElement { +public: + + // Constructor/destructor + Crypt(); + ~Crypt(); + + // Click-related stuff + static void static_initialize() { RNAElement::static_initialize_default(); }; + static void static_cleanup() { RNAElement::static_initialize_default(); }; + const char *class_name() const { return default_class_name(); }; + const char *port_count() const { return "-/-"; } + const char *processing() const { return PUSH; } + + // Configuration... + int configure(Vector &, ErrorHandler *); + int configure_phase() { return CONFIGURE_PHASE_LAST; }; + int finish_configuration(); // Complete the configuration step... + bool can_live_reconfigure() const { return true; } + + // Message handling...Encrypts messages going downstream + // and decrypts messages going upstream... + void push_data(int port, Packet *p); + + // Helper functions... + Packet *encrypt (Packet *p); + Packet *decrypt (Packet *p); + + private: + unsigned char key[16]; + +}; + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/modules_demultiplexor.cc diff -u /dev/null rna/elements/rna/modules_demultiplexor.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_demultiplexor.cc Fri Jun 27 10:40:57 2008 @@ -0,0 +1,277 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "modules_demultiplexor.hh" + +// Initialization and cleanup... + +Demultiplexor::Demultiplexor() +{ + set_type(DEMULTIPLEXOR); + first = true; +} + +Demultiplexor::~Demultiplexor() +{ + // Do nothing... +} + +//################################################################ +// +// parse input arguments... +// +//################################################################ +int +Demultiplexor::configure(Vector &conf, ErrorHandler *errh) +{ + + RNAElement::configure(conf, errh); + + if (debug) + rna_click_chatter(FUNC_ENTRY, "[%s] Configuring Demultiplexor \n", + instance.c_str()); + + if (exec_finish_configuration) + finish_configuration(); + + return 0; +} + +// ################################################################ +// Call from the module that is composing this demuxer, i.e., +// metaprotocol. +// ################################################################ + +int +Demultiplexor::rna_finish_configuration(){ + + if (debug) + rna_click_chatter(FUNC_ENTRY,"[%s] rna_finish_configuration Entry \n", + instance_name()); + + // Obtain a list of all the links to downstream elements and + // initialize the linkstate corresponding to each (e.g., obtain a + // connection state associated with each link). + + Vector downstream; + downstream = list_downstream_elements(true, // downstream + true, // layeragnostic + false, // crosslayer + true,// agnostic remote + false // remote is unknown + ); + + for(int i = 0; i < downstream.size(); i++) { + LinkState *l = downstream[i]; + initialize_link(l); + }; + + rna_click_chatter(FUNC_EXIT,"[%s] rna_finish_configuration Exit \n", + instance_name()); + + return 0; +}; + + +// ################################################################ +// +// Look for an outgoing link that is headed towards downstream (or +// upstream) and crosslayer (or not). +// +// ################################################################ +LinkState *Demultiplexor::select_outgoing_link(Packet *p, + LinkState *incoming, + bool downstream, + bool layeragnostic, + bool crosslayer, + bool agnostic_remote, + bool remote_unknown){ + (void) incoming; + + rna_click_chatter(FUNC_ENTRY, + "[%s] Demultiplexor::select_outgoing_link Entered \n", + instance_name()); + + LinkState *return_l = NULL; + + if (!downstream) { + + // Look at packets that are headed upstream... Otherwise ignore + // the messages... + + // Extract the data... + const char *header = (const char *)p->data(); + + // Match the registered pattern; + Vector v; + for (int i = 0; i < DemuxTable.size(); i++){ + MuxDemuxCmd *m = DemuxTable[i]; + if (!m) + continue; + const char *pattern = m->pattern; + int length = m->len; + if (memcmp(header, pattern, length) == 0){ + // Found the match. + return_l = m->l; + rna_click_chatter(FUNC_DEFAULT, "[%s] Demultiplexor::" + "select_outgoing_link - Found a match\n", + instance_name()); + return_l->print(instance_name()); + break; + }; + }; + + } else { + + Vector templist; + + // Identify all possible links... + for (int i = 0; i < all_links.size(); i++){ + LinkState *l = all_links[i]; + + // Find a link in which I am an downstream node and + // the link is outgoing... + if (l->is_outgoing() // ignore incoming links + && ((!layeragnostic && (l->is_crosslayer() == crosslayer)) || + (layeragnostic )) + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (! agnostic_remote && + (l->is_remote_unknown() == remote_unknown))) + ) { + templist.push_back(l); + }; + }; + + if (templist.size() >= 2) { + if (first) { + click_chatter("[%s] Selecting alternative path 1 \n", instance_name()); + first = false; + return_l = templist[0]; + } else { + click_chatter("[%s] Selecting alternative path 2 \n", instance_name()); + first = true; + return_l = templist[1]; + } + } else if (templist.size() == 1 ) { + click_chatter("[%s] Selecting alternative path 1 (only available)\n", + instance_name()); + first = true; + return_l = templist[0]; + }; + + }; + + + rna_click_chatter(FUNC_EXIT, + "[%s] Demultiplexor::select_outgoing_link Exit\n", + instance_name()); + return return_l; +} + + +// ################################################################ +// +// Handle pattern registration requests from the upstream modules. +// +// ################################################################ + +RNAControlMsg * +Demultiplexor::module_specific_control(RNAControlMsg *c){ + + rna_click_chatter(FUNC_ENTRY, + "[%s] RNAElement::module_specific_control Entered \n", + instance_name()); + + // Create a reply object and the default response...and fill it up. + RNAControlMsg *reply = new RNAControlMsg(RNAControlMsg::REPLY); + reply->set_unsupported(); + reply->set_error("NONE!"); + + // Sanity check... + if (!c){ + reply->set_invalid(); + reply->set_error("c is empty!"); + rna_click_chatter(FUNC_EXIT, "[%s] RNAElement::control Exit \n", + instance_name()); + return reply; + }; + + c->print(instance_name()); + + reply->set_operationtype(c->o); + switch(c->m) { + case RNAControlMsg::COMMAND: + switch(c->o){ + case RNAControlMsg::CONFIGURE: + switch(c->op){ + case RNAControlMsg::DEMUX_PATTERN_ADD: + do { + MuxDemuxCmd *m = (MuxDemuxCmd *)c->get_data(); + if (m) { + m->print("Add demux pattern"); + LinkState *l = lookup_link(m->e, LinkState::INCOMING); + if (l) { + m->l = l; + DemuxTable.push_back(m); + reply->set_data(0); + reply->set_success(); + } else { + reply->set_error("MuxDemuxCmd Invalid parameter e"); + reply->set_invalid(); + } + } else { + reply->set_error("MuxDemuxCmd (data) is NULL!"); + reply->set_invalid(); + } + } while (0); + break; + case RNAControlMsg::DEMUX_PATTERN_DEL: + do { + MuxDemuxCmd *oldm = (MuxDemuxCmd *)c->get_data(); + Vector v; + for (int i = 0; i < DemuxTable.size(); i++){ + MuxDemuxCmd *m = DemuxTable[i]; + if (oldm != m){ // skip this one? + v.push_back(m); + }; + }; // For loop.. + DemuxTable.swap(v); + } while(0); + break; + default: + break; + }; + break; + default: + break; + }; + break; + default: + break; + + }; + + rna_click_chatter(FUNC_EXIT, "[%s] RNAElement::module_specific_control EXIT\n", + instance_name()); + return reply; + +}; + + + + +ELEMENT_REQUIRES(RNAElement) +EXPORT_ELEMENT(Demultiplexor) + +CLICK_ENDDECLS Index: rna/elements/rna/modules_demultiplexor.hh diff -u /dev/null rna/elements/rna/modules_demultiplexor.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_demultiplexor.hh Fri Jun 27 10:40:57 2008 @@ -0,0 +1,76 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_DEMULTIPLEXOR_HH +#define CLICK_DEMULTIPLEXOR_HH + +#include "rnaelement.hh" + +//############################################################### +// +// Demultiplexing module. +// +// | | | | | | +// +--+ +---+ +---+ +// || || || +// +---------------------------------+ +// \ / +// \ DEMUX / +// +---------------------------+ +// || +// + +// The demuxing module supports registration of the limited demuxing +// patterns from the modules attached to it upstream. +// +//############################################################### +class Demultiplexor : public RNAElement { + +public: + + // Constructor/destructors... + Demultiplexor(); + ~Demultiplexor(); + + // Click functions... + static void static_initialize() { RNAElement::static_initialize_default(); }; + static void static_cleanup() { RNAElement::static_initialize_default(); }; + const char *class_name() const { return default_class_name(); } + const char *port_count() const { return "-/-"; } + const char *processing() const { return PUSH; } + + // Initialization code... + int configure(Vector &, ErrorHandler *); + int finish_configuration() { return RNAElement::finish_configuration(); }; + int rna_finish_configuration(); + + + // Only the selection of the outgoing link is overridden. Other + // functions are reused from the base class. + virtual LinkState *select_outgoing_link(Packet *p, + LinkState *incoming, + bool downstream = true, + bool layeragnostic = false, + bool crosslayer = false, + bool agnostic_remote = true, + bool remote_unknown = false); + + // Handle registration requests from the modules above. + RNAControlMsg *module_specific_control(RNAControlMsg *c); + + private: + bool first; + Vector DemuxTable; + +}; + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/modules_multiplexor.cc diff -u /dev/null rna/elements/rna/modules_multiplexor.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_multiplexor.cc Fri Jun 27 10:40:58 2008 @@ -0,0 +1,184 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "modules_multiplexor.hh" + +//################################################################ +// Constructor/destructor... +//################################################################ + +Multiplexor::Multiplexor() +{ + set_type(MULTIPLEXOR); + first = true; + strategy = "ALTERNATE_TWO"; +} + +Multiplexor::~Multiplexor() +{ + // Do nothing... +} + +//################################################################ +// Parse the arguments provided in the configuration file. Called +// during the initialization of Click router. +//################################################################ +int +Multiplexor::configure(Vector &conf, ErrorHandler *errh) +{ + + RNAElement::configure(conf, errh); + + if (cp_va_parse(conf, this, errh, + cpKeywords, + "STRATEGY", cpString, "multiplexing strategy", &strategy, + cpEnd) < 0) + return -1; + + if (strategy != "ALTERNATE_TWO") + return -1; + + if (exec_finish_configuration) + finish_configuration(); + + return 0; +} + +//################################################################ +// +// This will effectively initialize all the links information. Called +// by the metaprotocol that has composed this module. +// +//################################################################ + +int +Multiplexor::rna_finish_configuration(){ + + if (debug) + rna_click_chatter(FUNC_ENTRY,"[%s] rna_finish_configuration Entry \n", + instance_name()); + + // Obtain the downstream element list and + Vector downstream; + downstream = list_downstream_elements(true, // downstream + true, // layeragnostic + false, // crosslayer + true,// agnostic remote + false // remote is unknown + ); + + for(int i = 0; i < downstream.size(); i++) { + LinkState *l = downstream[i]; + initialize_link(l); + }; + + if (debug) + rna_click_chatter(FUNC_EXIT,"[%s] rna_finish_configuration Exit \n", + instance_name()); + + return 0; +}; + +//################################################################ +// +// There could be multiple strategies for selecting one path down the +// multiplexor. The module currently supports only one strategy - +// ALTERNATE_TWO that alternates between two outgoing paths. There +// should be more ideally speaking. +// +//################################################################ + +LinkState * +Multiplexor::select_outgoing_link(Packet *p, + LinkState *incoming, + bool downstream, + bool layeragnostic, + bool crosslayer, + bool agnostic_remote, + bool remote_unknown){ + + (void) p; + (void) incoming; + + LinkState *return_l = NULL; + + if (strategy != "ALTERNATE_TWO") { + if (debug) + rna_click_chatter(FUNC_EXIT, + "[%s] Multiplexor::select_outgoing_link - Error! " + "Unknown strategy %s\n", + instance_name(), strategy.c_str()); + return NULL; + }; + + if (debug) + rna_click_chatter(FUNC_ENTRY, + "[%s] Multiplexor::select_outgoing_link - Entry \n", + instance_name()); + + // First obtain all possible outgoing links + Vector templist; + // Identify all possible links... + for (int i = 0; i < all_links.size(); i++){ + LinkState *l = all_links[i]; + + // Find a link in which I am an downstream node and + // the link is outgoing... + if (l->is_outgoing() // ignore incoming links + && ((!layeragnostic && (l->is_crosslayer() == crosslayer)) || + (layeragnostic )) + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (! agnostic_remote && (l->is_remote_unknown() == remote_unknown))) + ) { + templist.push_back(l); + }; + }; + + if (strategy == "ALTERNATE_TWO") { + + if (templist.size() >= 2) { + if (first) { + click_chatter("[%s] Selecting alternative path 1 \n", + instance_name()); + first = false; + return_l = templist[0]; + } else { + click_chatter("[%s] Selecting alternative path 2 \n", + instance_name()); + first = true; + return_l = templist[1]; + } + } else if (templist.size() == 1 ) { + click_chatter("[%s] Selecting alternative path 1 (only available)\n", + instance_name()); + first = true; + return_l = templist[0]; + } else { + return_l = NULL; + }; + + }; + + rna_click_chatter(FUNC_EXIT, + "[%s] Multiplexor::select_outgoing_link - Exit \n", + instance_name()); + return return_l; +}; + + + +ELEMENT_REQUIRES(RNAElement) +EXPORT_ELEMENT(Multiplexor) + +CLICK_ENDDECLS Index: rna/elements/rna/modules_multiplexor.hh diff -u /dev/null rna/elements/rna/modules_multiplexor.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_multiplexor.hh Fri Jun 27 10:40:58 2008 @@ -0,0 +1,76 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_MULTIPLEXOR_HH +#define CLICK_MULTIPLEXOR_HH + +#include "rnaelement.hh" + +// +//############################################################### +// +// Multiplexing module +// +// +// +---------------------------+ +// / MUX \ # +// / \ # +// +---------------------------------+ +// || || || +// +--+ +---+ +---+ +// | | | | | | +// +// +// The muxing uses various strategies (currently supports only one +// simple strategy) to select the outgoing link to the messages headed +// downstream. +// +//############################################################### + +class Multiplexor : public RNAElement { +public: + + // Constructor/destructor... + Multiplexor(); + ~Multiplexor(); + + // Click management functions + static void static_initialize() { RNAElement::static_initialize_default(); }; + static void static_cleanup() { RNAElement::static_initialize_default(); }; + const char *class_name() const { return default_class_name(); } + const char *port_count() const { return "-/-"; } + const char *processing() const { return PUSH; } + + // Configuration + int configure(Vector &, ErrorHandler *); + int finish_configuration() { return RNAElement::finish_configuration(); }; + virtual int rna_finish_configuration(); + bool can_live_reconfigure() const { return true; } + + // Override only the function selecting the outgoing link. + virtual LinkState *select_outgoing_link(Packet *p, + LinkState *incoming, + bool downstream = true, + bool layeragnostic = false, + bool crosslayer = false, + bool agnostic_remote = true, + bool remote_unknown = false); + + + private: + bool first; // used for the ALTERNATE_TWO strategy + String strategy; // The name of the strategy that must be used to mux the + // messages + +}; + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/modules_multitunnel.cc diff -u /dev/null rna/elements/rna/modules_multitunnel.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_multitunnel.cc Fri Jun 27 10:40:58 2008 @@ -0,0 +1,144 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "modules_multitunnel.hh" + +Multitunnel::Multitunnel() +{ + set_type(MULTITUNNEL); + first = true; +} + +Multitunnel::~Multitunnel() +{ + // Do nothing... +} + +int +Multitunnel::configure(Vector &conf, ErrorHandler *errh) +{ + + if (cp_va_parse(conf, this, errh, + cpKeywords, + "NAME", cpString, "Name", &instance, + "PROCESS", cpBool, "Enable processing configuration", + &exec_finish_configuration, + cpEnd) < 0) + return -1; + + click_chatter("Configuring Multitunnel... %s \n", instance.c_str()); + + if (exec_finish_configuration) + finish_configuration(); + + return 0; +} + +// This will effectively initialize all the links. + +int +Multitunnel::rna_finish_configuration(){ + + rna_click_chatter(FUNC_ENTRY,"[%s] rna_finish_configuration Entry \n", + instance_name()); + + Vector downstream; + downstream = list_downstream_elements(true, // downstream + true, // layeragnostic + false, // crosslayer + true,// agnostic remote + false // remote is unknown + ); + + for(int i = 0; i < downstream.size(); i++) { + LinkState *l = downstream[i]; + initialize_link(l); + }; + + rna_click_chatter(FUNC_EXIT,"[%s] rna_finish_configuration Exit \n", + instance_name()); + + return 0; +}; + +// The basic strategy is to select alternative link each time... +LinkState * +Multitunnel::select_outgoing_link(Packet *p, + LinkState *incoming, + bool downstream, + bool layeragnostic, + bool crosslayer, + bool agnostic_remote, + bool remote_unknown){ + + (void) p; + (void) incoming; + + LinkState *return_l = NULL; + + rna_click_chatter(FUNC_ENTRY, + "[%s] Multitunnel::select_outgoing_link - Entry \n", + instance_name()); + + Vector templist; + + // Identify all possible links... + for (int i = 0; i < all_links.size(); i++){ + LinkState *l = all_links[i]; + + // Find a link in which I am an downstream node and + // the link is outgoing... + if (l->is_outgoing() // ignore incoming links + && ((!layeragnostic && (l->is_crosslayer() == crosslayer)) || + (layeragnostic )) + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (! agnostic_remote && (l->is_remote_unknown() == remote_unknown))) + ) { + templist.push_back(l); + }; + }; + + if (templist.size() >= 2) { + if (first) { + click_chatter("[%s] Selecting alternative path 1 \n", + instance_name()); + first = false; + return_l = templist[0]; + } else { + click_chatter("[%s] Selecting alternative path 2 \n", + instance_name()); + first = true; + return_l = templist[1]; + } + } else if (templist.size() == 1 ) { + click_chatter("[%s] Selecting alternative path 1 (only available)\n", + instance_name()); + first = true; + return_l = templist[0]; + } else { + return_l = NULL; + }; + + rna_click_chatter(FUNC_EXIT, + "[%s] Multitunnel::select_outgoing_link - Exit \n", + instance_name()); + return return_l; +}; + + + +ELEMENT_REQUIRES(RNAElement) +EXPORT_ELEMENT(Multitunnel) + +CLICK_ENDDECLS Index: rna/elements/rna/modules_multitunnel.hh diff -u /dev/null rna/elements/rna/modules_multitunnel.hh:1.2 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_multitunnel.hh Mon Jun 30 12:43:20 2008 @@ -0,0 +1,58 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_MULTITUNNEL_HH +#define CLICK_MULTITUNNEL_HH + +#include "rnaelement.hh" + +//################################################### +// +// Minimal tunneling capability. Only a placeholder for now. Do not +// use. +// +// ################################################## + +class Multitunnel : public RNAElement { +public: + + Multitunnel(); + ~Multitunnel(); + + static void static_initialize() { RNAElement::static_initialize_default(); }; + static void static_cleanup() { RNAElement::static_initialize_default(); }; + + const char *class_name() const { return default_class_name(); } + const char *port_count() const { return "-/-"; } + const char *processing() const { return PUSH; } + + int configure(Vector &, ErrorHandler *); + int finish_configuration() { return RNAElement::finish_configuration(); }; + virtual int rna_finish_configuration(); + bool can_live_reconfigure() const { return true; } + + + virtual LinkState *select_outgoing_link(Packet *p, + LinkState *incoming, + bool downstream = true, + bool layeragnostic = false, + bool crosslayer = false, + bool agnostic_remote = true, + bool remote_unknown = false); + + + private: + bool first; + +}; + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/modules_pktsrc.cc diff -u /dev/null rna/elements/rna/modules_pktsrc.cc:1.2 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_pktsrc.cc Mon Jun 30 12:43:20 2008 @@ -0,0 +1,117 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "modules_pktsrc.hh" + +//############################################################# +// +// Simple wrapper around the packet source. +// +//############################################################# + +RNAPktSrc::RNAPktSrc() +{ + set_type(PKTSRC); + + // This is packet source. Dont check for connection state. + set_skip_conn_check(true); +} + +RNAPktSrc::~RNAPktSrc() +{ + // Do nothing... +} + +// +// This function assumes a unidirectional link +// +// Packet Generator +// | +// V +// RNAPktSrc +// | +// V +// Some other modules +// + +int +RNAPktSrc::finish_configuration() { + + if (debug) + rna_click_chatter(FUNC_ENTRY, + "[%s] RNAPktSrc finish_configuration \n", + instance_name()); + + // Add the links to begin with... + Vector links; + add_default_unidirectional_links(&links, true); // cross layer... + rna_click_chatter(FUNC_DEFAULT, + "[%s] linkspecs size = %d \n", + instance_name(), links.size()); + process_linkspecs(links); + print_links(); + + return 0; +}; + + +// +// Add the data header and send the message out... +// +void +RNAPktSrc::push_data(int port, Packet *p){ + + p->push(3); + unsigned char *data = (unsigned char *)p->data(); + *data = MESSAGE_DATA; + *(data + 1) = MESSAGE_DATA_NORMAL; + *(data + 2) = 0; + + if (1) + RNAElement::print_packet("push_data", p, false); + + RNAElement::push_data(port, p); + +}; + +// +// No module-specific configuration parameters. Use buffer with +// appropriate parameters to generate copies and management messages. +// +int +RNAPktSrc::configure(Vector &conf, ErrorHandler *errh) +{ + + RNAElement::configure(conf, errh); + + if (cp_va_parse(conf, this, errh, + cpKeywords, + cpEnd) < 0) + return -1; + + if (debug) + rna_click_chatter(FUNC_DEFAULT, + "[%s] Configuring RNAPktSrc. \n", + instance_name()); + + if (exec_finish_configuration) + finish_configuration(); + + return 0; +} + + +ELEMENT_REQUIRES(RNAElement) +EXPORT_ELEMENT(RNAPktSrc) +ELEMENT_MT_SAFE(RNAPktSrc) + +CLICK_ENDDECLS Index: rna/elements/rna/modules_pktsrc.hh diff -u /dev/null rna/elements/rna/modules_pktsrc.hh:1.2 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_pktsrc.hh Mon Jun 30 12:43:20 2008 @@ -0,0 +1,52 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_RNAPKTSRC_HH +#define CLICK_RNAPKTSRC_HH + +#include "rnaelement.hh" + +//############################################################# +// +// Simple wrapper around the Infinite Source packet generator in +// Click. This module introduces a data message header into the packet +// and sends it out. Derives basic control interface from the base +// class RNAElement. +// +//############################################################# +class RNAPktSrc : public RNAElement { +public: + + RNAPktSrc(); + ~RNAPktSrc(); + + // Click house keep functions... + static void static_initialize() { RNAElement::static_initialize_default(); }; + static void static_cleanup() { RNAElement::static_initialize_default(); }; + const char *class_name() const { return default_class_name(); }; + const char *port_count() const { return "-/-"; } + const char *processing() const { return PUSH; } + + // Configuration... + int configure(Vector &, ErrorHandler *); + int finish_configuration(); // Complete the configuration step... + bool can_live_reconfigure() const { return true; } + int configure_phase() { return CONFIGURE_PHASE_LAST; }; + + // Introduce a data header and send it out. + void push_data(int port, Packet *p); + + private: + +}; + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/modules_reorderbuffer.cc diff -u /dev/null rna/elements/rna/modules_reorderbuffer.cc:1.3 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_reorderbuffer.cc Mon Jun 30 12:43:20 2008 @@ -0,0 +1,301 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "modules_reorderbuffer.hh" + + +//############################################################ +// +// This code inserts a sequence number in the packet header and orders +// messages according to the sequence number. This module does not do +// retransmission. +// +//############################################################ + +// +//=================================================================== +// Buffering component of the reorder buffer. +// +ReorderBuffer::BufferedPacket::BufferedPacket(LinkState *incoming, + int seq, + Packet *p) { + assert(p); + _p = p; + _incoming_link = incoming; + _seq = seq; +}; + +void +ReorderBuffer::BufferedPacket::print() { + click_chatter("[BUFFER] seq = %u\n", _seq); + return; +}; + +bool +ReorderBuffer::BufferedPacket::match(int seq) { + return (_seq == seq); +}; + +// +//=================================================================== +// + +ReorderBuffer::ReorderBuffer() : + _rnabuffer_timer(static_rnabuffer_timer_hook, this) +{ + // Set the seed... + srand(0x2322311); + set_type(REORDERBUFFER); + _next_seq = 0; + _out_seq = 0; +} + +ReorderBuffer::~ReorderBuffer() +{ + // Do nothing... +} + +unsigned long +ReorderBuffer::diff_in_ms(timeval t1, timeval t2) +{ + unsigned long s, us, ms; + +// DEBUG_CHATTER ("diff_in_ms: t1 %ld %ld; t2 %ld %ld\n", +// t1.tv_sec, t1.tv_usec, +// t2.tv_sec, t2.tv_usec); + + while (t1.tv_usec < t2.tv_usec) { + t1.tv_usec += 1000000; + t1.tv_sec -= 1; + } + + assert(t1.tv_sec >= t2.tv_sec); + + s = t1.tv_sec - t2.tv_sec; + assert(s < ((unsigned long)(1<<31))/1000); + + us = t1.tv_usec - t2.tv_usec; + ms = s * 1000L + us / 1000L; + +// DEBUG_CHATTER ("diff_in_ms: difference is %ld %ld -> %ld\n", +// s, +// us, +// ms); + + return ms; +} + +int +ReorderBuffer::rna_finish_configuration() { + + + return 0; +}; + + +int +ReorderBuffer::initialize(ErrorHandler *) { + + click_chatter("[ReorderBuffer::initialize] \n"); + _rnabuffer_timer.initialize(this); + _rnabuffer_timer.schedule_after_msec(RNAREORDERBUFFER_TIMER_INTERVAL); + + return 0; +}; + + +void +ReorderBuffer::static_rnabuffer_timer_hook(Timer *, void *v) +{ + //click_chatter("[ReorderBuffer::static_rnabuffer_timer_hook] \n"); + ReorderBuffer *buf = (ReorderBuffer *)v; + buf->rnabuffer_timer_hook(); +} + +void +ReorderBuffer::rnabuffer_timer_hook() +{ + + deliver_ready_messages(); + _rnabuffer_timer.schedule_after_msec(RNAREORDERBUFFER_TIMER_INTERVAL); + +}; + +void +ReorderBuffer::deliver_ready_messages(){ + + bool found = false; + int size = rnabuffer.size(); + + if (size > 0) + click_chatter("[%s] ReorderBuffer::deliver_ready_messages() \n", + instance_name()); + + // Look through the list and clean it up. + do { + + found = false; + Vector remaining; + + // Go through all the stored messages and see if there is one + // with the next seq number... + for (int i = 0; i < rnabuffer.size(); i++){ + + BufferedPacket *buf = rnabuffer[i]; + + // Well if the packet with the next sequence number has been + // found, then skip everything... + if ( found || ! buf->match(_next_seq)){ + remaining.push_back(buf); + continue; + }; + + // Found the match... + found = true; + + // Extract + LinkState *incoming_link = buf->_incoming_link; + Packet *pkt = buf->_p; + int port = incoming_link->local_port; + + // Forward the packet... + RNAElement::push_data(port, pkt); + + }; // for(....) + + if (found) + _next_seq++; + + rnabuffer.swap(remaining); + + // + // if (found) + // rna_click_chatter(FUNC_DEFAULT,"[%s] Found = %d next_seq = %d (remaining in buffer = %d)\n", + // instance_name(), found, _next_seq, rnabuffer.size()); + + } while(found); + +}; // deliver_ready_messages.. + + +// +// Buffer only messages coming from downstream. Check their sequence +// numbers and send packets in order. Introduce a sequence number in +// messages headed downstream. +// +void +ReorderBuffer::push_data(int port, Packet *p){ + + click_chatter("[%s] ReorderBuffer::push_data \n", instance_name()); + + LinkState *incoming_link = lookup_link(port); + if (!incoming_link) { + rna_click_chatter(FUNC_DEFAULT, + "[%s] ReorderBuffer::push_data Dropping packet...incoming link\n", + instance_name()); + p->kill(); + return; + }; + + + if (incoming_link->is_downstream()) { + + // Message is coming from upstream + process_incoming_from_upstream(&p, incoming_link); + + // Introduce the header.... + p->push(3 + 4); + char *data = (char *)p->data(); + *(data + 0) = MESSAGE_DATA; + *(data + 1) = MESSAGE_DATA_NORMAL; + *(data + 2) = 0; + + click_chatter("[%s] ReorderBuffer::push_data Copying out_seq = %d \n", + instance_name(), _out_seq); + + // Copy the sequence number...This should be revised... + memcpy((data + 3), (char *)&_out_seq, 4); + _out_seq++; + + if (debug) + RNAElement::print_packet(instance, p, false); + + RNAElement::push_data(port, p); + + } else { + + // Remove the header... + char *data = (char *)p->data(); + + // I cant handle anything other than minimal capabilities... + if ( *(data + 1) != MESSAGE_DATA_NORMAL){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] ReorderElement::push_data " + "Dropping packet...message type\n", + instance_name()); + p->kill(); + return; + }; + + // Remove the rest of the header... + p->pull(3); + + // Message coming from downstream + process_incoming_from_downstream(&p, incoming_link); + + // Extract the sequence number... + data = (char *)p->data(); + int seqnum = 0; + memcpy(&seqnum, data, 4); + + // remove the seq number as well. + p->pull(4); + + rna_click_chatter(FUNC_DEFAULT,"[%s] Storing packet - seqnum = %d \n", + instance_name(), seqnum ); + + // Store this packet + BufferedPacket *b = new BufferedPacket(incoming_link, seqnum, p); + rnabuffer.push_back(b); + + }; // else... + + + return; + +}; + + +// +// Configure. No module-specific parameters to process, yet. +// +int +ReorderBuffer::configure(Vector &conf, ErrorHandler *errh) +{ + + RNAElement::configure(conf, errh); + + if (debug) + click_chatter("Configuring ReorderBuffer... %s \n", class_name()); + + if (exec_finish_configuration) + finish_configuration(); + + return 0; +} + + +ELEMENT_REQUIRES(RNAElement) +EXPORT_ELEMENT(ReorderBuffer) +ELEMENT_MT_SAFE(ReorderBuffer) + +CLICK_ENDDECLS Index: rna/elements/rna/modules_reorderbuffer.hh diff -u /dev/null rna/elements/rna/modules_reorderbuffer.hh:1.3 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/modules_reorderbuffer.hh Mon Jun 30 12:43:20 2008 @@ -0,0 +1,92 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_REORDERBUFFER_HH +#define CLICK_REORDERBUFFER_HH + +//############################################################## +// +// Reorder buffer is a modification of the default buffer that uses +// sequence numbers to order messages. A sequence number is +// incorporated into outgoing messages before being sent out. The +// incoming messages are buffered until the message with the right +// sequence number shows up. Then the packets are delivered upstream +// in order. This is a simple buffer with no capability to retransmit. +// +//############################################################## + +#include "rnaelement.hh" + +#define RNAREORDERBUFFER_TIMER_INTERVAL 1000 // Every second +#define RNAREORDERBUFFER_MAX_DELAY 1000 // Delay + +class ReorderBuffer : public RNAElement { +public: + + // One object for each packet coming in from downstream. + class BufferedPacket + { + public: + Packet *_p; + LinkState *_incoming_link; + int _seq; + + // Initialize the object + BufferedPacket(LinkState *incoming, int seq, Packet *p); + + // Check if the packet has a specific sequence number + bool match(int seq); + + // Debug message + void print(); + }; + + // Constructor and cleanup + ReorderBuffer(); + ~ReorderBuffer(); + + // Click housekeeping functions.. + int initialize(ErrorHandler *); + static void static_initialize() { RNAElement::static_initialize_default(); }; + static void static_cleanup() { RNAElement::static_initialize_default(); }; + const char *class_name() const { return default_class_name(); } + const char *port_count() const { return "-/-"; } + const char *processing() const { return PUSH; } + + // Configuration.. + int configure(Vector &, ErrorHandler *); + int rna_finish_configuration(); // Complete the configuration step... + bool can_live_reconfigure() const { return true; } + + // Data path. + void push_data(int i, Packet *p); + + + // Timer management + static unsigned long diff_in_ms(timeval t1, timeval t2); + static void static_rnabuffer_timer_hook(Timer *, void *); + void rnabuffer_timer_hook(); + + // Go through the buffer to see if there are messages that are ready + // to be delivered to the upstream... + void deliver_ready_messages(); + + private: + + int _next_seq; + int _out_seq; + Vector rnabuffer; + Timer _rnabuffer_timer; + +}; + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/patterns_parser.pl diff -u /dev/null rna/elements/rna/patterns_parser.pl:1.2 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/patterns_parser.pl Mon Jun 30 12:47:25 2008 @@ -0,0 +1,748 @@ +#! /usr/bin/perl + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +use Parse::RecDescent; +use Data::Dumper; + +my ($allowed_names, $patterns) = (undef) x 2; + +#------------------------------------- +# Grammar to setup the patterns... +#------------------------------------- + +## The default namespace... +#NAMESPACE DEFAULT_NAMES +# +#START MIN +# +## This simply specifies a buffer. no reodering etc. +#PATTERN MIN +# REQ MUST BUFFER 1 +# CONFIG LINK ADD CONTROL 0 BUFFER 1 +# CONFIG LINK ADD BUFFER 1 CONTROL 0 +# +## Next use this pattern in MIN is successful +#PATTERN ORDERED_DELIVERY +# FOLLOWS MIN +# REQ MUST REORDERBUFFER 1 +# CONFIG LINK DEL CONTROL 0 BUFFER 1 +# CONFIG LINK ADD CONTROL 0 REORDERBUFFER 1 +# CONFIG LINK ADD REORDERBUFFER 1 BUFFER 1 +# UNCONFIG LINK DEL CONTROL 0 REORDERBUFFER 1 +# UNCONFIG LINK DEL REORDERBUFFER 1 BUFFER 1 +# UNCONFIG LINK ADD CONTROL 0 BUFFER 1 +# +#PATTERN ENCRYPTED_ORDERED_DELIVERY +# FOLLOWS ORDERED_DELIVERY +# REQ MUST ENCRYPTION 1 +# REQ MUST REORDERBUFFER 1 +# REQ MUST DEMULTIPLEXOR 1 +# CONFIG ARG ENCRYPTION 1 algo des +# CONFIG ARG ENCRYPTION 1 keysize 512 +# CONFG LINK ADD DEMULTIPLEXOR 1 REORDERBUFFER 1 +# CONFIG LINK ADD REORDERBUFFER 1 ENCRYPTION 1 +# UNCONFG LINK DEL DEMULTIPLEXOR 1 REORDERBUFFER 1 +# UNCONFIG LINK DEL REORDERBUFFER 1 ENCRYPTION 1 +# + +#---------------------------------------- +# code implementing the grammar +#---------------------------------------- + +$::RD_ERRORS = 1; +$::RD_HINT = 0; +#$::RD_TRACE = 0; + +my $grammar = q { + +{ + use Data::Dumper; + my %results = (); + my %name_shortcuts = (); + my @lines = (); + + sub preprocess_text($){ + @lines = split (/\n/, shift @_); + #print Dumper(\@lines); + } +} + +PROGRAM: { preprocess_text($text); } COMMAND(s) eofile +{ + $return = \%results; +} + +eofile: /^\Z/ + +COMMAND: START_CMD + | NAME_CMD + | PATTERN_CMD + | COMMENT + | /!^\Z/ { + die ("Cannot parse line " . ($thisline + 1). " "); + } + + +START_CMD: 'START' IDENTIFIER +{ + $results{start} = $item{IDENTIFIER}; +} + +NAME_CMD: 'NAMESPACE' IDENTIFIER +{ + $results{namespace} = $item{IDENTIFIER}; +} + +PATTERN_CMD: 'PATTERN' IDENTIFIER RULES +{ + + my $name = $item{IDENTIFIER}; + my $rules = $item{RULES}; + #print "PATTERN_CMD RULES = " . Dumper($rules); + + $results{patterns}{$name} = $item{RULES}; +} + +COMMENT: ( /#/ | /^$/ ) + +#{ +# print "Comment $thisline ******\n"; +#} + + +RULES: RULE(s?) +{ + + #print "Entering rule" . Dumper(\@item); + + my %rules = (); + foreach my $rule (@{$item[1]}){ + next if (not defined $rule); + my $type = $rule->{type}; + next if ($type =~ /RENAME/); + delete ($rule->{type}); + push @{$rules{$type}}, $rule; + }; + + $return = \%rules; +} + +RULE: ( REQ_CMD | FOLLOWS_CMD | RENAME_CMD | CONF_CMD ) +{ + $return = $item[1]; +} + + +#0 1 2 3 4 5 +REQ_CMD: 'REQ' ('MUST') IDENTIFIER VALUE(?) OP(?) +{ + + #print "req_cmd = " . Dumper(\@item); + + my %reqcmd = (); + $reqcmd{type} = "REQ"; + $reqcmd{cond} = $item[2]; + $reqcmd{name} = $item[3]; + + #if (not defined main::lookup_module_name($reqcmd{name})){ + # die("Module type $reqcmd{var} must be defined before use\n". + # "[" . $thisline . "] " . $lines[$thisline-1]. "\n"); + # return undef; + #} + + my $instance = shift @{$item[4]}; + if (defined $instance) { + $reqcmd{instance} = $instance; + } else { + my $shortcut = $item[3]; + $reqcmd{instance} = $name_shortcuts{$shortcut}{instance}; + $reqcmd{name} = $name_shortcuts{$shortcut}{name}; + }; + + my $op = shift @{$item[5]}; + if (defined $op) { + $reqcmd{op} = $op; + } else { + $reqcmd{op} = '='; + }; + + $return = \%reqcmd; + + #print "Req = " . Dumper($return); +} + +##0 1 2 3 4 +#COND_CMD: 'CONDITION' IDENTIFIER LOGICAL_OP IDENTIFIER +#{ +# +# for (my $i = 0; $i <= $#item; $i++){ +# print "COND_CMD var $i = " . Dumper($item[$i]); +# }# +# +# my %condcmd = (); +# $condcmd{type} = "COND"; +# $condcmd{var} = $item[2]; +# $condcmd{op} = $item[3]; +# $condcmd{val} = $item[4]; +# +# $return = \%condcmd; +# +#} + +#0 1 2 +FOLLOWS_CMD: 'FOLLOWS' IDENTIFIER +{ + my $pattern = $item{IDENTIFIER}; + + if (defined $results{patterns}{$pattern}){ + my %patterncmd = (); + $patterncmd{type} = "FOLLOWS"; + $patterncmd{dependency} = $pattern; + $return = \%patterncmd; + } else { + die("Pattern variable $pattern must be defined before use\n". + "[" . $thisline . "] " . $lines[$thisline-1]. "\n"); + } +} + +#0 #1 #2 +CONF_CMD: ('CONFIG' | 'UNCONFIG') (ARG_CMD | LINK_CMD) +{ + my $conf_type = $item[1]; + my $cmd = $item[2]; + $cmd->{conf} = $conf_type; + $return = $cmd; + #print "Conf command = " . Dumper($return); +} + +#0 1 2 3 4 5 +ARG_CMD: 'ARG' IDENTIFIER VALUE(?) TEXT TEXT +{ + + my $mod_name = $item[2]; + my $mod_instance = $item[3][0]; + my $arg_name = $item[4]; + my $arg_val = $item[5]; + + if (not defined $mod_instance) { + my $shortcut = $mod_name; + $mod_instance = $name_shortcuts{$shortcut}{instance}; + $mod_name = $name_shortcuts{$shortcut}{name}; + }; + + #if (not defined main::lookup_module_name($mod_name)){ + # die("Module type $mod_name must be defined before use\n". + # "[" . $thisline . "] " . $lines[$thisline-1]. "\n"); + # return undef; + #}; + + #if (($arg_type =~ /MODULE/) and + # (not defined main::lookup_module_name($arg_name))){ + # die("Module type $arg_name must be defined before use\n". + # "[" . $thisline . "] " . $lines[$thisline-1]. "\n"); + # return undef; + #}; + + my %arg = (); + $arg{type} = 'ARG'; + $arg{mod_name} = $mod_name; + $arg{mod_instance} = $mod_instance; + $arg{arg_name} = $arg_name; + $arg{arg_val} = $arg_val; + + $return = \%arg; + + #print "Arg = " . Dumper($return); +} + +#0 1 2 3 4 5 6 7 8 9 +LINK_CMD: 'LINK' ('ADD'|'DEL') IDENTIFIER VALUE(?) VALUE(?) IDENTIFIER VALUE(?) VALUE(?) KEYWORD(s?) +{ + + my $link_op = $item[2]; + my $mod1_name = $item[3]; + my $mod1_instance = $item[4][0]; + my $mod1_count = $item[5][0]; + my $mod2_name = $item[6]; + my $mod2_instance = $item[7][0]; + my $mod2_count = $item[8][0]; + my $keywords = $item[9]; + + if (not defined $mod1_instance) { + my $shortcut = $mod1_name; + $mod1_instance = $name_shortcuts{$shortcut}{instance}; + $mod1_name = $name_shortcuts{$shortcut}{name}; + }; + + if (not defined $mod2_instance) { + my $shortcut = $mod2_name; + $mod2_instance = $name_shortcuts{$shortcut}{instance}; + $mod2_name = $name_shortcuts{$shortcut}{name}; + }; + + $mod1_count = 1 if (not defined $mod1_count); + $mod2_count = 1 if (not defined $mod2_count); + + die ("Only one side of the link cmd may be a wild card on line $thisline") + if (($mod1_count > 1) and ($mod2_count > 1)); + + my %link = (); + $link{type} = 'LINK'; + $link{op} = $link_op; + $link{mod1_name} = $mod1_name; + $link{mod1_instance} = $mod1_instance; + $link{mod1_count} = $mod1_count; + $link{mod2_name} = $mod2_name; + $link{mod2_instance} = $mod2_instance; + $link{mod2_count} = $mod2_count; + $link{keywords} = $keywords; + + $return = \%link; + + #print "Link = " . Dumper($return); + +} + +#0 1 2 3 4 +RENAME_CMD: 'RENAME' IDENTIFIER VALUE TEXT +{ + my $mod_name = $item[2]; + my $mod_instance = $item[3]; + my $new_mod_name = $item[4]; + + #if (not defined main::lookup_module_name($mod_name)){ + # die("Module $mod_name must be defined before use\n". + # "[" . $thisline . "] " . $lines[$thisline-1]. "\n"); + # return undef; + #}; + + # XXX The count must be verified.... + + $name_shortcuts{$new_mod_name}{name}= $mod_name; + $name_shortcuts{$new_mod_name}{instance}= $mod_instance; + + #print "RENAME " . Dumper(\%name_shortcuts); + my %dummy = ( + type => 'RENAME' + ); + $return = \%dummy; + +} + +OP: ('>='|'<='|'='|'<'|'>') + +LOGICAL_OP: ('XOR'|'AND'|'OR') + +IDENTIFIER: /[A-Za-z_][A-Za-z0-9_]*/ + +KEYWORD: (SIMPLE_KEYWORD|RANGE_KEYWORD) +{ + + #print "Keyword = " . Dumper(\@item); + + my $name = $item[1][0]; + if ($name =~ /(BIDIRECTIONAL|ALL)/){ + $return = $name; + } elsif ($name =~ /RANGE/) { + $return = $name; + }; +} + +SIMPLE_KEYWORD: ('BIDIRECTIONAL'|'ALL') +{ + #print "Simple keyword = " . Dumper(\@item); + $return = [$item[1]]; +} + + +# This is not handled at this point... + +RANGE_KEYWORD: 'RANGE' VALUE '-' VALUE +{ + #print "Range Cmd = " . Dumper(\@item); + $return = [ 'RANGE', $item[2], $item[4] ]; + + die("Range command not supported right now..."); +} + +TEXT: /\S+/ + +VALUE: /\d+/ + +}; + + +sub read_module_namespace($){ + my $file = shift; + + my %allowed_names_local = (); + + return if (not defined $file); + open(FILE, "<$file") || die("Cannot open file $file "); + + my $classname = undef; + while(){ + + # Cleanup the line first... + chomp; + s/\s+//g; + s/=.*$//g; + s/,//g; + + # Track the enum + if (not defined $classname) { + my $line = $_; + $line =~ s/\s*enum//g; + $line =~ s/\{//g; + $line =~ s/\s+//g; + $classname = $line; + next; + }; + + if (defined $classname and /\}/){ + $classname = undef; + next; + } + + next if (/(_END|_BEGIN)/); + + $allowed_names_local{$classname}{$_} = 1; + }; + + close(FILE); + + #print Dumper(\%allowed_names_local); + return \%allowed_names_local; +}; + + +sub read_patterns($){ + my $file = shift; + my $text = ""; + + return undef if (not defined $file); + + open(FILE, "<$file") || die("Cannot open file $file "); + while(){ + chop; + unless ( /(^\s*\#)|(^\s*$ )/ ){ + $text .= $_; + } + $text .= "\n"; + }; + + print $text; + close(FILE); + + + return $text; +}; + +sub lookup_module_name($) { + + my $varname = shift; + + my $val = (defined $allowed_names + and defined $varname + and defined $$allowed_names{RNAElementType}{$varname}); + + #print "in Lookup_module_name $varname val = $val " . + #Dumper($allowed_names) . $allowed_names{$varname}; + + return 1 if ($val == 1); + return undef; +}; + +########################################## +# +# Generate the output file... +# +########################################## + +#=> Example..... +# 'patterns' => { +# 'MIN' => { +# 'REQ' => [ +# { +# 'cond' => 'MUST', +# 'name' => 'NEGOTIATE', +# 'instance' => '1', +# 'op' => '=' +# }, +# { +# 'cond' => 'MUST', +# 'name' => 'DEMUX', +# 'instance' => '1', +# 'op' => '=' +# } +# ], +# 'LINK' => [ +# { +# 'mod1_instance' => '0', +# 'mod1_name' => 'SELF', +# 'mod2_name' => 'DEMUX', +# 'mod2_instance' => '1' +# }, +# { +# 'mod1_instance' => '0', +# 'mod1_name' => 'SELF', +# 'mod2_name' => 'NEGOTIATE', +# 'mod2_instance' => '1' +# } +# ], +# 'ARG' => [ +# { +# 'mod_instance' => '1', +# 'arg_val' => '"ordered_delivery"', +# 'arg_name' => 'PREFERENCE', +# 'mod_name' => 'NEGOTIATE' +# }, +# { +# 'mod_instance' => '1', +# 'arg_val' => '"encryped_ordered_delivery"', +# 'arg_name' => 'PREFERENCE', +# 'mod_name' => 'NEGOTIATE' +# } +# ] +# }, +# 'ORDERED_DELIVERY' => { +# 'REQ' => [ +# { +# 'cond' => 'MUST', +# 'name' => 'REORDERBUFFER', +# 'instance' => '1', +# 'op' => '=' +# }, +# { +# 'cond' => 'MUST', +# 'name' => 'DEMUX', +# 'instance' => '1', +# 'op' => '=' +# } +# ], +# 'LINK' => [ +# { +# 'mod1_instance' => '1', +# 'mod1_name' => 'DEMUX', +# 'mod2_name' => 'REORDERBUFFER', +# 'mod2_instance' => '1' +# } +# ], +# 'FOLLOWS' => [ +# { +# 'dependency' => 'MIN' +# } +# ] +# }, +# 'ENCRYPTED_ORDERED_DELIVERY' => { +# 'REQ' => [ +# { +# 'cond' => 'MUST', +# 'name' => 'ENCRYPTION', +# 'instance' => '1', +# 'op' => '=' +# }, +# { +# 'cond' => 'MUST', +# 'name' => 'REORDERBUFFER', +# 'instance' => '1', +# 'op' => '=' +# }, +# { +# 'cond' => 'MUST', +# 'name' => 'DEMUX', +# 'instance' => '1', +# 'op' => '=' +# } +# ], +# 'LINK' => [ +# { +# 'mod1_instance' => '1', +# 'mod1_name' => 'DEMUX', +# 'mod2_name' => 'REORDERBUFFER', +# 'mod2_instance' => '1' +# }, +# { +# 'mod1_instance' => '1', +# 'mod1_name' => 'REORDERBUFFER', +# 'mod2_name' => 'ENCRYPTION', +# 'mod2_instance' => '1' +# } +# ], +# 'FOLLOWS' => [ +# { +# 'dependency' => 'ORDERED_DELIVERY' +# } +# ], +# 'ARG' => [ +# { +# 'mod_instance' => '1', +# 'arg_val' => 'des', +# 'arg_name' => 'algo', +# 'mod_name' => 'ENCRYPTION' +# }, +# { +# 'mod_instance' => '1', +# 'arg_val' => '512', +# 'arg_name' => 'keysize', +# 'mod_name' => 'ENCRYPTION' +# } +# ] +# } +# }, +# 'namespace' => 'DEFAULT_NAMES', +# 'start' => 'MIN' +# }; + + +sub gen_code_for_patterns($){ + my $allpatterns = shift; + + #print "gen_code_for_patterns" . Dumper($allpatterns); + + my $msg = ""; + $msg .= "\tVector patternlist; \n"; + $msg .= "\tPattern *pat;\n"; + $msg .= "\tVector parents;\n"; + $msg .= "\tVector reqs; \n"; + $msg .= "\tVector args; \n"; + $msg .= "\tVector links; \n"; + $msg .= "\tReq *r;\n"; + $msg .= "\tArg *a;\n"; + $msg .= "\tLink *l;\n"; + $msg .= "\tVector keywords;\n"; + + foreach my $pattern (keys %{$allpatterns->{patterns}}){ + + my $thispattern = $allpatterns->{patterns}{$pattern}; + #print "Looking at pattern $pattern " . Dumper($thispattern); + + $msg .= "\n// Code for pattern $pattern\n{\n"; + $msg .= "\tparents.clear();\n"; + $msg .= "\treqs.clear(); \n"; + $msg .= "\targs.clear(); \n"; + $msg .= "\tlinks.clear(); \n"; + + my $parent_arr = $thispattern->{FOLLOWS}; + foreach my $parent (@{$parent_arr}){ + $msg .= "\tparents.push_back(\"$parent->{dependency}\");\n"; + }; + + my $r_arr = $thispattern->{REQ}; + foreach my $r (@{$r_arr}){ + + my $cond = $r->{cond}; + my $name = $r->{name}; + my $instances = $r->{instance}; + + if ($cond =~ /MUST/){ + $cond = "CONSTRAINT_REQUIRE_MUST"; + }; + + $msg .= "\tr = new Req($cond,$name,$instances);\n"; + $msg .= "\treqs.push_back(r);\n"; + }; + + my $a_arr = $thispattern->{ARG}; + foreach my $a (@{$a_arr}){ + + my $name = $a->{mod_name}; + my $instance = $a->{mod_instance}; + my $var = $a->{arg_name}; + my $val = $l->{arg_val}; + + $msg .= "\ta = new Arg($name, $instance, \"$var\", \"$val\");\n"; + $msg .= "\targs.push_back(a); \n"; + }; + + my $l_arr = $thispattern->{LINK}; + foreach my $l (@{$l_arr}){ + + my $name1 = $l->{mod1_name}; + my $name2 = $l->{mod2_name}; + my $instance1 = $l->{mod1_instance}; + my $instance2 = $l->{mod2_instance}; + my $count1 = $l->{mod1_count}; + my $count2 = $l->{mod2_count}; + + my $op = "OP_" . $l->{op}; + my $conf = "CONF_" . $l->{conf}; + my $keywords = $l->{keywords}; + + $msg .= "\tkeywords.clear(); \n"; + foreach my $str (@{$keywords}){ + $msg .= "\tkeywords.push_back(\"$str\");\n"; + }; + + $msg .= "\tl = new Link($name1, $instance1, $count1, " . + "$name2, $instance2, $count2, $op, $conf, keywords);\n"; + $msg .= "\tlinks.push_back(l); \n"; + + }; + + $msg .= "\tpat = new Pattern(this, \"$pattern\", parents, reqs, ". + "args, links); \n"; + $msg .= "\tpatternlist.push_back(pat); \n"; + $msg .= "}; \n//Completed pattern $pattern\n"; + + + }; + + # Add a NULL pattern.... + $msg .= "\n// Code for NULL\n{\n"; + $msg .= "\tparents.clear();\n"; + $msg .= "\treqs.clear(); \n"; + $msg .= "\targs.clear(); \n"; + $msg .= "\tlinks.clear(); \n"; + $msg .= "\tpat = new Pattern(this, \"NULL\", parents, reqs, args, links); \n"; + $msg .= "\tpatternlist.push_back(pat); \n"; + $msg .= "}; \n//Completed pattern NULL\n"; + + return $msg; +}; + +########################################## +sub Usage() { + + print "Usage: perl patterns_parser.pl ". + "\n"; + die; +}; + +my ($patterns_file, $module_namespace_file, $code_file) = @ARGV; +Usage() unless (defined $patterns_file and + defined $module_namespace_file and + defined $code_file); + + +# ----------------- +# Read variable names from another file... +# ----------------- +$allowed_names = read_module_namespace($module_namespace_file); + +# ----------------- +# Read patterns from the file... +# ----------------- +$patterns = read_patterns($patterns_file); + +# ----------------- +# Generate a parser from the specification in $grammar +# ----------------- +my $parser = new Parse::RecDescent ($grammar); +my $parser_result = $parser->PROGRAM($patterns); +print "Result = " . Dumper($parser_result); + +# ----------------- +# Generate code and dump it in the patterns file... +# ----------------- +my $code = gen_code_for_patterns($parser_result); +open(FILE, ">$code_file") || die("Cannot open file $code_file to write"); +print FILE $code; +close(FILE); Index: rna/elements/rna/rnaelement.cc diff -u /dev/null rna/elements/rna/rnaelement.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement.cc Fri Jun 27 10:40:58 2008 @@ -0,0 +1,104 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "rnaelement.hh" + +// +// Core RNA element...All the interesting code is elsewhere such as in +// the neighbors, control etc. +// + +// Gather all the upstream and downstream nodes +#include "rnaelement_neighbors.cc" + +// Parse the arguments to the module; configuration commands. +#include "rnaelement_parse.cc" + +// Process the links. +#include "rnaelement_links.cc" + +// Control interface to the module. If the message is not handled by +// the default code, then run the module-specific control code; also +// included is the connection state at the next layer... +#include "rnaelement_control.cc" + +// Miscellaneous +#include "rnaelement_handlers.cc" + +// Message handling +#include "rnaelement_messages.cc" + + +#define QUOTE(EXP) #EXP + +const char *str_elementtype[] = { + QUOTE(ELEMTYPE_BEGIN), + QUOTE(UNKNOWN), + QUOTE(ANY), + QUOTE(ROOT), + QUOTE(DISCOVERY), + QUOTE(BUFFER), + QUOTE(CONTROL), + QUOTE(CRYPT), + QUOTE(ENCRYPTION), + QUOTE(MULTITUNNEL), + QUOTE(MULTIPLEXOR), + QUOTE(DEMULTIPLEXOR), + QUOTE(MUXDEMUX), + QUOTE(NEGOTIATE), + QUOTE(OPTIONS), + QUOTE(REORDERBUFFER), + QUOTE(NETSTACK), + QUOTE(RINGBUFFER), + QUOTE(PKTSRC), + QUOTE(ELEMTYPE_END), +}; + +//############################################################ +// +// Constructor and destructor... +// +//############################################################ +RNAElement::RNAElement() { + + if (0) + rna_click_chatter(FUNC_ENTRY, "RNAElement::RNAElement()\n"); + + type = UNKNOWN; + instance = String::stable_string(""); + exec_finish_configuration = false; + connection_oriented = false; + skip_connection_check = false; + state = 0; + debug = true; + conns.clear(); + + _preconfigured_element_list = false; + _upstream_element_list.clear(); + _downstream_element_list.clear(); + +} + +RNAElement::~RNAElement() { + // Do nothing.... +}; + + + +ELEMENT_REQUIRES(LinkState) +ELEMENT_REQUIRES(RNAError) +ELEMENT_REQUIRES(RNAControlMsg) +ELEMENT_REQUIRES(ConnectionState) + +ELEMENT_PROVIDES(RNAElement) + +CLICK_ENDDECLS Index: rna/elements/rna/rnaelement.hh diff -u /dev/null rna/elements/rna/rnaelement.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement.hh Fri Jun 27 10:40:58 2008 @@ -0,0 +1,323 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_RNAELEMENT_HH +#define CLICK_RNAELEMENT_HH + +#include "rnaelement_common.hh" + +class LinkState; +class State; +class RNAElement; +class RNAControlMsg; + +extern const char *str_elementtype[]; +#include "module_namespace.txt" + +#include "rnaelement_error.hh" +#include "rnaelement_connstate.hh" +#include "rnaelement_ctlmsg.hh" +#include "rnaelement_messages.hh" +#include "rnaelement_linkstate.hh" +#include "metaprotocol_patterns.hh" + + +CLICK_DECLS + + +//########################################################## +// Misc definitions +//########################################################## +#define MAX_PRINT_PKT 50 + +//########################################################## +// This is high-level specification from the configure function. +// +// This is just an internal structure to pass parameters; not the most +// important. +// +//########################################################## +class linkspec { +public: + bool local_is_upstream; + bool crosslayer; + bool intrastack; + int local_elem; + int local_out; + int remote_elem; + int remote_in; + LinkState *l0; // linkcmd at the local node + LinkState *l1; // linkcmd at the remote node +}; + +//######################################################### +//# +//# RNA Element structure... +//# +//######################################################### + + +//######################################################### +// +// RNAElement +// +// This is a wrapper around the basic element structure provided by +// Click. This adds: +// +// * Control interface - to communicate between RNAElements for discovery +// and state modification +// +// * Link management - addition/deletion of the links on the fly +// +// * Message flow - default algorithms to move data across modules; do +// pre and post processing of the messages. +// +// * Element management - maintain the list of elements +// +// * Template - the state and pattern management. +// +// +// LIMITATIONS: +// +// * Only push interface is supported right now. Pull interface is not +// fundamentally different in terms of the functionality except the +// RNAElement structure must be generalized a little more. +// +// * Template is static. Patterns are statically generated and stored. +// +//######################################################### + +//class RNAElement : public RNAControlElement, public Element { +class RNAElement : public Element { + +protected: + + bool debug; // Is debug enabled for this module? + String instance; // name of this element + RNAElementType type; // the type of this RNA element + bool skip_connection_check; // should I check for connection state? + Vector conns; // my connection state + bool connection_oriented; // Is this protocol connection-oriented? + String controlnode; // ?? + State *state; // Store of the patterns + Vector all_links; // All the links associated with this element + bool exec_finish_configuration; // should I initiate the connection process? + + Vector _elemlist; // Elements specified and how they are eventually + // connected. + + + // Input provided by user until it can be automatically computed... + bool _preconfigured_element_list; + Vector _upstream_element_list; + Vector _downstream_element_list; + +public: + + //============================================================ + // Constructor and destructor... + //============================================================ + RNAElement(); + ~RNAElement(); + + //============================================================ + // Handle Click router-related calls... + //============================================================ + static void static_initialize_default(); + static void static_cleanup_default(); + + // This is called by the Click router and used to parse the + // argued parsed. + virtual int configure(Vector &conf, ErrorHandler *errh); + + // Misc functions... + void *cast(const char *n); + virtual const char *default_class_name() const { return "RNAElement"; } + + // Callback handlers. Not doing much at this point. + static String rna_read_handler(Element *e, void *thunk); + static int rna_write_handler(const String &conf, Element *e, + void *p, ErrorHandler *errh); + + + //============================================================ + // Handle messages from other layers and modules + //============================================================ + virtual void push_data(int i, Packet *); + virtual void push_control(int i, Packet *); + virtual void push_management(int i, Packet *); + virtual void push(int i, Packet *p); + + + //============================================================ + // parse the element list specified in the configure + // command. + //============================================================ + static void elementlist_parse(cp_value *v, const String &arg, + ErrorHandler *errh, const char *argname, + Element *context); + static void elementlist_store(cp_value *v, Element *); + + // Not used. + static Vector elementlist_find_prefix(String name, + Element *); + // Not used. + RNAElement *elementlist_lookup_one(Vector& array, + RNAElementType t, + bool modify = false); + // Not used. + Vector elementlist_lookup(Vector& array, + RNAElementType t, + bool modify = false); + + //============================================================ + // Identifies what type this module is. This is useful in + // matching the module to the specification of the protocol + //============================================================ + void set_type(RNAElementType s) { type = s; } + RNAElementType get_type() { return type; } + + //============================================================ + // Functions to enable human readability + //============================================================ + const char *instance_name() { return instance.printable().c_str(); } + void print_packet(String label, Packet *p, bool print_annotations = false); + + //============================================================ + // Control interface to the module + //============================================================ + bool is_control() { return ((type == CONTROL) || (type == NETSTACK)); } + virtual RNAControlMsg *control(RNAControlMsg *c); // added by RNA + + virtual RNAControlMsg *module_specific_control(RNAControlMsg *c); // added by RNA + + + // Complete the configuration. During the initialization by Click + // and later by RNA metaprotocol while finishing up the composition. + virtual int finish_configuration(); // Called from the default configure + // if PROCESS is enabled. + virtual int rna_finish_configuration(); // Complete the configuration step... + + // Misc click callback handler. Not really used. + void add_handlers(); + + //============================================================ + // Connection State Management + //============================================================ + + // Should I do connection check when sending a message on a certain + // outgoing link? (typically necessary for downstream protocol that + // is connection-oriented + void set_skip_conn_check(bool val) { skip_connection_check = val; return; } + bool get_skip_conn_check() { return skip_connection_check; } + + // Check the state in the incoming message + bool check_connectionstate(LinkState *incoming_link, Packet *p_in); + + // Update the connection state for each outgoing link... + bool open_connection(LinkState *incoming_link = NULL); + void discover_connectionstate(LinkState *l); + void initialize_link(LinkState *l); + + //============================================================ + // Link management functions. + // Information about the incoming and outgoing links. + //============================================================ + int add_default_bidirectional_links(Vector *links, + bool crosslayer); + int add_default_unidirectional_links(Vector *links, + bool crosslayer); + int add_default_autodetect_links(Vector *links, + bool crosslayer); + int process_linkspecs(Vector &linkspecs); + int delete_link(LinkState *); + void print_links(); + void print_allelements_links(); + + + //============================================================ + // Manipulation of the predessor and successor lists + //============================================================ + void skip_type(Vector &v, char *typename_in); + void filter(char *what, Vector& v); + Element *upstream_element(Element *e, int inputport); + Vector upstream_elements(Element *e, int inputport = -1); + Vector downstream_elements(Element *e); + + + //============================================================ + // Handle the incoming and outgoing messages + //============================================================ + virtual void process_incoming_from_downstream(Packet **p_in, + LinkState *incoming = NULL, + MessageStatus *status = NULL); + virtual void process_incoming_from_upstream (Packet **p_in, + LinkState *incoming = NULL, + MessageStatus *status = NULL); + virtual void process_outgoing_to_downstream (Packet **p_in, + LinkState *outgoing = NULL, + MessageStatus *status = NULL); + virtual void process_outgoing_to_upstream (Packet **p_in, + LinkState *outgoing = NULL, + MessageStatus *status = NULL); + + //============================================================ + // Link state management functions... + //============================================================ + // Select the outgoing links to forward the message to.. + virtual LinkState *check_for_duplicate_link(LinkState *l); + void merge_link_information(LinkState *existing_link, LinkState *newlink); + + LinkState *lookup_link(int port, bool incoming = true); + LinkState *lookup_link(RNAElement *e, bool incoming = true); + + // Which way should a packet go? + virtual LinkState *select_outgoing_link(Packet *p, + LinkState *incoming, + bool downstream = true, + bool layeragnostic = false, + bool crosslayer = false, + bool agnostic_remote = true, + bool remote_unknown = false, + ConnectionState *preferred = 0); + virtual Vector + list_outgoing_link(Packet *p, + LinkState *incoming, + bool downstream = true, + bool layeragnostic = false, + bool crosslayer = false, + bool agnostic_remote = true, + bool remote_unknown = false, + ConnectionState *preferred = 0); + + virtual int count_outgoing_links(Packet *p, LinkState *incoming, + bool downstream, + bool layeragnostic, + bool crosslayer, + bool agnostic_remote, + bool remote_unknown, + ConnectionState *preferred = 0); + + virtual Vector + list_downstream_elements(bool downstream, + bool layeragnostic, + bool crosslayer, + bool agnostic_remote, + bool remote_unknown, + ConnectionState *preferred = 0); + +}; + + + + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/rnaelement_common.hh diff -u /dev/null rna/elements/rna/rnaelement_common.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_common.hh Fri Jun 27 10:40:58 2008 @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include +#include +#ifdef CLICK_LINUXMODULE +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#include + +CLICK_DECLS + Index: rna/elements/rna/rnaelement_connstate.cc diff -u /dev/null rna/elements/rna/rnaelement_connstate.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_connstate.cc Fri Jun 27 10:40:58 2008 @@ -0,0 +1,107 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "rnaelement_connstate.hh" + +//############################################ +// Initialization and cleanup +//############################################ +ConnectionState::ConnectionState() +{ + // Do nothing... +} + +ConnectionState::~ConnectionState() +{ + + while (varlist.size() > 0){ + Variable *v = varlist.back(); + if (v) + delete v; + varlist.pop_back(); + }; +}; + +int +ConnectionState::add_variable(VariableType t, void *data){ + Variable *v = new Variable(t, data); + add_variable(v); + return 0; + +}; + +//############################################ +// Add and delete variables from the state.. +//############################################ + +int +ConnectionState::add_variable(Variable *v){ + varlist.push_back(v); + return 0; + +}; + +int +ConnectionState::del_variable(int index){ + + Vector modified; + for (int i = 0; i < varlist.size(); i++) + if (i != index) + modified.push_back(varlist[i]); + varlist.swap(modified); + + return 0; + +}; + +int +ConnectionState::del_variable(Variable *v){ + + Vector modified; + for (int i = 0; i < varlist.size(); i++) + if (v != varlist[i]) + modified.push_back(varlist[i]); + varlist.swap(modified); + + return 0; + +}; + +//################################################################ +// +// Extract either the complete list of variable or one of a specific +// kind. +// +//################################################################ + +Vector +ConnectionState::get_variables(){ + return varlist; +}; + +void * +ConnectionState::get_data(VariableType t){ + + for (int i = 0; i < varlist.size(); i++){ + Variable *v = varlist[i]; + if (v->get_type() == t) + return v->get_data(); + }; + + return NULL; + +}; + + +CLICK_ENDDECLS +ELEMENT_PROVIDES(ConnectionState) + Index: rna/elements/rna/rnaelement_connstate.hh diff -u /dev/null rna/elements/rna/rnaelement_connstate.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_connstate.hh Fri Jun 27 10:40:59 2008 @@ -0,0 +1,99 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_CONNECTIONSTATE_HH +#define CLICK_CONNECTIONSTATE_HH + +#include "rnaelement_common.hh" + +//######################################################### +// +// Connection state information that is exchanged between protocols. A +// pointer to the connection state is included in each message that is +// retrieved and used by the next layer to determine the next steps. +// +//######################################################### + +// The connection state consists of a set of variables. Each variable +// has a type and value. A set of functions are supported to add and +// delete variables. + +//############################################ +// Variable definition +//############################################ + +enum VariableType{ + VAR_UNKNOWN, + VAR_LINKINFO, + +}; + +class Variable { + +protected: + VariableType var_type;// Type of this variable... + void *var_data; // pointer to the memory + +public: + + Variable(VariableType t, void *data){ + var_type = t; + var_data = data; + }; + + ~Variable() { + } + + void *get_data(){ + return var_data; + }; + + void set_data (void *d) { + var_data = d; + }; + + VariableType get_type(){ + return var_type; + }; + + void set_type (VariableType t) { + var_type = t; + }; + +}; + + +//############################################ +// Store and retrieve a set of variables. +//############################################ +class ConnectionState { + +public: + + ConnectionState(); + ~ConnectionState(); + + // Simple operations on the variables... + int add_variable(VariableType t, void *); + int add_variable(Variable *v); + int del_variable(int index); + int del_variable(Variable *v); + Vector get_variables(); + void *get_data(VariableType t); + + private: + + Vector varlist; + +}; + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/rnaelement_control.cc diff -u /dev/null rna/elements/rna/rnaelement_control.cc:1.2 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_control.cc Mon Jun 30 12:43:20 2008 @@ -0,0 +1,480 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +// The RNA control interface between layers and between modules within +// a single module. + +//############################################################ +// +// Process the control messages from the top and bottom +// +//############################################################ + +// This function is called if the default RNAElement::control() +// function cannot handle the specific call. This is virtual and +// overridden by modules. + +RNAControlMsg * +RNAElement::module_specific_control(RNAControlMsg *c){ + // Module-specific control + (void)c; + return NULL; +}; + +// Give additional information that is used to update internal state. +RNAControlMsg * +RNAElement::control(RNAControlMsg *c){ + + rna_click_chatter(FUNC_ENTRY, "[%s] RNAElement::control Entered \n", + instance_name()); + + bool handled_here = false; + + // Create a reply object and the default response...and fill it up. + RNAControlMsg *reply = new RNAControlMsg(RNAControlMsg::REPLY); + reply->set_unsupported(); + reply->set_error("NONE!"); + + // Sanity check... + if (!c){ + reply->set_invalid(); + reply->set_error("ControlMsg c is empty!"); + rna_click_chatter(FUNC_EXIT, "[%s] RNAElement::control Exit \n", + instance_name()); + return reply; + }; + + c->print(instance_name()); + + reply->set_operationtype(c->o); + switch(c->m) { + case RNAControlMsg::COMMAND: + switch(c->o){ + + case RNAControlMsg::CONFIGURE: + switch(c->op){ + case RNAControlMsg::CONF_LINK_ADD: + do { + LinkState *l = (LinkState *)c->get_data(); + if (l) { + l->print(instance_name()); + LinkState *l0 = check_for_duplicate_link(l); + if (!l0) { + all_links.push_back(l); + } else { + rna_click_chatter(FUNC_EXIT, + "[%s] RNAElement::control Found duplicate link\n", + instance_name()); + merge_link_information(l0, l); + }; + reply->set_success(); + } else { + reply->set_error("LinkState (data) is NULL!"); + reply->set_invalid(); + }; + handled_here = true; + } while (0); // To ensure that l is not visible outside.. + break; + + case RNAControlMsg::CONF_LINK_PROCESS: + do { + if (finish_configuration() >= 0) + reply->set_success(); + else + reply->set_failure(); + } while(0); + handled_here = true; + break; + default: + break; // Do nothing... + }; // CONFIGURE + break; + + case RNAControlMsg::DISCOVER: + switch(c->op){ + case RNAControlMsg::DISC_ELEMENT: + do { + DiscoverCmd *d = static_cast(c->get_data()); + if (d) { + switch(d->get_discover_type()){ + case DiscoverCmd::ELEMENT: + d->set_elem_type(type); + d->set_connection_oriented(connection_oriented); + d->print(); + // more stuff here about the element eventually.. + reply->set_data(d); + reply->set_success(); + break; + default: + reply->set_error("Unsupported command"); + reply->set_invalid(); + break; + }; + } else { + reply->set_error("Data is NULL"); + reply->set_invalid(); + } + } while(0); + handled_here = true; + break; + default: + break; + } + break; + + case RNAControlMsg::CONNECTION: + switch(c->op){ + case RNAControlMsg::CONN_OPEN: + do { + rna_click_chatter(FUNC_DEFAULT, + "[%s] connection_oriented = %s\n", + instance_name(), + (connection_oriented? "true":"false")); + if (connection_oriented) { + DiscoverCmd *d = new DiscoverCmd(); + if (conns.size() > 0) { + reply->set_success(); + d->set_conn(conns[0]); + } else { + if (open_connection()) { + reply->set_success(); + d->set_conn(conns[0]); + } else { + reply->set_error("Could not open connection state"); + }; + }; + reply->set_data(d); + } else { + reply->set_success(); + reply->set_data(NULL); + }; + + } while(0); + handled_here = true; + break; + + default: + break; + }; + break; + + default: + break;// Do nothing.. + }; // COMMAND + break; + + default: + break; + };// MESSAGETYPE + + // If this cannot be handled by the default handler, then call the + // module-specific handler. Notes for future: Module-specific + // handler may be called first instead. + if (!handled_here) { + delete reply; + reply = module_specific_control(c); + } + + if (debug) print_links(); + if (debug) reply->print(instance_name()); + if (debug) rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::control Exit \n", + this->instance_name()); + return reply; +}; + + +//############################################################ +// +// Lookup the outgoing links... +// +//############################################################ + +// +// Find the link that is to/from a specific port. +// + +LinkState * +RNAElement::lookup_link(int port, bool incoming){ + LinkState *link = NULL; + + for (int i = 0; i < all_links.size(); i++){ + LinkState *l = all_links[i]; + + if (((incoming && l->dir == LinkState::INCOMING) + || (!incoming && l->dir == LinkState::OUTGOING)) + && l->local_port == port) { + link = l; + break; + }; + }; + + if (!link) { + rna_click_chatter(FUNC_DEFAULT, + "[%s] %s::lookup_link(port = %d) failed\n", + class_name(), instance_name(), port); + if (debug) + print_links(); + }; + + return link; + +} + +// +// Find the link that is to/from a specific element, if any. +// + +LinkState * +RNAElement::lookup_link(RNAElement *e, bool incoming){ + LinkState *link = NULL; + + for (int i = 0; i < all_links.size(); i++){ + LinkState *l = all_links[i]; + + if (((incoming && l->dir == LinkState::INCOMING) + || (!incoming && l->dir == LinkState::OUTGOING)) + && l->e == e) { + link = l; + break; + }; + }; + + if (debug) { + if (!link) { + rna_click_chatter(FUNC_DEFAULT, + "[%s] %s::lookup_link(element = %d) failed\n", + class_name(), instance_name(), (int)e); + print_links(); + } else { + rna_click_chatter(FUNC_DEFAULT, + "[%s] %s::lookup_link(element = %d) successful\n", + class_name(), instance_name(), (int)e); + link->print(instance_name()); + } + }; + + return link; +} + + +// For each outgoing link, extract the connection state from the next +// layer and store it. +void +RNAElement::discover_connectionstate(LinkState *l){ + + if (!l) + return; + + if (!l->is_initialized()) + open_connection(l); + + if (!l->connection_oriented) + return; + +}; + + + +//############################################################ +// +// Initialize the link with connection state from the downstream +// element. Discover the type of the downstream link. +// +//############################################################ + +void +RNAElement::initialize_link(LinkState *l) { + + if (debug) + rna_click_chatter(FUNC_ENTRY,"[%s] initialize_link Entry\n", + instance_name()); + + do { + + if (!l) + break; + + if (debug) + click_chatter("[%s] RNAElement::initialize_link Looking at link \n", + instance_name()); + + if (l->is_initialized()) + break; + + l->print(instance_name()); + + Element *e = l->e; + if (!e) + break; + + const char * remote_class_name = e->class_name(); + + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::initialize_link remote node = %s !\n", + instance_name(), remote_class_name); + + if (strcmp(remote_class_name, "RNAElement") != 0){ + l->set_initialized(); + }; + + if (strcmp(remote_class_name, "RNAElement") == 0){ + + RNAElement *erna = (RNAElement *)e->cast("RNAElement"); + + if (debug) + rna_click_chatter(FUNC_DEFAULT, + "[%s] Calling RNA module Control interface %s \n", + instance_name(), erna->instance_name()); + + if (l->elemtype == UNKNOWN) { + // Discover + DiscoverCmd *d = new DiscoverCmd(DiscoverCmd::ELEMENT); + RNAControlMsg *ctl = new RNAControlMsg(RNAControlMsg::COMMAND, + RNAControlMsg::DISCOVER, + RNAControlMsg::DISC_ELEMENT, + d); + RNAControlMsg *reply = erna->control(ctl); + + // Obtain the discover reply.. + if ( ! reply || + reply->m != RNAControlMsg::REPLY || + reply->op != RNAControlMsg::REPL_SUCCESS){ + //l->set_initialized(); + l->print("Initialized Failed - Unknown element!"); + break; + }; + + DiscoverCmd *d1 = (DiscoverCmd *)reply->get_data(); + if (!d1){ + l->print("Initialized Failed!"); + break; + }; + + //Store somewhere... + d1->print(instance_name()); + l->elemtype = d1->get_elem_type(); + l->connection_oriented = d1->get_connection_oriented(); + + if (!l->connection_oriented){ + l->set_initialized(); + l->print("Initialized"); + }; + + // Cleanup + delete d; + delete reply; + }; + + if (l->elemtype != UNKNOWN && l->connection_oriented) { + // If connection oriented, then we have open the connection at + // the next layer? + + // connection data... + DiscoverCmd *d = new DiscoverCmd(DiscoverCmd::CONNECTION); + RNAControlMsg *ctl = new RNAControlMsg(RNAControlMsg::COMMAND, + RNAControlMsg::CONNECTION, + RNAControlMsg::CONN_OPEN, + d); + RNAControlMsg *reply = erna->control(ctl); + + // Obtain the discover reply.. + if ( ! reply || + reply->m != RNAControlMsg::REPLY || + reply->op != RNAControlMsg::REPL_SUCCESS){ + //l->set_initialized(); + l->print("Initialized Failed! Discovery failed"); + break; + }; + + //obtain the connection state from the next layer... + d = (DiscoverCmd *)reply->get_data(); + if (!d) { + //l->set_initialized(); + l->print("Initialized Failed! Reply data invalid"); + break; + }; + + l->connstate_set(d->get_conn()); + l->set_initialized(); + l->print("Initialized"); + break; + }; + + + }; // strcmd... + + } while(0); + + if (debug) + rna_click_chatter(FUNC_ENTRY,"[%s] initialize_link Exit\n", + instance_name()); + + return; + +}; + +//############################################################ +// +// Create the connection state +// +//############################################################ + +// If the incoming link is specified, then open connection +// to the endpoint of that link alone. If not open +// connections to all the next link layers. +bool +RNAElement::open_connection(LinkState *incoming_link) { + + + if (debug) + rna_click_chatter(FUNC_ENTRY,"[%s] open_connection Entry \n", + instance_name()); + + if (debug && incoming_link) + incoming_link->print("RNAElement::open_connection"); + + Vector downstream; + + if (! incoming_link) { + downstream = list_downstream_elements(true, // downstream + false, // layeragnostic + true, // crosslayer + true,// agnostic remote + false // remote is unknown + ); + } else { + if (incoming_link->is_outgoing() && + incoming_link->is_crosslayer() && + incoming_link->is_upstream() && + !incoming_link->is_remote_unknown()) { + downstream.push_back(incoming_link); + }; + }; + + if (debug) + rna_click_chatter(FUNC_ENTRY,"[%s] open_connection: Found %d downstream elements\n", + instance_name(), downstream.size()); + + for(int i = 0; i < downstream.size(); i++) { + LinkState *l = downstream[i]; + initialize_link(l); + }; + + if (debug) + rna_click_chatter(FUNC_EXIT,"[%s] open_connection Exit\n", + instance_name()); + + + return true; + +}; Index: rna/elements/rna/rnaelement_ctlmsg.cc diff -u /dev/null rna/elements/rna/rnaelement_ctlmsg.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_ctlmsg.cc Fri Jun 27 10:40:59 2008 @@ -0,0 +1,209 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "rnaelement_ctlmsg.hh" + + +RNAControlMsg::RNAControlMsg(MessageType m_in) : + m(m_in), o(UNKNOWN), op(NOP), data(0) { + // Do nothing... +} + +RNAControlMsg::RNAControlMsg(MessageType m_in, OperationType o_in, + Operation op_in, void *d_in): + m(m_in), o(o_in), op(op_in), data(d_in) { +} + +RNAControlMsg::RNAControlMsg(RNAControlMsg& c) { + m = c.m; + o = c.o; + op = c.op; + data = c.data; +}; + +RNAControlMsg::~RNAControlMsg(){ + // Do nothing... +}; + +void +RNAControlMsg::print(const char *s) { + + char *m_arr[] = { + QUOTE(NONE), + QUOTE(COMMAND), + QUOTE(REPLY), + QUOTE(LAST_MTYPE), + }; + + char *o_arr[] = { + QUOTE(UNKNOWN), + QUOTE(CONFIGURE), + QUOTE(CONNECTION), + QUOTE(MUX), + QUOTE(DISCOVER), + QUOTE(LAST_OPTYPE), + }; + + char *op_arr[] = { + QUOTE(NOP), + QUOTE(CONF_LINK_ADD), + QUOTE(CONF_LINK_DELETE), + QUOTE(CONF_LINK_PROCESS), + QUOTE(CONN_OPEN), + QUOTE(CONN_CLOSE), + QUOTE(DEMUX_PATTERN_ADD), + QUOTE(DEMUX_PATTERN_DEL), + QUOTE(MUX_PATTERN_ADD), + QUOTE(MUX_PATTERN_DEL), + QUOTE(DISC_ELEMENT), + QUOTE(REPL_INVALID), + QUOTE(REPL_SUCCESS), + QUOTE(REPL_FAILURE), + QUOTE(REPL_UNSUPPORTED), + QUOTE(LAST_OP), + }; + + if ((m >= NONE && m < LAST_MTYPE) && + (o >= UNKNOWN && o < LAST_OPTYPE) && + (op >= NOP && op < LAST_OP)) + click_chatter("[%s] Control Message %s %s %s %x error = %s\n", + (s ? s : ""), + m_arr[m], o_arr[o], op_arr[op], + (caddr_t)data, error.c_str()); + else + click_chatter("[CONTROL] Misconfigured message \n"); + + return; + +}; + +// Update the operation +int +RNAControlMsg::set_messagetype(MessageType m_in){ + if (m_in >= NONE && m_in < LAST_MTYPE){ + m = m_in; + return 0; + } else { + return -1; + } +}; + +// Update the operation +int +RNAControlMsg::set_operationtype(OperationType o_in){ + if (o_in >= UNKNOWN && o_in < LAST_OPTYPE){ + o = o_in; + return 0; + } else { + return -1; + } +}; + + +// Update the operation +int +RNAControlMsg::set_operation(Operation op_in){ + + if (op_in >= NOP && op_in < LAST_OP){ + op = op_in; + return 0; + } else { + return -1; + } +} + +void * +RNAControlMsg::get_data() { + return data; +}; + +int +RNAControlMsg::set_data(void *d_in){ + data = d_in; + return 0; +}; + + +// Some short cuts.... +void +RNAControlMsg::set_unsupported(){ + if (m == REPLY) + op = REPL_UNSUPPORTED; +}; + +// Some short cuts.... +void +RNAControlMsg::set_failure(){ + if (m = REPLY) + op = REPL_FAILURE; +}; + +// Some short cuts.... +void +RNAControlMsg::set_invalid(){ + if (m = REPLY) + op = REPL_INVALID; +}; + +// Some short cuts.... +void +RNAControlMsg::set_success(){ + if (m = REPLY) + op = REPL_SUCCESS; +}; + +// Store error message along with the error state... +void +RNAControlMsg::set_error(const char *s){ + error = s; +}; + +void +DiscoverCmd::set_conn_array(Vector conn_array_in){ + conn_array.clear(); + for(int i = 0; conn_array_in.size(); i++){ + conn_array.push_back(conn_array_in[i]); + }; +}; + +void +DiscoverCmd::set_elem_array(Vector elem_array_in){ + elem_array.clear(); + for(int i = 0; elem_array_in.size(); i++){ + elem_array.push_back(elem_array_in[i]); + }; +}; + +void +DiscoverCmd::print(const char *s) { + + char *m_arr[] = { + QUOTE(ELEMENT), + QUOTE(CONNECTION) + }; + + char *bool_arr[] = { + "FALSE", + "TRUE" + }; + + click_chatter("[%s] DiscoverCmd type = %s, type = %s " + "connoriented = %s", + (s ? s : ""), + m_arr[dtype], + str_elementtype[elemtype], + bool_arr[connection_oriented] + ); +}; + +CLICK_ENDDECLS +ELEMENT_PROVIDES(RNAControlMsg) Index: rna/elements/rna/rnaelement_ctlmsg.hh diff -u /dev/null rna/elements/rna/rnaelement_ctlmsg.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_ctlmsg.hh Fri Jun 27 10:40:59 2008 @@ -0,0 +1,144 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_RNACONTROLMSG_HH +#define CLICK_RNACONTROLMSG_HH + +class LinkState; + +#include "rnaelement.hh" + +#define QUOTE(EXP) #EXP + +class RNAControlMsg { + +public: + + enum MessageType { NONE, COMMAND, REPLY, LAST_MTYPE }; + enum OperationType { UNKNOWN, CONFIGURE, CONNECTION, + MUX, DISCOVER, NEGOTIATE, LAST_OPTYPE }; + enum Operation { + NOP, // NONE + CONF_LINK_ADD, CONF_LINK_DELETE, CONF_LINK_PROCESS, // Configure + CONN_OPEN, CONN_CLOSE, // Connection State + DEMUX_PATTERN_ADD, DEMUX_PATTERN_DEL, // Add/del matching patterns + MUX_PATTERN_ADD, MUX_PATTERN_DEL, // Add/del matching patterns + DISC_ELEMENT, // Discover what? + REPL_INVALID, REPL_SUCCESS, REPL_FAILURE,// Reply status + REPL_UNSUPPORTED, + LAST_OP, + }; + + MessageType m; + OperationType o; + Operation op; + String error; + void *data; + + // Constructor/Destructor.. + RNAControlMsg(MessageType m_in); + RNAControlMsg(MessageType m_in, OperationType o_in, + Operation op_in, void *d_in = NULL); + RNAControlMsg(RNAControlMsg& c); + ~RNAControlMsg(); + + // + void print(const char *s = NULL); + int set_messagetype(MessageType m_in); + int set_operationtype(OperationType o_in); + int set_operation(Operation op_in); + + // Set/get the data + void *get_data(); + int set_data(void *d_in); + + // + void set_error(const char *s); + + // Some short cuts.... + void set_unsupported(); + void set_failure(); + void set_invalid(); + void set_success(); + +}; + + + +class DiscoverCmd { +public: + enum DiscoverType { ELEMENT, CONNECTION }; + + // Discover what? + DiscoverType dtype; + + // About this element + RNAElementType elemtype; + bool connection_oriented; + + // About the connections... + ConnectionState *conn; + Vector conn_array; + Vector elem_array; + + DiscoverCmd(DiscoverType t): dtype(t), elemtype(UNKNOWN), + connection_oriented(false), conn(0) {}; + + DiscoverCmd(): dtype(ELEMENT), elemtype(UNKNOWN), conn(0) {}; + ~DiscoverCmd() {}; + + ConnectionState *get_conn() { return conn; }; + void set_conn(ConnectionState *conn_in) { conn = conn_in; return; }; + + DiscoverType get_discover_type() { return dtype; }; + void set_discover_type(DiscoverType t) { dtype = t; return; }; + + bool get_connection_oriented() { return connection_oriented; } + void set_connection_oriented(bool v) { connection_oriented = v; }; + + RNAElementType get_elem_type() { return elemtype; }; + void set_elem_type(RNAElementType t) { elemtype = t; }; + + + void set_conn_array(Vector conn_array_in); + void set_elem_array(Vector elem_array_in); + + void print(const char *s = NULL); + +}; + + +class MuxDemuxCmd { +public: + const char *pattern; + int len; + RNAElement *e; + LinkState *l; + MuxDemuxCmd () {} + void print(char *s = NULL){ + click_chatter("[MuxDemuxCmd] %s pattern = %s, e = %x \n", + (s? s : ""), pattern, e); + return; + } +}; + +class NegotiateCmd { +public: + Vector *_elemlist; + String _initpattern; + NegotiateCmd(Vector *elemlist, String initpattern) { + _elemlist = elemlist; + _initpattern = initpattern; + }; + +}; +CLICK_ENDDECLS +#endif Index: rna/elements/rna/rnaelement_error.cc diff -u /dev/null rna/elements/rna/rnaelement_error.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_error.cc Fri Jun 27 10:40:59 2008 @@ -0,0 +1,33 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "rnaelement_common.hh" +#include "rnaelement_error.hh" + +void +rna_click_chatter(ErrorClass x, const char *fmt, ...) +{ + (void)x; + + va_list ap; + va_start(ap, fmt); +#ifdef COMMENT + click_chatter(fmt, ap); +#endif + vfprintf(stderr, fmt, ap); + va_end(ap); + +} + + +CLICK_ENDDECLS +ELEMENT_PROVIDES(RNAError) Index: rna/elements/rna/rnaelement_error.hh diff -u /dev/null rna/elements/rna/rnaelement_error.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_error.hh Fri Jun 27 10:40:59 2008 @@ -0,0 +1,30 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_RNAERROR_HH +#define CLICK_RNAERROR_HH + +#include "rnaelement_common.hh" + +enum ErrorClass { + FUNC_ENTRY, + FUNC_EXIT, + FUNC_DEFAULT, + MESSAGE, + MYDATA, + ERROR, +}; + +void +rna_click_chatter(ErrorClass x, const char *fmt, ...); + +CLICK_ENDDECLS +#endif Index: rna/elements/rna/rnaelement_handlers.cc diff -u /dev/null rna/elements/rna/rnaelement_handlers.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_handlers.cc Fri Jun 27 10:40:59 2008 @@ -0,0 +1,92 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +//============================================================== +// +// Allow processing of element names as argument to the element +// +//============================================================== +void +RNAElement::static_initialize_default() +{ + + //rna_click_chatter(FUNC_DEFAULT,"RNAElement::static_initialize()\n"); + + cp_register_argtype("ELEMENTS", + "list of elements", + cpArgNormal, + elementlist_parse, + elementlist_store, + 0); + +}; + +void +RNAElement::static_cleanup_default() +{ + + rna_click_chatter(FUNC_DEFAULT,"RNAElement::static_cleanup()\n"); + cp_unregister_argtype("ELEMENTS"); +} + +int +RNAElement::rna_write_handler(const String &conf, Element *e, + void *vparam, ErrorHandler *errh) +{ + (void)vparam; + (void)errh; + + RNAElement *erna = (RNAElement *)(e->cast("RNAElement")); + + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::rna_write_handler String = %s \n", + erna->instance_name(), + conf.printable().c_str()); + + return 1; +} + +String +RNAElement::rna_read_handler(Element *e, void *thunk) +{ + (void)thunk; + + RNAElement *erna = (RNAElement *)(e->cast("RNAElement")); + + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::rna_read_handler String = %s \n", + erna->instance_name(), + erna->instance_name()); + + return String(erna->instance_name()); + +} + +void +RNAElement::add_handlers() +{ + //rna_click_chatter(FUNC_DEFAULT,"RNAElement::add_handlers()\n"); + add_read_handler("control", rna_read_handler, (void *)0); + add_write_handler("control", rna_write_handler, (void *)0); +} + + +void * +RNAElement::cast(const char *n) +{ + if (strcmp(n, "RNAElement") == 0) + return (RNAElement *) this; + else + return 0; +} + + Index: rna/elements/rna/rnaelement_links.cc diff -u /dev/null rna/elements/rna/rnaelement_links.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_links.cc Fri Jun 27 10:40:59 2008 @@ -0,0 +1,578 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +//############################################################### +// +// Link information processing - check, merge, print etc. +// Misc functions. +// +//############################################################### + + +// Delete only if the linkcmd pointer points to a legitimate link. +int RNAElement::delete_link(LinkState *l){ + + int match = -1; + + if (!l) + return match; + + for (int i = 0; i < all_links.size(); i++){ + LinkState *l0 = all_links[i]; + if (l0 == l) { + match = i; + break; + }; + }; + + if (match < 0) + return -1; + + all_links[match] = all_links.back(); + all_links.pop_back(); + + return 0; +} + +LinkState * +RNAElement::check_for_duplicate_link(LinkState *l){ + + LinkState *match = NULL; + + if (!l) + return match; + + for (int i = 0; i < all_links.size(); i++){ + LinkState *l0 = all_links[i]; + if (l0->minimal_match(l)){ + match = l0; + break; + }; + }; + + return match; +} + +void +RNAElement::merge_link_information(LinkState *existing_link, LinkState *newlink){ + + // Update only the element information + if ( !existing_link || !newlink) + return; + + // Only the remote element and port are updated and that + // only when the local information is UNKNOWN + if (existing_link->is_remote_unknown()) { + existing_link->remote_port = newlink->remote_port; + existing_link->e = newlink->e; + }; + + return; +}; + + +//############################################################### +// +// Print the link information for this/all element(s). These functions +// go through each type of link and prints them - incoming/outgoing +// and intra/cross layer. +// +//############################################################### +void +RNAElement::print_links(){ + + if (0) rna_click_chatter(FUNC_ENTRY, + "[%s] RNAElement::print_links Enter\n", + instance_name()); + + for (int j = 0; j < 4; j++) { + + for (int i = 0; i < all_links.size(); i++){ + LinkState *l = all_links[i]; + + switch(j){ + case 0: + if (l->is_downstream() && l->dir == LinkState::INCOMING ) + l->print(instance_name()); + break; + case 1: + if (!l->is_downstream() && l->dir == LinkState::INCOMING ) + l->print(instance_name()); + break; + case 2: + if (l->is_downstream() && l->dir == LinkState::OUTGOING ) + l->print(instance_name()); + break; + case 3: + if (!l->is_downstream() && l->dir == LinkState::OUTGOING ) + l->print(instance_name()); + break; + default: + break; + }; + }; + + }; + + if (0) rna_click_chatter(FUNC_EXIT, + "[%s] RNAElement::print_links Exit \n", + instance_name()); + +}; + +void +RNAElement::print_allelements_links(){ + + rna_click_chatter(FUNC_ENTRY, + "[%s] RNAElement::print_allelements_links Enter\n", + instance_name()); + + // List all the possible elements; + Vector allelements = router()->elements(); + + // For each element look through all the outputs... + for (int i = 0; i < allelements.size(); i++){ + Element *e = allelements[i]; + if (strcmp(e->class_name(), "RNAElement") == 0){ + RNAElement *e1 = static_cast(e->cast("RNAElement")); + e1->print_links(); + }; + }; + + rna_click_chatter(FUNC_EXIT, + "[%s] RNAElement::print_allelement_links Exit \n", + instance_name()); + +}; + + +//############################################################### +// +// Process link information during configuration phase. +// +// Look at all the links going in and out of the element and add them +// +// This function is supposed to autodetect the links including +// crosslayer functionality and upstream/downstream-ness. This is +// right now incomplete. The upstream/downstream is not handled right +// now. The cross layer is not detected either. +// +//############################################################### + +int +RNAElement::add_default_autodetect_links(Vector *links, + bool crosslayer){ + + struct linkspec *link; + + if (_preconfigured_element_list) { + + click_chatter("[%s] RNAElement::add_default_autodetect_links - " + "Found preconf element list \n", + instance_name()); + + + // Take care of incoming links from upstream nodes... + for(int i = 0; i < _upstream_element_list.size(); i++){ + Element *upstream_e = _upstream_element_list[i]; + for (int p = 0; p < upstream_e->noutputs(); p++){ + if (upstream_e->output(p).element() == this){ + + link = new linkspec; + link->local_elem = upstream_e->eindex(); + link->local_out = p; + link->remote_elem = this->eindex(); + link->remote_in = upstream_e->output(p).port(); + link->local_is_upstream = true; + link->crosslayer = crosslayer; + links->push_back(link); + }; + }; + }; + + // Take care of incoming links from downstream nodes.. + for(int i = 0; i < _downstream_element_list.size(); i++){ + Element *downstream_e = _downstream_element_list[i]; + for (int p = 0; p < downstream_e->noutputs(); p++){ + if (downstream_e->output(p).element() == this){ + + link = new linkspec; + link->local_elem = downstream_e->eindex(); + link->local_out = p; + link->remote_elem = this->eindex(); + link->remote_in = downstream_e->output(p).port(); + link->local_is_upstream = false; + link->crosslayer = crosslayer; + links->push_back(link); + }; + }; + }; + + + // Take care of outgoing links... + for (int j = 0; j < noutputs(); j++){ + + link = new linkspec; + link->local_elem = this->eindex(); + link->local_out = j; + + Element *remote_e = output(j).element(); + if (remote_e) { + link->remote_elem = remote_e->eindex(); + link->remote_in = output(j).port(); + } else { + link->remote_elem = -1; + link->remote_in = -1; + }; + + if (!remote_e) + click_chatter("[%s] remote_e is NULL \n", instance_name()); + + // XXX How do I know which is upstream? + // link->local_is_upstream = true; + + for (int j = 0; j < _upstream_element_list.size(); j++){ + if (_upstream_element_list[j] == remote_e) { + link->local_is_upstream = false; + break; + }; + }; + + for (int j = 0; j < _downstream_element_list.size(); j++){ + if (_downstream_element_list[j] == remote_e) { + link->local_is_upstream = true; + break; + }; + }; + + + link->crosslayer = crosslayer; + links->push_back(link); + }; + + } else { + + // Could be wrong! Needs to be checked. + bool crosslayer = true; + + for (int i = 0; i < ninputs(); i++){ + link = new linkspec; + + //link->local_elem = -1; + //link->local_out = -1; + Element *local_e = input(i).element(); + if (local_e) { + link->local_elem = local_e->eindex(); + link->local_out = input(i).port(); + } else { + link->local_elem = -1; + link->local_out = -1; + }; + link->remote_elem = this->eindex(); + link->remote_in = i; + + // XXX How do I know which is upstream? + link->local_is_upstream = true; + link->crosslayer = crosslayer; + links->push_back(link); + + }; + + for (int j = 0; j < noutputs(); j++){ + + link = new linkspec; + link->local_elem = this->eindex(); + link->local_out = j; + + Element *remote_e = output(j).element(); + if (remote_e) { + link->remote_elem = remote_e->eindex(); + link->remote_in = output(j).port(); + } else { + link->remote_elem = -1; + link->remote_in = -1; + }; + + // XXX How do I know which is upstream? + link->local_is_upstream = true; + link->crosslayer = crosslayer; + links->push_back(link); + }; + }; + + + return 0; + +}; +//############################################################### +// +// Process link information during configuration phase. +// +// WAIT!!!! +// This function makes assumptions about the specific links being added +// and their port numbers. So use this function with caution.. +// +//############################################################### + +int +RNAElement::add_default_bidirectional_links(Vector *links, + bool crosslayer){ + + + struct linkspec *link; + + //================================================= + // All other non-RNAElement connections + // These are fixed and known ahead of time... + //src -> [0] r1 [1] -> [0] l + // l[0] -> Print -> [1] r1 [0] -> Discard + + //============================= + + // src -> r1 [0] + link = new linkspec; + + //link->local_elem = -1; + //link->local_out = -1; + Element *local_e = input(0).element(); + if (local_e) { + link->local_elem = local_e->eindex(); + link->local_out = input(0).port(); + } else { + link->local_elem = -1; + link->local_out = -1; + }; + link->remote_elem = this->eindex(); + link->remote_in = 0; + link->local_is_upstream = true; + link->crosslayer = crosslayer; + links->push_back(link); + + //============================= + + // r1 [1] -> [0]l + link = new linkspec; + link->local_elem = this->eindex(); + link->local_out = 1; + + Element *remote_e = output(1).element(); + if (remote_e) { + link->remote_elem = remote_e->eindex(); + link->remote_in = output(1).port(); + } else { + link->remote_elem = -1; + link->remote_in = -1; + }; + + link->local_is_upstream = true; + link->crosslayer = crosslayer; + links->push_back(link); + + //============================= + + // Print -> [1] r1 + link = new linkspec; + + //link->local_elem = -1; + //link->local_out = -1; + local_e = input(1).element(); + if (local_e) { + link->local_elem = local_e->eindex(); + link->local_out = input(1).port(); + } else { + link->local_elem = -1; + link->local_out = -1; + }; + link->remote_elem = this->eindex(); + link->remote_in = 1; + link->local_is_upstream = false; + link->crosslayer = crosslayer; + links->push_back(link); + + //============================= + + // r1 [0] -> Discard + link = new linkspec; + link->local_elem = this->eindex(); + link->local_out = 0; + + remote_e = output(0).element(); + if (remote_e) { + link->remote_elem = remote_e->eindex(); + link->remote_in = output(0).port(); + } else { + link->remote_elem = -1; + link->remote_in = -1; + }; + + link->local_is_upstream = false; + link->crosslayer = crosslayer; + links->push_back(link); + + return 0; + +} + +//############################################################### +// +// WAIT!!!! +// This function makes assumptions about the specific links being added +// and their port numbers. So use this function with caution.. +// +//############################################################### + +int +RNAElement::add_default_unidirectional_links(Vector *links, + bool crosslayer){ + + struct linkspec *link; + + //================================================= + // All other non-RNAElement connections + // These are fixed and known ahead of time... + //src -> [0] r1 [0] -> dst + + // src -> Ctl [0] + link = new linkspec; + link->local_elem = -1; + link->local_out = -1; + link->remote_elem = this->eindex(); + link->remote_in = 0; + link->local_is_upstream = true; + link->crosslayer = crosslayer; + links->push_back(link); + + // Ctl [0] -> Discard + link = new linkspec; + link->local_elem = this->eindex(); + link->local_out = 0; + + Element *remote_e = output(0).element(); + if (remote_e) { + link->remote_elem = remote_e->eindex(); + link->remote_in = output(0).port(); + } else { + link->remote_elem = -1; + link->remote_in = -1; + }; + + link->local_is_upstream = true; + link->crosslayer = crosslayer; + links->push_back(link); + + return 0; + +} + + +//############################################################### +// +// Macro processors for adding links +// +//############################################################### + +int RNAElement::process_linkspecs(Vector &linkspecs){ + + rna_click_chatter(FUNC_ENTRY, + "[%s] RNAElement::process_linkspecs \n", + instance_name()); + + Router *r = router(); + for (int i = 0; i < linkspecs.size(); i++){ + + struct linkspec *l = linkspecs[i]; + + // Initialize...the elements and the link command structures... + RNAElement *e0 = NULL, *e1 = NULL; + l->l0 = l->l1 = 0; + + if (l->local_elem >= 0) + e0 = (RNAElement *) + ((r->element(l->local_elem))->cast("RNAElement")); + + if (l->remote_elem >= 0) + e1 = (RNAElement *) + ((r->element(l->remote_elem))->cast("RNAElement")); + + // Add this link only if both the end points are defined. + // Pre-existing links are just accounted for in the all_links + // structure and not added. + if (l->local_elem >= 0 && l->remote_elem >= 0) { + int retval = r->add_connection(l->local_elem, + l->local_out, + l->remote_elem, + l->remote_in); + + rna_click_chatter(FUNC_DEFAULT, + "[%s] Add_connection [retval = %d]:\t%s[%d,%d, %s]\t->" + "\t[%d,%d,%s]%s \n", + instance_name(), + retval, (e0? e0->instance_name(): "UNKNOWN"), + l->local_elem, l->local_out, + (l->local_is_upstream? "UPSTREAM" : "DOWNSTREAM"), + l->remote_elem, l->remote_in, + (l->local_is_upstream? "DOWNSTREAM" : "UPSTREAM"), + (e1 ? e1->instance_name() : "UNKNOWN")); + }; + + // e0 --> e1. if e0 is upstream node, then local_is_upstream will + // be set. + + // Tell e0 that this is an outgoing link to e1. + if (e0) { + LinkState *l0 = new LinkState(true, // outgoing + l->local_is_upstream, + l->local_out, + l->remote_in, + l->crosslayer, + e1); + RNAControlMsg c(RNAControlMsg::COMMAND, + RNAControlMsg::CONFIGURE, + RNAControlMsg::CONF_LINK_ADD, + l0); + e0->control(&c); + + // Return the linkcmd created... + l->l0 = l0; + }; + + // Tell e1 that this is an incoming link from e0 + if (e1) { + LinkState *l1 = new LinkState(false, // incoming + !l->local_is_upstream, + l->remote_in, + l->local_out, + l->crosslayer, + e0); + RNAControlMsg c(RNAControlMsg::COMMAND, + RNAControlMsg::CONFIGURE, + RNAControlMsg::CONF_LINK_ADD, + l1); + + e1->control(&c); + + // Return the linkcmd created... + l->l1 = l1; + + }; + + }; + + // Commit the changes + int retval = r->update_connections(); + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::process_linkspecs updated connections: " + "retval = %d \n", + instance_name(), retval); + + return 0; +}; Index: rna/elements/rna/rnaelement_linkstate.cc diff -u /dev/null rna/elements/rna/rnaelement_linkstate.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_linkstate.cc Fri Jun 27 10:40:59 2008 @@ -0,0 +1,232 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +#include "rnaelement_linkstate.hh" + +//############################################################ +// +// Constructor and destructor...of LinkState... +// +//############################################################ + +// +// Instantiate an empty link. This is not used in general. +// +LinkState::LinkState() { + + dir = NODIR; + type = NOTYPE; + local_port = -1; + remote_port = -1; + crosslayer = true; + e = 0; + ltype = LINK_TYPE_DATA; + initialized = false; + connection_oriented = false; + elemtype = UNKNOWN; + conns.clear(); + initialized = true; + +}; + +// +// Instantiate a link with all the information. We dont however +// instantiate the connection state from the next layer. That is +// obtained explicitly through the open_connection() function. +// +LinkState::LinkState (bool outgoing, + bool upstream, + int local_port_in, + int remote_port_in, + bool crosslayer_in, + RNAElement *e_in, + bool control){ + + dir = outgoing? OUTGOING : INCOMING; + type = upstream ? UPSTREAM : DOWNSTREAM; + local_port = local_port_in; + remote_port = remote_port_in; + crosslayer = crosslayer_in; + e = e_in; + ltype = (control? LINK_TYPE_CONTROL: LINK_TYPE_DATA); + initialized = false; + connection_oriented = false; + elemtype = UNKNOWN; + conns.clear(); + + if (!e) + initialized = true; + else + initialized = false; + +}; + +// +// Make a copy of the state of the link. +// + +LinkState::LinkState (LinkState &l) { + dir = l.dir; + type = l.type; + remote_port = l.remote_port; + local_port = l.local_port; + crosslayer = l.crosslayer; + e = l.e; + initialized = l.initialized; + connection_oriented = l.connection_oriented; + elemtype = l.elemtype; + conns = l.conns; +}; + +// +// Cleanup including the connection state. This simply updates the +// local state. There is change in the state stored in the router +// itself. +// +LinkState::~LinkState() { + // Do nothing... +}; + + +// +// User-readable message +// +void +LinkState::print(const char *s) { + + rna_click_chatter(MYDATA, "[LINK] <<%s, %s, %s link, %s >> " + "[%s local, %d port] %s [%s remote, %d port]]\n", + (initialized? "INIT=YES" : "INIT=NO "), + (dir == LinkState::INCOMING? "INCOMING" : "OUTGOING"), + (crosslayer ? "cross-layer" : "intra-layer"), + (type == LinkState::UPSTREAM? + ((dir == LinkState::INCOMING)? + "From DOWNSTREAM" : "To DOWNSTREAM"): + ((dir == LinkState::INCOMING)? + "From UPSTREAM " : "To UPSTREAM ")), + (s ? s : "-"), + local_port, + ((dir == LinkState::INCOMING)? "<-" : "->"), + (e ? e->instance_name(): "UNKNOWN"), + remote_port + ); +}; + +// +// This is useful while creating links to see if there is a duplicate +// link. +// +bool +LinkState::minimal_match(LinkState *incoming) { + + if (!incoming) + return false; + + if ((is_outgoing() == incoming->is_outgoing()) && + (local_port == incoming->local_port)){ + return true; + }; + + return false; +}; + + +//############################################################ +// +// Connection state management. Each link is associated with a set of +// connection state structures, one which is used during message +// delivery. +// +//############################################################ + +// +// Add the connecton state if it does not already exist. +// +int +LinkState::connstate_add(ConnectionState *c) { + for (int i = 0; i < conns.size(); i++) + if (conns[i] == c) + return 0; + + conns.push_back(c); + return 0; +} + +// +// Delete a connection state if it exists.. +// +int +LinkState::connstate_del(ConnectionState *c) { + + Vector modified; + + for (int i = 0; i < conns.size(); i++) + if (conns[i] != c) + modified.push_back(conns[i]); + + if (conns.size() == modified.size()) + return -1; + + conns.swap(modified); + + return 0; +} + +// +// Store the connection state - an array +// +int +LinkState::connstate_set(Vector &conns_in) { + + conns.clear(); + for (int i = 0; i < conns_in.size(); i++) + conns.push_back(conns_in[i]); + + return 0; +} + +// +// Store the connection state - an instance +// +int +LinkState::connstate_set(ConnectionState * c) { + + conns.clear(); + conns.push_back(c); + return 0; +} + + +// +// Return the first instance of the connection state +// +ConnectionState * +LinkState::connstate_get() { + if (conns.size() > 0 ) { + return conns[0]; + } else { + return NULL; + }; +} + +// +// Return the connection state array... +// +Vector +LinkState::connstate_getall() { + return conns; +} + + +ELEMENT_PROVIDES(LinkState) + +CLICK_ENDDECLS Index: rna/elements/rna/rnaelement_linkstate.hh diff -u /dev/null rna/elements/rna/rnaelement_linkstate.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_linkstate.hh Fri Jun 27 10:40:59 2008 @@ -0,0 +1,106 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +#ifndef CLICK_LINKINFO_HH +#define CLICK_LINKINFO_HH + +#include "rnaelement.hh" +#include "rnaelement_error.hh" +#include "rnaelement_connstate.hh" +#include "rnaelement_ctlmsg.hh" + +//#################################################################### +// Each RNAElement, including the metaprotocol, maintains a list of links +// to other elements. This is necessary to determine how to route a given +// packet. This LinkState is a datastructure that is created upon addition +// of a link or during initialization process. The datastructure +// maintains information about +// +// * ports - the local and remote ports, +// * element - a pointer to the element structure +// * direction - the direction of traffic flow because Click links are +// unidirectional (they flow from the output port of a given element to +// the input port of another element), +// * optional linktype - which tells whether the link from the module +// goes to the metaprotocol element or another data processing element. +// * Whether the next layer is connection-oriented or not and if yes, +// whether the connection state has been obtained or not +// * Exported connection state from the next layer. Ideally this should +// be per-connection and not per-link. May be this should be an array. +// +//####################################################################### + +class RNAElement; + +// control operation is config +class LinkState { +public: + enum LinkType { LINK_TYPE_CONTROL, LINK_TYPE_DATA }; + enum LinkDir { NODIR, INCOMING, OUTGOING }; + enum MyNodeType { NOTYPE, UPSTREAM, DOWNSTREAM }; + + // How does this module relate to other modules. + LinkDir dir; + MyNodeType type; + int local_port; + int remote_port; + bool crosslayer; + RNAElement *e; + LinkType ltype; + + // Each outgoing link may be associated with multiple + // connection states... + bool initialized; // obtained the connection state? + bool connection_oriented; + RNAElementType elemtype; + Vector conns; + + // Constructor/destructor... + LinkState(); + LinkState (bool outgoing, bool upstream, int local_port_in, int remote_port_in = -1, + bool crosslayer_in = true, RNAElement *e_in = 0, bool control = false); + LinkState (LinkState &l); + ~LinkState(); + + // Am I downstream to the node from which the message + // is coming? + bool is_downstream() { return (type == DOWNSTREAM); } + bool is_upstream() { return (type == UPSTREAM); } + + // What is the direction? + bool is_outgoing() { return (dir == OUTGOING); } + bool is_incoming() { return (dir == INCOMING); } + + // Get/set the connection state associated with the next layer... + int connstate_add(ConnectionState *c); + int connstate_del(ConnectionState *c); + int connstate_set(Vector &conns); + int connstate_set(ConnectionState *c); + ConnectionState *connstate_get(); + Vector connstate_getall(); + + // Is this cross-layer? + bool is_crosslayer() { return crosslayer; }; + bool is_remote_unknown() { return (!e); } + + // initialization routines... + bool is_initialized() { return initialized; }; + void set_initialized() { initialized = true; return; } + + // minimal match + bool minimal_match(LinkState *incoming); + + // Debug .. + void print(const char *s = NULL); + +}; + +#endif Index: rna/elements/rna/rnaelement_messages.cc diff -u /dev/null rna/elements/rna/rnaelement_messages.cc:1.2 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_messages.cc Mon Jun 30 12:43:20 2008 @@ -0,0 +1,823 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +//######################################################### +// +// Misc functions... +// +//#########################################################// + + +// Copied from element/standard/Print.cc + +void +RNAElement::print_packet(String label, Packet *p, bool print_annotation){ + + int _bytes = ((p->length() > MAX_PRINT_PKT) ? MAX_PRINT_PKT : p->length()); + + StringAccum sa(instance.length() + 3 + + label.length() + 2 // label: + + 9 // length | + + Packet::USER_ANNO_SIZE*2 + 3 // annotations | + + 2 * _bytes); + + if (sa.out_of_memory()) { + click_chatter("no memory for Print"); + return; + } + + sa << "[" << instance << "] "; + + sa << label; + if (label) + sa << ": "; + + // sa.reserve() must return non-null; we checked capacity above + int len; + len = sprintf(sa.reserve(9), "%4d | ", p->length()); + sa.forward(len); + + if (print_annotation) { + char *buf = sa.reserve(Packet::USER_ANNO_SIZE*2); + int pos = 0; + for (unsigned j = 0; j < Packet::USER_ANNO_SIZE; j++, pos += 2) + sprintf(buf + pos, "%02x", p->user_anno_c(j)); + sa.forward(pos); + + len = sprintf(sa.reserve(3), " | "); + sa.forward(len); + } + + char *buf = sa.data() + sa.length(); + int pos = 0; + + for (unsigned i = 0; i < p->length(); i++) { + sprintf(buf + pos, "%02x", p->data()[i] & 0xff); + pos += 2; + if ((i % 4) == 3) buf[pos++] = ' '; + } + sa.forward(pos); + + click_chatter("%s", sa.c_str()); + + return; + +}; + + +//######################################################### +// +// Identify outgoing link for a given message +// upstream/downstream messages. +// +//######################################################### + +int +RNAElement::count_outgoing_links(Packet *p, LinkState *incoming, + bool downstream, + bool layeragnostic, + bool crosslayer, + bool agnostic_remote, + bool remote_unknown, + ConnectionState *required){ + + //rna_click_chatter(FUNC_DEFAULT, + // "[%s] RNAElement::count_outgoing_links\n", + // instance_name()); + + int count = 0; + (void)p; + (void)incoming; + + if (0) print_links(); + + if (required){ + + // Right now this function only knows about this type of + // connection state. but can be expanded later on... + LinkState *l = (LinkState *)required->get_data(VAR_LINKINFO); + if (l && + l->is_outgoing() // ignore incoming links + && ((layeragnostic) || + (!layeragnostic && (l->is_crosslayer() == crosslayer))) // + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (! agnostic_remote && (l->is_remote_unknown() == remote_unknown))) + ) { + count++; + }; + + } else { + + for (int i = 0; i < all_links.size(); i++){ + LinkState *l = all_links[i]; + + // Find a link in which I am an downstream node and + // the link is outgoing... + if (l->is_outgoing() // ignore incoming links + && ((layeragnostic) || + (!layeragnostic && (l->is_crosslayer() == crosslayer))) // + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (! agnostic_remote && (l->is_remote_unknown() == remote_unknown))) + ) { + count++; + }; + }; + }; + + return count; +}; + +// Look for an outgoing link that is headed towards downstream (or +// upstream) and crosslayer (or not). +// This could be potentially replaced by a specific module whether control +// or data module. There could be a map between the cross-layer links +// and intra-layer links for multiplexing modules. +// +// agnostic_remote = do I care about whether the remote endpoint is +// known or not? +// remote_known = if I care, do I care that it IS unknown or NOT? +// +LinkState * +RNAElement::select_outgoing_link(Packet *p, + LinkState *incoming, + bool downstream, + bool layeragnostic, + bool crosslayer, + bool agnostic_remote, + bool remote_unknown, + ConnectionState *required){ + + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::select_outgoing_link " + "(%s, %s, %s, %s, %s, %s)\n", + instance_name(), + (downstream? "downstream" : "upstream"), + (layeragnostic? "layer agnostic": "layer sensitive"), + (crosslayer? "crosslayer": "intra-layer"), + (agnostic_remote? "agnostic remote": "sensitive remote"), + (remote_unknown? "remote unknown" : "remote known"), + (required? "conn state required" : "conn state not required") + ); + + (void)p; + (void)incoming; + + if (0) print_links(); + + if (required){ + + // Right now this function only knows about this type of + // connection state. but can be expanded later on... + LinkState *l = (LinkState *)required->get_data(VAR_LINKINFO); + if (l && + l->is_outgoing() // ignore incoming links + && ((layeragnostic) || + (!layeragnostic && (l->is_crosslayer() == crosslayer))) // + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (! agnostic_remote && (l->is_remote_unknown() == remote_unknown))) + ) { + //l->print("Selected this link"); + return l; + }; + } else { + + for (int i = 0; i < all_links.size(); i++){ + LinkState *l = all_links[i]; + + // Find a link in which I am an downstream node and + // the link is outgoing... + if (l->is_outgoing() // ignore incoming links + && ((layeragnostic) || + (!layeragnostic && (l->is_crosslayer() == crosslayer))) // + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (! agnostic_remote && (l->is_remote_unknown() == remote_unknown))) + ) { + //l->print("Selected this link"); + return l; + }; + }; + }; + + return NULL; +}; + + +Vector +RNAElement::list_outgoing_link(Packet *p, + LinkState *incoming, + bool downstream, + bool layeragnostic, + bool crosslayer, + bool agnostic_remote, + bool remote_unknown, + ConnectionState *required){ + + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::list_outgoing_link\n", + instance_name()); + + (void)p; + (void)incoming; + Vector link_list; + + if (0) print_links(); + + if (required){ + + // Right now this function only knows about this type of + // connection state. but can be expanded later on... + LinkState *l = (LinkState *)required->get_data(VAR_LINKINFO); + // the link is outgoing... + if (l && + l->is_outgoing() // ignore incoming links + && ((layeragnostic) || + (!layeragnostic && (l->is_crosslayer() == crosslayer))) // + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (! agnostic_remote && (l->is_remote_unknown() == remote_unknown))) + ) { + link_list.push_back(l); + //l->print("Selected this link"); + }; + } else { + + for (int i = 0; i < all_links.size(); i++){ + LinkState *l = all_links[i]; + + // Find a link in which I am an downstream node and + // the link is outgoing... + if (l->is_outgoing() // ignore incoming links + && ((layeragnostic) || + (!layeragnostic && (l->is_crosslayer() == crosslayer))) // + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (! agnostic_remote && (l->is_remote_unknown() == remote_unknown))) + ) { + link_list.push_back(l); + //l->print("Selected this link"); + }; + }; + }; + + return link_list; +}; + + +//######################################################### +// +// Pre-processing messages from incoming/outgoing to +// upstream/downstream messages. +// +//######################################################### + +// Default data path processing.... +void +RNAElement::process_incoming_from_downstream(Packet **p_in, + LinkState *incoming, + MessageStatus *status){ + // Do nothing... + (void)p_in; + (void)incoming; + (void)status; +} + +void +RNAElement::process_outgoing_to_downstream(Packet **p_in, + LinkState *outgoing, + MessageStatus *status){ + // Do nothing + (void)outgoing; + (void)status; + (void) p_in; + + if (0) + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::process_outgoing_to_downstream " + "Adding byte\n", instance_name()); + + // Write out a control/data one byte header... + // WritablePacket *p = (*p_in)->push(1); + // char *data = reinterpret_cast(p->data()); + // *data = MESSAGE_DATA; + // *p_in = p; + +} + +void +RNAElement::process_incoming_from_upstream(Packet **p_in, + LinkState *incoming, + MessageStatus *status){ + // Do nothing + (void)p_in; + (void)incoming; + (void)status; +} + +void +RNAElement::process_outgoing_to_upstream(Packet **p_in, + LinkState *outgoing, + MessageStatus *status){ + // Do nothing + (void)p_in; + (void)outgoing; + (void)status; +} + + +// +// Check if the state is correct +// +bool +RNAElement::check_connectionstate(LinkState *incoming_link, Packet *p_in){ + + if (0) + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::check_connectionstate \n", + instance_name()); + + if (!incoming_link || !p_in) + return false; + + // XXX To be filled later. Skip if I am upstream + if (incoming_link->is_upstream()) + return true; + + // Nothing to check if this is not connection oriented... + if (!connection_oriented) + return true; + + ConnectionState *c = GET_CONN_ANNO(p_in); + + if (!c) + return false; + + for (int i = 0; i < conns.size(); i++) + if (c == conns[i]) + return true; + + return false; + +}; + + +//######################################################### +// +// Handle a message on the data path.... +// +//######################################################### + +// Where should I send it next? +void +RNAElement::push_data(int port, Packet *p_in) +{ + + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::push_data(port = %d)\n", + instance_name(), port); + + LinkState *incoming_link = lookup_link(port); + if (! incoming_link ){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] Dropping packet...\n", + instance_name()); + p_in->kill(); + return; + }; + + incoming_link->print(instance_name()); + + if (0) + rna_click_chatter(FUNC_DEFAULT, + "[%s] %s::push_data Incoming message on port = %d " + "direction = %s remote = %s \n", + instance_name(), class_name(), port, + (incoming_link->is_upstream() ? "UPSTREAM":"DOWNSTREAM"), + (incoming_link->e ? incoming_link->e->instance_name() : + "UNKNOWN")); + + bool sent = false; + + // + //========================================================== + // If this layer is connection-oriented check if the + // previous layer has correctly specified the state. + if (!skip_connection_check && + !check_connectionstate(incoming_link, p_in)){ + // Packet has to be dropped... + rna_click_chatter(FUNC_DEFAULT, + "[%s] Did not specify the connection. Dropping packet\n", + instance_name()); + p_in->kill(); + return; + }; + + // Find the required connection state... + ConnectionState *required_connstate = 0; + if (!skip_connection_check) + required_connstate = GET_CONN_ANNO(p_in); + + + // + //========================================================== + // + if (0) print_links(); + + // If this is not control, then dont look for cross-layer outgoing + // links. If the non-control module (e.g., a data processing module) + // has less than 4 links (2 each to downstream and upstream), then + // we have to force the data down the available paths... + + int count = count_outgoing_links(p_in, incoming_link, + incoming_link->is_downstream(), + true, true, // layer agnostic + true, true, + required_connstate); + + //rna_click_chatter(FUNC_DEFAULT,"[%s] %s::push_data " + // "# outgoing links = %d \n", + // instance_name(), class_name(), count); + + // What if there are no choices? + if (count == 1){ + + // Need to send this up to the next layer above... + if (incoming_link->is_upstream()) + process_incoming_from_downstream(&p_in, incoming_link); + else + process_incoming_from_upstream(&p_in, incoming_link); + + // upstream, layer agnostic, cross-layer + LinkState *l = select_outgoing_link(p_in, + incoming_link, + incoming_link->is_downstream(), + true, // layer agnostic + true, // cross layer + true, // remote agnostic + true, // dont care + required_connstate); + if (l){ + + if (0) + rna_click_chatter(FUNC_DEFAULT,"[%s] connection_oriented = %d, " + "conn = %x \n", + instance_name(), l->connection_oriented, + l->connstate_get()); + + // Dont discover connection state for links going + // upstream...atleast not yet...XXX + // discover_connectionstate(l); + + if (l->connection_oriented) { + ConnectionState *c = l->connstate_get(); + SET_CONN_ANNO(p_in, c); + }; + + click_chatter("[10] Sending packet to: "); + l->print(instance_name()); + + Port p = output(l->local_port); + if (p.active()){ + if (l->is_upstream()) + process_outgoing_to_downstream(&p_in, l); + else + process_outgoing_to_upstream(&p_in, l); + p.push(p_in); + sent = true; + } else { + rna_click_chatter(FUNC_DEFAULT, "Output port is not active.\n"); + }; + }; + + } else { + + // There are choices.... + bool treat_as_interlayer = false; + if (this->is_control()){ + if (incoming_link->is_crosslayer()){ + treat_as_interlayer = true; + } + } else { + // incoming/outgoing downstream/upstream + treat_as_interlayer = true; + }; + + if (treat_as_interlayer){ + + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::push_data inter-layer message \n", + instance_name()); + + if (incoming_link->is_downstream()) { + + // XXX Message coming from the layer above... Forward on any + // of the ports to the modules within the protocol. Ideally + // there should be a selection function here.... + + process_incoming_from_upstream(&p_in, incoming_link); + + // downstream, layer specific, intra-layer + LinkState *l = select_outgoing_link(p_in, + incoming_link, + true, + false, // layer sensitive + false, // intra-layer + true, // agnostic_remote + false, // dont care + required_connstate); + if (l){ + + if (0) + rna_click_chatter(FUNC_DEFAULT, + "[%s] connection_oriented = %d, conn = %x \n", + instance_name(), l->connection_oriented, + l->connstate_get()); + + discover_connectionstate(l); + + if (l->connection_oriented) { + ConnectionState *c = l->connstate_get(); + SET_CONN_ANNO(p_in, c); + }; + + click_chatter("[11] Sending packet to: "); + l->print(instance_name()); + + Port p = output(l->local_port); + if (p.active()){ + process_outgoing_to_downstream(&p_in, l); + p.push(p_in); + sent = true; + } else { + rna_click_chatter(FUNC_DEFAULT,"output port is not active.\n"); + }; + }; + + rna_click_chatter(FUNC_DEFAULT,"[%s] \n\n", instance_name()); + + } else { // if downstream && cross layer.. + + // message coming from the layer below...This message should + // eventually be delivered to one of module paths. A message + // must exit the layer only when the message is delivered back + // to the control module after processing in the module path. + // XXX + process_incoming_from_downstream(&p_in, incoming_link); + + // upstream, layer specific, intra-layer + LinkState *l = select_outgoing_link(p_in, + incoming_link, + false, // upstream + false, // layer sensitive + false, // intra-layer + true, // remote agnostic + true, // dont care + required_connstate); + if (l){ + + if (0) + rna_click_chatter(FUNC_DEFAULT, + "[%s] connection_oriented = %d, conn = %x \n", + instance_name(), l->connection_oriented, + l->connstate_get()); + + discover_connectionstate(l); + + if (l->connection_oriented) { + ConnectionState *c = l->connstate_get(); + SET_CONN_ANNO(p_in, c); + }; + + + click_chatter("[12] Sending packet to: "); + l->print(instance_name()); + + Port p = output(l->local_port); + if (p.active()){ + process_outgoing_to_upstream(&p_in, l); + p.push(p_in); + sent = true; + } else { + rna_click_chatter(FUNC_DEFAULT,"output port is not active....\n"); + }; + }; + + }; // if downstream && cross layer.. + + } else { + + + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::push_data intra-protocol message\n", + instance_name()); + + // Intra-layer...Depending on the path down or up, + // accordingly forward the message. + + // Am I upstream or downstream? + if (incoming_link->is_downstream()) { + + // Need to send this up to the next layer below... + process_incoming_from_upstream(&p_in, incoming_link); + + // downstream, layer-specific, cross-layer, + LinkState *l = select_outgoing_link(p_in, + incoming_link, + true, + false, + true, + true, // remote agnostic + true, // dont care + required_connstate); + if (!l) { + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::push_data Cannot " + "find link\n", instance_name()); + }; + + if (l){ + + if (debug) + rna_click_chatter(FUNC_DEFAULT, + "[%s] connection_oriented = %d, conn = %x \n", + instance_name(), l->connection_oriented, + l->connstate_get()); + + discover_connectionstate(l); + + if (l->connection_oriented) { + ConnectionState *c = l->connstate_get(); + SET_CONN_ANNO(p_in, c); + }; + + click_chatter("[13] Sending packet to: "); + l->print(instance_name()); + + Port p = output(l->local_port); + if (p.active()){ + process_outgoing_to_downstream(&p_in, l); + p.push(p_in); + sent = true; + } else { + rna_click_chatter(FUNC_DEFAULT,"output port is not active....\n"); + }; + }; + + } else { + + // Need to send this up to the next layer above... + process_incoming_from_downstream(&p_in, incoming_link); + + // upstream, layer specific, cross-layer + LinkState *l = select_outgoing_link(p_in, + incoming_link, + false, + false, // layer sensitive + true, // intra-layer + true, // remote agnostic + true, // dont care + required_connstate); + if (l){ + + if (0) + rna_click_chatter(FUNC_DEFAULT, + "[%s] connection_oriented = %d, conn = %x \n", + instance_name(), l->connection_oriented, + l->connstate_get()); + + discover_connectionstate(l); + + if (l->connection_oriented) { + ConnectionState *c = l->connstate_get(); + SET_CONN_ANNO(p_in, c); + }; + + click_chatter("[14] Sending packet to: "); + l->print(instance_name()); + + Port p = output(l->local_port); + if (p.active()){ + process_outgoing_to_upstream(&p_in, l); + p.push(p_in); + sent = true; + } else { + rna_click_chatter(FUNC_DEFAULT,"output port is not active....\n"); + }; + }; + + }; // else inter-layer if..downstream.. + }; // ..if..crosslayer....... + }; // if count... + + if (! sent) { + rna_click_chatter(FUNC_DEFAULT,"push_data: Could not send the packet.\n"); + p_in->kill(); + }; + + return; + +}; // push ... + + +void +RNAElement::push_control(int port, Packet *p_in) +{ + (void)port; + (void)p_in; + // Do nothing for now... + return; +}; + +void +RNAElement::push_management(int port, Packet *p_in) +{ + (void)port; + (void)p_in; + + // Do nothing for now... + return; +}; + +void +RNAElement::push(int i, Packet *p) +{ + + unsigned char type = MESSAGE_DATA; + + if (!p || !p->data()) + return; + + // If the message is coming from downstream and has + // the first byte as control, then hand it off to a + // control message processor. Otherwise give it to + // data message processor (push_data); + LinkState *incoming_link = lookup_link(i); + if (! incoming_link ){ + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::push Dropping packet...\n", + instance_name()); + p->kill(); + return; + }; + + if (incoming_link->is_upstream() || + (incoming_link->is_downstream() && + !incoming_link->is_remote_unknown())){ + const unsigned char *data = p->data(); + type = *data; + }; + + if (debug) + rna_click_chatter(FUNC_DEFAULT,"\n\n"); + + if (debug) + RNAElement::print_packet("RNAElement::push", p, false); + + switch(type){ + + case MESSAGE_CONTROL: + push_control(i,p); + break; + + case MESSAGE_DATA: + push_data(i,p); + break; + + case MESSAGE_MANAGEMENT: + push_management(i, p); + break; + + default: + { + if (debug) + rna_click_chatter(FUNC_DEFAULT," [%s] RNAElement::push " + "type(UNKNOWN %d)\n", instance_name(), type); + p->kill(); + break; + }; + + }; + + return; + +}; + + Index: rna/elements/rna/rnaelement_messages.hh diff -u /dev/null rna/elements/rna/rnaelement_messages.hh:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_messages.hh Fri Jun 27 10:40:59 2008 @@ -0,0 +1,77 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ +//########################################################## +// Message definitions. +//########################################################## + +enum MessageType { + MESSAGE_CONTROL = 0xa0, + MESSAGE_DATA = 0xb0, + MESSAGE_MANAGEMENT = 0xc0 +}; + +// +// Right now only type of control message is supported - NEGOTIATE. +// + +enum ControlMessageType { + MESSAGE_CONTROL_NEGOTIATE = 0x10 +}; + +// +// What is the nature of the negotiate control message? +// + +enum NegotiateMessageType { + MESSAGE_CONTROL_NEGOTIATE_REQUEST = 0x11, + MESSAGE_CONTROL_NEGOTIATE_REPLY_SUCCESS = 0x12, + MESSAGE_CONTROL_NEGOTIATE_REPLY_FAILURE = 0x13 +}; + + +// +// When a message is delivered to a particular module, should it +// process it or strip the headers and deliver it to the next layer? +// +enum DataMessageType{ + MESSAGE_DATA_NORMAL = 0x20, + MESSAGE_DATA_TEST = 0x30 +}; + +enum TestMessageType{ + MESSAGE_DATA_TEST_ECHO_REQUEST = 0x31, + MESSAGE_DATA_TEST_ECHO_REPLY = 0x32 +}; + + +enum ManagementMessageType { + MESSAGE_MANAGEMENT_ADD_MODULE, + MESSAGE_MANAGEMENT_DEL_MODULE, + MESSAGE_MANAGEMENT_REPLY, + MESSAGE_MANAGEMENT_INFORMATION +}; + + + +#define GET_CONN_ANNO(p) ((ConnectionState *)(p)->user_anno_u(4)) +#define SET_CONN_ANNO(p, v) ((p)->set_user_anno_u(4, ((unsigned int)(v)))) + +// Default processing on the outgoing and incoming messages. +// Replace this in instances of the RNAElement. +typedef enum { + MESSAGE_STATUS_KILL, + MESSAGE_STATUS_CONTINUE, + MESSAGE_STATUS_IGNORE, + MESSAGE_STATUS_REPLY +} MessageStatus; + + Index: rna/elements/rna/rnaelement_neighbors.cc diff -u /dev/null rna/elements/rna/rnaelement_neighbors.cc:1.1 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_neighbors.cc Fri Jun 27 10:40:59 2008 @@ -0,0 +1,206 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +//============================================================== +// +// This is for processing the list of predecessors/successors +// +//============================================================== + +void +RNAElement::skip_type(Vector& v, char *typename_in ) +{ + Vector nv; + + if (!typename_in) + return; + + for (int i = 0; i < v.size(); i++){ + const char *mytypename = v[i]->class_name(); + if (strcmp(mytypename, typename_in) != 0) + nv.push_back(v[i]); + }; + + v.swap(nv); +} + + +void +RNAElement::filter(char *what, Vector& v){ + + Vector nv; + for (int i = 0; i < v.size(); i++){ + const char *elemname = v[i]->class_name(); + if (!what || strcmp(what, elemname)) + nv.push_back(v[i]); + v.swap(nv); + }; + + return; +}; + +Vector +RNAElement::upstream_elements(Element *e, int inputport){ + + Vector v; + if (!e) + return v; + + // List all the possible elements; + Vector allelements = router()->elements(); + + // For each element look through all the outputs... + for (int i = 0; i < allelements.size(); i++){ + + // ith element + Element *e0 = allelements[i]; + + // For each element go through the list of output ports. + for (int j = 0; j < e0->noutputs(); j++){ + + // find out who is at the other end of the output. + Port p = e0->output(j); + Element *temp = p.element(); + + rna_click_chatter(FUNC_DEFAULT, + "upstream_elements: %s [%d] -> %s [%d] \n", + e0->class_name(), j, + (temp? temp->class_name() : "NULL"), + p.port()); + + // Does the port numbers match? p.port() is the value of + // input port at the other end. + if (temp && temp == this) { + if (inputport >= 0) { + if (inputport == p.port()){ + rna_click_chatter(FUNC_DEFAULT,"upstream_elements: Selected!\n"); + v.push_back(e0); + }; + } else { + rna_click_chatter(FUNC_DEFAULT,"upstream_elements: Selected!\n"); + v.push_back(e0); + }; + }; + }; // for all outputs + }; // for all elements... + + return v; +}; // upstream_elements... + + +// Return one element that connects to a given element on +// a given input port... +Element * +RNAElement::upstream_element(Element *e, int inputport){ + + // The input port must be specified. + if (inputport < 0 || !e) + return NULL; + + Vector v = upstream_elements(e, inputport); + + if (v.size() == 0) + return NULL; + + // Return the first element... + return v[0]; + +}; + +Vector +RNAElement::downstream_elements(Element *e){ + + Vector v; + + // If no element is specified return an empty list... + if (!e) + return v; + + // For each element go through the list of output ports. + for (int j = 0; j < e->noutputs(); j++){ + + // find out who is at the other end of the output. + Port p = e->output(j); + Element *temp = p.element(); + + rna_click_chatter(FUNC_DEFAULT, + "downstream_elements: %s [%d] -> %s [%d] \n", + e->class_name(), j, + (temp? temp->class_name() : "NULL"), p.port()); + + // If the port exists, then include it. + if (temp) + v.push_back(temp); + + }; // for all outputs... + + return v; +}; // downstream_elements + + +Vector +RNAElement::list_downstream_elements(bool downstream, + bool layeragnostic, + bool crosslayer, + bool agnostic_remote, + bool remote_unknown, + ConnectionState *required){ + + rna_click_chatter(FUNC_DEFAULT, + "[%s] RNAElement::list_downstream_elements " + "downstream = %d, layeragnostic = %d crosslayer = %d" + " agnostic_remote = %d, remote_unknown = %d \n", + instance_name(), + downstream, layeragnostic, crosslayer, + agnostic_remote, remote_unknown); + + Vector list; + + if (required){ + + // Right now this function only knows about this type of + // connection state. but can be expanded later on... + LinkState *l = (LinkState *)required->get_data(VAR_LINKINFO); + if (l && + l->is_outgoing() // ignore incoming links + && ((layeragnostic) || + (!layeragnostic && (l->is_crosslayer() == crosslayer))) // + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (!agnostic_remote && (l->is_remote_unknown() == remote_unknown))) + ) { + list.push_back(l); + }; + + } else { + + for (int i = 0; i < all_links.size(); i++){ + LinkState *l = all_links[i]; + + // Find a link in which I am an downstream node and + // the link is outgoing... + if (l->is_outgoing() // ignore incoming links + && ((layeragnostic) || + (!layeragnostic && (l->is_crosslayer() == crosslayer))) // + && ((downstream && l->is_upstream()) || + (!downstream && l->is_downstream())) + && ((agnostic_remote) || + (!agnostic_remote && (l->is_remote_unknown() == remote_unknown))) + ) { + list.push_back(l); + }; + }; + }; + + return list; +}; Index: rna/elements/rna/rnaelement_parse.cc diff -u /dev/null rna/elements/rna/rnaelement_parse.cc:1.2 --- /dev/null Tue Jul 1 09:16:54 2008 +++ rna/elements/rna/rnaelement_parse.cc Fri Jun 27 18:13:43 2008 @@ -0,0 +1,326 @@ +/* + +################################################################ +# # +# (c) University of Southern California # +# # +# See LICENSE.RNA for the complete license # +# # +################################################################ + +*/ + +//################################################################ +// +// Extract the modules of the right kind from the element list that +// has been provided using the ELEMENTS argument. +// +//################################################################ + +Vector +RNAElement::elementlist_lookup(Vector& array, + RNAElementType t, + bool modify){ + + Vector returned_list; + if ( + t < ELEMTYPE_BEGIN || + t > ELEMTYPE_END || + t == UNKNOWN || + t == ROOT + ) + return returned_list; + + Vector array_modified; + for (int i = 0; i < array.size(); i++){ + + RNAElement *e = array[i]; + if (!e) + continue; + + +#ifdef COMMENT + if ((strcmp(e->class_name(), "RNAElement") != 0)){ + array_modified.push_back(e); + continue; + } + + RNAElement *e1 = static_cast(e->cast("RNAElement")); + if (e1->get_type() == t) { + returned_list.push_back(e1); + if (!modify) + array_modified.push_back(e); + } else { + array_modified.push_back(e); + } +#endif + + if (e->get_type() == t) { + returned_list.push_back(e); + if (!modify) + array_modified.push_back(e); + } else { + array_modified.push_back(e); + }; + }; + + array.swap(array_modified); + + return returned_list; + +}; + +//################################################################ +// +// Extract the modules of the right kind from the element list that +// has been provided using the ELEMENTS argument. +// +//################################################################ +RNAElement * +RNAElement::elementlist_lookup_one(Vector& array, + RNAElementType t, + bool modify){ + + RNAElement * returned = NULL; + if ( + t < ELEMTYPE_BEGIN || + t > ELEMTYPE_END || + t == UNKNOWN || + t == ROOT + ) + return returned; + + if (array.size() == 0) + return returned; + + Vector array_modified; + for (int i = 0; i < array.size(); i++){ + + RNAElement *e = array[i]; + if (!e) + continue; + +#ifdef COMMENT + if (returned || + (strcmp(e->class_name(), "RNAElement") != 0)){ + array_modified.push_back(e); + continue; + } + + RNAElement *e1 = static_cast(e->cast("RNAElement")); + if (e1->get_type() == t) { + returned = e1; + if (!modify) + array_modified.push_back(e); + } else { + array_modified.push_back(e); + } +#endif + if (returned){ + array_modified.push_back(e); + continue; + } + + if (e->get_type() == t) { + returned = e; + if (!modify) + array_modified.push_back(e); + } else { + array_modified.push_back(e); + } + }; + + array.swap(array_modified); + + return returned; + +}; + +//################################################################ +// +// Parse the element list +// +//################################################################ + +// +// Expects the name of an element and matches it exact or looks for a +// prefix such as in case of compound elements... +// +Vector +RNAElement::elementlist_find_prefix(String prefix, Element *context){ + + Vector list; + + // click_chatter("[RNA] prefix = %s \n", prefix.c_str()); + + Router *r = context->router(); + Vector allelements = r->elements(); + + for (int j=0; j < allelements.size(); j++){ + + Element *e = allelements[j]; + String ename = e->name(); + + //click_chatter("[RNA] RNAElement::elementlist_find_prefix name[%d] = %s \n", + // j, ename.c_str()); + + if (ename == prefix){ + list.push_back(e); + break; + }; + + // Name doesnt match...words[i] == l0 and name == l0/Socket@1 + int slash = ename.find_left('/'); + if (slash >= 0) { + String ename1 = ename.substring(0, slash); + //click_chatter("[RNA] RNAElement::elementlist_find_prefix slash = %d %s \n", + // slash, ename1.c_str()); + if (ename1 == prefix){ + list.push_back(e); + }; + }; + }; // for... + + //for (int j = 0; j < list.size(); j++) + // click_chatter("[RNA] Found element[%d] = %s \n", j, list[j]->name().c_str()); + + return list; +}; + +void +RNAElement::elementlist_parse(cp_value *v, const String &arg, + ErrorHandler *errh, + const char *argname, Element *context){ + (void) argname; + + // Do the processing the store function... + v->v_string = arg; + + // Check the validity of the error. + Vector *array = (Vector *)v->store; + if (! array){ + errh->error("Failed to process element lis. Empty argument (%s,%s)", + v->description, + v->v_string.printable().c_str()); + return; + }; + + // Check whether the element list is fine... + Vector words; + cp_spacevec(v->v_string, words); + + + for (int i = 0; i < words.size(); i++){ + + String test; + + if (!cp_string(words[i], &test)) { + if (errh) + errh->error("cp_string bad name format"); + return; + } + + + Vector list = elementlist_find_prefix(words[i], context); + if (list.size() == 0){ + if (errh) + errh->error("Cannot find elements"); + return; + } + + }; // For all words.... + + return; +} + +void +RNAElement::elementlist_store(cp_value *v, Element *context){ + + // Check the validity of the error. + Vector *array = (Vector *)v->store; + + Vector words; + cp_spacevec(v->v_string, words); + + Router *r = context->router(); + Vector allelements = r->elements(); + + // Process the element list provided... + for (int i = 0; i < words.size(); i++){ + + Vector list = elementlist_find_prefix(words[i], context); + for (int j = 0; j < list.size(); j++) + array->push_back(list[j]); + + }; // for all words... + + return; +} + +//################################################################ +// +// Handle a default set of keywords... +// +//################################################################ +int +RNAElement::configure(Vector &conf, ErrorHandler *errh) +{ + + if (cp_va_parse_remove_keywords(conf, 0, this, errh, + cpKeywords, + "NAME", cpString, "Name", &instance, + "ELEMENTS", "ELEMENTS", "Names of Elements", &_elemlist, + "PROCESS", cpBool, "Enable processing configuration", + &exec_finish_configuration, + "CONN", cpBool, + "Has a notion of connection state", &connection_oriented, + "UPSTREAM", "ELEMENTS", "Names of Upstream Elements", + &_upstream_element_list, + "DOWNSTREAM", "ELEMENTS", "Names of Downstream Elements", + &_downstream_element_list, + "DEBUG", cpBool, "Debug option enabled for this module", + &debug, + cpEnd) < 0) + return -1; + + + if (_upstream_element_list.size() > 0 || + _downstream_element_list.size() > 0 ) + _preconfigured_element_list = true; + + for(int i = 0; i < _upstream_element_list.size(); i++){ + Element *e = _upstream_element_list[i]; + click_chatter("[%s] upstream_element[%d]: index = %d %s \n", + instance_name(), i, + e->eindex(), e->class_name()); + }; + + for(int i = 0; i < _downstream_element_list.size(); i++){ + Element *e = _downstream_element_list[i]; + click_chatter("[%s] downstream_element[%d]: index = %d %s \n", + instance_name(), i, + e->eindex(), e->class_name()); + }; + + + + return 0; +}; + + +// This will be overridden by individual elements. +// +int +RNAElement::finish_configuration() { + // Do nothing... + return 0; +} + +int +RNAElement::rna_finish_configuration() { + // Do nothing... + rna_click_chatter(FUNC_ENTRY,"[%s] rna_finish_configuration Enter/Exit\n", + instance_name()); + + return 0; +} Index: rna/elements/userlevel/fromdump.cc diff -u rna/elements/userlevel/fromdump.cc:1.1.1.1 rna/elements/userlevel/fromdump.cc:1.2 --- rna/elements/userlevel/fromdump.cc:1.1.1.1 Fri Jun 27 10:36:44 2008 +++ rna/elements/userlevel/fromdump.cc Fri Jun 27 12:17:52 2008 @@ -47,7 +47,7 @@ ( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) ) FromDump::FromDump() - : _packet(0), _end_h(0), _task(this) + : _packet(0), _end_h(0), _count(0), _timer(this), _task(this) { } @@ -211,6 +211,7 @@ return -1; if (output_is_push(0)) ScheduleInfo::initialize_task(this, &_task, _active, errh); + _timer.initialize(this); // skip if hotswapping if (hotswap_element()) @@ -330,15 +331,8 @@ const Timestamp *ts_ptr; int len, caplen, skiplen = 0; Packet *p; - int tries = 0; assert(!_packet); - retry: - // quit if we have tried too many times - tries++; - if ((tries % 16) == 0 && output_is_push(0)) - return true; - // record file position _packet_filepos = _ff.file_pos(); @@ -383,7 +377,7 @@ if (_have_first_time) { if (*ts_ptr < _first_time) { _ff.shift_pos(caplen + skiplen); - goto retry; + return true; } else _have_first_time = false; } @@ -402,7 +396,7 @@ if (_sampling_prob < (1 << SAMPLING_SHIFT) && (uint32_t)(random() & ((1<= _sampling_prob) { _ff.shift_pos(caplen + skiplen); - goto retry; + return true; } // create packet @@ -416,28 +410,47 @@ if (_force_ip && !fake_pcap_force_ip(p, _linktype)) { checked_output_push(1, p); - goto retry; + p = 0; } _packet = p; return true; } +void +FromDump::run_timer(Timer *) +{ + if (_active) { + if (output_is_push(0)) + _task.reschedule(); + else + _notifier.wake(); + } +} + bool -FromDump::run_task() +FromDump::run_task(Task *) { if (!_active) return false; bool more = true; if (!_packet) - more = read_packet(0); - if (_packet && _timing) - if (_packet->timestamp_anno() > Timestamp::now() - _time_offset) { - _task.fast_reschedule(); + for (int i = 0; i < 16; i++) + if (!(more = read_packet(0)) || _packet) + break; + if (_packet && _timing) { + Timestamp now = Timestamp::now(); + Timestamp t = _packet->timestamp_anno() + _time_offset; + if (t > now) { + t -= Timestamp::make_msec(50); + if (t > now) + _timer.schedule_at(t); + else + _task.fast_reschedule(); return false; } - + } if (more) _task.fast_reschedule(); else if (_end_h) @@ -445,6 +458,7 @@ if (_packet) { output(0).push(_packet); + _count++; _packet = 0; return true; } else @@ -462,23 +476,35 @@ bool more = true; if (!_packet) more = read_packet(0); - if (_packet && _timing) - if (_packet->timestamp_anno() > Timestamp::now() - _time_offset) + if (_packet && _timing) { + Timestamp now = Timestamp::now(); + Timestamp t = _packet->timestamp_anno() + _time_offset; + if (t > now) { + t -= Timestamp::make_msec(50); + if (t > now) { + _timer.schedule_at(t); + _notifier.sleep(); + } return 0; + } + } // notify presence/absence of more packets _notifier.set_active(more, true); if (!more && _end_h) _end_h->call_write(ErrorHandler::default_handler()); - - Packet *p = _packet; - _packet = 0; - return p; + + if (Packet *p = _packet) { + _count++; + _packet = 0; + return p; + } else + return 0; } enum { H_SAMPLING_PROB, H_ACTIVE, H_ENCAP, H_STOP, H_PACKET_FILEPOS, - H_EXTEND_INTERVAL + H_EXTEND_INTERVAL, H_COUNT, H_RESET_COUNTS }; String @@ -493,7 +519,9 @@ case H_ENCAP: return String(fake_pcap_unparse_dlt(fd->_linktype)); case H_PACKET_FILEPOS: - return String(fd->_packet_filepos); + return String((unsigned int)fd->_packet_filepos); + case H_COUNT: + return String(fd->_count); default: return ""; } @@ -527,6 +555,9 @@ } else return errh->error("'extend_interval' takes a time interval"); } + case H_RESET_COUNTS: + fd->_count = 0; + return 0; default: return -EINVAL; } @@ -543,6 +574,8 @@ add_write_handler("stop", write_handler, (void *)H_STOP); add_read_handler("packet_filepos", read_handler, (void *)H_PACKET_FILEPOS); add_write_handler("extend_interval", write_handler, (void *)H_EXTEND_INTERVAL); + add_read_handler("count", read_handler, (void *)H_COUNT); + add_write_handler("reset_counts", write_handler, (void *)H_RESET_COUNTS); if (output_is_push(0)) add_task_handlers(&_task); } Index: rna/elements/userlevel/fromdump.hh diff -u rna/elements/userlevel/fromdump.hh:1.1.1.1 rna/elements/userlevel/fromdump.hh:1.2 --- rna/elements/userlevel/fromdump.hh:1.1.1.1 Fri Jun 27 10:36:44 2008 +++ rna/elements/userlevel/fromdump.hh Fri Jun 27 12:17:52 2008 @@ -3,6 +3,7 @@ #define CLICK_FROMDUMP_HH #include #include +#include #include #include "fromfile.hh" CLICK_DECLS @@ -128,6 +129,14 @@ If FromDump uses mmap, then a corrupt file might cause Click to crash with a segmentation violation. +=h count read-only + +Returns the number of packets output so far. + +=h reset_counts write-only + +Resets "count" to 0. + =h sampling_prob read-only Returns the sampling probability (see the SAMPLE keyword argument). @@ -189,7 +198,8 @@ FromDump *hotswap_element() const; void take_state(Element *, ErrorHandler *); - bool run_task(); + void run_timer(Timer *); + bool run_task(Task *); Packet *pull(int); void set_active(bool); @@ -221,6 +231,14 @@ Timestamp _last_time; HandlerCall *_end_h; +#if HAVE_INT64_TYPES + typedef uint64_t counter_t; +#else + typedef uint32_t counter_t; +#endif + counter_t _count; + + Timer _timer; Task _task; ActiveNotifier _notifier; Index: rna/elements/userlevel/fromfile.cc diff -u rna/elements/userlevel/fromfile.cc:1.1.1.1 rna/elements/userlevel/fromfile.cc:1.2 --- rna/elements/userlevel/fromfile.cc:1.1.1.1 Fri Jun 27 10:36:44 2008 +++ rna/elements/userlevel/fromfile.cc Fri Jun 27 12:17:52 2008 @@ -5,7 +5,7 @@ * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 2001-2003 International Computer Science Institute - * Copyright (c) 2004 The Regents of the University of California + * Copyright (c) 2004-2007 The Regents of the University of California * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -38,11 +38,7 @@ FromFile::FromFile() : _fd(-1), _buffer(0), _data_packet(0), #ifdef ALLOW_MMAP -# ifdef __linux__ - _mmap(false), -# else _mmap(true), -# endif #endif _filename(), _pipe(0), _landmark_pattern("%f"), _lineno(0) { @@ -547,7 +543,7 @@ FromFile *fd = reinterpret_cast((uint8_t *)e + (intptr_t)thunk); struct stat s; if (fd->_fd >= 0 && fstat(fd->_fd, &s) >= 0 && S_ISREG(s.st_mode)) - return String(s.st_size); + return String((unsigned int)s.st_size); else return "-"; } @@ -556,7 +552,7 @@ FromFile::filepos_handler(Element* e, void* thunk) { FromFile* fd = reinterpret_cast((uint8_t*)e + (intptr_t)thunk); - return String(fd->_file_offset + fd->_pos); + return String((unsigned int)(fd->_file_offset + fd->_pos)); } int Index: rna/elements/userlevel/socket.cc diff -u rna/elements/userlevel/socket.cc:1.1.1.1 rna/elements/userlevel/socket.cc:1.2 --- rna/elements/userlevel/socket.cc:1.1.1.1 Fri Jun 27 10:36:44 2008 +++ rna/elements/userlevel/socket.cc Fri Jun 27 13:03:35 2008 @@ -4,6 +4,7 @@ * Mark Huang * * Copyright (c) 2004 The Trustees of Princeton University (Trustees). + * Copyright (c) 2006 Regents of the University of California * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -24,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -31,13 +33,19 @@ #include #include "socket.hh" +#ifdef HAVE_PROPER +#include +#endif + CLICK_DECLS Socket::Socket() : _task(this), _timer(this), _fd(-1), _active(-1), _rq(0), _wq(0), + _local_port(0), _local_pathname(""), + _timestamp(true), _sndbuf(-1), _rcvbuf(-1), _snaplen(2048), _nodelay(1), - _verbose(false), _client(false) + _verbose(false), _client(false), _proper(false), _allow(0), _deny(0) { } @@ -58,22 +66,39 @@ socktype = socktype.upper(); // remove keyword arguments + Element *allow = 0, *deny = 0; if (cp_va_parse_remove_keywords(conf, 2, this, errh, "VERBOSE", cpBool, "be verbose?", &_verbose, "SNAPLEN", cpUnsigned, "maximum packet length", &_snaplen, + "TIMESTAMP", cpBool, "set timestamps on received packets?", &_timestamp, + "RCVBUF", cpUnsigned, "maximum socket receive buffer size?", &_rcvbuf, + "SNDBUF", cpUnsigned, "maximum socket send buffer size?", &_sndbuf, "NODELAY", cpUnsigned, "disable Nagle algorithm?", &_nodelay, "CLIENT", cpBool, "client or server?", &_client, + "PROPER", cpBool, "use Proper", &_proper, + "ALLOW", cpElement, "routing table of good hosts", &allow, + "DENY", cpElement, "routing table of bad hosts", &deny, cpEnd) < 0) return -1; + if (allow && !(_allow = (IPRouteTable *)allow->cast("IPRouteTable"))) + return errh->error("%s is not an IPRouteTable", allow->name().c_str()); + + if (deny && !(_deny = (IPRouteTable *)deny->cast("IPRouteTable"))) + return errh->error("%s is not an IPRouteTable", deny->name().c_str()); + if (socktype == "TCP" || socktype == "UDP") { _family = AF_INET; _socktype = socktype == "TCP" ? SOCK_STREAM : SOCK_DGRAM; _protocol = socktype == "TCP" ? IPPROTO_TCP : IPPROTO_UDP; + CpVaParseCmd portcmd = (socktype == "TCP" ? cpTCPPort : cpUDPPort); if (cp_va_parse(conf, this, errh, cpIgnore, - cpIPAddress, "IP address", &_ip, - cpUnsignedShort, "port number", &_port, + cpIPAddress, "IP address", &_remote_ip, + portcmd, "port number", &_remote_port, + cpOptional, + cpIPAddress, "local IP address", &_local_ip, + portcmd, "local port number", &_local_port, cpEnd) < 0) return -1; } @@ -83,11 +108,21 @@ _socktype = socktype == "UNIX" ? SOCK_STREAM : SOCK_DGRAM; _protocol = 0; if (cp_va_parse(conf, this, errh, - cpIgnore, cpString, "filename", &_pathname, + cpIgnore, + cpString, "filename", &_remote_pathname, + cpOptional, + cpString, "local filename", &_local_pathname, cpEnd) < 0) return -1; - if (_pathname.length() >= (int)sizeof(((struct sockaddr_un *)0)->sun_path)) - return errh->error("filename too long"); + int max_path = (int)sizeof(((struct sockaddr_un *)0)->sun_path); + // if not in the abstract namespace (begins with zero byte), + // reserve room for trailing NUL + if ((_remote_pathname[0] && _remote_pathname.length() >= max_path) || + (_remote_pathname[0] == 0 && _remote_pathname.length() > max_path)) + return errh->error("remote filename '%s' too long", _remote_pathname.printable().c_str()); + if ((_local_pathname[0] && _local_pathname.length() >= max_path) || + (_local_pathname[0] == 0 && _local_pathname.length() > max_path)) + return errh->error("local filename '%s' too long", _local_pathname.printable().c_str()); } else @@ -120,46 +155,98 @@ return initialize_socket_error(errh, "socket"); if (_family == AF_INET) { - _sa.in.sin_family = _family; - _sa.in.sin_port = htons(_port); - _sa.in.sin_addr = _ip.in_addr(); - _sa_len = sizeof(_sa.in); + _remote.in.sin_family = _family; + _remote.in.sin_port = htons(_remote_port); + _remote.in.sin_addr = _remote_ip.in_addr(); + _remote_len = sizeof(_remote.in); + _local.in.sin_family = _family; + _local.in.sin_port = htons(_local_port); + _local.in.sin_addr = _local_ip.in_addr(); + _local_len = sizeof(_local.in); } else { - _sa.un.sun_family = _family; - strcpy(_sa.un.sun_path, _pathname.c_str()); - _sa_len = offsetof(struct sockaddr_un, sun_path) + _pathname.length() + 1; + _remote.un.sun_family = _family; + _remote_len = offsetof(struct sockaddr_un, sun_path) + _remote_pathname.length(); + if (_remote_pathname[0]) { + strcpy(_remote.un.sun_path, _remote_pathname.c_str()); + _remote_len++; + } else + memcpy(_remote.un.sun_path, _remote_pathname.c_str(), _remote_pathname.length()); + _local.un.sun_family = _family; + _local_len = offsetof(struct sockaddr_un, sun_path) + _local_pathname.length(); + if (_local_pathname[0]) { + strcpy(_local.un.sun_path, _local_pathname.c_str()); + _local_len++; + } else + memcpy(_local.un.sun_path, _local_pathname.c_str(), _local_pathname.length()); + } + + // enable timestamps + if (_timestamp) { + int one = 1; + if (setsockopt(_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)) < 0) + return initialize_socket_error(errh, "setsockopt(SO_TIMESTAMP)"); } #ifdef TCP_NODELAY // disable Nagle algorithm if (_protocol == IPPROTO_TCP && _nodelay) if (setsockopt(_fd, IP_PROTO_TCP, TCP_NODELAY, &_nodelay, sizeof(_nodelay)) < 0) - return initialize_socket_error(errh, "setsockopt"); + return initialize_socket_error(errh, "setsockopt(TCP_NODELAY)"); #endif + // set socket send buffer size + if (_sndbuf >= 0) + if (setsockopt(_fd, SOL_SOCKET, SO_SNDBUF, &_sndbuf, sizeof(_sndbuf)) < 0) + return initialize_socket_error(errh, "setsockopt(SO_SNDBUF)"); + + // set socket receive buffer size + if (_rcvbuf >= 0) + if (setsockopt(_fd, SOL_SOCKET, SO_RCVBUF, &_rcvbuf, sizeof(_rcvbuf)) < 0) + return initialize_socket_error(errh, "setsockopt(SO_RCVBUF)"); + + // if a server, then the first arguments should be interpreted as + // the address/port/file to bind() to, not to connect() to + if (!_client) { + memcpy(&_local, &_remote, _remote_len); + _local_len = _remote_len; + } + + // if a server, or if the optional local arguments have been + // specified, bind() to the specified address/port/file + if (!_client || _local_port != 0 || _local_pathname != "") { +#ifdef HAVE_PROPER + int ret = -1; + if (_proper) { + ret = prop_bind_socket(_fd, (struct sockaddr *)&_local, _local_len); + if (ret < 0) + errh->warning("prop_bind_socket: %s", strerror(errno)); + } + if (ret < 0) +#endif + if (bind(_fd, (struct sockaddr *)&_local, _local_len) < 0) + return initialize_socket_error(errh, "bind"); + } + if (_client) { // connect if (_socktype == SOCK_STREAM) { - if (connect(_fd, (struct sockaddr *)&_sa, _sa_len) < 0) + if (connect(_fd, (struct sockaddr *)&_remote, _remote_len) < 0) return initialize_socket_error(errh, "connect"); if (_verbose) - click_chatter("%s: opened connection %d to %s:%d", declaration().c_str(), _fd, IPAddress(_sa.in.sin_addr).unparse().c_str(), ntohs(_sa.in.sin_port)); + click_chatter("%s: opened connection %d to %s:%d", declaration().c_str(), _fd, IPAddress(_remote.in.sin_addr).unparse().c_str(), ntohs(_remote.in.sin_port)); } _active = _fd; } else { - // bind to port - if (bind(_fd, (struct sockaddr *)&_sa, _sa_len) < 0) - return initialize_socket_error(errh, "bind"); // start listening if (_socktype == SOCK_STREAM) { if (listen(_fd, 2) < 0) return initialize_socket_error(errh, "listen"); if (_verbose) { if (_family == AF_INET) - click_chatter("%s: listening for connections on %s:%d (%d)", declaration().c_str(), IPAddress(_sa.in.sin_addr).unparse().c_str(), ntohs(_sa.in.sin_port), _fd); + click_chatter("%s: listening for connections on %s:%d (%d)", declaration().c_str(), IPAddress(_local.in.sin_addr).unparse().c_str(), ntohs(_local.in.sin_port), _fd); else - click_chatter("%s: listening for connections on %s (%d)", declaration().c_str(), _sa.un.sun_path, _fd); + click_chatter("%s: listening for connections on %s (%d)", declaration().c_str(), _local.un.sun_path, _fd); } } else { _active = _fd; @@ -173,11 +260,13 @@ if (noutputs()) add_select(_fd, SELECT_READ); - if (ninputs()) { + if (ninputs() && input_is_pull(0)) { ScheduleInfo::join_scheduler(this, &_task, errh); _signal = Notifier::upstream_empty_signal(this, 0, &_task); + add_select(_fd, SELECT_WRITE); _timer.initialize(this); } + return 0; } @@ -201,21 +290,48 @@ #endif close(_fd); if (_family == AF_UNIX) - unlink(_pathname.c_str()); + unlink(_local_pathname.c_str()); _fd = -1; } } +bool +Socket::allowed(IPAddress addr) +{ + IPAddress gw; + + if (_allow && _allow->lookup_route(addr, gw) >= 0) + return true; + else if (_deny && _deny->lookup_route(addr, gw) >= 0) + return false; + else + return true; +} + +void +Socket::close_active(void) +{ + if (_active >= 0) { + remove_select(_active, SELECT_READ | SELECT_WRITE); + close(_active); + if (_verbose) + click_chatter("%s: closed connection %d", declaration().c_str(), _active); + _active = -1; + } +} + void Socket::selected(int fd) { int len; + union { struct sockaddr_in in; struct sockaddr_un un; } from; + socklen_t from_len = sizeof(from); + bool allow; if (noutputs()) { // accept new connections if (_socktype == SOCK_STREAM && !_client && _active < 0 && fd == _fd) { - _sa_len = sizeof(_sa); - _active = accept(_fd, (struct sockaddr *)&_sa, &_sa_len); + _active = accept(_fd, (struct sockaddr *)&from, &from_len); if (_active < 0) { if (errno != EAGAIN) @@ -223,18 +339,29 @@ return; } - if (_verbose) { - if (_family == AF_INET) - click_chatter("%s: opened connection %d from %s:%d", declaration().c_str(), _active, IPAddress(_sa.in.sin_addr).unparse().c_str(), ntohs(_sa.in.sin_port)); - else - click_chatter("%s: opened connection %d from %s", declaration().c_str(), _active, _sa.un.sun_path); + if (_family == AF_INET) { + allow = allowed(IPAddress(from.in.sin_addr)); + + if (_verbose) + click_chatter("%s: %s connection %d from %s:%d", declaration().c_str(), + allow ? "opened" : "denied", + _active, IPAddress(from.in.sin_addr).unparse().c_str(), ntohs(from.in.sin_port)); + + if (!allow) { + close(_active); + _active = -1; + return; + } + } else { + if (_verbose) + click_chatter("%s: opened connection %d from %s", declaration().c_str(), _active, from.un.sun_path); } fcntl(_active, F_SETFL, O_NONBLOCK); fcntl(_active, F_SETFD, FD_CLOEXEC); - add_select(_active, SELECT_READ); - _events = SELECT_READ; + add_select(_active, SELECT_READ | SELECT_WRITE); + _events = SELECT_READ | SELECT_WRITE; } // read data from socket @@ -247,121 +374,166 @@ len = recv(_active, _rq->data(), _rq->length(), MSG_TRUNC); else { // datagram server, find out who we are talking to - _sa_len = sizeof(_sa); - len = recvfrom(_active, _rq->data(), _rq->length(), MSG_TRUNC, (struct sockaddr *)&_sa, &_sa_len); + len = recvfrom(_active, _rq->data(), _rq->length(), MSG_TRUNC, (struct sockaddr *)&from, &from_len); + + if (_family == AF_INET && !allowed(IPAddress(from.in.sin_addr))) { + if (_verbose) + click_chatter("%s: dropped datagram from %s:%d", declaration().c_str(), + IPAddress(from.in.sin_addr).unparse().c_str(), ntohs(from.in.sin_port)); + len = -1; + errno = EAGAIN; + } else if (len > 0) { + memcpy(&_remote, &from, from_len); + _remote_len = from_len; + } } + + // this segment OK if (len > 0) { if (len > _snaplen) { + // truncate packet to max length (should never happen) assert(_rq->length() == (uint32_t)_snaplen); SET_EXTRA_LENGTH_ANNO(_rq, len - _snaplen); - } else + } else { + // trim packet to actual length _rq->take(_snaplen - len); + } + // set timestamp - _rq->timestamp_anno().set_now(); + if (_timestamp) + _rq->timestamp_anno().set_now(); + + // push packet output(0).push(_rq); _rq = 0; - } else { - if (len == 0 || errno != EAGAIN) { - if (errno != EAGAIN) - click_chatter("%s: %s", declaration().c_str(), strerror(errno)); - goto err; - } } - } - } - if (ninputs()) { - // write data to socket - Packet *p; - if (_wq) { - p = _wq; - _wq = 0; - } else { - p = input(0).pull(); - } - if (p) { - while (p->length()) { - if (!IPAddress(_ip) && _client && _family == AF_INET && _socktype != SOCK_STREAM) { - // If the IP address specified when the element was created is 0.0.0.0, - // send the packet to its IP destination annotation address - _sa.in.sin_addr = p->dst_ip_anno(); - } - if (_socktype == SOCK_STREAM) - len = write(_active, p->data(), p->length()); - else { - if (_family == AF_INET) - _sa_len = sizeof(_sa.in); - else - _sa_len = offsetof(struct sockaddr_un, sun_path) + strlen(_sa.un.sun_path) + 1; - len = sendto(_active, p->data(), p->length(), 0, - (struct sockaddr *)&_sa, _sa_len); - } - if (len < 0) { - if (errno == ENOBUFS || errno == EAGAIN) { - // socket queue full, try again later - _wq = p; - remove_select(_active, SELECT_WRITE); - _events &= ~SELECT_WRITE; - _backoff = (!_backoff) ? 1 : _backoff*2; - _timer.schedule_after(Timestamp::make_usec(_backoff)); - return; - } else if (errno == EINTR) { - // interrupted by signal, try again immediately - continue; - } else { - // connection probably terminated - if (_verbose) - click_chatter("%s: %s", declaration().c_str(), _sa.un.sun_path); - p->kill(); - goto err; - } - } else { - p->pull(len); - } + // connection terminated or fatal error + else if (len == 0 || errno != EAGAIN) { + if (errno != EAGAIN && _verbose) + click_chatter("%s: %s", declaration().c_str(), strerror(errno)); + close_active(); + return; } - _backoff = 0; - p->kill(); } + } - // nothing to write, wait for upstream signal - if (!p && !_signal && (_events & SELECT_WRITE)) { - remove_select(_active, SELECT_WRITE); - _events &= ~SELECT_WRITE; + if (ninputs() && input_is_pull(0)) + run_task(0); +} + +int +Socket::write_packet(Packet *p) +{ + int len; + + assert(_active >= 0); + + while (p->length()) { + if (!IPAddress(_remote_ip) && _client && _family == AF_INET && _socktype != SOCK_STREAM) { + // If the IP address specified when the element was created is 0.0.0.0, + // send the packet to its IP destination annotation address + _remote.in.sin_addr = p->dst_ip_anno(); } - } - return; + // write segment + if (_socktype == SOCK_STREAM) + len = write(_active, p->data(), p->length()); + else + len = sendto(_active, p->data(), p->length(), 0, + (struct sockaddr *)&_remote, _remote_len); + + // error + if (len < 0) { + // out of memory or would block + if (errno == ENOBUFS || errno == EAGAIN) + return -1; + + // interrupted by signal, try again immediately + else if (errno == EINTR) + continue; - err: - if (_active != _fd) { - remove_select(_active, SELECT_READ | SELECT_WRITE); - close(_active); - if (_verbose) - click_chatter("%s: closed connection %d", declaration().c_str(), _active); - _active = -1; + // connection probably terminated or other fatal error + else { + if (_verbose) + click_chatter("%s: %s", declaration().c_str(), strerror(errno)); + close_active(); + break; + } + } else + // this segment OK + p->pull(len); } + + p->kill(); + return 0; } void -Socket::run_timer(Timer *) +Socket::push(int, Packet *p) { - if ((_wq || _signal) && !(_events & SELECT_WRITE) && _active >= 0) { - add_select(_active, SELECT_WRITE); - _events |= SELECT_WRITE; - selected(_active); - } + fd_set fds; + int err; + + if (_active >= 0) { + // block + do { + FD_ZERO(&fds); + FD_SET(_active, &fds); + err = select(_active + 1, NULL, &fds, NULL, NULL); + } while (err < 0 && errno == EINTR); + + if (err >= 0) { + // write + do { + err = write_packet(p); + } while (err < 0 && (errno == ENOBUFS || errno == EAGAIN)); + } + + if (err < 0) { + if (_verbose) + click_chatter("%s: %s, dropping packet", declaration().c_str(), strerror(err)); + p->kill(); + } + } else + p->kill(); } bool -Socket::run_task() +Socket::run_task(Task *) { - if ((_wq || _signal) && !(_events & SELECT_WRITE) && _active >= 0) { - add_select(_active, SELECT_WRITE); - _events |= SELECT_WRITE; - selected(_active); - return true; + assert(ninputs() && input_is_pull(0)); + bool any = false; + + if (_active >= 0) { + Packet *p = 0; + int err = 0; + + // write as much as we can + do { + p = _wq ? _wq : input(0).pull(); + _wq = 0; + if (p) { + any = true; + err = write_packet(p); + } + } while (p && err >= 0); + + if (err < 0) { + // queue packet for writing when socket becomes available + _wq = p; + p = 0; + add_select(_active, SELECT_WRITE); + } else if (_signal) + // more pending + _task.fast_reschedule(); + else + // wrote all we could and no more pending + remove_select(_active, SELECT_WRITE); } - return false; + + // true if we wrote at least one packet + return any; } void @@ -371,5 +543,5 @@ } CLICK_ENDDECLS -ELEMENT_REQUIRES(userlevel) +ELEMENT_REQUIRES(userlevel IPRouteTable) EXPORT_ELEMENT(Socket) Index: rna/elements/userlevel/socket.hh diff -u rna/elements/userlevel/socket.hh:1.1.1.1 rna/elements/userlevel/socket.hh:1.2 --- rna/elements/userlevel/socket.hh:1.1.1.1 Fri Jun 27 10:36:44 2008 +++ rna/elements/userlevel/socket.hh Fri Jun 27 13:03:35 2008 @@ -6,16 +6,17 @@ #include #include #include +#include "../ip/iproutetable.hh" #include CLICK_DECLS /* =c -Socket("TCP", IP, PORTNUMBER [, I]) -Socket("UDP", IP, PORTNUMBER [, I]) -Socket("UNIX", FILENAME [, I]) -Socket("UNIX_DGRAM", FILENAME [, I]) +Socket("TCP", IP, PORTNUMBER [, LOCALIP] [, LOCALPORTNUMBER] [, I]) +Socket("UDP", IP, PORTNUMBER [, LOCALIP] [, LOCALPORTNUMBER] [, I]) +Socket("UNIX", FILENAME [, LOCALFILENAME] [, I]) +Socket("UNIX_DGRAM", FILENAME [, LOCALFILENAME] [, I]) =s comm @@ -47,6 +48,18 @@ address, the Socket will send input packets to the destination IP annotation of each packet. +If "LOCALIP"/"LOCALPORTNUMBER" or "LOCALFILENAME" is specified, CLIENT +is assumed if not set and the specified local address/port/file will +be bound before the connection attempt is made. If CLIENT is set to +false, any "LOCALIP"/"LOCALPORTNUMBER" and "LOCALFILENAME" arguments +are ignored. + +Socket inputs are agnostic, i.e., they may be either "pull" or +"push". If pushed, packets will block on the underlying socket; +otherwise, the socket will pull packets as it can accept them. For +best performance, place a Notifier element (such as NotifierQueue) +upstream of a "pull" Socket. + Keyword arguments are: =over 8 @@ -76,11 +89,55 @@ Socket element has no input and CLIENT is unspecified, it is assumed to be a server socket. +=item SNDBUF + +Unsigned integer. Sets the maximum size in bytes of the underlying +socket send buffer. The default value is set by the wmem_default +sysctl and the maximum allowed value is set by the wmem_max sysctl. + +=item RCVBUF + +Unsigned integer. Sets the maximum size in bytes of the underlying +socket receive buffer. The default value is set by the rmem_default +sysctl and the maximum allowed value is set by the rmem_max sysctl. + +=item TIMESTAMP + +Boolean. If set, sets the timestamp field on received packets to the +current time. Default is true. + +=item ALLOW + +The name of an IPRouteTable element, like RadixIPLookup or +DirectIPLookup. If set and the Socket element is a server, the Socket +element will lookup source IP addresses of clients in the specified +IPRouteTable before accepting a connection (if SOCK_STREAM) or +datagram (if SOCK_DGRAM). If the address is found, the connection or +datagram is accepted. If the address is not found, the DENY table will +then be checked (see below). + +=item DENY + +The name of an IPRouteTable element, like RadixIPLookup or +DirectIPLookup. If set and the Socket element is a server, the Socket +element will lookup source IP addresses of clients in the specified +IPRouteTable before accepting a connection (if SOCK_STREAM) or +datagram (if SOCK_DGRAM). If the address is found, the connection or +datagram is dropped, otherwise it is accepted. Note that the ALLOW +table, if specified, is checked first. Wildcard matches may be +specified with netmasks; for example, to deny all hosts, specify a +route to "0.0.0.0/0" in the DENY table. + =item VERBOSE Boolean. When true, Socket will print messages whenever it accepts a new connection or drops an old one. Default is false. +=item PROPER + +Boolean. PlanetLab specific. If true and Click has been configured +--with-proper, use Proper to bind a reserved port. + =back =e @@ -97,6 +154,15 @@ // A bi-directional client socket ... -> Socket(TCP, 1.2.3.4, 80, CLIENT true) -> ... + // A bi-directional client socket bound to a particular local port + ... -> Socket(TCP, 1.2.3.4, 80, 0.0.0.0, 54321) -> ... + + // A localhost server socket + allow :: RadixIPLookup(127.0.0.1 0); + deny :: RadixIPLookup(0.0.0.0/0 0); + allow -> deny -> allow; // (makes the configuration valid) + Socket(TCP, 0.0.0.0, 80, ALLOW allow, DENY deny) -> ... + =a RawSocket */ class Socket : public Element { public: @@ -107,17 +173,21 @@ const char *class_name() const { return "Socket"; } const char *port_count() const { return "0-1/0-1"; } - const char *processing() const { return "l/h"; } + const char *processing() const { return "a/h"; } const char *flow_code() const { return "x/y"; } - int configure(Vector &conf, ErrorHandler *); - int initialize(ErrorHandler *); - void cleanup(CleanupStage); - void add_handlers(); + virtual int configure(Vector &conf, ErrorHandler *); + virtual int initialize(ErrorHandler *); + virtual void cleanup(CleanupStage); - bool run_task(); + void add_handlers(); + bool run_task(Task *); void selected(int); - void run_timer(Timer *); + void push(int port, Packet*); + + bool allowed(IPAddress); + void close_active(void); + int write_packet(Packet*); protected: Task _task; @@ -127,10 +197,14 @@ int _fd; // socket descriptor int _active; // connection descriptor - // bind() parameters during initialization, sendto() address for - // non-connection-mode sockets - union { struct sockaddr_in in; struct sockaddr_un un; } _sa; - socklen_t _sa_len; + // local address to bind() + union { struct sockaddr_in in; struct sockaddr_un un; } _local; + socklen_t _local_len; + + // remote address to connect() to or sendto() (for + // non-connection-mode sockets) + union { struct sockaddr_in in; struct sockaddr_un un; } _remote; + socklen_t _remote_len; NotifierSignal _signal; // packet is available to pull() WritablePacket *_rq; // queue to receive pulled packets @@ -141,14 +215,23 @@ int _family; // AF_INET or AF_UNIX int _socktype; // SOCK_STREAM or SOCK_DGRAM int _protocol; // for AF_INET, IPPROTO_TCP, IPPROTO_UDP, etc. - IPAddress _ip; // for AF_INET, address to bind() - unsigned short _port; // for AF_INET, port to bind() - String _pathname; // for AF_UNIX, file to bind() - + IPAddress _local_ip; // for AF_INET, address to bind() + uint16_t _local_port; // for AF_INET, port to bind() + String _local_pathname; // for AF_UNIX, file to bind() + IPAddress _remote_ip; // for AF_INET, address to connect() to or sendto() + uint16_t _remote_port; // for AF_INET, port to connect() to or sendto() + String _remote_pathname; // for AF_UNIX, file to sendto() + + bool _timestamp; // set the timestamp on received packets + int _sndbuf; // maximum socket send buffer in bytes + int _rcvbuf; // maximum socket receive buffer in bytes int _snaplen; // maximum received packet length int _nodelay; // disable Nagle algorithm bool _verbose; // be verbose bool _client; // client or server + bool _proper; // (PlanetLab only) use Proper to bind port + IPRouteTable *_allow; // lookup table of good hosts + IPRouteTable *_deny; // lookup table of bad hosts int initialize_socket_error(ErrorHandler *, const char *); Index: rna/include/click/algorithm.hh diff -u /dev/null rna/include/click/algorithm.hh:1.1 --- /dev/null Tue Jul 1 09:16:58 2008 +++ rna/include/click/algorithm.hh Fri Jun 27 18:25:53 2008 @@ -0,0 +1,24 @@ +#ifndef CLICK_ALGORITHM_HH +#define CLICK_ALGORITHM_HH +CLICK_DECLS + +template +inline T * +find(T *begin, T *end, const T &val) +{ + while (begin < end && *begin != val) + begin++; + return begin; +} + +template +inline const T * +find(const T *begin, const T *end, const T &val) +{ + while (begin < end && *begin != val) + begin++; + return begin; +} + +CLICK_ENDDECLS +#endif Index: rna/include/click/element.hh diff -u rna/include/click/element.hh:1.1.1.1 rna/include/click/element.hh:1.2 --- rna/include/click/element.hh:1.1.1.1 Fri Jun 27 10:36:40 2008 +++ rna/include/click/element.hh Fri Jun 27 12:17:51 2008 @@ -38,7 +38,7 @@ virtual Packet* pull(int port); virtual Packet* simple_action(Packet*); - virtual bool run_task(); // return true iff did useful work + virtual bool run_task(Task *); // return true iff did useful work virtual void run_timer(Timer *); #if CLICK_USERLEVEL virtual void selected(int fd); @@ -211,6 +211,7 @@ inline void add_output() CLICK_ELEMENT_PORT_COUNT_DEPRECATED; bool ports_frozen() const CLICK_DEPRECATED; + virtual bool run_task() CLICK_DEPRECATED; virtual void run_timer() CLICK_DEPRECATED; private: @@ -239,6 +240,10 @@ void initialize_ports(const int* input_codes, const int* output_codes); int connect_port(bool isoutput, int port, Element*, int); + + // RNA commands... + int connect_port_rna(bool isoutput, int port, Element*, int); + int disconnect_port_rna(bool isoutput, int port, Element* e, int e_port); void add_default_handlers(bool writable_config); @@ -463,6 +468,8 @@ inline bool Element::port_active(bool isoutput, int port) const { + if (0) printf("port_active: nports = %d, port = %d, _port = %d \n", + port, nports(isoutput), _ports[isoutput][port]._port); return (unsigned) port < (unsigned) nports(isoutput) && _ports[isoutput][port].active(); } @@ -519,6 +526,7 @@ Element::Port::Port() : _e(0), _port(-2) PORT_CTOR_INIT(0) { + } inline @@ -596,6 +604,7 @@ #else _e->push(_port, p); #endif + } /** @brief Pull a packet over this port and return it. Index: rna/include/click/router.hh diff -u rna/include/click/router.hh:1.1.1.1 rna/include/click/router.hh:1.2 --- rna/include/click/router.hh:1.1.1.1 Fri Jun 27 10:36:40 2008 +++ rna/include/click/router.hh Fri Jun 27 12:17:51 2008 @@ -29,6 +29,7 @@ static void static_initialize(); static void static_cleanup(); + enum { ROUTER_NEW, ROUTER_PRECONFIGURE, ROUTER_PREINITIALIZE, ROUTER_LIVE, ROUTER_DEAD // order is important @@ -129,6 +130,11 @@ int initialize(ErrorHandler*); void activate(bool foreground, ErrorHandler*); inline void activate(ErrorHandler* errh); + + // RNA + int update_connections(); + void set_connections_rna(); + int disconnect_rna(Element *, int, Element *, int); /** @cond never */ // Needs to be public for Lexer, etc., but not useful outside Index: rna/include/click/routerthread.hh diff -u rna/include/click/routerthread.hh:1.1.1.1 rna/include/click/routerthread.hh:1.2 --- rna/include/click/routerthread.hh:1.1.1.1 Fri Jun 27 10:36:40 2008 +++ rna/include/click/routerthread.hh Fri Jun 27 13:03:35 2008 @@ -77,7 +77,7 @@ uint32_t driver_task_epoch() const { return _driver_task_epoch; } timeval task_epoch_time(uint32_t epoch) const; # if CLICK_LINUXMODULE - struct task_struct *sleeper() const { return _sleeper; } + struct task_struct *sleeper() const { return _linux_task; } # endif #endif @@ -90,17 +90,21 @@ #ifdef HAVE_TASK_HEAP Vector _task_heap; int _task_heap_hole; + unsigned _pass; #endif Master *_master; int _id; - Spinlock _lock; +#if CLICK_LINUXMODULE + struct task_struct *_linux_task; + spinlock_t _lock; atomic_uint32_t _task_lock_waiting; +#endif + atomic_uint32_t _pending; #if CLICK_LINUXMODULE - struct task_struct *_sleeper; bool _greedy; #endif @@ -144,7 +148,8 @@ inline void add_pending(); // task running functions - inline void nice_lock_tasks(); + inline void driver_lock_tasks(); + inline void driver_unlock_tasks(); inline void run_tasks(int ntasks); inline void run_os(); #ifdef HAVE_ADAPTIVE_SCHEDULER @@ -270,29 +275,42 @@ inline void RouterThread::lock_tasks() { - _task_lock_waiting++; - _lock.acquire(); - _task_lock_waiting--; +#if CLICK_LINUXMODULE + if (unlikely(current != _linux_task)) { + _task_lock_waiting++; + spin_lock(&_lock); + _task_lock_waiting--; + } +#endif } inline bool RouterThread::attempt_lock_tasks() { - return _lock.attempt(); +#if CLICK_LINUXMODULE + if (likely(current == _linux_task)) + return true; + return spin_trylock(&_lock); +#else + return true; +#endif } inline void RouterThread::unlock_tasks() { - _lock.release(); +#if CLICK_LINUXMODULE + if (unlikely(current != _linux_task)) + spin_unlock(&_lock); +#endif } inline void RouterThread::wake() { #if CLICK_LINUXMODULE - if (_sleeper) - wake_up_process(_sleeper); + if (_linux_task) + wake_up_process(_linux_task); #endif #if CLICK_BSDMODULE && !BSD_NETISRSCHED if (_sleep_ident) Index: rna/include/click/string.hh diff -u rna/include/click/string.hh:1.1.1.1 rna/include/click/string.hh:1.2 --- rna/include/click/string.hh:1.1.1.1 Fri Jun 27 10:36:40 2008 +++ rna/include/click/string.hh Fri Jun 27 12:17:52 2008 @@ -4,6 +4,7 @@ #ifdef HAVE_PERMSTRING # include "permstr.hh" #endif +#include CLICK_DECLS /** @file @@ -31,7 +32,11 @@ explicit String(unsigned u); explicit String(long i); explicit String(unsigned long u); -#if HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG +#if HAVE_LONG_LONG + explicit String(long long q); + explicit String(unsigned long long q); +#endif +#if HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG && !HAVE_INT64_IS_LONG_LONG explicit String(int64_t q); explicit String(uint64_t q); #endif @@ -41,11 +46,28 @@ inline ~String(); static inline const String &empty_string(); - static inline const String &null_string() CLICK_DEPRECATED; static String garbage_string(int len); // len garbage characters static String stable_string(const char *s, int len = -1); // stable read-only mem. static inline String stable_string(const char *begin, const char *end); +#if HAVE_LONG_LONG + typedef long long int_large_t; + typedef unsigned long long uint_large_t; +#elif HAVE_INT64_TYPES + typedef int64_t int_large_t; + typedef uint64_t uint_large_t; +#else + typedef long int_large_t; + typedef unsigned long uint_large_t; +#endif + + static String numeric_string(int_large_t num, int base = 10, bool uppercase = true); + static String numeric_string(uint_large_t num, int base = 10, bool uppercase = true); +#if HAVE_LONG_LONG && HAVE_INT64_TYPES && SIZEOF_LONG_LONG > 8 + static inline String numeric_string(int64_t num, int base = 10, bool uppercase = true); + static inline String numeric_string(uint64_t num, int base = 10, bool uppercase = true); +#endif + inline int length() const; inline const char *data() const; @@ -63,7 +85,6 @@ inline char back() const; const char *c_str() const; // pointer returned is semi-transient - inline const char *cc() const CLICK_DEPRECATED; bool equals(const char *s, int len) const; // bool operator==(const String &, const String &); @@ -398,17 +419,6 @@ return *null_string_p; } -/** @brief Return an empty String (deprecated). - * @deprecated Use empty_string() instead. - * - * Returns a global constant, so it's quicker than String::String(). - */ -inline const String & -String::null_string() -{ - return *null_string_p; -} - /** @brief Return a String that directly references the character data in * [@a begin, @a end). * @param begin pointer to the first character in the character data. @@ -427,14 +437,29 @@ return String(); } -/** @brief Null-terminates the string (deprecated). - * @deprecated This function is a synonym for c_str(). You should call - * c_str() instead, since the C++ standard library uses that name. */ -inline const char * -String::cc() const +#if HAVE_LONG_LONG && HAVE_INT64_TYPES && SIZEOF_LONG_LONG > 8 +/** @brief Create and return a String containing an ASCII representation of @a num. + * @param num Number. + * @param base Base; must be 8, 10, or 16. Defaults to 10. + * @param uppercase If true, then use uppercase letters in base 16. + */ +inline String +String::numeric_string(int64_t num, int base, bool uppercase) +{ + return String::numeric_string(static_cast(num), base, uppercase); +} + +/** @brief Create and return a String containing an ASCII representation of @a num. + * @param num Number. + * @param base Base; must be 8, 10, or 16. Defaults to 10. + * @param uppercase If true, then use uppercase letters in base 16. + */ +inline String +String::numeric_string(uint64_t num, int base, bool uppercase) { - return c_str(); + return String::numeric_string(static_cast(num), base, uppercase); } +#endif /** @brief Return a substring of the current string starting at @a begin and * ending before @a end. @@ -716,13 +741,6 @@ // find methods -inline const char *find(const char *begin, const char *end, char c) -{ - while (begin < end && *begin != c) - begin++; - return begin; -} - inline const char *rfind(const char *begin, const char *end, char c) { for (const char *bb = end - 1; bb >= begin; bb--) Index: rna/lib/confparse.cc diff -u rna/lib/confparse.cc:1.1.1.1 rna/lib/confparse.cc:1.2 --- rna/lib/confparse.cc:1.1.1.1 Fri Jun 27 10:36:41 2008 +++ rna/lib/confparse.cc Fri Jun 27 12:17:51 2008 @@ -921,7 +921,7 @@ bool cp_file_offset(const String &str, off_t *return_value) { -# if SIZEOF_OFF_T == 4 +# if ((SIZEOF_OFF_T == 4) || !defined(HAVE_INT64_TYPES)) return cp_unsigned(str, reinterpret_cast(return_value)); # elif SIZEOF_OFF_T == 8 return cp_unsigned(str, reinterpret_cast(return_value)); Index: rna/lib/element.cc diff -u rna/lib/element.cc:1.1.1.1 rna/lib/element.cc:1.3 --- rna/lib/element.cc:1.1.1.1 Fri Jun 27 10:36:41 2008 +++ rna/lib/element.cc Fri Jun 27 13:03:35 2008 @@ -134,8 +134,8 @@ -# Removes all element handlers. -# Calls each element's cleanup() function in reverse configuration order, - passing a constant that specifies which configuration functions - returned successfully. + passing a constant that specifies which of that element's configuration + functions were called and returned successfully. -# Deletes each element. This step might be delayed relative to cleanup() to allow the programmer to examine an erroneous router's state. @@ -340,15 +340,24 @@ int Element::set_nports(int new_ninputs, int new_noutputs) { + + // click_chatter("Element::set_nports [%s,%d] Entering \n", class_name(), eindex()); + // exit on bad counts, or if already initialized if (new_ninputs < 0 || new_noutputs < 0) return -EINVAL; + if (_router && _router->_have_connections) { +#ifndef RNA + // This section of the code had to be disabled because the + // reorganization is happening on the fly. there might be more + // cleaner ways of doing this! if (_router->_state >= Router::ROUTER_PREINITIALIZE) return -EBUSY; +#endif _router->_have_connections = false; } - + // decide if inputs & outputs were inlined bool old_in_inline = (_ports[0] == _inline_ports); @@ -368,6 +377,10 @@ || (new_noutputs <= INLINE_PORTS && !new_in_inline)); // create new port arrays + + //click_chatter("Element::set_nports [%s,%d] Allocating new ports + //(%d,%d) \n", class_name(), eindex(), new_ninputs, new_noutputs); + Port *new_inputs = (new_in_inline ? _inline_ports : new Port[new_ninputs]); if (!new_inputs) // out of memory -- return @@ -497,7 +510,7 @@ notify_noutputs(noutputs); return 0; } - + const char *s = s_in, *ends = s + strlen(s); int ninlo, ninhi, noutlo, nouthi, equal = 0; @@ -598,12 +611,16 @@ for (int i = 0; i < ninputs(); i++) { // allowed iff in_v[i] == VPULL int port = (in_v[i] == VPULL ? 0 : -1); + //click_chatter("Element::initialize_ports inputs [%s, %d] Calling Port(%d)\n", + // class_name(), eindex(), i); _ports[0][i] = Port(this, 0, port); } for (int o = 0; o < noutputs(); o++) { // allowed iff out_v[o] != VPULL int port = (out_v[o] == VPULL ? -1 : 0); + //click_chatter("Element::initialize_ports outputs [%s, %d] Calling Port(%d)\n", + // class_name(), eindex(), o); _ports[1][o] = Port(this, 0, port); } } @@ -611,13 +628,67 @@ int Element::connect_port(bool isoutput, int port, Element* e, int e_port) { - if (port_active(isoutput, port)) { + if (isoutput && 0) { + click_chatter("Element::connect_port [%s] [%s, %d, %d]\t\t-->" + "\t[%s, %d, %d] active = %d \n", + (isoutput ? "OUTPUT" : "INPUT"), + this->class_name(), eindex(), port, + e->class_name(), e->eindex(), e_port, + port_active(isoutput, port)); + if (port_active(isoutput, port) == 0 || 1){ + int first = ((unsigned) port < (unsigned) nports(isoutput)); + int second = _ports[isoutput][port].port(); + click_chatter("Element::connect_port [%s] first = %d, second = %d \n", + this->class_name(), first, second); + }; + }; + + if (port_active(isoutput, port)) { + //click_chatter("Element::connect_port Calling Port()\n"); _ports[isoutput][port] = Port(this, e, e_port); return 0; } else return -1; } +#ifdef RNA + +// Free up the port information within the element. +int +Element::disconnect_port_rna(bool isoutput, int port, Element* e, int e_port) +{ + if (1) + click_chatter("Element::disconnect_port_rna [%s, %d, %d]\t\t-->" + "\t[%s, %d, %d] active = %d \n", + this->class_name(), eindex(), port, + e->class_name(), e->eindex(), e_port, + port_active(isoutput, port)); + + // if (port_active(isoutput, port)) { + _ports[isoutput][port] = Port(this, 0, -1); + return 0; + //} else + //return -1; +}; + +int +Element::connect_port_rna(bool isoutput, int port, Element* e, int e_port) +{ + if (isoutput) + click_chatter("Element::connect_port [%s, %d, %d]\t\t-->\t" + "[%s, %d, %d] active = %d \n", + this->class_name(), eindex(), port, + e->class_name(), e->eindex(), e_port, + port_active(isoutput, port)); + + // if (port_active(isoutput, port)) { + if (isoutput) + _ports[isoutput][port] = Port(this, e, e_port); + return 0; + // } else + // return -1; +} +#endif // FLOW @@ -2136,7 +2207,7 @@ * @endcode * * An element that implements its processing with simple_action() should have - * a processing() code like #AGNOSTIC or "a/ah", and a flow_code() like + * a processing() code like AGNOSTIC or "a/ah", and a flow_code() like * COMPLETE_FLOW or "x/x" indicating that packets can flow between the first * input and the first output. * @@ -2156,8 +2227,29 @@ * @return true if the task accomplished some meaningful work, false otherwise * * The Task(Element *) constructor creates a Task object that calls this - * method when it fires. Most elements that have tasks use this method. The - * default implementation causes an assertion failure. + * method when it fires. Most elements that have tasks use this method. + * + * @note The default implementation calls the deprecated run_timer() method + * (the one with no parameters). In future, the default implementation will + * cause an assertion failure. + */ +bool +Element::run_task(Task *) +{ + return run_task(); +} + +/** @brief Called to run an element's task (deprecated). + * + * @return true if the task accomplished some meaningful work, false otherwise + * + * @deprecated This method is deprecated. Elements should override the + * run_task(Task *) function instead, which can differentiate between + * multiple Task objects. + * + * The Task(Element *) constructor creates a Task object that calls this + * method (via Element::run_task(Task *)) when it fires. The default + * implementation causes an assertion failure. */ bool Element::run_task() Index: rna/lib/router.cc diff -u rna/lib/router.cc:1.1.1.1 rna/lib/router.cc:1.2 --- rna/lib/router.cc:1.1.1.1 Fri Jun 27 10:36:41 2008 +++ rna/lib/router.cc Fri Jun 27 12:17:51 2008 @@ -140,7 +140,8 @@ while (1) { int got = -1; String n = prefix + name; - for (int i = 0; i < _elements.size(); i++) + + for (int i = 0; i < _elements.size(); i++){ if (_element_names[i] == n) { if (got >= 0) { if (errh) errh->error("more than one element named '%s'", n.c_str()); @@ -148,6 +149,7 @@ } else got = i; } + } if (got >= 0) return _elements[got]; if (!prefix) @@ -166,7 +168,7 @@ Router::find(const String &name, Element *context, ErrorHandler *errh) const { String prefix = ename(context->eindex()); - int slash = prefix.find_right('/'); + int slash = prefix.find_right('/'); return find(name, (slash >= 0 ? prefix.substring(0, slash + 1) : String()), errh); } @@ -259,8 +261,13 @@ Router::add_connection(int from_idx, int from_port, int to_idx, int to_port) { assert(from_idx >= 0 && from_port >= 0 && to_idx >= 0 && to_port >= 0); + +#ifndef RNA + // This prevents runtime reconfiguration of the router. So has + // been disabled. - Venkata Sep 2007 if (_state != ROUTER_NEW) return -1; +#endif Hookup hfrom(from_idx, from_port); Hookup hto(to_idx, to_port); // only add new connections @@ -576,9 +583,16 @@ if (errh->nerrors() != before) return -1; + + for (int e = 0; e < nelements(); e++){ + + //click_chatter("[Router::check_push_and_pull] [%s,%d] Calling + //initialize ports here \n", _elements[e]->class_name(), + //_elements[e]->eindex()); - for (int e = 0; e < nelements(); e++) _elements[e]->initialize_ports(input_pers.begin() + _gports[0].e2g[e], output_pers.begin() + _gports[1].e2g[e]); + + }; return 0; } @@ -657,13 +671,21 @@ make_hookup_gports(); int nresult = ngports(!forward); int nsource = ngports(forward); - + Bitvector old_results(nresult, false); results.assign(nresult, false); Bitvector diff, scratch; + if (0) printf("%s->nports(%s) = %d ; nresult = %d, nsource = %d\n", + first_element->class_name(), + (forward ? "forward" : "backward"), + first_element->nports(forward), nresult, nsource); + Bitvector source(nsource, false); int first_gport = _gports[forward].e2g[first_element->eindex()]; + if (0) printf("first_gport = %d, first_port = %d \n", + first_gport, first_port); + if (first_port < 0) for (int i = 0; i < first_element->nports(forward); i++) source[first_gport + i] = true; @@ -671,14 +693,22 @@ source[first_gport + first_port] = true; while (true) { + if (0) printf("Another iteration \n"); + old_results = results; - for (const int* gfrom = _hookup_gports[forward].begin(); gfrom < _hookup_gports[forward].end(); gfrom++) + for (const int* gfrom = _hookup_gports[forward].begin(); gfrom < _hookup_gports[forward].end(); gfrom++){ + + if (0) printf("Looking at gfrom = %d ", *gfrom); + if (source[*gfrom]) { int i = gfrom - _hookup_gports[forward].begin(); + if (0) printf(" Selected...i = %d \n", i); results[_hookup_gports[!forward][i]] = true; + } else { + if (0) printf("\n"); } - + } diff = results - old_results; if (diff.zero()) break; @@ -793,6 +823,83 @@ _elements[i]->add_handlers(); } +#ifdef RNA + +// This enables runtime disconnection between modules. +int +Router::disconnect_rna(Element *from_e, int from_port, Element *to_e, int to_port){ + + if (!from_e || !to_e) + return -1; + + int from_idx = from_e->eindex(); + int to_idx = to_e->eindex(); + + // Deallocate the ports corresponding to this link in the individual + // elements. + int found_c = -1; + for (int c = 0; c < _hookup_from.size(); c++) { + Hookup& hfrom = _hookup_from[c]; + Hookup& hto = _hookup_to[c]; + + if (hfrom.idx == from_idx && + hfrom.port == from_port && + hto.idx == to_idx && + hto.port == to_port) { + + found_c = c; + + from_e->disconnect_port_rna(true, hfrom.port, to_e, hto.port); + to_e->disconnect_port_rna(false, hto.port, from_e, hfrom.port); + break; + + }; + }; + + // Delete the hookup entry as well. + if (found_c >= 0) { + _hookup_from[found_c] = _hookup_from.back(); + _hookup_from.pop_back(); + _hookup_to[found_c] = _hookup_to.back(); + _hookup_to.pop_back(); + }; + + + return 0; +}; + +void +Router::set_connections_rna() +{ + // actually assign ports + for (int c = 0; c < _hookup_from.size(); c++) { + Hookup& hfrom = _hookup_from[c]; + Element* frome = _elements[hfrom.idx]; + Hookup& hto = _hookup_to[c]; + Element* toe = _elements[hto.idx]; + frome->connect_port_rna(true, hfrom.port, toe, hto.port); + toe->connect_port_rna(false, hto.port, frome, hfrom.port); + } + _have_connections = true; +} + +int Router::update_connections() { + + ErrorHandler *errh = ErrorHandler::default_handler(); + + //click_chatter("Router::update_connections() \n"); + + //check_hookup_range(errh, false); + //check_hookup_completeness(errh, false); + notify_hookup_range(errh); + check_push_and_pull(errh); + make_gports(); + set_connections(); + + return 0; +}; +#endif + int Router::initialize(ErrorHandler *errh) { Index: rna/lib/routerthread.cc diff -u rna/lib/routerthread.cc:1.1.1.1 rna/lib/routerthread.cc:1.2 --- rna/lib/routerthread.cc:1.1.1.1 Fri Jun 27 10:36:42 2008 +++ rna/lib/routerthread.cc Fri Jun 27 13:03:35 2008 @@ -5,7 +5,7 @@ * * Copyright (c) 2000-2001 Massachusetts Institute of Technology * Copyright (c) 2001-2002 International Computer Science Institute - * Copyright (c) 2004-2006 Regents of the University of California + * Copyright (c) 2004-2007 Regents of the University of California * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -72,13 +72,16 @@ : Task(Task::error_hook, 0), _master(m), _id(id) #endif { -#ifndef HAVE_TASK_HEAP +#ifdef HAVE_TASK_HEAP + _pass = 0; +#else _prev = _next = _thread = this; #endif - _task_lock_waiting = 0; _pending = 0; #if CLICK_LINUXMODULE - _sleeper = 0; + _linux_task = 0; + _task_lock_waiting = 0; + spin_lock_init(&_lock); #endif #ifdef HAVE_ADAPTIVE_SCHEDULER _max_click_share = 80 * Task::MAX_UTILIZATION / 100; @@ -131,23 +134,23 @@ } inline void -RouterThread::nice_lock_tasks() +RouterThread::driver_lock_tasks() { #if CLICK_LINUXMODULE // If other people are waiting for the task lock, give them a chance to // catch it before we claim it. -# if 0 - if (_task_lock_waiting > 0 && !_greedy) { - unsigned long done_jiffies = click_jiffies() + CLICK_HZ; - while (_task_lock_waiting > 0 && click_jiffies() < done_jiffies) - /* XXX schedule() instead of spinlock? */; - } -# else for (int i = 0; _task_lock_waiting > 0 && i < 10; i++) schedule(); -# endif + spin_lock(&_lock); +#endif +} + +inline void +RouterThread::driver_unlock_tasks() +{ +#if CLICK_LINUXMODULE + spin_unlock(&_lock); #endif - lock_tasks(); } @@ -352,6 +355,11 @@ #else t->fast_unschedule(); #endif + + // 21.May.2007: Always set the current thread's pass to the current + // task's pass, to avoid problems when fast_reschedule() interacts + // with fast_schedule() (passes got out of sync). + _pass = t->_pass; t->call_hook(); @@ -384,10 +392,9 @@ { #if CLICK_LINUXMODULE // set state to interruptible early to avoid race conditions - _sleeper = current; - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); #endif - unlock_tasks(); + driver_unlock_tasks(); #if CLICK_USERLEVEL _master->run_selects(active()); @@ -400,7 +407,7 @@ } else if (active()) { short_pause: SET_STATE(S_PAUSED); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); schedule(); } else if (_id != 0) { block: @@ -422,7 +429,7 @@ if (_greedy) /* do nothing */; else if (active()) { // just schedule others for a moment - yield(curproc, NULL); + yield(curthread, NULL); } else { _sleep_ident = &_sleep_ident; // arbitrary address, != NULL tsleep(&_sleep_ident, PPAUSE, "pause", 1); @@ -432,12 +439,7 @@ # error "Compiling for unknown target." #endif - nice_lock_tasks(); - -#if CLICK_LINUXMODULE - // set state to interruptible early to avoid race conditions - _sleeper = 0; -#endif + driver_lock_tasks(); } void @@ -445,8 +447,12 @@ { const volatile int * const stopper = _master->stopper_ptr(); int iter = 0; +#if CLICK_LINUXMODULE + // this task is running the driver + _linux_task = current; +#endif - nice_lock_tasks(); + driver_lock_tasks(); #ifdef HAVE_ADAPTIVE_SCHEDULER int restride_iter = 0; @@ -528,10 +534,10 @@ #ifndef BSD_NETISRSCHED // check to see if driver is stopped - if (*stopper) { - unlock_tasks(); + if (*stopper > 0) { + driver_unlock_tasks(); bool b = _master->check_driver(); - nice_lock_tasks(); + driver_lock_tasks(); if (!b) goto finish_driver; } @@ -544,11 +550,14 @@ #endif finish_driver: - unlock_tasks(); + driver_unlock_tasks(); #ifdef HAVE_ADAPTIVE_SCHEDULER _cur_click_share = 0; #endif +#if CLICK_LINUXMODULE + _linux_task = 0; +#endif } @@ -565,16 +574,23 @@ #ifdef CLICK_BSDMODULE /* XXX MARKO */ int s = splimp(); #endif - lock_tasks(); +#if CLICK_LINUXMODULE + // this task is running the driver + _linux_task = current; + spin_lock(&_lock); +#endif Task *t = task_begin(); if (t != task_end()) { t->fast_unschedule(); t->call_hook(); } - unlock_tasks(); #ifdef CLICK_BSDMODULE /* XXX MARKO */ splx(s); #endif +#if CLICK_LINUXMODULE + spin_unlock(&_lock); + _linux_task = 0; +#endif } void