Mailing List Archive

ripd fixes [was Re: ripd status]
Here's a patch to address issues raised in [quagga-dev 490] and
re-opened in [quagga-dev 669]. I've tested this successfully
on linux and found all results satisfactory.

The changes are:

- rip_interface.c: obsolete unbind code in rip_interface_multicast_set,
and instead do the more portable (though slower) method of creating a
socket for each outgoing packet and binding the source address on the
new socket.
- rip_interface.c, ripd.c, ripd.h: Modify rip_request_send so that source
address is determined by the caller of rip_request_send for
ripv1 packets and non-multicast interfaces (rip_request_send loops
over all connected address in all other cases).
- ripd.c/rip_send_packet: don't send packets with source set to
ZEBRA_IFA_SECONDARY connected addresses; improved debug messages;

I've also fixed indenting as appropriate, though (on Paul's request)
the -uwb flags to rcsdiff doesn't list all the white-space fixes.

--Sowmini

===================================================================
RCS file: rip_interface.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -uwb -r1.13 -r1.14
--- /tmp/T0P.a9ej Wed Jan 21 12:26:45 2004
+++ /tmp/T1Q.a9ej Wed Jan 21 12:26:46 2004
@@ -146,16 +146,20 @@
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)
+ if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF, addr, 0, 0) < 0)
{
zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock);
return;
@@ -171,8 +175,9 @@
else
from.sin_port = htons (RIP_PORT_DEFAULT);

- /* Address shoud be any address. */
+ /* Address should be any address. */
from.sin_family = AF_INET;
+ if (connected)
addr = ((struct prefix_ipv4 *) connected->address)->prefix;
from.sin_addr = addr;
#ifdef HAVE_SIN_LEN
@@ -182,7 +187,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)
{
@@ -209,7 +213,7 @@
if (IS_RIP_DEBUG_EVENT)
zlog_info ("multicast request on %s", ifp->name);

- rip_request_send (NULL, ifp, version);
+ rip_request_send (NULL, ifp, version, NULL);
return;
}

@@ -238,7 +242,7 @@
if (IS_RIP_DEBUG_EVENT)
zlog_info ("SEND request to %s", inet_ntoa (to.sin_addr));

- rip_request_send (&to, ifp, version);
+ rip_request_send (&to, ifp, version, connected);
}
}
}
@@ -284,7 +288,7 @@
to.sin_port = htons (RIP_PORT_DEFAULT);
to.sin_addr = addr;

- rip_request_send (&to, NULL, rip->version_send);
+ rip_request_send (&to, NULL, rip->version_send, NULL);
}

/* Request routes at all interfaces. */
===================================================================
RCS file: ripd.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -uwb -r1.11 -r1.12
--- /tmp/T0DVG.ej Wed Jan 21 12:27:05 2004
+++ /tmp/T1EVG.ej Wed Jan 21 12:27:05 2004
@@ -61,7 +61,7 @@

void rip_output_process (struct interface *, struct prefix *,
struct sockaddr_in *, int, u_char,
- struct prefix_ipv4 *);
+ struct connected *, struct prefix_ipv4 *);

/* RIP output routes type. */
enum
@@ -1235,11 +1235,33 @@
/* RIP packet send to destination address. */
int
rip_send_packet (caddr_t buf, int size, struct sockaddr_in *to,
- struct interface *ifp)
+ struct interface *ifp, struct connected *connected)
{
- int ret;
+ int ret, send_sock;
struct sockaddr_in sin;

+ if (IS_RIP_DEBUG_PACKET)
+ {
+ char dst[20];
+ if (to)
+ {
+ strcpy(dst, inet_ntoa(to->sin_addr));
+ }
+ else
+ {
+ sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
+ strcpy(dst, inet_ntoa(sin.sin_addr));
+ }
+ zlog_info("rip_send_packet %s > %s (%s)",
+ inet_ntoa(connected->address->u.prefix4), dst, ifp->name);
+ }
+ if (connected->flags & ZEBRA_IFA_SECONDARY)
+ {
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_info("duplicate dropped");
+ return 0;
+ }
+
/* Make destination address. */
memset (&sin, 0, sizeof (struct sockaddr_in));
sin.sin_family = AF_INET;
@@ -1252,6 +1274,7 @@
{
sin.sin_port = to->sin_port;
sin.sin_addr = to->sin_addr;
+ send_sock = rip->sock;
}
else
{
@@ -1259,11 +1282,28 @@
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 for each packet.
+ */
+ send_sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (send_sock < 0)
+ {
+ zlog_warn("rip_send_packet 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, connected, if_is_pointopoint(ifp));
+ }

- 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 +1313,9 @@
if (ret < 0)
zlog_warn ("can't send packet : %s", strerror (errno));

+ if (!to)
+ close(send_sock);
+
return ret;
}

@@ -1456,7 +1499,7 @@

/* All route with split horizon */
rip_output_process (ifp, NULL, from, rip_all_route, packet->version,
- &saddr);
+ NULL, &saddr);
}
else
{
@@ -1488,7 +1531,7 @@
}
packet->command = RIP_RESPONSE;

