Mailing List Archive

Problems with ripd in quagga-0.96.4
Hello,

After switching from zebra-0.93b to quagga-0.96.4 on one of my routers I
notice two problems with ripd:

1. There are a lot of "RIP: Can't bind socket: Invalid argument" messages
in my ripd logs. It seems that every time ripd tries to send RIP message
it send this error message. After little modification in ripd.c,
rip_interface.c and ripd.h which shows device name in such message I know
that there is a problem with my eth0 device:

(...)
2003/11/05 19:57:34 RIP: Can't bind socket on eth0: Invalid argument
2003/11/05 19:57:45 RIP: Can't bind socket on eth0: Invalid argument
2003/11/05 19:58:00 RIP: Can't bind socket on eth0: Invalid argument
2003/11/05 19:58:09 RIP: Can't bind socket on eth0: Invalid argument
2003/11/05 19:58:19 RIP: Can't bind socket on eth0: Invalid argument
2003/11/05 19:58:25 RIP: Can't bind socket on eth0: Invalid argument
2003/11/05 19:58:39 RIP: Can't bind socket on eth0: Invalid argument
(...)

This is quite strange since there was no problem with old zebra. eth0 is
normal ethernet device, with inet address and inet6 scope link address:

eth0 Link encap:Ethernet HWaddr 00:10:5A:63:F0:88
inet addr:XXX.XXX.210.1 Bcast:XXX.XXX.210.15 Mask:255.255.255.240
inet6 addr: fe80::210:5aff:fe63:f088/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:258817742 errors:2 dropped:0 overruns:0 frame:2
TX packets:218332628 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3695505971 (3524.3 Mb) TX bytes:1047039677 (998.5 Mb)
Interrupt:11 Base address:0xd400

2: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:10:5a:63:f0:88 brd ff:ff:ff:ff:ff:ff
inet XXX.XXX.210.1/28 brd XXX.XXX.210.15 scope global eth0
inet6 fe80::210:5aff:fe63:f088/64 scope link

This is Linux 2.4.23-pre9 kernel.

2. I don't know why but someone changed format of "show ip rip". Now
it is totally unreadable:

Network Next Hop Metric From Tag Time
S(r) 0.0.0.0/0 0.0.0.0 1 self 0
R(n) XXX.XXX.129.0/24XXX.XXX.210.11 2 XXX.XXX.210.11 0 00:43
R(n) XXX.8.133.0/30 XXX.XXX.210.2 3 XXX.XXX.210.2 0 00:43
S(r) XXX.XXX.210.0/230.0.0.0 1 self 0
C(i) XXX.XXX.210.0/280.0.0.0 1 self 0
C(r) XXX.XXX.210.16/290.0.0.0 1 self 0
R(n) XXX.XXX.210.64/27XXX.XXX.210.11 2 XXX.XXX.210.11 0 00:43
R(n) XXX.XXX.211.0/27XXX.XXX.210.11 2 XXX.XXX.210.11 0 00:43
R(n) XXX.XXX.211.224/27XXX.XXX.210.11 2 XXX.XXX.210.11 0 00:43
S(r) XXX.XXX.251.64/27XXX.XXX.210.13 1 self 0
S(r) XXX.XXX.251.64/30XXX.XXX.210.3 1 self 0
R(n) XXX.XXX.251.80/29XXX.XXX.210.3 4 XXX.XXX.210.3 0 00:45
S(r) XXX.XXX.251.80/30XXX.XXX.210.3 1 self 0
R(n) XXX.XXX.127.236/30XXX.XXX.210.3 4 XXX.XXX.210.3 0 00:45
C(r) XXX.XX.32.44/30 0.0.0.0 1 self 0
R(n) XXX.XX.32.180/30XXX.XXX.210.2 3 XXX.XXX.210.2 0 00:43
S(r) XXX.XX.46.64/26 XXX.XXX.210.13 1 self 0
S(r) XXX.XX.46.64/27 XXX.XXX.210.13 1 self 0

