


Intellingent Bridging for ethernet devices
===========================

This implementation provides kernel support for bridging between the ethernet 
devices. Bridging is required if the linux system has to be used
to connect two independent segments, but part of single IP or IPX 
network.  The linux implementation should perform better than
the many PC implementations already available due to its 32 bit
performance though no studies have been made. The implementation
is as efficient as possible; the packets are duplicated only when
necessary. 

The advantages this implementation offers are that you can manage 
the bridge system from any site because it allows TCP-IP protocol to 
coexist with the bridge, and therefore allow you to login from any other 
machine. These patches replace the earlier 'ipxbridge' program which could
run only in user mode.



"intelligent"  means, if a packet is between two machines A and B 
on same side of bridge - both on single segment,  it is not put on
other segments. (You don't even have to specify that A and B are
on same side; the bridge learns automatically.) 

A better algorithm is used to build the host->segment table; it results 
in table lookup only for the destination. Usually the table lookup 
is performed for source address also. It is performed for every packet 
so that the source address is inserted in table as soon as a new machine 
comes up on network. In this implementation, we use slightly complicated
algorithm to insert the source in directed manner;  after few
packet exchanges, it is no more looked up in source.

Spanning tree algorithm is not (yet) implemented. (i.e. connecting
many  bridges should not result in loops between the segments.) 

Different configurations:  
=========================
1.  As "brouter" ... 

You can enable/disable any protocol that you want to bridge. If linux
is used as IP router,  you can enable bridging to allow IPX and other
protocols but disallow bridging of IP packets.  
 

2. As fullfledged bridge.

In this mode, all packets are allowed to be bridged; used mainly
for isolation of network traffic between two or more segments. However 
it requires two IP addresses to be assigned.


(In all modes, linux itself can be used for usual purposes, though 
it could be slow because every packet on the network causes network 
interrupt due to promiscuous mode.)
 

INSTALLATION:
============
Patch the kernel with appropriate bridge patches by issuing the
command 'patch -p0 < bridge.patches.for.1.2.xx'.
(Supplied patches with this package are for 1.2.11.)

These patches create net/inet/bridge.c, patch dev.c, and update Makefile
and config files. They also allow eth1 to be probed in drivers/net/Space.c. 

First, edit net/inet/bridge.c and set the required options. You can
select the protocols  which should not be bridged, and declare the
names of devices which are to be considered for bridging. The defaults
are, bridging of all packets, and usual devices - eth0, eth1 etc.

When you do 'make config', select the Bridge option.

After the new kernel comes up, the device gets added to the
bridge-device-list  when it is opened using ifconfig.  Similarly,
if the device is brought down, it is removed from the list.
(In such case, the table that maps the ethernet addresses to 
their segments  is also cleared, and freshly built again.)

You will also have to set the all the devices to promiscous mode by
issuing command 'ifconfig eth0 promisc' etc.  


The internal tables can be cleared (to learn the hosts->segment
mapping afresh) by bringing "lo" device down, and then up again.
No periodic cleaning is done automatically. (If required, you can
put the command to bring down lo and then bring that up again, in cron 
tables.)


( Newbies : If you want to use this to filter the traffic between 
  segments, look at the file /etc/rc.d/rc.inet1 and see how 
  device eth0 is initialised. You should initialise eth1 in similar way,
  though you have to give new IP address. You should include one more
  entry to add static route: 'route add -host  IP-2 eth1' where IP-2 is
  the IP address assigned to eth1. 
)



Technical Notes:
================

Hash table:  
===========
   Let the Ethernet address be aa:bb:cc:dd:ee:ff. 

   Hash table is of size 64K. So each byte of it can be addressed by 16-bit
   number.  However, we address using only 15 bits, with last bit 
   set to zero. So an addressable  "block" would be of 2 bytes.

   Each element of hash table is however of the size of 12 bytes, 
   and contains two slots (which should both have same corresponding
   device name). 

   Given ethernet address of aa:bb:cc:dd:ee:ff, We can use any two
   bytes for hashing. Usually ee:ff are most random since people buy cards 
   in bulk from same manufacturer. We use index= ff * 256 + (ee 
   shift left by 1). 

   So addresses of the form ee:ff,(ee+1):ff , (ee+2):ff, .. and 6 of them
   can destroy the slots.  (However, ee:ff, and ee+2:ff are properly 
   put in two slots.) 

Algorithm to insert a new entry ... 
===================================

   Insertion is driven by destination lookup. The algorithm uses a
   tag with each address to do directed source insertion.  
   If there are two hosts A and B, two packets 1) A to B and  
   2) B to A  will guarantee that both of them will get 
   inserted. Once inserted, the algorithm will not be invoked
   again. Algorithm is given below:
   
   When packet (a,b) arrives,
               Look up the table for destination b.  
               If b is not found:   
                    Look up the source a, insert it if it is not found.
                    Tag a.
                    return.

               If b is found, check its tag. 
               If tag is not set, return.
               If tag is set, 
                    Lookup the source, insert it if it is not found. 
                    Clear the tag.
 
                          Dest. is Not Found          Dest  is tagged. 

Source Inserted Now          Set the source tag.      Clear the Dest. tag.

Source already inserted.     Set the source tag.      (*) Decrement the 
                                                          destination tag.

(*) There can be different options here: Leave the tag unchanged, 
    Unset it, or to decrement it. If source is already inserted, the 
    tag could be for some other source; but it can't be confirmed 
    easily. There is a possibility that all sources are already added; 
    so there should be some other condition also which will 
    deterministically set the tag to zero.  
    To take care of this, we assign an integer value when a tag is set. 
    During this condition, this value is decremented. It in turn means
    that after these many packets are received, the tag is automatically
    cleared. (So the reply from the actual source to be added 
    should arrive within these many packets ...).


Skbuffs:
      You have to take some care while handling skbuffs:

      1. The length field is decremented in dev.c so as to deduct 
         the first 14 bytes. Depending on where you place the
         bridge() code, you may/maynot have to consider this 
         length while sending the packets to other interfaces.

     2.  The same skb is used to send to each destination interface 
         as far as possible(i.e. it is not cloned). When this is done,
         skb-> free is set to zero so that the skb is not freed
         in device driver. 

     3.  When skb enters the bridge() routine, it is assumed to be 
         locked. When calling device driver routine hard_xmit, we
         have to unlock it and lock it again. If we have to use 
         the general transmit pool (i.e. dev_queue_xmit), we have
         to clone the skb. 

     4.  The received skb is either freed by bridge() routine itself,
         or is sent to upper layers.  bridge() therefore returns 
         this status. 
              
     5.  If the skb is sent to the protocol layer, then be sure to
         restore all the parameters such as skb->dev etc.