- rip_send_packet ((caddr_t) packet, size, from, ifp);
+ rip_send_packet ((caddr_t) packet, size, from, ifp, NULL);
}
rip_global_queries++;
}
@@ -1882,6 +1925,8 @@
if (ret < 0)
{
perror ("bind");
+ if (ripd_privs.change (ZPRIVS_LOWER))
+ zlog_err ("rip_create_socket: could not lower privs");
return ret;
}
if (ripd_privs.change (ZPRIVS_LOWER))
@@ -1981,7 +2026,7 @@
void
rip_output_process (struct interface *ifp, struct prefix *ifaddr,
struct sockaddr_in *to, int route_type, u_char version,
- struct prefix_ipv4 *saddr)
+ struct connected *connected, struct prefix_ipv4 *saddr)
{
int ret;
struct stream *s;
@@ -2117,9 +2162,20 @@
/* if (split_horizon == rip_split_horizon) */
if (ri->split_horizon == RIP_SPLIT_HORIZON)
{
- /* We perform split horizon for RIP and connected route. */
- if ((rinfo->type == ZEBRA_ROUTE_RIP ||
- rinfo->type == ZEBRA_ROUTE_CONNECT) &&
+ /*
+ * We perform split horizon for RIP and connected route.
+ * For rip routes, we want to suppress the route if we would
+ * end up sending the route back on the interface that we
+ * learned it from, with a higher metric. For connected routes,
+ * we suppress the route if the prefix is a subset of the
+ * source address that we are going to use for the packet
+ * (in order to handle the case when multiple subnets are
+ * configured on the same interface).
+ */
+ if (rinfo->type == ZEBRA_ROUTE_RIP &&
+ rinfo->ifindex == ifp->ifindex)
+ continue;
+ if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
prefix_match((struct prefix *)p, (struct prefix *)saddr))
continue;
}
@@ -2204,10 +2260,22 @@
* for RIP and connected routes.
**/
if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
- if ((rinfo->type == ZEBRA_ROUTE_RIP ||
- rinfo->type == ZEBRA_ROUTE_CONNECT) &&
+ /*
+ * We perform split horizon for RIP and connected route.
+ * For rip routes, we want to suppress the route if we would
+ * end up sending the route back on the interface that we
+ * learned it from, with a higher metric. For connected routes,
+ * we suppress the route if the prefix is a subset of the
+ * source address that we are going to use for the packet
+ * (in order to handle the case when multiple subnets are
+ * configured on the same interface).
+ */
+ if (rinfo->type == ZEBRA_ROUTE_RIP &&
rinfo->ifindex == ifp->ifindex)
rinfo->metric_out = RIP_METRIC_INFINITY;
+ if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
+ prefix_match((struct prefix *)p, (struct prefix *)saddr))
+ rinfo->metric_out = RIP_METRIC_INFINITY;
}

/* Write RTE to the stream. */
@@ -2218,7 +2286,7 @@
rip_auth_md5_set (s, ifp);

ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
- to, ifp);
+ to, ifp, connected);

if (ret >= 0 && IS_RIP_DEBUG_SEND)
rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
@@ -2234,7 +2302,8 @@
if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
rip_auth_md5_set (s, ifp);

- ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifp);
+ ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifp,
+ connected);