There are two ways to fix it - break line if network is to long
(like in "show ip bgp") or revert the change which removed two spaces
between "Network" and "Next Hop". AFAIK Cisco routers do no not have such
command so if we do the second thing it won't breaks "compatibility".
There is also third solution - allow user to decide which type of output
he wants at time of compiling or starting zebra. Any other ideas?

Best regards,

Krzysztof Olêdzki
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Wed, 5 Nov 2003 sowmini.varadhan@sun.com wrote:

> >
> > 1. There are a lot of "RIP: Can't bind socket: Invalid argument" messages
> > in my ripd logs. It seems that every time ripd tries to send RIP message
> > it send this error message. After little modification in ripd.c,
> > rip_interface.c and ripd.h which shows device name in such message I know
> > that there is a problem with my eth0 device:
> >
> > 2003/11/05 19:57:45 RIP: Can't bind socket on eth0: Invalid argument
>
> Can you send me the diffs that you made to ripd.c, rip_interface.c and
> ripd.h in "diff -uwb" mode?

Yes, of course. This looks ugly since full ifp structure is no longer
passwd to rip_interface_multicast_set in original quagga-0.96.4 but it
works. ;-) I think it would be better to pass only ifp->name or revert
patch which removed ifp from call - now we need more elements from
"struct interface".

Best Regards,


Krzysztof Olêdzki
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
Couple of things to try:

1. In your conf file, can you add the lines

debug rip event
log file /var/tmp/ripd.out

and send the resulting ripd.out?


2. are you comfortable with using gdb? If yes, can you do the following:

