mirror of https://github.com/tLDP/LDP
1518 lines
70 KiB
Plaintext
1518 lines
70 KiB
Plaintext
<!doctype linuxdoc system>
|
||
<article>
|
||
<title>Multicast over TCP/IP HOWTO
|
||
<author>Juan-Mariano de Goyeneche <tt><jmseyas@dit.upm.es></tt>
|
||
<date>v1.0, 20 March 1998
|
||
<abstract>
|
||
This HOWTO tries to cover most aspects related to multicast over TCP/IP
|
||
networks. So, a lot of information within it is not Linux-specific (just in
|
||
case you don't use GNU/Linux... yet). Multicast is currently an active area
|
||
of research and, at the time of writing, many of the "standards" are merely
|
||
drafts. Keep it in mind while reading the lines that follow.
|
||
</abstract>
|
||
|
||
|
||
|
||
<toc>
|
||
|
||
|
||
<sect>Introduction.
|
||
|
||
<p>I'll try to give here the most wide range, up to date and accurate
|
||
information related to multicasting over TCP/IP networks that I can. Any
|
||
feedback is very welcome. If you find any
|
||
mistakes in this document, have any comments about its contents or an update or
|
||
addition, please send them to me at the address listed at the top of this howto.
|
||
|
||
|
||
<sect1>What is Multicast.
|
||
|
||
<p>Multicast is... a need. Well, at least in some scenarios. If you
|
||
have information (a <em/lot/ of information, usually) that should be
|
||
transmitted to various (but usually not <em/all/) hosts over an internet,
|
||
then Multicast is the answer. One common situation in which
|
||
it is used is when distributing real time audio and video to the
|
||
set of hosts which have joined a distributed conference.
|
||
|
||
Multicast is much like radio or TV in the sense that only those who
|
||
have tuned their receivers (by selecting a particular frequency
|
||
they are interested on) receive the information. That is:
|
||
you hear the channel you are interested in, but not the others.
|
||
|
||
|
||
<sect1>The problem with Unicast.
|
||
|
||
<p>Unicast is anything that is not broadcast nor multicast. All right,
|
||
the definition
|
||
is not very bright... When you send a packet and there is only one
|
||
sender process -yours- and one recipient process (the <em/one/ you are
|
||
sending the packet to), then this is unicast. TCP is, by its own nature,
|
||
unicast oriented. UDP supports a lot more paradigms, but if you are
|
||
sending UDP packets and there is only one precess supposed to receive
|
||
them, this is unicast too.
|
||
|
||
For years unicast transmissions proved to be enough for the Internet.
|
||
It was not until 1993 when the first implementation of multicast saw
|
||
the light in the 4.4 BSD release. It seems nobody needed it until
|
||
then. Which were those new problems that multicast addressed?
|
||
|
||
Needless to say that the Internet has changed a lot since the "early
|
||
days". Particularly, the appearance of the Web strongly transformed
|
||
the situation: people didn't just want connections to remote hosts,
|
||
mail and FTP. First they wanted to see the pictures people placed in
|
||
their home pages, but later they also wanted to <em/see/ and <em/hear/
|
||
that people.
|
||
|
||
With today's technology it is possible to afford the "cost" of making
|
||
a unicast connection with everyone who wants to see your web page.
|
||
However, if you are to send audio and video, which needs a <em/huge/
|
||
amount of bandwidth compared with web applications, you have -you <em/had/,
|
||
until multicast came into scene- two options: to establish a separate
|
||
unicast connection with <em/each/ of the recipients, or to use broadcast.
|
||
The first solution is not affordable: if we said that a <em/single/
|
||
connection sending audio/video consumes a huge bandwidth, imagine
|
||
having to establish hundreds or, may be, thousands of those connections.
|
||
Both the sending computer and your network would collapse.
|
||
|
||
Broadcast seems to be <em/a/ solution, but it's not certainly <em/the/ solution.
|
||
If you want all the hosts in your LAN to attend the conference, you
|
||
may use broadcast. Packets will be sent only once and every host will
|
||
receive them as they are sent to the broadcast address. The problem
|
||
is that perhaps only a <em/few/ of the hosts and not <em/all/ are interested
|
||
in those packets. Furthermore: perhaps some hosts are really interested
|
||
in your conference, but they are outside of your LAN, a few routers away.
|
||
And you know that broadcast works fine inside a LAN, but problems arise
|
||
when you want broadcast packets to be routed across different LANs.
|
||
|
||
The best solution seems to be one in which you send packets to a certain
|
||
special address (a certain frequency in radio/TV transmissions). Then,
|
||
all hosts which have decided to join the conference will be aware of
|
||
packets with that destination address, read them when they traverse
|
||
the network, and pass them to the IP layer to be demultiplexed. This is
|
||
similar to broadcasting in that you send only one broadcast packet and
|
||
all the hosts in the network recognize and read it; it differs, however,
|
||
in that not all multicast packets are read and processed, but only those
|
||
that were previously registered in the kernel as being "of interest".
|
||
|
||
Those special packets are routed at kernel level like any packet because
|
||
they <em/are/ IP packets. The only difference might reside in the routing
|
||
algorithm which tells the kernel where to route or not to route them.
|
||
|
||
|
||
|
||
<sect>Multicast Explained.
|
||
|
||
|
||
<sect1>Multicast addresses.
|
||
|
||
<p>As you probably know, the range of IP addresses is divided into "classes"
|
||
based on the high order bits of a 32 bits IP address:
|
||
|
||
<code>
|
||
Bit --> 0 31 Address Range:
|
||
+-+----------------------------+
|
||
|0| Class A Address | 0.0.0.0 - 127.255.255.255
|
||
+-+----------------------------+
|
||
+-+-+--------------------------+
|
||
|1 0| Class B Address | 128.0.0.0 - 191.255.255.255
|
||
+-+-+--------------------------+
|
||
+-+-+-+------------------------+
|
||
|1 1 0| Class C Address | 192.0.0.0 - 223.255.255.255
|
||
+-+-+-+------------------------+
|
||
+-+-+-+-+----------------------+
|
||
|1 1 1 0| MULTICAST Address | 224.0.0.0 - 239.255.255.255
|
||
+-+-+-+-+----------------------+
|
||
+-+-+-+-+-+--------------------+
|
||
|1 1 1 1 0| Reserved | 240.0.0.0 - 247.255.255.255
|
||
+-+-+-+-+-+--------------------+
|
||
</code>
|
||
|
||
The one which concerns us is the "Class D Address". Every IP datagram whose
|
||
destination address starts with "1110" is an IP Multicast datagram.
|
||
|
||
The remaining 28 bits identify the multicast "<em/group/" the datagram is sent
|
||
to. Following with the previous analogy, you have to tune your radio
|
||
to hear a program that is transmitted at some specific frequency, in the
|
||
same way you have to "tune" your kernel to receive packets sent to an
|
||
specific multicast group. When you do that, it's said that the host has
|
||
<em/joined/ that group in the interface you specified. More on this later.
|
||
|
||
There are some special multicast groups, say "well known multicast
|
||
groups", you should not use in your particular applications due the
|
||
special purpose they are destined to:
|
||
|
||
<itemize>
|
||
<item> 224.0.0.1 is the <em/all-hosts/ group. If you ping that group, all
|
||
multicast capable hosts on the network should answer, as every
|
||
multicast capable host <em/must/ join that group at start-up on all
|
||
it's multicast capable interfaces.
|
||
|
||
<item> 224.0.0.2 is the <em/all-routers/ group. All multicast routers must
|
||
join that group on all it's multicast capable interfaces.
|
||
|
||
<item> 224.0.0.4 is the <em/all DVMRP routers/, 224.0.0.5 the <em/all OSPF routers/,
|
||
224.0.013 the <em/all PIM routers/, etc.
|
||
</itemize>
|
||
|
||
All this special multicast groups are regularly published in the
|
||
"Assigned Numbers" RFC.
|
||
|
||
In any case, range 224.0.0.0 through 224.0.0.255 is reserved for local
|
||
purposes (as administrative and maintenance tasks) and datagrams
|
||
destined to them are never forwarded by multicast routers. Similarly,
|
||
the range 239.0.0.0 to 239.255.255.255 has been reserved for
|
||
"administrative scoping" (see section 2.3.1 for information on
|
||
administrative scoping).
|
||
|
||
|
||
<sect1>Levels of conformance.
|
||
|
||
<p>Hosts can be in three different levels of conformance with the Multicast
|
||
specification, according to the requirements they meet.
|
||
|
||
<bf/Level 0/ is the "no support for IP Multicasting" level. Lots of hosts
|
||
and routers in the Internet are in this state, as multicast support
|
||
is not mandatory in IPv4 (it is, however, in IPv6). Not too much
|
||
explanation is needed here: hosts in this level can neither send nor receive
|
||
multicast packets. They must ignore the ones sent by other multicast
|
||
capable hosts.
|
||
|
||
<bf/Level 1/ is the "support for sending but not receiving multicast IP
|
||
datagrams" level. Thus, note that it is not necessary to join a multicast
|
||
group to be able to send datagrams to it. Very few additions are needed
|
||
in the IP module to make a "Level 0" host "Level 1-compliant", as shown in
|
||
section 2.3.
|
||
|
||
<bf/Level 2/ is the "full support for IP multicasting" level. Level 2 hosts must be
|
||
able to both send and receive multicast traffic. They must know the way
|
||
to join and leave multicast groups and to propagate this information to
|
||
multicast routers. Thus, they must include an Internet Group Management
|
||
Protocol (IGMP) implementation in their TCP/IP stack.
|
||
|
||
|
||
<sect1>Sending Multicast Datagrams.
|
||
|
||
<p>By now, it should be obvious that multicast traffic is handled at the
|
||
transport layer with UDP, as TCP provides point-to-point connections,
|
||
not feasibles for multicast traffic. (Heavy research is taking place to
|
||
define and implement new multicast-oriented transport protocols. See
|
||
section <ref id="sect-trans-prots" name="Multicast Transport Protocols">
|
||
for details).
|
||
|
||
In principle, an application just needs to open a UDP socket and fill
|
||
with a class D multicast address the destination address where it wants
|
||
to send data to.
|
||
However, there are some operations that a sending process must be able
|
||
to control.
|
||
|
||
|
||
<sect2>TTL.
|
||
|
||
<p>The TTL (Time To Live) field in the IP header has a double significance
|
||
in multicast. As always, it controls the live time of the datagram to
|
||
avoid it being looped forever due to routing errors. Routers decrement
|
||
the TTL of every datagram as it traverses from one network to another
|
||
and when its value reaches 0 the packet is dropped.
|
||
|
||
The TTL in IPv4 multicasting has also the meaning of "threshold". Its
|
||
use becomes evident with an example: suppose you set a long, bandwidth
|
||
consuming, video conference between all the hosts belonging to your
|
||
department. You want that huge amount of traffic to remain in your
|
||
LAN. Perhaps your department is big enough to have various LANs. In
|
||
that case you want those hosts belonging to each of <em/your/ LANs to
|
||
attend the conference, but in any case you want to collapse the entire
|
||
Internet with your multicast traffic. There is a need to limit how "long"
|
||
multicast traffic will expand across routers. That's what the TTL is used
|
||
for. Routers have a TTL threshold assigned to each of its interfaces,
|
||
and only datagrams with a TTL greater than the interface's threshold
|
||
are forwarded. Note that when a datagram traverses a router with a certain
|
||
threshold assigned, the datagram's TTL is <em/not/ decremented by the value
|
||
of the threshold. Only a comparison is made. (As before, the TTL is
|
||
decremented by 1 each time a datagram passes across a router).
|
||
|
||
A list of TTL thresholds and their associated scope follows:
|
||
|
||
<code>
|
||
TTL Scope
|
||
----------------------------------------------------------------------
|
||
0 Restricted to the same host. Won't be output by any interface.
|
||
1 Restricted to the same subnet. Won't be forwarded by a router.
|
||
<32 Restricted to the same site, organization or department.
|
||
<64 Restricted to the same region.
|
||
<128 Restricted to the same continent.
|
||
<255 Unrestricted in scope. Global.
|
||
</code>
|
||
|
||
Nobody knows what "site" or "region" mean exactly. It is up to the
|
||
administrators to decide what this limits apply to.
|
||
|
||
The TTL-trick is not always flexible enough for all needs, specially
|
||
when dealing with overlapping regions or trying to establish geographic,
|
||
topologic and bandwidth limits simultaneously. To solve this problems,
|
||
administratively scoped IPv4 multicast regions were established in 1994.
|
||
(see D. Meyer's "<em/Administratively Scoped IP Multicast/" Internet draft).
|
||
It does scoping based on multicast addresses rather than on
|
||
TTLs. The range 239.0.0.0 to 239.255.255.255 is reserved for this
|
||
administrative scoping.
|
||
|
||
|
||
<sect2>Loopback.
|
||
|
||
<p>When the sending host is Level 2 conformant and is also a member of
|
||
the group datagrams are being sent to, a copy is looped back by default.
|
||
This does not mean that the interface card reads its own transmission,
|
||
recognizes it as belonging to a group the interface belongs to, and reads it
|
||
from the network. On the contrary, is the IP layer which, by default, recognizes
|
||
the to-be-sent datagram and copies and queues it on the IP input queue
|
||
before sending it.
|
||
|
||
This feature is desirable in some cases, but not in others. So the sending
|
||
process can turn it on and off at wish.
|
||
|
||
|
||
<sect2>Interface selection.
|
||
|
||
<p>Hosts attached to more than one network should provide a way for
|
||
applications to decide which network interface will be used
|
||
to output the transmissions. If not specified, the kernel chooses a
|
||
default one based on system administrator's configuration.
|
||
|
||
|
||
|
||
<sect1>Receiving Multicast Datagrams.
|
||
|
||
|
||
<sect2>Joining a Multicast Group.
|
||
|
||
<p>Broadcast is (in comparison) easier to implement than multicast. It
|
||
doesn't require processes to give the kernel some rules regarding
|
||
what to do with broadcast packets. The kernel just knows what to do:
|
||
read and deliver <em/all/ of them to the proper applications.
|
||
|
||
With multicast, however, it is necessary to advise the kernel which
|
||
multicast groups we are interested in. That is, we have to ask the
|
||
kernel to "join" those multicast groups. Depending on the underlying
|
||
hardware, multicast datagrams are filtered by the hardware or by the
|
||
IP layer (and, in some cases, by both). Only those with a destination
|
||
group previously registered via a join are accepted.
|
||
|
||
Essentially, when we join a group we are telling the kernel: "OK. I
|
||
know that, by default, you ignore multicast datagrams, but remember
|
||
that I am interested in <em/this/ multicast group. So, do read and deliver
|
||
(to any process interested in them, not only to me) any datagram that
|
||
you see in this network interface with this multicast group in its
|
||
destination field".
|
||
|
||
Some considerations: first, note that you don't just join a group.
|
||
You join a group <em/on/ a particular network interface. Of course, it is
|
||
possible to join the same group on more than one interface. If you don't
|
||
specify a concrete interface, then the kernel will choose it based on its
|
||
routing tables when datagrams are to be sent. It is also possible that
|
||
more than one process joins the same multicast group on the same interface.
|
||
They will all receive the datagrams sent to that group via that interface.
|
||
|
||
As said before, any multicast-capable hosts join the <em/all-hosts/ group
|
||
at start-up , so "pinging" 224.0.0.1 returns all hosts in the network that
|
||
have multicast enabled.
|
||
|
||
Finally, consider that for a process to receive multicast datagrams
|
||
it has to ask the kernel to join the group <em/and/ bind the port those
|
||
datagrams were being sent to. The UDP
|
||
layer uses both the destination address and port to demultiplex the
|
||
packets and decide which socket(s) deliver them to.
|
||
|
||
|
||
<sect2>Leaving a Multicast Group.
|
||
|
||
<p>When a process is no longer interested in a multicast group, it informs
|
||
the kernel that <em/it/ wants to leave that group. It is important to understand
|
||
that this doesn't mean that the kernel will no longer accept multicast
|
||
datagrams destined to that multicast group. It will still do so if there are
|
||
more precesses who issued a "multicast join" petition for that group and
|
||
are still interested. In that case <em/the host/ remains member of the group,
|
||
until all the processes decide to leave the group.
|
||
|
||
Even more: if you leave the group, but remain bound to the port you were
|
||
receiving the multicast traffic on, and there are more processes that
|
||
joined the group, you will still receive the multicast transmissions.
|
||
|
||
The idea is that joining a multicast group only tells the IP and data
|
||
link layer (which in some cases explicitly tells the hardware) to accept
|
||
multicast datagrams destined to that group. It is not a per-process
|
||
membership, but a per-host membership.
|
||
|
||
|
||
<sect2>Mapping of IP Multicast Addresses to Ethernet/FDDI addresses.
|
||
|
||
<p>Both Ethernet and FDDI frames have a 48 bit destination address field.
|
||
In order to avoid a kind of multicast ARP to map multicast IP addresses
|
||
to ethernet/FDDI ones, the IANA reserved a range of addresses for multicast:
|
||
every ethernet/FDDI frame with its destination in the range 01-00-5e-00-00-00
|
||
to 01-00-5e-ff-ff-ff (hex) contains data for a multicast group. The prefix
|
||
01-00-5e identifies the frame as multicast, the next bit is always 0 and
|
||
so only 23 bits are left to the multicast address. As IP multicast groups
|
||
are 28 bits long, the mapping can not be one-to-one. Only the 23 least
|
||
significant bits of the IP multicast group are placed in the frame.
|
||
The remaining 5 high-order bits are ignored, resulting in 32 different
|
||
multicast groups being mapped to the same ethernet/FDDI address. This means
|
||
that the ethernet layer acts as an imperfect filter, and the IP layer will
|
||
have to decide whether to accept the datagrams the data-link layer passed
|
||
to it. The IP layer acts as a definitive perfect filter.
|
||
|
||
Full details on IP Multicasting over FDDI are given in RFC 1390: "<em/Transmission
|
||
of IP and ARP over FDDI Networks/". For more information on mapping IP Multicast
|
||
addresses to ethernet ones, you may consult <tt>draft-ietf-mboned-intro-multicast-03.txt</tt>:
|
||
"<em/Introduction to IP Multicast Routing/".
|
||
|
||
If you are interested in IP Multicasting over Token-Ring Local Area Networks,
|
||
see RFC 1469 for details.
|
||
|
||
|
||
|
||
<sect>Kernel requirements and configuration.
|
||
|
||
<p>Linux is, of course (you doubted it?), full Level-2 Multicast-Compliant.
|
||
It meets all requirements to send, receive and act as a router (mrouter)
|
||
for multicast datagrams.
|
||
|
||
If you want just to send and receive, you must say yes to "<em/IP: multicasting/"
|
||
when configuring your kernel. If you also want your Linux box to act as a
|
||
multicast router (mrouter) you also need to enable multicast routing in the
|
||
kernel by selecting "<em>IP: forwarding/gatewaying</em>", "<em/IP: multicast routing/"
|
||
and "<em/IP: tunneling/", the latter because new versions of <tt/mrouted/
|
||
relay on IP tunneling to send multicast datagrams encapsulated into unicast
|
||
ones. This is necessary when establishing tunnels
|
||
between multicast hosts separated by unicast-only networks and routers.
|
||
(The <tt/mrouted/ is a daemon that implements the multicast routing algorithm
|
||
-the routing policy- and instructs the kernel on how to route multicast
|
||
datagrams).
|
||
|
||
Some kernel versions label multicast routing as "<em/EXPERIMENTAL/", so you
|
||
should enable "<em>Prompt for development and/or incomplete code/drivers</em>"
|
||
in the "<em/Code maturity level options/" section.
|
||
|
||
If, when running the <tt/mrouted/, traffic generated in the same network your
|
||
Linux box is connected to is correctly forwarded to the other network, but
|
||
you can't see the other's network traffic on your local network, check
|
||
whether you are receiving ICMP protocol error messages. Almost sure
|
||
you forgot to turn on IP tunneling in your Linux router. It's a kind of
|
||
stupid error when you know it but, believe me, its quite time-consuming
|
||
when you don't, and there is no apparent reason that explains what is going
|
||
wrong. A sniffer proves to be quite useful in these situations!
|
||
|
||
(You can see more on multicast routing on section <ref id="sect-routing"
|
||
name="Routing Policies and Forwarding Techniques">; <tt/mrouted/ and
|
||
tunnels are also explained in sections <ref id="sect-mbone" name="The
|
||
MBone"> and <ref id="sect-applications" name="Multicast applications">).
|
||
|
||
Once you have compiled and installed your new kernel, you should provide
|
||
a default route for multicast traffic. The goal is to add a route to the
|
||
network 224.0.0.0.
|
||
|
||
The problem most people seem to face in this stage of the configuration
|
||
is with the value of the mask to supply. If you have read Terry Dawson's
|
||
excellent NET-3-HOWTO, it should not be difficult to guess the correct
|
||
value, though. As explained there, the netmask is a 32 bit number
|
||
filled with all-1s in the network part of your IP address, and with
|
||
all-0s in the host part. Recall from section 2.1 that a class D multicast
|
||
address has no netwok/host sections. Instead it has a 28-bit group
|
||
identifier and a 4-bit class D identifier. Well, this 4 bits are the
|
||
network part and the remaining 28 the host part. So the netmask needed
|
||
is 11110000000000000000000000000000 or, easier to read: 240.0.0.0.
|
||
Then, the full command should be:
|
||
<tscreen><verb>
|
||
route add 224.0.0.0 netmask 240.0.0.0 dev eth0
|
||
</verb></tscreen>
|
||
|
||
Depending on how old your <tt/route/ program is, you might need to add
|
||
the <tt/-net/ flag after the <tt/add/.
|
||
|
||
Here we supposed that <tt/eth0/ was multicast-capable and that, when not
|
||
otherwise specified, we wanted multicast traffic to be output there.
|
||
If this is not your case, change the <tt/dev/ parameter as appropriate.
|
||
|
||
The <tt>/proc</tt> filesystem proves here to be useful once again: you
|
||
can check <tt>/proc/net/igmp</tt> to see the groups your host is
|
||
currently subscribed to.
|
||
|
||
|
||
|
||
<sect>The MBone.<label id="sect-mbone">
|
||
|
||
<p>Using a new technology usually carries some advantages and disadvantages.
|
||
The advantages of multicast are -I think- clear. The main disadvantage is
|
||
that hundreds of hosts and, specially, routers don't support it yet. As a
|
||
consequence, people who started working on multicast, bought new equipment,
|
||
modified their operating systems, and built <em/multicast islands/ in
|
||
their local places. Then they discovered that it was difficult to
|
||
communicate with people doing similar things because if only one of the
|
||
routers between them didn't support multicast there was nothing to do...
|
||
|
||
The solution was clear: they decided to build a <em/virtual multicast network/
|
||
in the top of the Internet. That is: sites with multicast routers between
|
||
them could communicate directly. But sites joined across unicast routers would send
|
||
their island's multicast traffic encapsulated in unicast packets to other
|
||
multicast islands. Routers in the middle would not have problems, as they would
|
||
be dealing with unicast traffic. Finally, in the receiving site, traffic would be
|
||
de-encapsulated, and sent to the island in the original multicast way.
|
||
Two ends converting from multicast to unicast, and then again to multicast
|
||
define what is called a multicast <em/tunnel/.
|
||
|
||
The <em/MBone/ or <em/Multicast Backbone/ is that virtual multicast network
|
||
based on multicast islands connected by multicast tunnels.
|
||
|
||
Several activities take place in the MBone daily, but it deserves to be
|
||
remarked the profusion of tele-conferences with real time audio and video
|
||
taking place across the whole Internet. As an example, it was recently
|
||
transmitted (live) the talk Linus Torvalds gave to the Silicon Valley Linux
|
||
Users Group.
|
||
|
||
For more information on the MBone, see:
|
||
<p><url url="http://www.mediadesign.co.at/newmedia/more/mbone-faq.html">
|
||
|
||
|
||
<sect>Multicast applications.<label id="sect-applications">
|
||
|
||
<p>Most people dealing with multicast, sooner or later decide to connect
|
||
to the MBone, and then they usually need an <tt/mrouted/. You'll also need
|
||
it if you don't have a multicast-capable router and you want multicast
|
||
traffic generated in one of your subnets to be "heard" on another.
|
||
<tt/mrouted/ does circunvect the problem of sending multicast traffic
|
||
across unicast routers -it encapsulates multicast datagrams into unicast
|
||
ones (IP into IP)- but this is not the only feature it provides. Most
|
||
important, it instructs the kernel on how to route (or not-to-route) multicast
|
||
datagrams based on their source and destination. So, even having a
|
||
multicast capable router, <tt/mrouted/ can be used to tell it <em/what/
|
||
to do with the datagrams (note I said <em/what/, and not <em/how/;
|
||
<tt/mrouted/ says "forward this to the network connected to that interface",
|
||
but actual forwarding is performed by the kernel). This distinction between
|
||
actual-forwarding and the algorithm that decides who and how to forward is
|
||
very useful as it allows to write forwarding code only once and place it
|
||
into the kernel. Forwarding algorithms and policies are then implemented
|
||
in user space daemons, so it is very easy to change from one policy to
|
||
another without the need of kernel re-compilation.
|
||
|
||
You can get a version of <em/mrouted/ ported to Linux from:
|
||
<p><url url="ftp://www.video.ja.net/mice/mrouted/Linux/">. This site is
|
||
mirrored all across the world. Be sure to read the
|
||
<url url="ftp://www.video.ja.net/mice/README.mirrors"> file to choose the one
|
||
nearest you.
|
||
|
||
Next, we'll focus specially on multicast applications written to connect to
|
||
the MBone, which have been ported to Linux. The list is picked up from
|
||
Michael Esler's "Linux Multicast Information" page
|
||
<url url="http://www.cs.virginia.edu/~mke2e/multicast/">. I recommend you that page
|
||
for lots of information and resources on multicast and Linux.
|
||
|
||
|
||
<bf/Audio Conferencing/
|
||
<itemize>
|
||
<item>NeVoT - Network Voice Terminal
|
||
<url url="http://www.fokus.gmd.de/step/nevot">
|
||
|
||
<item>RAT - UCL Robust-Audio Tool
|
||
<url url="http://www-mice.cs.ucl.ac.uk/mice/rat">
|
||
|
||
<item>vat - LBL visual audio tool
|
||
<url url="http://www-nrg.ee.lbl.gov/vat/">
|
||
</itemize>
|
||
|
||
<bf/Video Conferencing/
|
||
<itemize>
|
||
<item>ivs - Inria video conferencing system
|
||
<url url="http://www.inria.fr/rodeo/ivs.html">
|
||
|
||
<item>nv - Network video tool
|
||
<url url="ftp://ftp.parc.xerox.com/pub/net-research/">
|
||
|
||
<item>nv w/ Meteor - Release of nv w/ support for the Matrox Meteor (UVa)
|
||
<url url="ftp://ftp.cs.virginia.edu/pub/gwtts/Linux/nv-meteor.tar.gz">
|
||
|
||
<item>vic - LBL video conferencing tool
|
||
<url url="http://www-nrg.ee.lbl.gov/vic/">
|
||
|
||
<item>vic w/ Meteor - Release of vic w/ support for the Matrox Meteor (UVa)
|
||
<url url="ftp://ftp.cs.virginia.edu/pub/gwtts/Linux/vic2.7a38-meteor.tar.gz">
|
||
</itemize>
|
||
|
||
<bf/Other Utilities/
|
||
<itemize>
|
||
<item>mmphone Multimedia phone service
|
||
<url url="http://www.eit.com/software/mmphone/phoneform.html">
|
||
|
||
<item>wb - LBL shared white board
|
||
<url url="http://www-nrg.ee.lbl.gov/wb/">
|
||
|
||
<item>webcast - Reliable multicast application for linking Mosaic browsers
|
||
<url url="http://www.ncsa.uiuc.edu/SDG/Software/XMosaic/CCI/webcast.html">
|
||
</itemize>
|
||
|
||
<bf/Session Tools/
|
||
<p>I placed session tools later because I think they deserve some explanation.
|
||
When a conference takes places, several multicast groups and ports are
|
||
assigned to each service you want for your conference (audio, video, shared
|
||
white-boards, etc...) Announces of the conferences that will take place,
|
||
along with information on multicast groups, ports and programs that will
|
||
be used (vic, vat, ...) are periodically multicasted to the MBone. Session
|
||
tools "hear" this information and present you in an easy way which conferences
|
||
are taking (or will take) place, so you can decide which interest you. Also,
|
||
they facilitate the task of joining a session. Instead of launching
|
||
each program that will be used and telling which multicast group/port to
|
||
join, you usually just need to click and the session tool launches the
|
||
proper programs suppling them all information needed to join the conference.
|
||
Session tools usually let you announce your own conferences on the MBone.
|
||
|
||
<itemize>
|
||
<item>gwTTS - University of Virginia tele-tutoring system
|
||
<url url="http://www.cs.Virginia.EDU/~gwtts">
|
||
|
||
<item>isc - Integrated session controller
|
||
<url url="http://www.fokus.gmd.de/step/isc">
|
||
|
||
<item>mmcc - Multimedia conference control
|
||
<url url="ftp://ftp.isi.edu/confctrl/mmcc">
|
||
|
||
<item>sd - LBL session directory tool
|
||
<url url="ftp://ftp.ee.lbl.gov/conferencing/sd">
|
||
|
||
<item>sd-snoop - Tenet Group session directory snoop utility
|
||
<url url="ftp://tenet.berkeley.edu/pub/software">
|
||
|
||
<item>sdr - UCL's next generation session directory
|
||
<url url="ftp://cs.ucl.ac.uk/mice/sdr">
|
||
</itemize>
|
||
|
||
|
||
|
||
<sect>Multicast programming.
|
||
|
||
<p>Multicast programming... or writing your own multicast applications.
|
||
|
||
Several extensions to the programming API are needed in order to support
|
||
multicast. All of them are handled via two system calls: <tt/setsockopt()/
|
||
(used to pass information to the kernel) and <tt/getsockopt()/ (to retrieve
|
||
information regarded multicast behavior). This does <em/not/ mean that
|
||
2 new system calls were added to support multicast. The pair
|
||
<tt/setsockopt()//<tt/getsockopt()/ has been there for years. Since 4.2 BSD
|
||
at least. The addition consists on a new set of options (multicast options)
|
||
that are passed to these system calls, that the kernel must understand.
|
||
|
||
The following are the <tt/setsockopt()//<tt/getsockopt()/ function prototypes:
|
||
<tscreen><verb>
|
||
int getsockopt(int s, int level, int optname, void* optval, int* optlen);
|
||
|
||
int setsockopt(int s, int level, int optname, const void* optval, int optlen);
|
||
</verb></tscreen>
|
||
|
||
The first parameter, <tt/s/, is the socket the system call applies to.
|
||
For multicasting, it must be a socket of the family <tt/AF_INET/ and its
|
||
type may be either <tt/SOCK_DGRAM/ or <tt/SOCK_RAW/. The most common use
|
||
is with <tt/SOCK_DGRAM/ sockets, but if you plan to write a routing daemon or
|
||
modify some existing one, you will probably need to use <tt/SOCK_RAW/ ones.
|
||
|
||
The second one, <tt/level/, identifies the layer that is to handle the
|
||
option, message or query, whatever you want to call it. So, <tt/SOL_SOCKET/
|
||
is for the socket layer, <tt/IPPROTO_IP/ for the IP layer, etc...
|
||
For multicast programming, <tt/level/ will always be <tt/IPPROTO_IP/.
|
||
|
||
<tt/optname/ identifies the option we are setting/getting. Its value
|
||
(either supplied by the program or returned by the kernel) is
|
||
<tt/optval/. The optnames involved in multicast programming are the
|
||
following:
|
||
|
||
<code>
|
||
setsockopt() getsockopt()
|
||
IP_MULTICAST_LOOP yes yes
|
||
IP_MULTICAST_TTL yes yes
|
||
IP_MULTICAST_IF yes yes
|
||
IP_ADD_MEMBERSHIP yes no
|
||
IP_DROP_MEMBERSHIP yes no
|
||
</code>
|
||
|
||
<tt/optlen/ carries the size of the data structure <tt/optval/ points to.
|
||
Note that in <tt/getsockopt()/ it is a value-result rather than a value:
|
||
the kernel writes the value of <tt/optname/ in the buffer pointed by
|
||
<tt/optval/ and informs us of that value's size via <tt/optlen/.
|
||
|
||
Both <tt/setsockopt()/ and <tt/getsockopt()/ return 0 on success and -1 on
|
||
error.
|
||
|
||
|
||
<sect1>IP_MULTICAST_LOOP.
|
||
|
||
<p>You have to decide, as the application writer, whether you want the
|
||
data you send to be looped back to your host or not. If you plan to
|
||
have more than one process or user "listening", loopback must be
|
||
enabled. On the other hand, if you are sending the images your video
|
||
camera is producing, you probably don't want loopback, even if you
|
||
want to see yourself on the screen. In that latter case, your application
|
||
will probably receive the images from a device attached to the computer
|
||
and send them to the socket. As the application already "has" that data,
|
||
it is improbable it wants to receive it again on the socket. Loopback
|
||
is by default enabled.
|
||
|
||
Regard that <tt/optval/ is a pointer. You can't write:
|
||
<tscreen><verb>
|
||
setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, 0, 1);
|
||
</verb></tscreen>
|
||
to disable loopback. Instead write:
|
||
<tscreen><verb>
|
||
u_char loop;
|
||
setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, &ero;loop, sizeof(loop));
|
||
</verb></tscreen>
|
||
and set <tt/loop/ to 1 to enable loopback or 0 to disable it.
|
||
|
||
To know whether a socket is currently looping-back or not use something like:
|
||
<tscreen><verb>
|
||
u_char loop;
|
||
int size;
|
||
|
||
getsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, &ero;loop, &ero;size)
|
||
</verb></tscreen>
|
||
|
||
|
||
<sect1>IP_MULTICAST_TTL.
|
||
|
||
<p>If not otherwise specified, multicast datagrams are sent with a default
|
||
value of 1, to prevent them to be forwarded beyond the local network.
|
||
To change the TTL to the value you desire (from 0 to 255), put that value
|
||
into a variable (here I name it "ttl") and write somewhere in your program:
|
||
<tscreen><verb>
|
||
u_char ttl;
|
||
setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ero;ttl, sizeof(ttl));
|
||
</verb></tscreen>
|
||
|
||
The behavior with <tt/getsockopt()/ is similar to the one seen on IP_MULTICAST_LOOP.
|
||
|
||
|
||
<sect1>IP_MULTICAST_IF.
|
||
|
||
<p>Usually, the system administrator specifies the default interface multicast
|
||
datagrams should be sent from. The programmer can override this and choose
|
||
a concrete outgoing interface for a given socket with this option.
|
||
<tscreen><verb>
|
||
struct in_addr interface_addr;
|
||
setsockopt (socket, IPPROTO_IP, IP_MULTICAST_IF, &ero;interface_addr, sizeof(interface_addr));
|
||
</verb></tscreen>
|
||
|
||
>From now on, all multicast traffic generated in this socket will be output
|
||
from the interface chosen. To revert to the original behavior and let the
|
||
kernel choose the outgoing interface based on the system administrator's
|
||
configuration, it is enough to call <tt/setsockopt()/ with this same option
|
||
and <tt/INADDR_ANY/ in the interface field.
|
||
|
||
In determining or selecting outgoing interfaces, the following <tt/ioctl/s
|
||
might be useful: <tt/SIOCGIFADDR/ (to get an interface's address),
|
||
<tt/SIOCGIFCONF/ (to get the list of all the interfaces) and <tt/SIOCGIFFLAGS/
|
||
(to get an interface's flags and, thus, determine whether the interface is
|
||
multicast capable or not -the <tt/IFF_MULTICAST/ flag-).
|
||
|
||
If the host has more than one interface and the IP_MULTICAST_IF option is
|
||
not set, multicast transmissions are sent from the default interface,
|
||
although the remainding interfaces might be used
|
||
for multicast <em/forwarding/ if the host is acting as a multicast router.
|
||
|
||
|
||
<sect1>IP_ADD_MEMBERSHIP.<label id="sect-ADD-MEMBERSHIP">
|
||
|
||
<p>Recall that you need to tell the kernel which multicast groups you are interested
|
||
in. If no process is interested in a group, packets destined to it that arrive
|
||
to the host are discarded. In order to inform the kernel of your interests and,
|
||
thus, become a member of that group, you should first fill a <tt/ip_mreq/
|
||
structure which is passed later to the kernel in the <tt/optval/ field of the
|
||
<tt/setsockopt()/ system call.
|
||
|
||
The ip_mreq structure (taken from <tt>/usr/include/linux/in.h</tt>) has the
|
||
following members:
|
||
<tscreen><verb>
|
||
struct ip_mreq
|
||
{
|
||
struct in_addr imr_multiaddr; /* IP multicast address of group */
|
||
struct in_addr imr_interface; /* local IP address of interface */
|
||
};
|
||
</verb></tscreen>
|
||
|
||
(Note: the "physical" definition of the structure is in the file above
|
||
specified. Nonetheless, you should not include <tt><linux/in.h></tt> if
|
||
you want your code to be portable. Instead, include <tt><netinet/in.h></tt>
|
||
which, in turn, includes <tt><linux/in.h></tt> itself).
|
||
|
||
The first member, <tt/imr_multiaddr/, holds the group address you want to join.
|
||
Remember that memberships are also associated with interfaces, not
|
||
just groups. This is the reason you have to provide a value for the second
|
||
member: <tt/imr_interface/. This way, if you are in a multihomed host, you can
|
||
join the same group in several interfaces. You can always fill this last
|
||
member with the wildcard address (<tt/INADDR_ANY/) and then the kernel will deal
|
||
with the task of choosing the interface.
|
||
|
||
With this structure filled (say you defined it as: <tt/struct ip_mreq mreq;/)
|
||
you just have to call <tt/setsockopt()/ this way:
|
||
<tscreen><verb>
|
||
setsockopt (socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ero;mreq, sizeof(mreq));
|
||
</verb></tscreen>
|
||
|
||
Notice that you can join several groups to the same socket, not just one. The
|
||
limit to this is <tt/IP_MAX_MEMBERSHIPS/ and, as of version 2.0.33, it has the value
|
||
of 20.
|
||
|
||
|
||
<sect1>IP_DROP_MEMBERSHIP.
|
||
|
||
<p>The process is quite similar to joining a group:
|
||
<tscreen><verb>
|
||
struct ip_mreq mreq;
|
||
setsockopt (socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ero;mreq, sizeof(mreq));
|
||
</verb></tscreen>
|
||
|
||
where <tt/mreq/ is the same structure with the same data used when joining the
|
||
group. If the <tt/imr_interface/ member is filled with <tt/INADDR_ANY/, the
|
||
first matching group is dropped.
|
||
|
||
If you have joined a lot of groups to the same socket, you don't need to
|
||
drop memberships in all of them in order to terminate. When you close a
|
||
socket, all memberships associated with it are dropped by the kernel. The
|
||
same occurs if the process that opened the socket is killed.
|
||
|
||
Finally, keep in mind that a process dropping membership for a group does
|
||
not imply that the host will stop receiving datagrams for that group. If
|
||
another socket joined that group in that same interface previously to this
|
||
<tt/IP_DROP_MEMBERSHIP/, <em/the host/ will keep being a member of that group.
|
||
|
||
Both ADD_MEMBERSHIP and DROP_MEMBERSHIP are nonblocking operations. They
|
||
should return immediately indicating either success or failure.
|
||
|
||
|
||
|
||
<sect>The internals.
|
||
|
||
<p>This section's aim is to provide some information, not needed to reach
|
||
a basic understanding on how multicast works nor to be able to write
|
||
multicast programs, but which is very interesting, gives some insight on
|
||
the underlying multicast protocols and implementations, and may be useful to
|
||
avoid common errors and misunderstandings.
|
||
|
||
|
||
<sect1>IGMP.
|
||
<p>When talking about <tt/IP_ADD_MEMBERSHIP/ and <tt/IP_DROP_MEMBERSHIP/,
|
||
we said that the information provided by this "commands" was used by the
|
||
kernel to choose which multicast datagrams accept or discard. This is true,
|
||
but it is not all the truth. Such a simplification would imply that
|
||
multicast datagrams for <em/all/ multicast groups around the world
|
||
would be received by our host, and then it would check the memberships
|
||
issued by processes running on it to decide whether to pass the traffic to
|
||
them or to throw it out. As you can imagine, this is a complete bandwidth
|
||
waste.
|
||
|
||
What actually happens is that hosts instruct their routers telling them
|
||
which multicast groups they are interested in; then, those routers
|
||
tell their up-stream routers they want to receive that traffic, and so
|
||
on. Algorithms employed for making the decision of <em/when/ to
|
||
ask for a group's traffic or saying that it is not desired anymore,
|
||
vary a lot. There's something, however, that never changes: <em/how/
|
||
this information is transmitted. <bf/IGMP/ is used for that. It stands for
|
||
Internet Group Management Protocol. It is a new protocol, similar in many
|
||
aspects to ICMP, with a protocol number of 2, whose messages are carried in
|
||
IP datagrams, and which all level 2-compliant host are required to implement.
|
||
|
||
As said before, it is used both by hosts giving membership information to
|
||
its routers, and by routers to communicate between themselves. In the
|
||
following I'll cover only the hosts-routers relationships, mainly because
|
||
I was unable to find information describing router to router communication
|
||
other than the mrouted source code (rfc 1075 describing the Distance Vector
|
||
Multicast Routing Protocol is now obsoleted, and <tt/mrouted/ implements
|
||
a modified DVMRP not yet documented).
|
||
|
||
IGMP version 0 is specified in RFC-988 which is now obsoleted. Almost no one
|
||
uses version 0 now.
|
||
|
||
IGMP version 1 is described in RFC-1112 and, although it is updated by RFC-2236
|
||
(IGMP version 2) it is in wide use still. The Linux kernel implements the full
|
||
IGMP version 1 and parts of version 2 requirements, but not all.
|
||
|
||
Now I'll try to give an informal description of the protocol. You can check
|
||
RFC-2236 for an in-proof formal description, with lots of state diagrams
|
||
and time-out boundaries.
|
||
|
||
All IGMP messages have the following structure:
|
||
<code>
|
||
0 1 2 3
|
||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
| Type | Max Resp Time | Checksum |
|
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
| Group Address |
|
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
</code>
|
||
|
||
IGMP version 1 (hereinafter IGMPv1) labels the "Max Resp Time" as "Unused",
|
||
zeroes it when sent, and ignores it when received. Also, it brakes
|
||
the "Type" field in two 4-bits wide fields: "Version" and "Type". As IGMPv1
|
||
identifies a "Membership Query" message as 0x11 (version 1, type 1) and
|
||
IGMPv2 as 0x11 too, the 8 bits have the same effective interpretation.
|
||
|
||
I think it is more instructive to give first the IGMPv1 description and next
|
||
point out the IGMPv2 additions, as they are mainly that, additions.
|
||
|
||
For the following discussions it is important to remember that multicast
|
||
routers receive <em/all/ IP multicast datagrams.
|
||
|
||
|
||
<sect2>IGMP version 1.<label id="sect-IGMPv1">
|
||
|
||
<p>Routers periodically send <em/IGMP Host Membership Queries/ to the all-hosts
|
||
group (224.0.0.1) with a TTL of 1 (once every minute or two). All
|
||
multicast-capable hosts hear them,
|
||
but don't answer immediately to avoid an IGMP Host Membership Report storm.
|
||
Instead, they start a random delay timer for each group they belong to
|
||
<em/on the interface/ they received the query.
|
||
|
||
Sooner or later, the timer expires in one of the hosts, and it sends an
|
||
IGMP <em/Host Membership Report/ (also with TTL 1) to the multicast address of the
|
||
group being reported. As it is sent to the group, all hosts that joined
|
||
the group -and which are currently waiting for their own timer to expire-
|
||
receive it, too. Then, they stop their timers and don't generate any other
|
||
report. Just one is generated -by the host that chose the smaller timeout-,
|
||
and that is enough for the router. It only needs to know that there are
|
||
members for that group in the subnet, not how many nor which.
|
||
|
||
When no reports are received for a given group after a certain number
|
||
of queries, the router assumes that no members are left, and thus it
|
||
doesn't have to forward traffic for that group on that subnet. Note that
|
||
in IGMPv1 there are no "Leave Group messages".
|
||
|
||
When a host joins a <em/new/ group, the kernel sends a report for that
|
||
group, so that the respective process needs not to wait a minute or two
|
||
until a new membership query is received. As you can see this IGMP packet
|
||
is generated by the kernel as a response to the <tt/IP_ADD_MEMBERSHIP/
|
||
command, seen in section <ref id="sect-ADD-MEMBERSHIP" name="IP_ADD_MEMBERSHIP">.
|
||
Note the emphasis in the adjective "new": if a process issues an
|
||
<tt/IP_ADD_MEMBERSHIP/ command for a group the host is already a member of,
|
||
no IGMP packets are sent as we must already be receiving traffic for that
|
||
group; instead, a counter for that group's use is incremented.
|
||
<tt/IP_DROP_MEMBERSHIP/ generates no datagrams in IGMPv1.
|
||
|
||
Host Membership Queries are identified by Type 0x11, and Host Membership
|
||
Reports by Type 0x12.
|
||
|
||
No reports are sent for the all-hosts group. Membership in this group is
|
||
permanent.
|
||
|
||
|
||
<sect2>IGMP version 2.
|
||
|
||
<p>One important addition to the above is the inclusion of a <em/Leave
|
||
Group/ message (Type 0x17). The reason is to reduce the bandwidth
|
||
waste between the time the last host in the subnet drops membership and
|
||
the time the router times-out for its queries and decides there are no more
|
||
members present for that group (leave latency). Leave Group messages should
|
||
be addressed to
|
||
the all-routers group (224.0.0.2) rather than to the group being left, as that
|
||
information is of no use for other members (kernel versions up to 2.0.33
|
||
send them to the group; although it does no harm to the hosts, it's a waste
|
||
of time as they have to process them, but don't gain useful information).
|
||
There are certain subtle details regarding when and when-not to send Leave
|
||
Messages; if interested, see the RFC.
|
||
|
||
When an IGMPv2 router receives a Leave Message for a group, it sends
|
||
<em/Group-Specific Queries/ to the group being left. This is another
|
||
addition. IGMPv1 has no group-specific queries. All queries are sent to the
|
||
all-hosts group. The Type in the IGMP header does not change (0x11, as
|
||
before), but the "Group Address" is filled with the address of the
|
||
multicast group being left.
|
||
|
||
The "Max Resp Time" field, which was set to 0 in transmission and ignored
|
||
on reception in IGMPv1, is meaningful only
|
||
in "Membership Query" messages. It gives the maximum time allowed before
|
||
sending a report in units of 1/10 second. It is used as a tune mechanism.
|
||
|
||
IGMPv2 adds another message type: 0x16. It is a "Version 2 Membership
|
||
Report" sent by IGMPv2 hosts if they detect an IGMPv2 router is present
|
||
(an IGMPv2 host knows an IGMPv1 router is present when it receives a query
|
||
with the "Max Response" field set to 0).
|
||
|
||
When more than one router claims to act as querier, IGMPv2
|
||
provides a mechanism to avoid "discussions": the router with the lowest IP
|
||
address is designed to be querier. The other routers keep timeouts. If the router
|
||
with lower IP address crashes or is shutdown, the decision of who will be
|
||
the querier is taken again after the timers expire.
|
||
|
||
|
||
|
||
<sect1>Kernel corner.
|
||
|
||
<p>This sub-section gives some start-points to study the multicast implementation
|
||
of the Linux kernel. It does not explain that implementation. It just says
|
||
where to find things.
|
||
|
||
The study was carried over version 2.0.32, so it could be a bit outdated by
|
||
the time you read it (network code seems to have changed <em/A LOT/ in
|
||
2.1.x releases, for instance).
|
||
|
||
Multicast code in the Linux kernel is always surrounded by
|
||
<tt/#ifdef CONFIG_IP_MULTICAST/ / <tt/#endif/ pairs, so that you can include/
|
||
exclude it from your kernel based on your needs (this inclusion/exclusion
|
||
is done at compile time, as you probably know if reading that section...
|
||
<tt/#ifdef/s are handled by the preprocessor. The decision is made based in
|
||
what you selected when doing either a <tt/make config/, <tt/make menuconfig/ or
|
||
<tt/make xconfig/).
|
||
|
||
You might want multicast features, but if your Linux box is not going to
|
||
act as a multicast router you will probably not want multicast router features
|
||
included in your new kernel. For this you have the multicast routing code
|
||
surrounded by <tt/#ifdef CONFIG_IP_MROUTE/ / <tt/#endif/ pairs.
|
||
|
||
Kernel sources are usually placed in /usr/src/linux. However, the place
|
||
may change so, both for accuracy and brevity, I will refer to the
|
||
root directory of the kernel sources as just LINUX. Then, something like
|
||
<tt>LINUX/net/ipv4/udp.c</tt> should be the same as
|
||
<tt>/usr/src/linux/net/ipv4/udp.c</tt> if you unpacked the kernel
|
||
sources in the <tt>/usr/src/linux</tt> directory.
|
||
|
||
All multicast interfaces with user programs shown in the section devoted
|
||
to multicast programming were driven across the <tt/setsockopt()//
|
||
<tt/getsockopt()/
|
||
system calls. Both of them are implemented by means of functions that
|
||
make some tests to verify the parameters passed to them and which, in turn,
|
||
call another function that makes some additional tests, demultiplexes the
|
||
call based on the <tt/level/ parameter to either system call, and then calls
|
||
another function which... (if interested in all this jumps, you can follow
|
||
them in <tt>LINUX/net/socket.c</tt> (functions <tt/sys_socketcall()/ and
|
||
<tt/sys_setsockopt()/,
|
||
<tt>LINUX/net/ipv4/af_inet.c</tt> (function <tt/inet_setsockopt()/) and
|
||
<tt>LINUX/net/ipv4/ip_sockglue.c</tt> (function <tt/ip_setsockopt()/) ).
|
||
|
||
The one which interests us is <tt>LINUX/net/ipv4/ip_sockglue.c</tt>. Here we find
|
||
<tt/ip_setsockopt()/ and <tt/ip_getsockopt()/ which are mainly a
|
||
<tt/switch/ (after some error checking) verifying each possible value for
|
||
<tt/optname/. Along with
|
||
unicast options, all multicast ones seen here are handled:
|
||
<tt/IP_MULTICAST_TTL/, <tt/IP_MULTICAST_LOOP/, <tt/IP_MULTICAST_IF/,
|
||
<tt/IP_ADD_MEMBERSHIP/ and <tt/IP_DROP_MEMBERSHIP/. Previously to the
|
||
<tt/switch/, a test is made to determine
|
||
whether the options are multicast router specific, and if so, they are
|
||
routed to the <tt/ip_mroute_setsockopt()/ and <tt/ip_mroute_getsockopt()/
|
||
functions (file <tt>LINUX/net/ipv4/ipmr.c</tt>).
|
||
|
||
In <tt>LINUX/net/ipv4/af_inet.c</tt> we can see the default values we talked about
|
||
in previous sections (loopback enabled, TTL=1) provided when the socket is
|
||
created (taken from function <tt/inet_create()/ in this file):
|
||
<code>
|
||
#ifdef CONFIG_IP_MULTICAST
|
||
sk->ip_mc_loop=1;
|
||
sk->ip_mc_ttl=1;
|
||
*sk->ip_mc_name=0;
|
||
sk->ip_mc_list=NULL;
|
||
#endif
|
||
</code>
|
||
|
||
Also, the assertion of "closing a socket makes the kernel drop all memberships
|
||
this socket had" is corroborated by:
|
||
<code>
|
||
#ifdef CONFIG_IP_MULTICAST
|
||
/* Applications forget to leave groups before exiting */
|
||
ip_mc_drop_socket(sk);
|
||
#endif
|
||
</code>
|
||
taken from <tt/inet_release()/, on the same file as before.
|
||
|
||
Device independent operations for the Link Layer are kept in
|
||
<tt>LINUX/net/core/dev_mcast.c</tt>.
|
||
|
||
Two important functions are still missing: the processing of input and
|
||
output multicast datagrams. As any other datagrams, incoming datagrams are
|
||
passed from the device drivers to the <tt/ip_rcv()/ function
|
||
(<tt>LINUX/net/ipv4/ip_input.c</tt>).
|
||
In this function is where the perfect filtering is applied to multicast
|
||
packets that crossed the devices layer (recall that lower layers only perform
|
||
best-effort filtering and is IP who 100% knows whether we are interested in
|
||
that multicast group or not). If the host is acting as a multicast router, this
|
||
function decides too whether the datagram should be forwarded and calls
|
||
<tt/ipmr_forward()/ appropriately. (<tt/ipmr_forward()/ is implemented in
|
||
<tt>LINUX/net/ipv4/ipmr.c</tt>).
|
||
|
||
Code in charge of out-putting packets is kept in
|
||
<tt>LINUX/net/ipv4/ip_output.c</tt>.
|
||
Here is where the <tt/IP_MULTICAST_LOOP/ option takes effect, as it is checked
|
||
to see whether to loop back the packets or not (function <tt/ip_queue_xmit()/).
|
||
Also the TTL of the outgoing
|
||
packet is selected based on whether it is a multicast or unicast one. In the
|
||
former case, the argument passed to the <tt/IP_MULTICAST_TTL/ option is used
|
||
(function (<tt/ip_build_xmit()/).
|
||
|
||
While working with <tt/mrouted/ (a program which gives the kernel information
|
||
about how to route multicast datagrams), we detected that
|
||
all multicast packets originated on the local network were properly
|
||
routed..., except the ones from the Linux box that was acting as the multicast
|
||
router!! ip_input.c was working OK, but it seemed ip_output.c wasn't.
|
||
Reading the source code for the output functions, we found that
|
||
outgoing datagrams were not being passed to <tt/ipmr_forward()/, the function
|
||
that had to decide whether they should be routed or not. The packets were
|
||
outputed to the local network but, as network cards are usually unable to
|
||
read their own transmissions, those datagrams were never routed.
|
||
We added the necessary code to the <tt/ip_build_xmit()/ function and
|
||
everything was OK again. (Having
|
||
the sources for your kernel is not a luxury or pedantry; it's a need!)
|
||
|
||
<tt/ipmr_forward()/ has been mentioned a couple of times. It is an important
|
||
function as it solves one important misunderstanding that appears to be
|
||
widely expanded. When routing multicast traffic, it is <em/not/ <tt/mrouted/
|
||
who makes the copies and sends them to the proper recipients. <tt/mrouted/
|
||
receives all multicast traffic and, based on that information, computes
|
||
the multicast routing tables and <em/tells the kernel/ how to route:
|
||
"datagrams for this group coming from that interface should be forwarded
|
||
to those interfaces". This information is passed to the kernel by calls
|
||
to <tt/setsockopt()/ on a raw socket opened by the <tt/mrouted/ daemon (the
|
||
protocol specified when the raw socket was created <em/must/ be
|
||
<tt/IPPROTO_IGMP/). This
|
||
options are handled in the <tt/ip_mroute_setsockopt()/ function from
|
||
<tt>LINUX/net/ipv4/ipmr.c</tt>. The first option (would be better to call them
|
||
commands rather than options) issued on that socket must be <tt/MRT_INIT/.
|
||
All other commands are
|
||
ignored (returning <tt/-EACCES/) if <tt/MRT_INIT/ is not issued first. Only one
|
||
instance of <tt/mrouted/ can be running at the same time in the same host.
|
||
To keep track of this, when the first <tt/MRT_INIT/ is received, an important
|
||
variable, <tt/struct sock* mroute_socket/, is pointed to the socket <tt/MRT_INIT/
|
||
was received on. If <tt/mroute_socket/ is not null when attending an
|
||
<tt/MRT_INIT/ this means another mrouted is already running and <tt/-EADDRINUSE/
|
||
is returned. All resting commands (<tt/MRT_DONE/, <tt/MRT_ADD_VIF/,
|
||
<tt/MRT_DEL_VIF/, <tt/MRT_ADD_MFC/, <tt/MRT_DEL_MFC/ and <tt/MRT_ASSERT/)
|
||
return <tt/-EACCES/ if they come from a socket different than
|
||
<tt/mroute_socket/.
|
||
|
||
As routed multicast datagrams can be received/sent across either physical
|
||
interfaces or tunnels, a common abstraction for both was devised: VIFs,
|
||
Virtual InterFaces. <tt/mrouted/ passes vif structures to the kernel,
|
||
indicating physical
|
||
or tunnel interfaces to add to its routing tables, and multicast forwarding
|
||
entries saying where to forward datagrams.
|
||
|
||
VIFs are added with <tt/MRT_ADD_VIF/ and deleted with <tt/MRT_DEL_VIF/. Both
|
||
pass a <tt/struct vifctl/ to the kernel (defined in
|
||
<tt>/usr/include/linux/mroute.h</tt>) with the following information:
|
||
<code>
|
||
struct vifctl {
|
||
vifi_t vifc_vifi; /* Index of VIF */
|
||
unsigned char vifc_flags; /* VIFF_ flags */
|
||
unsigned char vifc_threshold; /* ttl limit */
|
||
unsigned int vifc_rate_limit; /* Rate limiter values (NI) */
|
||
struct in_addr vifc_lcl_addr; /* Our address */
|
||
struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */
|
||
};
|
||
</code>
|
||
|
||
With this information a <tt/vif_device/ structure is built:
|
||
<code>
|
||
struct vif_device
|
||
{
|
||
struct device *dev; /* Device we are using */
|
||
struct route *rt_cache; /* Tunnel route cache */
|
||
unsigned long bytes_in,bytes_out;
|
||
unsigned long pkt_in,pkt_out; /* Statistics */
|
||
unsigned long rate_limit; /* Traffic shaping (NI) */
|
||
unsigned char threshold; /* TTL threshold */
|
||
unsigned short flags; /* Control flags */
|
||
unsigned long local,remote; /* Addresses(remote for tunnels)*/
|
||
};
|
||
</code>
|
||
|
||
Note the <tt/dev/ entry in the structure. The <tt/device/ structure is
|
||
defined in <tt>/usr/include/linux/netdevice.h</tt> file. It is a big structure,
|
||
but the field that interests us is:
|
||
<code>
|
||
struct ip_mc_list* ip_mc_list; /* IP multicast filter chain */
|
||
</code>
|
||
|
||
The <tt/ip_mc_list/ structure -defined in <tt>/usr/include/linux/igmp.h</tt>-
|
||
is as follows:
|
||
<code>
|
||
struct ip_mc_list
|
||
{
|
||
struct device *interface;
|
||
unsigned long multiaddr;
|
||
struct ip_mc_list *next;
|
||
struct timer_list timer;
|
||
short tm_running;
|
||
short reporter;
|
||
int users;
|
||
};
|
||
</code>
|
||
|
||
So, the <tt/ip_mc_list/ member from the <tt/dev/ structure is a pointer to a linked
|
||
list of <tt/ip_mc_list/ structures, each containing an entry for each multicast
|
||
group the network interface is a member of. Here again we see membership is
|
||
associated to interfaces. <tt>LINUX/net/ipv4/ip_input.c</tt> traverses this
|
||
linked list to decide whether the received datagram is destined to any group
|
||
the interface that received the datagram belongs to:
|
||
<code>
|
||
#ifdef CONFIG_IP_MULTICAST
|
||
if(!(dev->flags&ero;IFF_ALLMULTI) &ero;&ero; brd==IS_MULTICAST
|
||
&ero;&ero; iph->daddr!=IGMP_ALL_HOSTS
|
||
&ero;&ero; !(dev->flags&ero;IFF_LOOPBACK))
|
||
{
|
||
/*
|
||
* Check it is for one of our groups
|
||
*/
|
||
struct ip_mc_list *ip_mc=dev->ip_mc_list;
|
||
do
|
||
{
|
||
if(ip_mc==NULL)
|
||
{
|
||
kfree_skb(skb, FREE_WRITE);
|
||
return 0;
|
||
}
|
||
if(ip_mc->multiaddr==iph->daddr)
|
||
break;
|
||
ip_mc=ip_mc->next;
|
||
}
|
||
while(1);
|
||
}
|
||
#endif
|
||
</code>
|
||
|
||
The <tt/users/ field in the <tt/ip_mc_list/ structure is used to implement
|
||
what was said in section <ref id="sect-IGMPv1" name="IGMP version 1">: if a
|
||
process joins a group and the
|
||
interface is already a member of that group (ie, another process joined
|
||
that same group in that same interface before) only the count of members
|
||
(<tt/users/)
|
||
is incremented. No IGMP messages are sent, as you can see in the following
|
||
code (taken from <tt/ip_mc_inc_group()/, called
|
||
by <tt/ip_mc_join_group()/, both in <tt>LINUX/net/ipv4/igmp.c</tt>):
|
||
<code>
|
||
for(i=dev->ip_mc_list;i!=NULL;i=i->next)
|
||
{
|
||
if(i->multiaddr==addr)
|
||
{
|
||
i->users++;
|
||
return;
|
||
}
|
||
}
|
||
</code>
|
||
|
||
When dropping memberships, the counter is decremented and additional operations
|
||
are performed only when the count reaches 0 (<tt>ip_mc_dec_group()</tt>).
|
||
|
||
<tt/MRT_ADD_MFC/ and <tt/MRT_DEL_MFC/ set or delete forwarding entries in the
|
||
multicast routing tables. Both pass a <tt/struct mfcctl/ to the kernel
|
||
(also defined in <tt>/usr/include/linux/mroute.h</tt>) with this information:
|
||
<code>
|
||
struct mfcctl
|
||
{
|
||
struct in_addr mfcc_origin; /* Origin of mcast */
|
||
struct in_addr mfcc_mcastgrp; /* Group in question */
|
||
vifi_t mfcc_parent; /* Where it arrived */
|
||
unsigned char mfcc_ttls[MAXVIFS]; /* Where it is going */
|
||
};
|
||
</code>
|
||
|
||
With all this information in hand, <tt/ipmr_forward()/ "walks" across the VIFs,
|
||
and if a matching is found <em/it/ duplicates the datagram and calls
|
||
<tt/ipmr_queue_xmit()/ which, in turn, uses the output device specified by
|
||
the routing table and the proper destination address if the packet is
|
||
to be sent across a tunnel (ie, the unicast destination address of the
|
||
other end of the tunnel).
|
||
|
||
Function <tt/ip_rt_event()/ (not directly related to output, but which is
|
||
in ip_output.c too) receives events related to a network device, like the device
|
||
going up. This function assures that then the device joins the ALL-HOSTS
|
||
multicast group.
|
||
|
||
IGMP functions are implemented in <tt>LINUX/net/ipv4/igmp.c</tt>. Important
|
||
information for that functions appears in <tt>/usr/include/linux/igmp.h</tt> and
|
||
<tt>/usr/include/linux/mroute.h</tt>. The IGMP entry in the <tt>/proc/net</tt>
|
||
directory is created with <tt/ip_init()/ in <tt>LINUX/net/ipv4/ip_output.c</tt>.
|
||
|
||
|
||
|
||
<sect>Routing Policies and Forwarding Techniques.<label id="sect-routing">
|
||
|
||
<p>One trivial algorithm to make worldwide multicast traffic available
|
||
everywhere could be to send it... everywhere, despite someone wants it
|
||
or not. As this does not seem quite optimized, several routing algorithms
|
||
and forwarding techniques have been implemented.
|
||
|
||
<bf/DVMRP/ (Distance Vector Multicast Routing Protocol) is, perhaps, the one
|
||
most multicast routers use now. It is a <em/dense mode/ routing protocol,
|
||
that is, it performs well in environments with high bandwidth and densely
|
||
distributed members. However, in <em/sparse mode/ scenarios, it suffers
|
||
from scalability problems.
|
||
|
||
Together with DVMRP we can find other dense mode routing protocols, such
|
||
as <bf/MOSPF/ (Multicast Extensions to OSPF -Open Shortest Path First-)
|
||
and PIM-DM (Protocol-Independent Multicast Dense Mode).
|
||
|
||
To perform routing in sparse mode environments, we have <bf/PIM-SM/
|
||
(Protocol Independent Multicast Sparse Mode) and <bf/CBT/ (Core Based
|
||
Trees).
|
||
|
||
OSPF version 2 is explained in RFC 1583, and MOSPF in RFC 1584.
|
||
PIM-SM and CBT specifications can be found in RFC 2117 and 2201,
|
||
respectively.
|
||
|
||
All this routing protocols use some type of multicast forwarding, such
|
||
as <em/flooding/, <em/Reverse Path Broadcasting/ (RPB), <em/Truncated
|
||
Reverse Path Broadcasting/ (TRPB), <em/Reverse Path Multicasting/ (RPM)
|
||
or <em/Shared Trees/.
|
||
|
||
It would be too long to explain them here and, as short descriptions
|
||
for them are publicly available, I'll just recommend reading the
|
||
<tt>draft-ietf-mboned-in.txt</tt> text. You can find it in the
|
||
same places RFCs are available, and it explains in some detail all
|
||
the above techniques and policies.
|
||
|
||
|
||
<sect>Multicast Transport Protocols.<label id="sect-trans-prots">
|
||
|
||
<p>So far we have been talking about multicast transmissions using UDP. This
|
||
is the usual practice, as it is impossible to do it with TCP. However,
|
||
intense research is taking place since a couple of years in order to develop
|
||
some new multicast transport protocols.
|
||
|
||
Several of these protocols have been implemented and are being tested. A good
|
||
lesson from them is that it seems no multicast transport protocol is general
|
||
and good enough for all types of multicast applications.
|
||
|
||
If transport protocols are complex and difficult to tune,
|
||
imagine dealing with delays (in multimedia conferences), data loss, ordering,
|
||
retransmissions, flow and congestion control, group management, etc, when
|
||
the receiver is not one, but perhaps hundreds or thousands of sparse hosts.
|
||
Here scalability is an issue, and new techniches are implemented, such as
|
||
not giving acknowledges for every packet received but, instead, send <em/negative
|
||
acknowledges/ (NACKs) for data not received. RFC 1458 gives the proposed
|
||
requirements for multicast protocols.
|
||
|
||
Giving descriptions of those multicast protocols is out of the scope of this
|
||
section. Instead, I'll give you the names of some of them and point you to
|
||
some sources of information: Real-Time Transport Protocol (RTP) is concerned
|
||
with multi-partite multimedia conferences, <bf/Scalable Reliable Multicast/ (SRM) is
|
||
used by the <tt/wb/ (the distributed White-Board tool, see section <ref
|
||
id="sect-applications" name="Multicast applications">),
|
||
<bf/Uniform Reliable Group Communication Protocol/ (URGC) enforces reliable and
|
||
ordered transactions based in a centralized control, <bf/Muse/ was developed as an
|
||
application specific protocol: to multicast news articles over the MBone, the
|
||
<bf/Multicast File Transfer Protocol/ (MFTP) is quite descriptive by itself
|
||
and people "join" to file transmission (previously announced) much in the same
|
||
way they would join a conference, <bf/Log-Based Receiver-reliable Multicast/
|
||
(LBRM) is a curious protocol that keeps track of all packets sent in a logging
|
||
server that tells the sender whether it has to retransmit the data or can
|
||
drop it safely as all receivers got it. One protocol with a funny name
|
||
-especially for a multicast protocol- is STORM (<bf/STructure-Oriented
|
||
Resilient Multicast/). Lots and lots of multicast protocols can be found
|
||
searching the Web, along with some interesting papers proposing new
|
||
activities for multicast (for instance, www page distribution using multicast).
|
||
|
||
A good page providing comparisons between reliable multicast protocols is
|
||
|
||
<url url="http://www.tascnets.com/mist/doc/mcpCompare.html">.
|
||
|
||
A very good and up-to-date site, with lots of interesting links (Internet
|
||
drafts, RFCs, papers, links to other sites) is:
|
||
<p><url url="http://research.ivv.nasa.gov/RMP/links.html">.
|
||
|
||
<url url="http://hill.lut.ac.uk/DS-Archive/MTP.html"> is also a good source
|
||
of information on the subject.
|
||
|
||
Katia Obraczka's "<em/Multicast Transport Protocols: A Survey and Taxonomy/"
|
||
article gives short descriptions for each protocol and tries to classify them
|
||
according to different features. You can read it in the IEEE Communications
|
||
magazine, January 1998, vol. 36, No. 1.
|
||
|
||
|
||
<sect>References.
|
||
|
||
<sect1>RFCs.
|
||
<p>
|
||
<itemize>
|
||
<item>RFC 1112 "Host Extensions for IP Multicasting". Steve Deering. August 1989.
|
||
|
||
<item>RFC 2236 "Internet Group Management Protocol, version 2". W. Fenner.
|
||
November 1997.
|
||
|
||
<item>RFC 1458 "Requirements for Multicast Protocols". Braudes, R and Zabele, S.
|
||
May 1993.
|
||
|
||
<item>RFC 1469 "IP Multicast over Token-Ring Local Area Networks". T. Pusateri.
|
||
June 1993.
|
||
|
||
<item>RFC 1390 "Transmission of IP and ARP over FDDI Networks". D. Katz.
|
||
January 1993.
|
||
|
||
<item>RFC 1583 "OSPF Version 2". John Moy. March 1994.
|
||
|
||
<item>RFC 1584 "Multicast Extensions to OSPF". John Moy. March 1994.
|
||
|
||
<item>RFC 1585 "MOSPF: Analysis and Experience". John Moy. March 1994.
|
||
|
||
<item>RFC 1812 "Requirements for IP version 4 Routers". Fred Baker,
|
||
Editor. June 1995
|
||
|
||
<item>RFC 2117 "Protocol Independent Multicast-Sparse Mode (PIM-SM):
|
||
Protocol Specification". D. Estrin, D. Farinacci, A. Helmy,
|
||
D. Thaler; S. Deering, M. Handley, V. Jacobson, C. Liu,
|
||
P. Sharma, and L. Wei. July 1997.
|
||
|
||
<item>RFC 2189 "Core Based Trees (CBT version 2) Multicast Routing".
|
||
A. Ballardie. September 1997.
|
||
|
||
<item>RFC 2201 "Core Based Trees (CBT) Multicast Routing Architecture".
|
||
A. Ballardie. September 1997.
|
||
</itemize>
|
||
|
||
|
||
<sect1>Internet Drafts.
|
||
<p>
|
||
<itemize>
|
||
<item>"Introduction to IP Multicast Routing". <tt/draft-ietf-mboned-intro-
|
||
multicast- 03.txt/. T. Maufer, C. Semeria. July 1997.
|
||
|
||
<item>"Administratively Scoped IP Multicast". <tt/draft-ietf-mboned-admin-ip-
|
||
space-03.txt/. D. Meyer. June 10, 1997.
|
||
</itemize>
|
||
|
||
|
||
<sect1>Web pages.
|
||
<p>
|
||
<itemize>
|
||
<item>Linux Multicast Homepage.
|
||
<url url="http://www.cs.virginia.edu/~mke2e/multicast.html">
|
||
|
||
<item>Linux Multicast FAQ.
|
||
<url url="http://andrew.triumf.ca/pub/linux/multicast-FAQ">
|
||
|
||
<item>Multicast and MBONE on Linux.
|
||
<url url="http://www.teksouth.com/linux/multicast/">
|
||
|
||
<item>Christian Daudt's MBONE-Linux Page.
|
||
<url url="http://www.microplex.com/~csd/linux/mbone.html">
|
||
|
||
<item>Reliable Multicast Links <url url="http://research.ivv.nasa.gov/RMP/links.html">
|
||
|
||
<item>Multicast Transport Protocols <url url="http://hill.lut.ac.uk/DS-Archive/MTP.html">
|
||
</itemize>
|
||
|
||
|
||
<sect1>Books.
|
||
<p>
|
||
<itemize>
|
||
<item>"TCP/IP Illustrated: Volume 1 The Protocols". Stevens, W. Richard.
|
||
Addison Wesley Publishing Company, Reading MA, 1994
|
||
|
||
<item>"TCP/IP Illustrated: Volume 2, The Implementation". Wright, Gary and
|
||
W. Richard Stevens. Addison Wesley Publishing Company, Reading MA, 1995
|
||
|
||
<item>"UNIX Network Programming Volume 1. Networking APIs: Sockets and
|
||
XTI". Stevens, W. Richard. Second Edition, Prentice Hall, Inc. 1998.
|
||
|
||
<item> "Internetworking with TCP/IP Volume 1 Principles, Protocols, and
|
||
Architecture". Comer, Douglas E. Second Edition, Prentice Hall, Inc.
|
||
Englewood Cliffs, New Jersey, 1991
|
||
</itemize>
|
||
|
||
|
||
<sect>Copyright and Disclaimer.
|
||
|
||
<p>Copyright 1998 Juan-Mariano de Goyeneche.
|
||
|
||
This HOWTO is free documentation; you can redistribute it and/or
|
||
modify it under the terms of the GNU General Public License as
|
||
published by the Free Software Foundation; either version 2 of the
|
||
License, or (at your option) any later version.
|
||
|
||
This document is distributed in the hope that it will be useful, but
|
||
without any warranty; without even the implied warranty of
|
||
merchantability or fitness for a particular purpose. See the GNU
|
||
General Public License for more details.
|
||
|
||
You can obtain a copy of the GNU General Public License by writing to
|
||
the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
|
||
MA 02111-1307, USA.
|
||
|
||
If you publish this document on a CD-ROM or in hardcopy form, a
|
||
complimentary copy would be appreciated; mail me for my postal
|
||
address. Also consider making a donation to the Linux Documentation
|
||
Project or the Free Software Foundation to help support free documentation
|
||
for GNU/Linux. Contact the Linux HOWTO coordinator, Tim Bynum
|
||
<htmlurl url="mailto:linux-howto@sunsite.unc.edu" name="linux-howto@sunsite.unc.edu">,
|
||
for more information.
|
||
|
||
|
||
<sect>Acknowledgements.
|
||
|
||
<p>This is the best opportunity I've ever had to thank so <em/many/ people
|
||
I feel grateful to. So, I'm afraid this is going to be a large section... It
|
||
is, in any case, the most important one of this paper (for me, at least...).
|
||
|
||
First, I want to thank Elena Apolinario Fern<72>ndez de Sousa (yes, Elena is
|
||
the first name; the REST is THE surname ;-) ). I tried to reflect
|
||
in this Howto all the knowledge I collected while working with her in connecting
|
||
our Department to the MBone and debugging problems with locally generated
|
||
CSCW software across multicast tunnels. She was of invaluable help in
|
||
finding and correcting network problems, discovering and fixing kernel bugs
|
||
that puzzled us for days, ... and keeping the sense of humor alive while
|
||
problems appeared and appeared, but solutions didn't. She also read and
|
||
corrected the drafts for this document and provided important ideas and
|
||
suggestions. If this howto is here and is usefull for somebody, it will be,
|
||
in many aspects, thanks to her. Thanks, Elena!
|
||
|
||
There is something I have been lucky enough to find all my (still-not-too-long)
|
||
live, but, despite being repetitive, has never stopped amazing me.
|
||
I'm talking about people that altruistically employ part of their time
|
||
and/or resources to help other people learn new things; and, what is better,
|
||
they enjoy doing it. This is not only (but also, too) explain things they
|
||
already know, but lend their books, provide access to their sources and
|
||
facilitate you the way to learn all things they know; sometimes, even
|
||
more... I know quite a few of that people, and I'd like to thank them for
|
||
all their help.
|
||
|
||
Pablo Basterrechea was my "first source of documentation" while I was in
|
||
my pre-Internet stage. I learned assembly and advanced structured programming
|
||
entirely from his books (well, the latter also from his programs...).
|
||
Thanks for all, Pablo.
|
||
|
||
In my first course at the University that "primary source of documentation"
|
||
moved to Pepe Ma<4D>as. He was teaching then Computer Programming there, and
|
||
soon I became addict to his bookshelf. He lent me his books lots of times
|
||
without asking for a minimum sign that could assure that I was going
|
||
to return them back to him, not even my name! My first approach to TCP/IP
|
||
was also by his hand: he lent me Comer's "Internetworking with TCP/IP,
|
||
Volume 1" for the whole summer. He did not even know my name by then,
|
||
but he lent me the book...
|
||
That book influenced me a lot, and TCP/IP has become one of my primary
|
||
fields of interest since that summer.
|
||
|
||
If there are two persons I must thank most, these are (in alphabetic
|
||
order ;-) ), Jos<6F> Manuel and Paco Moya. Nobody I asked more things more
|
||
times (C, C++, Linux, security, Web, OSs, signals & systems,
|
||
electronics, ... anything!) and, despite my persistence, I always got throughly
|
||
and friendly responses and help. If I'm using GNU/Linux now, this is, again,
|
||
thanks to them. I feel particularly lucky with friends like them. THANKS.
|
||
|
||
I<EFBFBD>igo Mascaraque also helped (from him I got my first System Administration
|
||
book) and encouraged me in my beginnings, but never stopped reminding me
|
||
that, although this was a fascinating world and an important part of my
|
||
career, I should not forget the other, less-interesting, parts. (I don't
|
||
forget, I$!).
|
||
|
||
As I am on the topic, I'd like to thank my parents, too. They always
|
||
tried to make the best opportunities available for me. Many thanks for
|
||
all.
|
||
|
||
I also feel grateful to Joaqu<71>n Seoane, the first who trusted me enough
|
||
to give me a root password in the time I was learning system administration
|
||
by myself, and Santiago Pav<61>n, the one who gave me my first opportunity
|
||
here at DIT.
|
||
|
||
W. Richard Stevens' books have been a real revelation for me (it's a pity
|
||
they are so expensive...). If he ever reads this paper, I'd like to thank
|
||
him for them, and encourage him to keep on writing. Anything that comes
|
||
out of his hands will -undoubtedly- be good for all of us.
|
||
|
||
Finally I'd like to thank Richard Stallman, Linus Torvalds, Alan Cox and
|
||
all contributors to the Linux kernel and the free software in general,
|
||
for giving us such a great OS.
|
||
|
||
I'm sure I'm forgetting someone here... Sorry. I'm certain they know I'm
|
||
grateful to them too, so if they tell me, everybody will know it... :-)
|
||
|
||
</article>
|