if (ret >= 0 && IS_RIP_DEBUG_SEND)
rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
@@ -2250,12 +2319,13 @@
/* Send RIP packet to the interface. */
void
rip_update_interface (struct interface *ifp, u_char version, int route_type,
- struct prefix_ipv4 *saddr)
+ struct connected *sconn)
{
struct prefix_ipv4 *p;
struct connected *connected;
listnode node;
struct sockaddr_in to;
+ struct prefix_ipv4 *saddr = (struct prefix_ipv4 *) sconn->address;

/* When RIP version is 2 and multicast enable interface. */
if (version == RIPv2 && if_is_multicast (ifp))
@@ -2264,7 +2334,7 @@
zlog_info ("multicast announce on %s ", ifp->name);

rip_output_process (ifp, NULL, NULL, route_type, rip->version_send,
- saddr);
+ sconn, saddr);
return;
}

@@ -2292,7 +2362,7 @@
inet_ntoa (to.sin_addr), ifp->name);

rip_output_process (ifp, connected->address, &to, route_type,
- rip->version_send, saddr);
+ rip->version_send, connected, saddr);
}
}
}
@@ -2346,10 +2416,11 @@
LIST_LOOP(ifp->connected, connected, ifnode)
{
struct prefix_ipv4 *ifaddr;
-
-
- /* If there is no version configuration in the interface,
- use rip's version setting. */
+ int done = 0;
+ /*
+ * If there is no version configuration in the interface,
+ * use rip's version setting.
+ */
int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
rip->version_send : ri->ri_send);

@@ -2358,12 +2429,14 @@
if (ifaddr->family != AF_INET)
continue;

- rip_interface_multicast_set(rip->sock, connected,
- if_is_pointopoint(ifp));
- if (vsend & RIPv1)
- rip_update_interface (ifp, RIPv1, route_type, ifaddr);
- if (vsend & RIPv2)
- rip_update_interface (ifp, RIPv2, route_type, ifaddr);
+ if ((vsend & RIPv1) && !done)
+ rip_update_interface (ifp, RIPv1, route_type, connected);
+ if ((vsend & RIPv2) && if_is_multicast(ifp))
+ rip_update_interface (ifp, RIPv2, route_type, connected);
+ done = 1;
+ if (!(vsend & RIPv2) || !if_is_multicast(ifp))
+ break;
+
}
}
}
@@ -2388,7 +2461,8 @@
to.sin_port = htons (RIP_PORT_DEFAULT);

/* RIP version is rip's configuration. */
- rip_output_process (ifp, NULL, &to, route_type, rip->version_send, p);
+ rip_output_process (ifp, NULL, &to, route_type, rip->version_send,
+ NULL, p);
}
}

@@ -2564,12 +2638,11 @@
/* Sned RIP request to the destination. */
int
rip_request_send (struct sockaddr_in *to, struct interface *ifp,
- u_char version)
+ u_char version, struct connected *connected)
{
struct rte *rte;
struct rip_packet rip_packet;
listnode node;
- struct connected *connected;

memset (&rip_packet, 0, sizeof (rip_packet));

@@ -2578,6 +2651,20 @@
rte = rip_packet.rte;
rte->metric = htonl (RIP_METRIC_INFINITY);

+ if (connected)
+ {
+ /*
+ * connected is only sent for ripv1 case, or when
+ * interface does not support multicast. Caller loops
+ * over each connected address for this case.
+ */
+ if (rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet),
+ to, ifp, connected) != sizeof (rip_packet))
+ return -1;
+ else
+ return sizeof (rip_packet);
+ }
+
/* send request on each connected network */
LIST_LOOP(ifp->connected, connected, node)
{
@@ -2588,10 +2675,8 @@
if (p->family != AF_INET)
continue;

- rip_interface_multicast_set(rip->sock, connected,
- if_is_pointopoint(ifp));
if (rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet),
- to, ifp) != sizeof (rip_packet))
+ to, ifp, connected) != sizeof (rip_packet))
return -1;
}
return sizeof (rip_packet);
===================================================================
RCS file: ripd.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -uwb -r1.8 -r1.9
--- /tmp/T0a4aafj Wed Jan 21 12:27:22 2004
+++ /tmp/T1b4aafj Wed Jan 21 12:27:22 2004
@@ -377,7 +377,8 @@
int if_check_address (struct in_addr addr);
int if_valid_neighbor (struct in_addr addr);