- compile with -g flag (you can edit the Makefile and change
CFLAGS = -g -Wall
to
CFLAGS = -g

- make ripd, and start it up under gdb. I am used to the dbx mode
so I do:

# gdb --dbx ripd
(gdb) stop in rip_interface_multicast_set
(gdb) run -f /path/to/conf/file

- then step through rip_interface_multicast_set until you hit
the bind error, and at that point,
(gdb) print from

Could you then please email me the output?

--Sowmini
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Wed, 5 Nov 2003 sowmini.varadhan@sun.com wrote:

>
> Couple of things to try:
>
> 1. In your conf file, can you add the lines
>
> debug rip event
> log file /var/tmp/ripd.out
>
> and send the resulting ripd.out?
2003/11/05 22:04:26 RIP: update timer fire!
2003/11/05 22:04:26 RIP: SEND UPDATE to eth0 ifindex 2
2003/11/05 22:04:26 RIP: Can't bind socket on eth0: Invalid argument
2003/11/05 22:04:26 RIP: multicast announce on eth0
2003/11/05 22:04:26 RIP: update routes on interface eth0 ifindex 2
2003/11/05 22:04:26 RIP: SEND to 224.0.0.9.520
2003/11/05 22:04:26 RIP: RECV packet from 195.177.210.3 port 520 on eth0
2003/11/05 22:04:26 RIP: RIPv2 MD5 authentication from 195.177.210.3
2003/11/05 22:04:26 RIP: RIPv2 MD5 authentication success
2003/11/05 22:04:31 RIP: RECV packet from 195.177.210.2 port 520 on eth0
2003/11/05 22:04:31 RIP: RIPv2 MD5 authentication from 195.177.210.2
2003/11/05 22:04:31 RIP: RIPv2 MD5 authentication success
2003/11/05 22:04:32 RIP: RECV packet from 195.177.210.12 port 520 on eth0
2003/11/05 22:04:32 RIP: RIPv2 MD5 authentication from 195.177.210.12
2003/11/05 22:04:32 RIP: RIPv2 MD5 authentication success
2003/11/05 22:04:32 RIP: RECV packet from 195.177.210.11 port 520 on eth0
2003/11/05 22:04:32 RIP: RIPv2 MD5 authentication from 195.177.210.11
2003/11/05 22:04:32 RIP: RIPv2 MD5 authentication success
2003/11/05 22:04:36 RIP: RECV packet from 195.177.210.3 port 520 on eth0
2003/11/05 22:04:36 RIP: RIPv2 MD5 authentication from 195.177.210.3
2003/11/05 22:04:36 RIP: RIPv2 MD5 authentication success

> 2. are you comfortable with using gdb? If yes, can you do the following:
>
> - compile with -g flag (you can edit the Makefile and change
> CFLAGS = -g -Wall
> to
> CFLAGS = -g
>
> - make ripd, and start it up under gdb. I am used to the dbx mode
> so I do:
>
> # gdb --dbx ripd
> (gdb) stop in rip_interface_multicast_set
> (gdb) run -f /path/to/conf/file
>
> - then step through rip_interface_multicast_set until you hit
> the bind error, and at that point,
> (gdb) print from
>
> Could you then please email me the output?

This has to wait. This is a quite important router so I'm afraid I can't
shutdown ripd now. I'll do it as soon as possible.


Best Regards,

Krzysztof Olêdzki
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Wed, 5 Nov 2003, Krzysztof Oledzki wrote:

>
>
> On Wed, 5 Nov 2003 sowmini.varadhan@sun.com wrote:
>
> >
> > Couple of things to try:
> >
> > 1. In your conf file, can you add the lines
<CIACH>
>
> > 2. are you comfortable with using gdb? If yes, can you do the following:
> >
> > - compile with -g flag (you can edit the Makefile and change
> > CFLAGS = -g -Wall
> > to
> > CFLAGS = -g
> >
> > - make ripd, and start it up under gdb. I am used to the dbx mode
> > so I do:
> >
> > # gdb --dbx ripd
> > (gdb) stop in rip_interface_multicast_set
> > (gdb) run -f /path/to/conf/file
> >
> > - then step through rip_interface_multicast_set until you hit
> > the bind error, and at that point,
> > (gdb) print from
> >
> > Could you then please email me the output?

OK. Done.

Breakpoint 1, rip_interface_multicast_set (sock=8, connected=0x80c7410, if_pointopoint=0, ifp=0x80c7a98)
at rip_interface.c:149
149 if (if_pointopoint)
(gdb) print from
$1 = {sin_family = 0, sin_port = 0, sin_addr = {s_addr = 0}, sin_zero = "\004\0\0\0 } @"}
(gdb) continue
Continuing.

And then, shortly after "continue" I have this "Can't bind socket on
eth0: Invalid argument". So like expected - error message is produced in
rip_interface_multicast_set().



And here is the output from strace:
bind(6, NULL, 0) = -1 EINVAL (Invalid argument)
bind(6, {sa_family=AF_INET, sin_port=htons(520), sin_addr=inet_addr("XXX.XXX.210.1")}, 16) = -1 EINVAL (Invalid argument)


Best Regards,


Krzysztof Olêdzki
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Wed, 5 Nov 2003, Krzysztof Oledzki wrote:

<CIACH>
> Breakpoint 1, rip_interface_multicast_set (sock=8, connected=0x80c7410, if_pointopoint=0, ifp=0x80c7a98)
> at rip_interface.c:149
> 149 if (if_pointopoint)
> (gdb) print from
> $1 = {sin_family = 0, sin_port = 0, sin_addr = {s_addr = 0}, sin_zero = "\004\0\0\0 } @"}
> (gdb) continue
> Continuing.
>
> And then, shortly after "continue" I have this "Can't bind socket on
> eth0: Invalid argument". So like expected - error message is produced in
> rip_interface_multicast_set().
>
>
>
> And here is the output from strace:
> bind(6, NULL, 0) = -1 EINVAL (Invalid argument)
> bind(6, {sa_family=AF_INET, sin_port=htons(520), sin_addr=inet_addr("XXX.XXX.210.1")}, 16) = -1 EINVAL (Invalid argument)

Ah. I have just noticed that sockfd from strace (6) differents from gdb's
one (8), probably because I didn't call gdb from strace and gdb used some
file desciprions, right?

Anyway, I'm reading the code from rip_interface_multicast_set(). I can see
two binds there:

bind (sock, NULL, 0); /* unbind any previous association */
ret = bind (sock, (struct sockaddr *) & from, sizeof (struct sockaddr_in));

According to strace, both fail. I'm wonder how RIP can work with this
failed bind... but it works ;-) This is the output from tcpdump:

23:24:13.888700 XXX.XXX.210.1.520 > 224.0.0.9.520: RIPv2-resp [items 18]: (...)


Best Regards,


Krzysztof Oledzki
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
>
> Anyway, I'm reading the code from rip_interface_multicast_set(). I can see
> two binds there:
>
> bind (sock, NULL, 0); /* unbind any previous association */
> ret = bind (sock, (struct sockaddr *) & from, sizeof (struct sockaddr_in));
>
> According to strace, both fail. I'm wonder how RIP can work with this
> failed bind... but it works ;-) This is the output from tcpdump:

Well, it does a bind for each outgoing packet, to make sure the right
interface is picked up. If you bind twice to the same socket with
a non-null sockaddr, the second bind will fail because the
socket is already bound to an address. The OS-es I'm familiar with
(*BSD, Solaris) allow you to unbind an existing associaton by
doing a bind(sock, NULL, 0) but evidently this is not the behavior
on linux. I'll have to investigate (any linux gurus there want
to comment? How does one pick an outgoing interface on linux?)

