5 Moving on
Now that we are familiar with inject and the basic format of a PLAN
program, we can write more useful programs. PLAN is meant specifically for
writing programs to be used in an active network---so let us run a very
simple program that uses the active network.
5.1 Ping
The Ping program tries to reach a remote host, and once that task is
accomplished, it sends the Ack program back to the original source which
prints ``Success.''
svc print : 'a -> unit
fun ack() = print ("Success")
svc thisHostIs : host -> bool
svc getRB : void -> int
svc defaultRoute : host -> host * dev
fun ping (source, destination) =
if (thisHostIs (destination)) then
OnRemote (|ack| (), source, getRB (), defaultRoute)
else
OnRemote (|ping| (source, destination),
destination, getRB (), defaultRoute)
5.2 Understanding the program :
the OnRemote primitive
The OnRemote primitive is one of the two primitives8 provided in the language for specifying computation at a node across
the network. It takes four arguments:
- [What]
The first argument specifies what to execute at the remote node. It
must be of the form of a function call.9 Note that the arguments to the function
call will be evaluated on the machine invoking OnRemote, while the
function will be evaluated on the remote machine.
- Where
-
The second argument specifies where to execute the packet
next. Note that the packet may go through many other
active nodes in the process of getting to the specified host, but it
will not be executed at any intermediate nodes.
- [How much]
The third argument specifies how much of the current packet's
resources to give to the outgoing packet.
- [How to]
The fourth argument specifies which routing function to use to
get to the remote host.
The other network primitive provided is OnNeighbor. It requires that
the second argument be adjacent to the current host; adjacency is
defined in terms of the underlying link layer. When PLAN is running on top
of IP, adjacency is defined by neighbors specified for each virtual IP
device in the interface specification file. In our example in
Section 3.1, interface file m1 specifies that m:3324
is adjacent to m:3325
. When PLAN is running on
top of Ethernet, two nodes are adjacent if they are on the same Ethernet.
When two nodes are adjacent, no routing function is required, since routing
is only necessary between physical networks. Instead, OnNeighbor needs the
network interface through which to send the packet (which is of PLAN type
dev).
The program consists of two function definitions. The first function, called
ack simply prints ``Success.'' The second function, ping, is
more interesting. It takes two arguments of type host and returns a
unit result. The arguments name the source and destination10 of the computation. The
body of the function first checks to see if the packet has arrived at the
destination (the thisHostIs call). If so, it sends the ack function
back to the source where ``Success'' will be printed. Otherwise, the
function resends itself towards the destination. Both of these actions make
use of the OnRemote primitive, and in both cases give all of current
resources to the outgoing packet, and specify defaultRoute as the
routing function to use.
5.3 Run this program
We'll use inject again, and we'll use the active network we set up at
the end of Section 3, so our two nodes are m:3324 and
m:3325. Suppose that you want to ping m:3325 from m:3324. The ping
program may be found in the file rout_tests/ping.plan. We'll give
this program a resource bound of 60 (will be explained later).
Then you invoke the program (from the plan directory) by the following :
% bin/inject -p 3324 rout_tests/ping.plan 60
And the initial invocation would be :
ping (getHostByName ("m:3324"), getHostByName ("m:3325"))
Notice that inject just provides a way from doing an OnRemote from the
shell: the initial invocation specifies the first argument to OnRemote, the
second and fourth arguments are specified with -ed
and -rf
options, and the third argument is specified by the RB.
Recall the initial invocation for the Hello World program -- simply the
function call doit(). Here, the initial invocation is a bit more
complex. We first specify that we want to execute the ping function
when we reach our injection node, and then we specify the arguments to give
to that function. Here, the first two arguments are themselves function
calls. The interesting thing is that these arguments are evaluated immediately before being sent to the injection point. Therefore, the getHostByName function is executed locally, in the inject program, in
order to resolve hostnames into PLAN values of type host. It is these
PLAN values that are actually sent in the PLAN packet. getHostByName
is one of a number of local services that are made available to
programs using inject. These local service calls may only appear, and
will only be evaluated, in the initial invocation provided to inject.
For a complete list of local services, please refer to the PLAN Programmer's
Guide [5]. Here, getHostByName looks up the name of the
machine that you gave it, m, in the DNS table and retrieves the address
for that machine which is then coupled with the provided port number to
complete the virtual address of the node (having PLAN type host).
After typing this in, you should see a message on your screen :
Success