-int rip_request_send (struct sockaddr_in *, struct interface *, u_char);
+int rip_request_send (struct sockaddr_in *, struct interface *, u_char,
+ struct connected *);
int rip_neighbor_lookup (struct sockaddr_in *);
void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int,
struct in_addr *);
Re: ripd fixes [was Re: ripd status] [ In reply to ]
+ rip_interface_multicast_set(send_sock, connected, if_is_pointopoint(ifp));

I would think that these send-only temp socket should not bind to
router/udp, but rip_interface_multicast_set does that.

I've also fixed indenting as appropriate, though (on Paul's request)
the -uwb flags to rcsdiff doesn't list all the white-space fixes.

My own opinion, FWIW is that diffs should not make gratuitous
whitespace changes, but should make changes like indenting stuff now
within an if that wasn't before.

This can be done with -wb, but my preference is to not use those
options, avoid making unintened changes, and run cvs diff repeatedly
cleaning them up in the working copying before submitting. I find
that after getting used to being careful this is very little to no
work. The advantage is that it allows needed whitespace changes to be
made, following the notion that correctly-indented code before a
patch should remain correctly indented afterwards.

Wholesale whitespace cleanups (arguably needed in this case since the
code is messy whitespace-wise) should be committed with no other
changes. This enables someone reading all the diffs (e.g. with the
help of cvsps) to omit whitespace-only diffs, since they are hard to
read.

So in this case the -wb bit is not important, since after this patch
goes in one of us should just reindent the file; right now it is hard
to read.
Re: ripd fixes [was Re: ripd status] [ In reply to ]
And I meant to say: other than the bit about binding to router/udp and
this below, it looked ok, but I didn't really look hard.

+ if (connected->flags & ZEBRA_IFA_SECONDARY)
+ {
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_info("duplicate dropped");
+ return 0;
+ }

A comment referring to the rip spec would be nice here. I suspect
that on non-Linux systems that the behavior will be different, since
ZEBRA_IFA_SECONDARY isn't set at the moment for subsequent addrs in a
prefix.
Re: ripd fixes [was Re: ripd status] [ In reply to ]
>
> + if (connected->flags & ZEBRA_IFA_SECONDARY)
> + {
> + if (IS_RIP_DEBUG_PACKET)
> + zlog_info("duplicate dropped");
> + return 0;
> + }
>
> A comment referring to the rip spec would be nice here. I suspect
> that on non-Linux systems that the behavior will be different, since
> ZEBRA_IFA_SECONDARY isn't set at the moment for subsequent addrs in a
> prefix.

Actually, I'm not really sure (I'll re-check) that the RIP spec
mandates anything here. The ZEBRA_IFA_SECONDARY is the common-sense
way to play with other RIPpers on the link (don't try to pretend
to be N nodes, just because you happen to be hogging N addresses on
that subnet), but I don't think it's a violation of the spec to
send the packet either.

As I said, I'll recheck.

--Sowmini
Re: ripd fixes [was Re: ripd status] [ In reply to ]
Actually, I'm not really sure (I'll re-check) that the RIP spec
mandates anything here. The ZEBRA_IFA_SECONDARY is the common-sense
way to play with other RIPpers on the link (don't try to pretend
to be N nodes, just because you happen to be hogging N addresses on
that subnet), but I don't think it's a violation of the spec to
send the packet either.

OK, well that belongs in a comment; it is certainly non-obvious what's
going on.
Re: ripd fixes [was Re: ripd status] [ In reply to ]
>
> Actually, I'm not really sure (I'll re-check) that the RIP spec
> mandates anything here. The ZEBRA_IFA_SECONDARY is the common-sense
> way to play with other RIPpers on the link (don't try to pretend
> to be N nodes, just because you happen to be hogging N addresses on
> that subnet), but I don't think it's a violation of the spec to
> send the packet either.
>
> OK, well that belongs in a comment; it is certainly non-obvious what's
> going on.
>

Ok, here goes:
---------------------------------------------------------------------------
The changes are:

- rip_interface.c: obsolete unbind code in rip_interface_multicast_set,
and instead do the more portable (though slower) method of creating a
socket for each outgoing packet and binding the source address on the
new socket.
- rip_interface.c, ripd.c, ripd.h: Modify rip_request_send so that source
address is determined by the caller of rip_request_send for
ripv1 packets and non-multicast interfaces (rip_request_send loops
over all connected address in all other cases).
- ripd.c/rip_send_packet: don't send packets with source set to
ZEBRA_IFA_SECONDARY connected addresses; improved debug messages;