In your case, things work because it's always binding to the same
address, and since the first bind succeeds, it doesn't matter that
the successive binds fail, which is why things seem to be working.

--Sowmini
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Thu, 6 Nov 2003 sowmini.varadhan@sun.com wrote:

> >
> > Anyway, I'm reading the code from rip_interface_multicast_set(). I can see
> > two binds there:
> >
> > bind (sock, NULL, 0); /* unbind any previous association */
> > ret = bind (sock, (struct sockaddr *) & from, sizeof (struct sockaddr_in));
> >
> > According to strace, both fail. I'm wonder how RIP can work with this
> > failed bind... but it works ;-) This is the output from tcpdump:
>
> Well, it does a bind for each outgoing packet, to make sure the right
> interface is picked up.
Ah, I see...

> If you bind twice to the same socket with a non-null sockaddr, the
> second bind will fail because the socket is already bound to an address.
True.

> The OS-es I'm familiar with (*BSD, Solaris) allow you to unbind an
> existing associaton by doing a bind(sock, NULL, 0) but evidently this is
> not the behavior on linux.
Ah. Which socket are ripd trying to unbind? It seems that this is the
global 0.0.0.0:520. This is a log from strace:

(...)
bind(6, {sa_family=AF_INET, sin_port=htons(520), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
(...)
bind(6, NULL, 0) = -1 EINVAL (Invalid argument)
bind(6, {sa_family=AF_INET, sin_port=htons(520), sin_addr=inet_addr("XXX.XXX.210.1")}, 16) = -1 EINVAL (Invalid argument)
(...)
bind(6, NULL, 0) = -1 EINVAL (Invalid argument)
bind(6, {sa_family=AF_INET, sin_port=htons(520), sin_addr=inet_addr("XXX.XXX.210.1")}, 16) = -1 EINVAL (Invalid argument)
(...)

Is it safe? What will happend when someone send us packets while the
socket is being unbinded?

Best regards,

Krzysztof Olêdzki
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
> Ah. Which socket are ripd trying to unbind? It seems that this is the
> global 0.0.0.0:520. This is a log from strace:

It's the socket with descriptor number 6.

> (...)
> bind(6, {sa_family=AF_INET, sin_port=htons(520), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
> (...)
> bind(6, NULL, 0) = -1 EINVAL (Invalid argument)

> Is it safe?

Yes.

> What will happend when someone send us packets while the
> socket is being unbinded?

the bind() only sets the local end-point (source address we'll use
in outgoing packets) in this case.

--Sowmini
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Thu, 6 Nov 2003 sowmini.varadhan@sun.com wrote:

> the bind() only sets the local end-point (source address we'll use
> in outgoing packets) in this case.

Can we will still receive all packets? I mean: those with dst address
difeerent from current local end-point?

Best regards,


Krzysztof Olêdzki
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
> Can we will still receive all packets? I mean: those with dst address
> difeerent from current local end-point?

yes, we are trying to receive datagrams on an unconnected UDP
socket.

But my bigger problem is that I don't know what one is supposed
to do on linux, in order to re-bind a socket to a different source
address. The man page mumbles that:

EINVAL The socket is already bound to an address. This
may change in the future: see linux/unix/sock.c for
details.

so a question for the linux enthusiasts- who or what is "linux/unix/sock.c"?

Right now, the only solution I can think of is to close and re-open
rip->sock so that I can bind it to the new address for #ifdef LINUX

Surely there's a more elegant solution for this?!!!

--Sowmini
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Thu, 2003-11-06 at 06:03, sowmini.varadhan@Sun.COM wrote:

> Well, it does a bind for each outgoing packet, to make sure the right
> interface is picked up. If you bind twice to the same socket with
> a non-null sockaddr, the second bind will fail because the
> socket is already bound to an address. The OS-es I'm familiar with
> (*BSD, Solaris) allow you to unbind an existing associaton by
> doing a bind(sock, NULL, 0) but evidently this is not the behavior
> on linux. I'll have to investigate (any linux gurus there want

I am not sure if this behavior is supported in Linux. Needs to be
checked. Let me see.

> to comment? How does one pick an outgoing interface on linux?)
>

set SO_BINDTODEVICE in the socket options I believe.

--
.| Amit Kucheria |.
...| Wireless Systems Engineer |...
.....| Metric Systems Corp., San Diego, CA |.....
......| www.metricsystems.com |......
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
>
> > to comment? How does one pick an outgoing interface on linux?)
> >=20
>
> set SO_BINDTODEVICE in the socket options I believe.

yes, but in this case, I later realized that I need to bind to a
different address (could have multiple address on the same intf,
and I need to set a different source address so that I can
send a rip packet for each connected network).

--Sowmini
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Thu, 2003-11-06 at 09:03, sowmini.varadhan@Sun.COM wrote:
> >
> > > to comment? How does one pick an outgoing interface on linux?)
> > >=20
> >
> > set SO_BINDTODEVICE in the socket options I believe.
>
> yes, but in this case, I later realized that I need to bind to a
> different address (could have multiple address on the same intf,
> and I need to set a different source address so that I can
> send a rip packet for each connected network).
>
> --Sowmini

As an aside, any particular reason why we don't have a different socket
bound to each interface (each address really), and then select the right
socket?

I might not be making complete sense, but hey I had to ask. :)

