Hi all,
First of all, let me start by stating that I am very impressed with the work of the Serval Project and the Serval app. I appreciate that it is still under development, but having experimented on several Android phones I have found it really easy to use and effective.
My name is Fraser Cadger and I am a third year PhD student at the University of Ulster in Northern Ireland. My project is concerned with developing a framework to allow the streaming of multimedia content both live (i.e. video call) and on-demand (recorded videos) in disaster recovery scenarios using a mesh network of WiFi-enabled devices (currently this entails a testbed of six Android phones). As I am working with Android devices this obviously adds a layer of difficult when trying to implement ad-hoc networking. After doing some searching I came across several different implementations of ad-hoc routing on Android, and after some experimentation the two I was most interested in were Serval and Commotion (who I believe the Serval Project collaborates with). In the end I decided to work with the Serval app because I felt that was the closest to what I was doing, and I also liked how it worked on the phones.
Currently what I am interested in doing is implementing my own routing protocol (which is still under development) on the phones using Serval as a base. That is to say, that I want to replace the modified BATMAN code Serval uses for routing with the current version of my routing algorithm (originally written in C++ for ns-2 but re-writing in C should not be a huge problem). Obviously I realise this will not be a simple as copying and pasting my code in and that is why I am sending this message. From reading various comments in the code I understand that one of the main modifications to Serval is to restrict broadcasting to link-local nodes (i.e. not network-wide broadcasting), if I have understand the code correctly that is. The protocol I am developing is a variation of the greedy routing protocol GPSR http://www0.cs.ucl.ac.uk/staff/b.karp/gpsr/gpsr.html . Both the original GPSR and my own protocol use limited broadcasting as well; beacon (regular hello messages) are broadcast as far as one hop and nodes maintain tables of neighbours who can be reached directly only. There is no conventional collection of routes; instead each node forwards a packet to their neighbour who best meets the criterion/criteria (generally geographic location, i.e. located closest to the destination) one hop at a time. So packets are effectively passed from node to node without a formal route existing. This version of geographic routing is not perfect, and that is why we are working on several modifications, but for now I am content to have some form of working geographic routing up and running.
I have been reading through the code and trying to determine what parts I need to change and where to add my code. What I am looking for is the point at which a node determines where to send a packet. I realise that this will vary depending on the packet's origin, that is to say that when a node generates a new packet it will usually be treated differently from when an intermediate node receives a packet from another node. Now, if I understand correctly Serval's version of BATMAN does not use an explicit routing table structure. I have came across a struct called subscriber defined in overlay_address.h, and from what I have read this seems to act as a record of different nodes (destinations). Within the subscriber struct there is an integer variable called reachable and this determines whether a node is reachable directly via unicast, broadcast, or must be reached indirectly. If a node must be reached indirectly then there is a field called next_hop which if I understand correctly is a pointer to another struct (the intermediate node between ourselves and the destination). Is this correct? Now, what I have noticed in the code is that sometimes next_hop contains a pointer to another next_hop (i.e. next_hop->next_hop). What I'm guessing this means is that if there are multiple intermediate nodes (i.e. to send a packet to node D node A needs to send it via B and C), then this is a way of linking them as a route. So in essence, the subscriber struct contains the route to a destination (by way of the next_hop attribute).
For the actual routing, from reading the code I'm guessing that the 'overlay_route_recalc_node_metrics' function is used to determine whether a destination can be reached directly or indirectly, and if indirectly it will then assign the appropriate intermediate nodes as next_hop's. Therefore, to create or change a route this function is called. Is this correct?
In my case, I would like to do things slightly differently. As I am not doing end-to-end routing I do not need a list of destinations, instead all I want is a list of 1-hop neighbours who can be accessed directly. Then from that list I would determine which of these is the most suitable as the next hop (obviously in my case this will require other stuff, for instance adding GPS coordinates to the packet header and storing this in the subscriber field) and forward the packet to that node, and so on until the packet has been delivered (or has to be dropped).
The main questions I have are:
Exactly where is a packet received and the node to which it should be sent decided?
i.e. if I want to decide which node to forward a packet to where should I decide this?
I came across a method called 'overlay_mdp_receive' in mdp_client.c, is this maybe what I'm looking for?
Concerning the subscriber entity, is there an actual table/list/array of these – as I can't seem to find one?
i.e. a list of neighbours/known nodes/destinations?
I apologise if my questions and this email aren't very well-worded. Essentially what I'm looking for is some advice/guidance on exactly how routing (determining intermediate nodes for nodes which cannot be reached directly) and forwarding (looking at a received/originated packet and determining which node to send it to) is done. As I indicated earlier in this message, there are a few functions/structs I have stumbled across that I think are relevant and I have made some guesses at what they are doing, so I would appreciate if someone could correct/expand on my guesses.
Any help/guidance I have would be greatly appreciated. It goes without saying that any code I develop myself I will happily share, and any issues/bugs I come across with Serval will be reported.
Thank you for taking the time to read this message, I'm sorry it's a bit on the long side but hopefully I've made myself clear.
Regards,
Fraser
Ps. I realise this topic has been covered before, but I think some of the questions I am asking in this message are new.
Paul,
Thank you very much for your fast reply!
Your suggestion of using Rhizome instead of the MDP overlay is interesting, and definitely worth considering. Although I read a little about Rhizome on the Serval website I don't think I really appreciated it's capabilities. Also, when I installed the release version of Serval from Google Play, selecting Rhizome didn't appear to do anything (I'm not sure if this was an error or because the Rhizome could wasn't fully functioning then). Therefore, when I came to read the Serval code I decided to skip the Rhizome code to save time.
Now it would seem as though this was a mistake, and your description of Rhizome in particular the journal concept sounds very interesting. I have been considering implementing some for of peer-to-peer/distributed approach for the actual streaming, due to the distribute nature of an ad-hoc/mesh network. In the envisaged networks node mobility will be permissible and this in addition to other dynamics calls for distributed approaches. The journal concept could be of great use here, with some tweaking as you mention. Using the p2p idea, I would envisage some form of peer/node selection for participation in the streaming, and then the use of my routing protocol to do the actual protocol. However, I have always intended interaction between the streaming application and routing layers, and so it is possible that the end result will lack the formal separation between overlay and 'underlay' routing found in traditional applications.
I also like your suggestion of using Serval Maps for sharing location. In most geographic routing protocols there is something known as a location service which acts as a mechanism for sharing node locations so that nodes who are not in direct contact with each other can still find their locations. Initially, to test geographic routing, I was just planning on running five phones in a static scenario and checking locations manually, just to test geographic routing was possible. However, as my project is actually concerned with mobility I will eventually need to find a way of allowing nodes to share their locations. The visual aspect of Serval Maps also sounds appealing for, as you say, choosing which nodes you want to see a video. Having a graphical means of selecting nodes for streaming is definitely something we would like.
One last question, I've had a quick look through the Serval code, and am I right in saying all of the Rhizome code is located in the serval-dna folder, or is there other Rhizome code elsewhere?
About contributing code, I am happy to do that via the repository.
Thanks again for your reply.
Fraser
Jeremy,
Thank you for your fast response.
Just to clarify, when you say that the payloads are almost always broadcast packets, does this mean that all data routing is done via broadcasting? So that when a call is being made, all of the VoIP packets are broadcast? None of them are unicast or delivered via multi-hop intermediate nodes? Apologies if I have misunderstood this. If that is the case, then is this a network-wide broadcast? I would assume this is quite traffic intensive, especially if more than one call is taking place at the same time? If it is restricted broadcast, then how are packets delivered to nodes located further away?
I actually looked at overlay_stuff_packet(), and I meant to ask about this, as I wasn't too sure about why it only covered broadcast traffic. However, if what I posted above is correct and all data is broadcast then that would make sense.
I will have a look at the methods/files you pointed out, although I have read through most of them there were obviously certain aspects I missed. Now that you've pointed me in the right direction, I will look again and things should become clearer.
With regards to the mdp_client_recv() function, to confirm when you talk about passing messages between daemons you mean on the same node and not actually sending messages between devices.
Thanks again,
Fraser
I would recommend you keep the existing messages and formats, and add
> However, what seems a bit more complicated is implementing the beaconing
> messages. I can see two ways of doing this; keep the current Serval system
> of self announcements, self announcement acks, and node announcements and
> simply add locations to these messages. The other would be to get rid of
> node announcements, and just use self announcement and self announcement
> acks to transmit location information between directly connected nodes.
new message types that are sent at the same time, in the same packet.
Firstly, if the existing messages change, you don't need to maintain
your forked version. Secondly, network nodes that aren't implementing
your routing protocol will still be able to communicate in other ways.
Hi Fraser,
It is great to see the depth of your explorations and thinking on all
this; most refreshing.
I am sure that Jeremy will have more input, but a few things that come to mind:
1. Using location-enabled routing is desirable, but there may be
instances where people don't want their location to be advertised, and
so whatever solution you create needs to be compatible with
non-location-based routing if it is to eventually end up in the Serval
source. I don't see this as a big problem, but it is probably
sensible to think about how you implement your schemes with that in
mind. For example, it probably suggests adding location as an
optional element to the self-announcement packets rather than doing
away with the self-announcement packets.
2. The local maxima / routing loop problem can be done away with if
you are performing directed routing of Rhizome bundles. This means
that simple greedy geographic routing can probably be fairly well
applied to Rhizome to help push bundles in the right direction, but
relying on the Rhizome semantics that mean that it is not a problem if
a bundle is offered to a node that has already seen it. Similarly,
bundles will "leak" out of peninsulas by the normal "brownian motion"
of undirected Rhizome manifest announcements. Thus there might end up
being two geographic routing schemes; one for Rhizome that is simpler,
and one for MDP traffic that is more complex.
I would add a "command line" function that sends an mdp frame to the
> As for getting the coordinates into servald, this could be slightly tricky
> but I don't think impossible. Although Android does not provide a C library
> which will allow NDK code to directly access the GPS device there have been
> several successful attempts at doing this. One possible approach would be to
> write a C wrapper for using the Android Locationmanager library, another
> could be to pass messages between the Java portion of Serval and the C
> portion, while a more convoluted (and probably slower) approach would be for
> the Java part to write GPS locations to a text file which would then be read
> by servald.
daemon. This can easily be called from Java as we already have a jni
wrapper on this interface.
The biggest reasons?
> This makes sense. Although I'm obviously aware that Serval places its own
> packets inside an UDP packet for the actual transmission, I somehow keep
> treating these packets as though they are independent packs being unicast.
> That is why I didn't consider the possibility of creating my own type of
> broadcast packet and sending it alongside the existing packets. I'm curious
> though, would it not make more sense to just add fields for coordinates to
> the existing packets? I would only need two fields, one for longitude and
> another for latitude so they shouldn't take up too much space. The only
> downside I could see to this is if the packet format change considerably (as
> you mention), but if I am only adding two new fields would I really need a
> new packet type?
Encapsulation - keep all of your new code as separate as possible from
everything else. As I've said before, I want to experiment with other
kinds of routing engines. We could potentially run more than one path
discovery process at the same time while evaluating them.
Maintenance - it will be easier to merge our latest version if you
only need to insert a couple of method calls here and there.
Compatibility - will your new payload format break nodes running older
or newer versions of the software?
Hi everyone,
It's been a wee while since my last post, but I was quite busy over the last couple of weeks and am only just turning my attention back to working with Serval.
Ok, so I've had a think about how best to implement location update message (which I'll refer to as beacons), without modifying the existing message structures. My initial thought was to create a struct called beacon (or similar) which would contain all of the fields (initially our address, and the longitude and latitude coordinates + the timestamp of when the coordinates were recorded) and when we were sending a beacon we would create an instance of this struct. The downside I thought would be that the beacon struct would have to be embedded in another packet as a payload, and so this would mean modifying existing messages (not good) or creating a new message and adding the struct as a payload which seems wasteful. So at this point I can't see any advantages in using the struct (except possibly as a template).
Instead I thought an approach similar to the node announcements could be used. A function called overlay_add_beacon() (for instance) could be called from overlay_init_packet(). The purpose of this would be to create the beacon message, it would be similar in form to overlay_route_add_advertisement(). So it would call call overlay_frame_build_header() to create the frame and then it would need to place the coordinates in the packet. I think the best way to do this would be to use a similar method to add_advertisement() which uses ob_append_byte() to add the best link score and observations to the packet, and before that overlay_address_append to add the address of the node we are advertising. However, if we are sending beacons for ourself then we do not need to append a subscriber address as the packet is obviously about us. Similarly, add_advertisement() is accessed by calling the callback function enum_subscribers() which is used to find the next (unadvertised) subscriber in the tree and the use of enum_subscribers() is obviously not necessary for sending messages about ourselves.
Therefore, I was thinking that two types of beacons would be better; i.e. self_beacon and subscriber_beacon. self_beacon would be similar to a self announce message while subscriber_beacon would be similar to a node announcement. This would entail slight differences in how they were sent. self_beacon could have a method called overlay_add_self_beacon() which function similarly to overlay_add_selfannouncement() except instead of calling ob_append_ui32() to add timestamps it would call ob_append_byte() twice as described above, to add the two coordinates and timestamp (or would it make more sense to use ob_append_ui32 for this timestamp?) . However it would not call overlay_address_append. On the other hand, subscriber_beacon would have a method called (for instance) add_subscriber_beacon() that would function identically to overlay_route_add_advertisement(), and would call enum_subscribers() as a callback to a function called add_beacon() which would be similar to add_advertisement() except that it would call ob_append_byte to add coordinates (instead of score and observation), then append the timestamp but would still use overlay_append_byte() to add the address.
Both overlay_add_self_beacon() and add_subscriber_beacon() would be called from overlay_init_packet() inside overlay_queue.c; with overlay_add_self_beacon() being called after overlay_add_selfannouncement() and add_subscriber_beacon() being called after overlay_route_add_advertisements() is called. Hopefully I'm right in thinking that doing this will mean that the self_beacon messages will go along with the self_announcement messages and the subscriber_beacon messages will be along with the corresponding node_advertisement messages for the same subscriber in the one real packet. Even if they are 'separated' (i.e. we receive a subscriber_beacon without a node_advertisement for the same subscriber) I could probably still handle it (i.e. search for that subscriber).
Other than the above, I think the only other step needed for using the self_beacon and subscriber_beacon messages would be to add them to constants.h. Actually, I'm wondering what numbers to use, I noticed 0x10 to 0x70 are taken by existing messages. Should I just use the next numbers up (0x80 and 0x90), or are there any plans by the Serval team to use those? I'm assuming these numbers are hex numbers, and as type is an integer number constants.h maps the message type i.e. OF_TYPE_SELF_ANNOUNCE to its corresponding hex number?
There might have been a couple of things I've misunderstood in the above, but I think the general approach I described should allow for me to add the beacon messages without causing any conflicts with devices running different versions or their own routing. Hopefully doing it the way I described above would mean that such devices would just ignore my beacon messages as they wouldn't recognise the codes for them and there would be no complications.
I intend to start the coding soon, but I'm just thought I'd check to see if my assumptions are correct and if other people think the way of doing this makes sense before I jump in. I've not mentioned anything about dealing with the beacons once they've been received, as I've mainly been focussing on sending them first. However, I imagine this would involve updating either the subscriber or node entity for that device to change location. I'll look into this in more detail while I'm working on sending the beacons.
Thanks,
Fraser