===================================================================
RCS file: ripd.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -uwb -r1.13 -r1.14
--- /tmp/T0VEWkgj Wed Jan 21 14:11:02 2004
+++ /tmp/T1WEWkgj Wed Jan 21 14:11:02 2004
@@ -61,7 +61,7 @@

void rip_output_process (struct interface *, struct prefix *,
struct sockaddr_in *, int, u_char,
- struct prefix_ipv4 *);
+ struct connected *, struct prefix_ipv4 *);

/* RIP output routes type. */
enum
@@ -1235,11 +1235,44 @@
/* RIP packet send to destination address. */
int
rip_send_packet (caddr_t buf, int size, struct sockaddr_in *to,
- struct interface *ifp)
+ struct interface *ifp, struct connected *connected)
{
- int ret;
+ int ret, send_sock;
struct sockaddr_in sin;

+ if (IS_RIP_DEBUG_PACKET)
+ {
+ char dst[20];
+ if (to)
+ {
+ strcpy(dst, inet_ntoa(to->sin_addr));
+ }
+ else
+ {
+ sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
+ strcpy(dst, inet_ntoa(sin.sin_addr));
+ }
+ zlog_info("rip_send_packet %s > %s (%s)",
+ inet_ntoa(connected->address->u.prefix4), dst, ifp->name);
+ }
+ if (connected->flags & ZEBRA_IFA_SECONDARY)
+ {
+ /*
+ * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
+ * with multiple addresses on the same subnet: the first address
+ * on the subnet is configured "primary", and all subsequent addresses
+ * on that subnet are treated as "secondary" addresses.
+ * In order to avoid routing-table bloat on other rip listeners,
+ * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
+ * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
+ * flag is set, we would end up sending a packet for a "secondary"
+ * source address on non-linux systems.
+ */
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_info("duplicate dropped");
+ return 0;
+ }
+
/* Make destination address. */
memset (&sin, 0, sizeof (struct sockaddr_in));
sin.sin_family = AF_INET;
@@ -1252,6 +1285,7 @@
{
sin.sin_port = to->sin_port;
sin.sin_addr = to->sin_addr;
+ send_sock = rip->sock;
}
else
{
@@ -1259,11 +1293,28 @@
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 for each packet.
+ */
+ send_sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (send_sock < 0)
+ {
+ zlog_warn("rip_send_packet 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, connected, if_is_pointopoint(ifp));
+ }

- 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 +1324,9 @@
if (ret < 0)
zlog_warn ("can't send packet : %s", strerror (errno));

+ if (!to)
+ close(send_sock);
+
return ret;
}

@@ -1456,7 +1510,7 @@

/* All route with split horizon */
rip_output_process (ifp, NULL, from, rip_all_route, packet->version,
- &saddr);
+ NULL, &saddr);
}
else
{
@@ -1488,7 +1542,7 @@
}
packet->command = RIP_RESPONSE;

- rip_send_packet ((caddr_t) packet, size, from, ifp);
+ rip_send_packet ((caddr_t) packet, size, from, ifp, NULL);
}
rip_global_queries++;
}
@@ -1983,7 +2037,7 @@
void
rip_output_process (struct interface *ifp, struct prefix *ifaddr,
struct sockaddr_in *to, int route_type, u_char version,
- struct prefix_ipv4 *saddr)
+ struct connected *connected, struct prefix_ipv4 *saddr)
{
int ret;
struct stream *s;
@@ -2243,7 +2297,7 @@
rip_auth_md5_set (s, ifp);

ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
- to, ifp);
+ to, ifp, connected);

if (ret >= 0 && IS_RIP_DEBUG_SEND)
rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
@@ -2259,7 +2313,8 @@
if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
rip_auth_md5_set (s, ifp);

- ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifp);
+ ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifp,
+ connected);

if (ret >= 0 && IS_RIP_DEBUG_SEND)
rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
@@ -2275,12 +2330,13 @@
/* Send RIP packet to the interface. */
void
rip_update_interface (struct interface *ifp, u_char version, int route_type,
- struct prefix_ipv4 *saddr)
+ struct connected *sconn)
{
struct prefix_ipv4 *p;
struct connected *connected;
listnode node;
struct sockaddr_in to;
+ struct prefix_ipv4 *saddr = (struct prefix_ipv4 *) sconn->address;

/* When RIP version is 2 and multicast enable interface. */
if (version == RIPv2 && if_is_multicast (ifp))
@@ -2289,7 +2345,7 @@
zlog_info ("multicast announce on %s ", ifp->name);

rip_output_process (ifp, NULL, NULL, route_type, rip->version_send,
- saddr);
+ sconn, saddr);
return;
}