/Amit


.| Amit Kucheria |.
...| Wireless Systems Engineer |...
.....| Metric Systems Corp., San Diego, CA |.....
......| www.metricsystems.com |......
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
> As an aside, any particular reason why we don't have a different socket
> bound to each interface (each address really), and then select the right
> socket?

because you don't need to have so many sockets- just one socket from
which you send to all the connected networks??
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Thu, 2003-11-06 at 09:29, sowmini.varadhan@Sun.COM wrote:
> > As an aside, any particular reason why we don't have a different socket
> > bound to each interface (each address really), and then select the right
> > socket?
>
> because you don't need to have so many sockets- just one socket from
> which you send to all the connected networks??

At the cost of bind() calls before each send? Looks like this is a CPU
vs. memory design trade off.

And the memory usage by a few more sockets isn't enormous. While the CPU
usage on a busy router might be killing.

And on embedded devices, its easier (and cheaper?) to add memory. Just
my opinion.

/Amit

--
.| Amit Kucheria |.
...| Wireless Systems Engineer |...
.....| Metric Systems Corp., San Diego, CA |.....
......| www.metricsystems.com |......
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
> > because you don't need to have so many sockets- just one socket from
> > which you send to all the connected networks??
>
> At the cost of bind() calls before each send? Looks like this is a CPU
> vs. memory design trade off.