@@ -2317,7 +2373,7 @@
inet_ntoa (to.sin_addr), ifp->name);

rip_output_process (ifp, connected->address, &to, route_type,
- rip->version_send, saddr);
+ rip->version_send, connected, saddr);
}
}
}
@@ -2371,10 +2427,11 @@
LIST_LOOP(ifp->connected, connected, ifnode)
{
struct prefix_ipv4 *ifaddr;
-
-
- /* If there is no version configuration in the interface,
- use rip's version setting. */
+ int done = 0;
+ /*
+ * If there is no version configuration in the interface,
+ * use rip's version setting.
+ */
int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
rip->version_send : ri->ri_send);

@@ -2383,12 +2440,14 @@
if (ifaddr->family != AF_INET)
continue;

- rip_interface_multicast_set(rip->sock, connected,
- if_is_pointopoint(ifp));
- if (vsend & RIPv1)
- rip_update_interface (ifp, RIPv1, route_type, ifaddr);
- if (vsend & RIPv2)
- rip_update_interface (ifp, RIPv2, route_type, ifaddr);
+ if ((vsend & RIPv1) && !done)
+ rip_update_interface (ifp, RIPv1, route_type, connected);
+ if ((vsend & RIPv2) && if_is_multicast(ifp))
+ rip_update_interface (ifp, RIPv2, route_type, connected);
+ done = 1;
+ if (!(vsend & RIPv2) || !if_is_multicast(ifp))
+ break;
+
}
}
}
@@ -2413,7 +2472,8 @@
to.sin_port = htons (RIP_PORT_DEFAULT);

/* RIP version is rip's configuration. */
- rip_output_process (ifp, NULL, &to, route_type, rip->version_send, p);
+ rip_output_process (ifp, NULL, &to, route_type, rip->version_send,
+ NULL, p);
}
}

@@ -2589,12 +2649,11 @@
/* Sned RIP request to the destination. */
int
rip_request_send (struct sockaddr_in *to, struct interface *ifp,
- u_char version)
+ u_char version, struct connected *connected)
{
struct rte *rte;
struct rip_packet rip_packet;
listnode node;
- struct connected *connected;

memset (&rip_packet, 0, sizeof (rip_packet));

@@ -2603,6 +2662,20 @@
rte = rip_packet.rte;
rte->metric = htonl (RIP_METRIC_INFINITY);

+ if (connected)
+ {
+ /*
+ * connected is only sent for ripv1 case, or when
+ * interface does not support multicast. Caller loops
+ * over each connected address for this case.
+ */
+ if (rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet),
+ to, ifp, connected) != sizeof (rip_packet))
+ return -1;
+ else
+ return sizeof (rip_packet);
+ }
+
/* send request on each connected network */
LIST_LOOP(ifp->connected, connected, node)
{
@@ -2613,10 +2686,8 @@
if (p->family != AF_INET)
continue;

- rip_interface_multicast_set(rip->sock, connected,
- if_is_pointopoint(ifp));
if (rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet),
- to, ifp) != sizeof (rip_packet))
+ to, ifp, connected) != sizeof (rip_packet))
return -1;
}
return sizeof (rip_packet);
===================================================================
RCS file: rip_interface.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -uwb -r1.13 -r1.14
--- /tmp/T0HgWngj Wed Jan 21 14:12:18 2004
+++ /tmp/T1IgWngj Wed Jan 21 14:12:18 2004
@@ -146,16 +146,20 @@
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)
+ if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF, addr, 0, 0) < 0)
{
zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock);
return;
@@ -171,8 +175,9 @@
else
from.sin_port = htons (RIP_PORT_DEFAULT);

- /* Address shoud be any address. */
+ /* Address should be any address. */
from.sin_family = AF_INET;
+ if (connected)
addr = ((struct prefix_ipv4 *) connected->address)->prefix;
from.sin_addr = addr;
#ifdef HAVE_SIN_LEN
@@ -182,7 +187,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)
{
@@ -209,7 +213,7 @@
if (IS_RIP_DEBUG_EVENT)
zlog_info ("multicast request on %s", ifp->name);

- rip_request_send (NULL, ifp, version);
+ rip_request_send (NULL, ifp, version, NULL);
return;
}