well, OPEN_MAX is usually 256.

> And on embedded devices, its easier (and cheaper?) to add memory. Just
> my opinion.

yes, but zebra is also used on non-embedded devices like workstations.

--Sowmini
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Thu, 2003-11-06 at 11:35, sowmini.varadhan@Sun.COM wrote:
> > > because you don't need to have so many sockets- just one socket from
> > > which you send to all the connected networks??
> >
> > At the cost of bind() calls before each send? Looks like this is a CPU
> > vs. memory design trade off.
>
> well, OPEN_MAX is usually 256.

Hmm..thats interesting. Learn something new everyday! Where can this
setting be found? Nothing in /proc.

> > And on embedded devices, its easier (and cheaper?) to add memory. Just
> > my opinion.
>
> yes, but zebra is also used on non-embedded devices like workstations.

Workstations don't have any such problems (memory or CPU). So I would
design for the lowest common denominator.

BTW, I wrote a quick program to check your case of two binds.

Executing it gives the "invalid argument" for bind as follows.

[amit@amit]-(..amit/proggy) $ sudo ./udpsock
bind: Invalid argument

So I checked the inet_bind() routine in the kernel
(/usr/src/linux/net/ipv4/af_inet.c). Reproducing the relevant parts
below:

------------ af_inet.c -------------------
/* Check these errors (active socket, double bind). */
err = -EINVAL;
if ((sk->state != TCP_CLOSE) ||
(sk->num != 0))
goto out;
------------------------------------------

So, its explicitly NOT allowed.

/Amit


----- socket application to check case of 2 binds-----------------
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>

#define IPPROTO_OLSR 698

int main()
{
int udpsock, ret;
struct sockaddr sock;
struct sockaddr_in *sin = (struct sockaddr_in *)&sock;
int i=1;

udpsock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udpsock < 0) {
strerror(errno);
exit(1);
}

memset(&sock, 0, sizeof (sock));
sin->sin_family = PF_INET;
sin->sin_port = htons(IPPROTO_OLSR);
(sin->sin_addr).s_addr = htonl(INADDR_ANY);

ret = bind(udpsock, (struct sockaddr *)sin, sizeof (*sin));
if (ret < 0) {
perror("bind");
exit(1);
}

ret = bind(udpsock, NULL, 0);
if (ret < 0) {
perror("bind");
exit(1);
}

while (1);

}


--
.| Amit Kucheria |.
...| Wireless Systems Engineer |...
.....| Metric Systems Corp., San Diego, CA |.....
......| www.metricsystems.com |......
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
> > well, OPEN_MAX is usually 256.
>
> Hmm..thats interesting. Learn something new everyday! Where can this
> setting be found? Nothing in /proc.

/usr/include/limits.h

>
> BTW, I wrote a quick program to check your case of two binds.=20
>

yes I know. I'm working on the patch to restore the
open/close_socket_for_each_send code for linux. This code was
removed (by me) when I made some changes in rev 1.13 of ripd.c

--Sowmini
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Thu, 2003-11-06 at 12:49, sowmini.varadhan@Sun.COM wrote:
> > > well, OPEN_MAX is usually 256.
> >
> > Hmm..thats interesting. Learn something new everyday! Where can this
> > setting be found? Nothing in /proc.
>
> /usr/include/limits.h

That was /usr/include/linux/limits.h for me. And its a per-process
limit. That doesn't look too bad for something like quagga. Do we know
many quagga users who use more that 200 ip addresses on a single
machine? :)

> >
> > BTW, I wrote a quick program to check your case of two binds.=20
> >
>
> yes I know. I'm working on the patch to restore the
> open/close_socket_for_each_send code for linux. This code was
> removed (by me) when I made some changes in rev 1.13 of ripd.c

I still *shudder* at this open-bind-close approach for _each_ packet
transmit. Maybe Paul or some other more-clued-in person could throw some
light onto why this approach was taken?

/Amit

--
.| Amit Kucheria |.
...| Wireless Systems Engineer |...
.....| Metric Systems Corp., San Diego, CA |.....
......| www.metricsystems.com |......
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Thu, 6 Nov 2003 sowmini.varadhan@sun.com wrote:

> >
> > Anyway, I'm reading the code from rip_interface_multicast_set(). I can see
> > two binds there:
> >
> > bind (sock, NULL, 0); /* unbind any previous association */
> > ret = bind (sock, (struct sockaddr *) & from, sizeof (struct sockaddr_in));
> >
> > According to strace, both fail. I'm wonder how RIP can work with this
> > failed bind... but it works ;-) This is the output from tcpdump:
>
> Well, it does a bind for each outgoing packet, to make sure the right
> interface is picked up. If you bind twice to the same socket with
> a non-null sockaddr, the second bind will fail because the
> socket is already bound to an address. The OS-es I'm familiar with
> (*BSD, Solaris) allow you to unbind an existing associaton by
> doing a bind(sock, NULL, 0) but evidently this is not the behavior
> on linux.

That's strange. I have just tested it on FreeBSD 4.9-RC and...
"bind: Invalid argument". Hm?

Best regards,

Krzysztof Olêdzki
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
On Thu, 6 Nov 2003 sowmini.varadhan@Sun.COM wrote:

> > Can we will still receive all packets? I mean: those with dst address
> > difeerent from current local end-point?
>
> yes, we are trying to receive datagrams on an unconnected UDP
> socket.

But what will happend if we rebind this socket to other address than
0.0.0.0?

No offence, only asking.

Best regards,

Krzysztof Olêdzki
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
>
> I still *shudder* at this open-bind-close approach for _each_ packet
> transmit. Maybe Paul or some other more-clued-in person could throw some
> light onto why this approach was taken?
>

because linux does not permit a re-bind?

--Sowmini
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
>
> That's strange. I have just tested it on FreeBSD 4.9-RC and...
> "bind: Invalid argument". Hm?
>

oops. you are right. more research reveals that only Solaris
supports this, based on some language about rebinding in XNET, but
this language is evidently not present in the Posix socket draft.

my mistake. I'll work on the fix so that the rebinding only happens
for Solaris.

--Sowmini
Re: Problems with ripd in quagga-0.96.4 [ In reply to ]
>
> That's strange. I have just tested it on FreeBSD 4.9-RC and...
> "bind: Invalid argument". Hm?
>
> Krzysztof Olêdzki

thanks Krzystof, for point this out. I think that since the solaris
support for unbinding is pretty funky, and is not portable, the most
portable solution is to open/bind/close a socket for each packet.
I understand that the IPv6 advanced API supports ancillary data
in the sendmsg command to avoid the obvious overhead needed
to do this, but for ipv4, we have to stick to the safest way.

I'm attaching the diffs below. It's not pretty, but I wanted
to avoid towing the source address on the stack as a function
argument, and having a global var is not any different than
binding the socket's local address up in rip_update_process()
or rip_request_send() in preparation for rip_send_packet.

akucheria@metricsystems.com writes:
> That doesn't look too bad for something like quagga. Do we know
> many quagga users who use more that 200 ip addresses on a single
> machine? :)

Having a socket-per-interface-address solution is not scalable.
Also, it's not hard to hit the 256 limit when tunnels enter the picture.

--Sowmini


===================================================================
RCS file: ripd/rip_interface.c,v
retrieving revision 1.13
diff -uwb -r1.13 ripd/rip_interface.c
--- ripd/rip_interface.c 2003/10/15 23:20:17 1.13
+++ ripd/rip_interface.c 2003/11/07 16:07:38
@@ -146,13 +146,18 @@
struct in_addr addr;
struct prefix_ipv4 *p;