@@ -238,7 +242,7 @@
if (IS_RIP_DEBUG_EVENT)
zlog_info ("SEND request to %s", inet_ntoa (to.sin_addr));

- rip_request_send (&to, ifp, version);
+ rip_request_send (&to, ifp, version, connected);
}
}
}
@@ -284,7 +288,7 @@
to.sin_port = htons (RIP_PORT_DEFAULT);
to.sin_addr = addr;

- rip_request_send (&to, NULL, rip->version_send);
+ rip_request_send (&to, NULL, rip->version_send, NULL);
}

/* Request routes at all interfaces. */
===================================================================
RCS file: ripd.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -uwb -r1.8 -r1.9
--- /tmp/T0_RWpgj Wed Jan 21 14:12:49 2004
+++ /tmp/T1aSWpgj Wed Jan 21 14:12:49 2004
@@ -377,7 +377,8 @@
int if_check_address (struct in_addr addr);
int if_valid_neighbor (struct in_addr addr);

-int rip_request_send (struct sockaddr_in *, struct interface *, u_char);
+int rip_request_send (struct sockaddr_in *, struct interface *, u_char,
+ struct connected *);
int rip_neighbor_lookup (struct sockaddr_in *);
void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int,
struct in_addr *);
Re: ripd fixes [was Re: ripd status] [ In reply to ]
On Wed, 21 Jan 2004, Greg Troxel wrote:

> And I meant to say: other than the bit about binding to router/udp and
> this below, it looked ok, but I didn't really look hard.
>
> + if (connected->flags & ZEBRA_IFA_SECONDARY)
> + {
> + if (IS_RIP_DEBUG_PACKET)
> + zlog_info("duplicate dropped");
> + return 0;
> + }
>
> A comment referring to the rip spec would be nice here. I suspect
> that on non-Linux systems that the behavior will be different, since
> ZEBRA_IFA_SECONDARY isn't set at the moment for subsequent addrs in a
> prefix.

Right, but Gilad is currently cooking up a patch to make zebra add
that flag even if kernel doesnt pass on equivalent information.

regards,
--
Paul Jakma paul@clubi.ie paul@jakma.org Key ID: 64A2FF6A
warning: do not ever send email to spam@dishone.st
Fortune:
Corruption is not the #1 priority of the Police Commissioner. His job
is to enforce the law and fight crime.
-- P.B.A. President E. J. Kiernan
Re: ripd fixes [was Re: ripd status] [ In reply to ]
> > A comment referring to the rip spec would be nice here. I suspect
> > that on non-Linux systems that the behavior will be different, since
> > ZEBRA_IFA_SECONDARY isn't set at the moment for subsequent addrs in a
> > prefix.
>
> Right, but Gilad is currently cooking up a patch to make zebra add
> that flag even if kernel doesnt pass on equivalent information.

If you look at the patch, I put in an XXX saying that the behavior
wouldl be different on non-linux systems because ZEBRA_IFA_SECONDARY is
currently not set for these guys. The XXX comment can be deleted
after Gilad's patch is done.

--Sowmini
Re: ripd fixes [was Re: ripd status] [ In reply to ]
On Wed, 21 Jan 2004 sowmini.varadhan@sun.com wrote:

> Ok, here goes:
> ---------------------------------------------------------------------------
> The changes are:
>
> - rip_interface.c: obsolete unbind code in rip_interface_multicast_set,
> and instead do the more portable (though slower) method of creating a
> socket for each outgoing packet and binding the source address on the
> new socket.

I'd dispute that :)

> ===================================================================
> RCS file: ripd.c,v
> retrieving revision 1.13
> retrieving revision 1.14
> diff -uwb -r1.13 -r1.14
> --- /tmp/T0VEWkgj Wed Jan 21 14:11:02 2004
> +++ /tmp/T1WEWkgj Wed Jan 21 14:11:02 2004

Strange file names....

regards,
--
Paul Jakma paul@clubi.ie paul@jakma.org Key ID: 64A2FF6A
warning: do not ever send email to spam@dishone.st
Fortune:
Let's organize this thing and take all the fun out of it.