+ if (connected != NULL)
+ {
if (if_pointopoint)
p = (struct prefix_ipv4 *) connected->destination;
else
p = (struct prefix_ipv4 *) connected->address;
-
addr = p->prefix;
-
+ }
+ else
+ {
+ addr.s_addr = INADDR_ANY;
+ }

if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
addr, 0, 0) < 0)
@@ -173,7 +178,10 @@

/* Address shoud be any address. */
from.sin_family = AF_INET;
+ if (connected)
addr = ((struct prefix_ipv4 *) connected->address)->prefix;
+ else
+ addr.s_addr = INADDR_ANY;
from.sin_addr = addr;
#ifdef HAVE_SIN_LEN
from.sin_len = sizeof (struct sockaddr_in);
@@ -182,7 +190,6 @@
if (ripd_privs.change (ZPRIVS_RAISE))
zlog_err ("rip_interface_multicast_set: could not raise privs");

- bind (sock, NULL, 0); /* unbind any previous association */
ret = bind (sock, (struct sockaddr *) & from, sizeof (struct sockaddr_in));
if (ret < 0)
{
===================================================================
RCS file: ripd/ripd.c,v
retrieving revision 1.11
diff -uwb -r1.11 ripd/ripd.c
--- ripd/ripd.c 2003/10/15 23:20:17 1.11
+++ ripd/ripd.c 2003/11/07 16:34:23
@@ -42,6 +42,11 @@
#include "ripd/ripd.h"
#include "ripd/rip_debug.h"

+/*
+ * The source address to be used when sending the packet
+ */
+struct connected *source_address;
+
extern struct zebra_privs_t ripd_privs;

/* RIP Structure. */
@@ -1237,7 +1242,7 @@
rip_send_packet (caddr_t buf, int size, struct sockaddr_in *to,
struct interface *ifp)
{
- int ret;
+ int ret, send_sock;
struct sockaddr_in sin;

/* Make destination address. */
@@ -1252,6 +1257,7 @@
{
sin.sin_port = to->sin_port;
sin.sin_addr = to->sin_addr;
+ send_sock = rip->sock;
}
else
{
@@ -1259,11 +1265,32 @@
sin.sin_port = htons (RIP_PORT_DEFAULT);
sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);

- /* caller has set multicast interface */
+ /*
+ * we have to open a new socket for each packet because
+ * this is the most portable way to bind to a different
+ * source ipv4 address.
+ */
+ send_sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (send_sock < 0)
+ {
+ zlog_warn("could not create socket %s", strerror(errno));
+ return -1;
+ }
+
+ sockopt_broadcast (send_sock);
+ sockopt_reuseaddr (send_sock);
+ sockopt_reuseport (send_sock);
+#ifdef RIP_RECVMSG
+ setsockopt_pktinfo (send_sock);
+#endif /* RIP_RECVMSG */
+ rip_interface_multicast_set(send_sock, source_address,
+ if_is_pointopoint(ifp));
+ /* reset source address */
+ source_address = NULL;

}

- ret = sendto (rip->sock, buf, size, 0, (struct sockaddr *)&sin,
+ ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
sizeof (struct sockaddr_in));

if (IS_RIP_DEBUG_EVENT)
@@ -1273,6 +1300,7 @@
if (ret < 0)
zlog_warn ("can't send packet : %s", strerror (errno));

+ close(send_sock);
return ret;
}

@@ -2358,8 +2386,7 @@
if (ifaddr->family != AF_INET)
continue;

- rip_interface_multicast_set(rip->sock, connected,
- if_is_pointopoint(ifp));
+ source_address = connected;
if (vsend & RIPv1)
rip_update_interface (ifp, RIPv1, route_type, ifaddr);
if (vsend & RIPv2)
@@ -2588,8 +2615,7 @@
if (p->family != AF_INET)
continue;

- rip_interface_multicast_set(rip->sock, connected,
- if_is_pointopoint(ifp));
+ source_address = connected;
if (rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet),
to, ifp) != sizeof (rip_packet))
return -1;

1 2  View All